BeamNG.Earth
BeamNG.drive용 1:1 비율 실시간 지구, 실제 고도·위성 이미지·부동 원점·보조 서버에서 LOD 스트리밍
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
gamearound
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
게임 가격, 플레이타임, 평점, 뉴스를 한 곳에서 보여주고 플랫폼별 할인 웹푸시를 보내는 서비스. 설계 근거: docs/손전등_개발설계서.md (MVP 범위만 구현). Next.js 16 App Router | TypeScript | Drizzle ORM | Neon Postgres | 자체 세션 인증(scrypt + DB 세션) | Upstash Redis | web-push | GitHub Actions 크롤러 | Vercel 레포 루트가 곧 앱 루트다. 설계, 기획 산출물은 docs/ 에 있다. • 계층 규칙: route → service → adapter | db, DB 쓰기는 sync/ 에서만. 자세한 규약은 AGENTS.md • src/proxy.ts 세션 쿠키 유무로 보호 경로 리다이렉트 (Next 16에서 middleware → proxy). role은 각 layout/action에서 재검증 • src/lib/routes.ts 경로 상수 + safeNextPath(오픈 리다이렉트 방지) • src/lib/site.ts 서비스 이름, 설명, 테마색, 크롤러 UA 단일 소스README 전문 보기 ↗
게임 가격, 플레이타임, 평점, 뉴스를 한 곳에서 보여주고 플랫폼별 할인 웹푸시를 보내는 서비스.
설계 근거: docs/손전등_개발설계서.md (MVP 범위만 구현).
Next.js 16 App Router | TypeScript | Drizzle ORM | Neon Postgres | 자체 세션 인증(scrypt + DB 세션) | Upstash Redis | web-push | GitHub Actions 크롤러 | Vercel
pnpm install
cp .env.example .env.local # 값 채우기
pnpm db:migrate # Neon에 마이그레이션 적용 (pg_trgm 포함)
pnpm seed # Steam 상위 N개 시드 (scripts/seed.ts)
pnpm dev
| 명령 | 설명 |
|---|---|
pnpm dev / pnpm build / pnpm start | Next.js |
pnpm typecheck / pnpm lint / pnpm test | 검증 |
pnpm e2e:auth | 인증 E2E (dev 서버 필요, 가입→로그인→보호경로→로그아웃, e2e 계정 자동 삭제) |
pnpm db:generate | 스키마 변경 → 마이그레이션 SQL 생성 |
pnpm db:migrate | 마이그레이션 적용 |
pnpm crawl -- --source=steam [--limit=N] [--seed-top=N] | 소스별 수집 (GitHub Actions와 동일 진입점) |
레포 루트가 곧 앱 루트다. 설계, 기획 산출물은 docs/ 에 있다.
src/
app/ 라우트 — (public) 홈, 검색, 목록, 상세, 가격그래프 / (auth) 로그인, 가입 / (user) 위시리스트, 알림, 설정 / (admin) 동기화, 검수, 정정 / api
components/ 화면 컴포넌트, ui/ 는 공용 프리미티브(Button, Chip, Page/Card, 입력)
lib/ 순수 유틸 — site(브랜드) | routes | cache | format | slug | games-query | motion | async | errors
server/
db/ Drizzle 스키마, 클라이언트, 마이그레이션
services/ 비즈니스 로직. games/ 는 dto, mappers, home, search, list, detail 로 나뉜다
adapters/ 소스별 수집기(가져오기만). http.ts 가 공통 HTTP 계층, steam/ 은 constants, schemas, parse, index
sync/ 수집 결과 DB 반영 — constants, context, retry, store-targets, store-fetch, game-writer, platform-writer, run-store, run-meta, run-news, revalidate, run-source
auth/ push/ redis 세션, 웹푸시, 락
scripts/ crawl.ts(GitHub Actions 진입점) | seed.ts
.github/workflows/ 크롤 스케줄 (레포 루트에 있어야 실행된다)
docs/ 기획서, 개발설계서, 리디자인 스펙
route → service → adapter | db, DB 쓰기는 sync/ 에서만. 자세한 규약은 AGENTS.mdsrc/proxy.ts 세션 쿠키 유무로 보호 경로 리다이렉트 (Next 16에서 middleware → proxy). role은 각 layout/action에서 재검증src/lib/routes.ts 경로 상수 + safeNextPath(오픈 리다이렉트 방지)src/lib/site.ts 서비스 이름, 설명, 테마색, 크롤러 UA 단일 소스scrypt(N=16384) 해시, 형식 scrypt$N$r$p$salt$hash로 알고리즘 교체 가능sjd_session, httpOnly/secure/lax)에 랜덤 토큰, DB sessions엔 sha256 해시. 30일 슬라이딩, 만료분은 daily cron이 정리SessionProvider가 /api/auth/me로 가져온다 — 루트 레이아웃에서 cookies()를 읽으면 홈 풀 라우트 캐시가 깨지기 때문users.passwordHash는 nullable(OAuth 전용 계정), provider 연결은 auth_accounts 테이블 추가로 대응DATABASE_URLADMIN_EMAILS에 관리자 이메일 등록 (가입/로그인 시 admin 승격)pnpm dlx web-push generate-vapid-keys → VAPID 3종CRAWL_SECRET, CRON_SECRET 임의 문자열vercel.json cron 자동 반영ADMIN_EMAILS 환경변수 또는 DB users.role 직접 수정| 항목 | 현재 가정 |
|---|---|
| 초기 카탈로그 범위 | Steam 인기/할인 상위 N개 시드 (--seed-top) |
| 가격 기준 | 한국 스토어 KRW만 |
| 한글 제목 | Steam 한국어 페이지, 없으면 영문 그대로 |
| 뉴스 RSS | 어댑터 상단 상수 목록 (교체 필요) |
| 평점 우선순위 | OpenCritic 1순위, Metacritic은 스텁 |
| 플랫폼 세분화 | PS4/PS5, Switch/Switch2 분리 |
| 멀티플레이 출처 | Steam 카테고리 태그 + 관리자 정정 |
| 정정 잠금 | 관리자가 해제할 때까지 영구 잠금 |
| 크롤 주기 (설계서 §4.3 이탈) | prices 하루 3회(KST 02:10/10:10/18:10), news 6h, meta 격일 ≈ 월 1,470분. 설계서는 prices 4h, news 1h(≈3,900분)이나 private 레포 Actions 무료 2,000분을 초과한다. 뉴스, 가격 모두 시간 단위 변동이 거의 없어 주기를 늘리는 대신, prices 실행 시각을 Steam 할인 전환 시각(KST 02:00) 직후로 고정해 할인 감지 지연을 8시간 → 10분으로 줄였다. public 전환(Actions 무제한)은 현재 불필요 |
미매칭(matched_by="none") 재시도 | game_source_refs.checked_at 기준 NONE_RETRY_DAYS(14일) 경과 행만 재검색 |
| HLTB 검색 UA (설계서 §10 이탈) | HLTB /api/search/site/init 이 봇 UA 에 403 을 주므로 검색 경로에서만 브라우저 UA(HLTB_SEARCH_USER_AGENT)를 쓴다. 게임 페이지 조회는 CRAWLER_USER_AGENT 유지. init 토큰에 UA 가 포함돼 init/search UA 가 같아야 함 |
| 할인 기간, 행사명 | 스토어가 주는 만큼만 저장한다. Steam=IStoreBrowseService/GetItems 의 active_discounts(종료 시각 + #discount_desc_* 토큰 → 한국어 라벨, 모르는 토큰은 표시 안 함), Xbox=Availability.Conditions 시작, 종료(상시 판매 센티널 9998년은 버림). PS Store, Nintendo 는 미지원 |
| HLTB 플레이타임 0 | comp_main/plus/100 이 전부 0 이면 "제보 없음"으로 보고 전부 null 을 정상 반환한다(에러 아님). 에러로 처리하면 해당 게임이 매 배치마다 재시도돼 sync_logs 가 계속 partial 이 된다 |
| 가격 그래프 표시 | 가격은 변동 시점만 기록되므로 차트는 마지막 기록 → 지금까지 수평으로 잇고, 진행 중 할인은 음영 + 종료선으로 표시한다. 미래 가격은 그리지 않는다 |