Live Steam concurrent players and discounts at a glance in a bubble map — a discovery tool combining popularity and purchase signals
Translation pending
CommerceGitHub @ZunaTtangOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗스팀 게임의 동접(인기 신호) × 할인(구매 신호) 을 결합한 다국어 발견 도구. 프로젝트의 모든 결정사항·제약은 CLAUDE.md가 단일 기준 문서입니다.
🟢 라이브: https://steambubbles.vercel.app (프로덕션 · ko + en 오픈)
ko(기본) + en 오픈. ja/zh·유럽어는 동결(트리거 대기).ALERT_WEBHOOK_URL 환경변수), Google Search Console 등록 + 색인 요청(브랜드·파비콘 반영 확인 겸 ko 노출 추이 계기판), 애드센스 신청(유입 축적 후). (Vercel Web Analytics는 활성 확인됨.)| 영역 | 선택 |
|---|---|
| 프레임워크 | Next.js 15 (App Router) + TypeScript |
| 스타일 | Tailwind CSS v4 |
| i18n | next-intl — /ko·/en 오픈 (구조는 ja/zh·유럽어 확장 대비) |
| DB | Neon Postgres (serverless) + Drizzle ORM |
| 수집 트리거 | Upstash QStash → /api/cron/* Route Handler |
| 시각화 | d3-force + PixiJS (Canvas/WebGL) |
| 배포 | Vercel (프로덕션 빌드는 webpack) |
npm install
DATABASE_URL이 없으면 자동으로 목업 데이터 모드로 동작합니다 (1,000개 게임 fixture, src/mocks/games.json). 실제 키 없이 npm run dev만으로 전체 UI를 확인할 수 있고, 화면 하단에 "목업 데이터 모드" 뱃지가 표시됩니다. 실데이터 전환은 .env에 값을 채우는 것만으로 이뤄집니다.
.env.example을 .env로 복사한 뒤 값을 채웁니다.
cp .env.example .env
| 변수 | 설명 | 발급처 |
|---|---|---|
DATABASE_URL | Neon Postgres 연결 문자열. 비우면 목업 모드 | https://console.neon.tech |
USE_MOCK_DATA | 1이면 DATABASE_URL이 있어도 목업 모드 강제 (선택) | — |
STEAM_API_KEY | Steam Web API 키 (일 10만 콜 예산) | https://steamcommunity.com/dev/apikey |
CRON_SECRET | /api/cron/* Bearer 인증용 랜덤 문자열 | 직접 생성 |
QSTASH_TOKEN | QStash 스케줄·체이닝 토큰 | https://console.upstash.com/qstash |
QSTASH_URL | QStash 지역 엔드포인트 (예: https://qstash-us-east-1.upstash.io) — SDK baseUrl에 필수 | 위 콘솔 |
SITE_URL | QStash 체이닝 콜백용 베이스 URL (배포 시) | — |
ALERT_WEBHOOK_URL | 데드맨스위치·서킷브레이커 알림용 Discord 웹훅 | 개인 Discord 서버 |
npm run db:push # 개발 초기: 스키마를 Neon에 직접 반영
# 또는 마이그레이션 기반:
npm run db:generate # ./drizzle 에 SQL 마이그레이션 생성
npm run db:migrate # 마이그레이션 적용
npm run dev
http://localhost:3000 접속 시 브라우저 언어에 따라 /ko 또는 /en으로 리다이렉트됩니다.
| 명령 | 설명 |
|---|---|
npm run dev | 개발 서버 (Turbopack) |
npm run build | 프로덕션 빌드 |
npm run lint | ESLint |
npm run db:push | Drizzle 스키마를 DB에 직접 반영 |
npm run db:generate / db:migrate | 마이그레이션 생성 / 적용 |
npm run db:studio | Drizzle Studio (DB 브라우저) |
node scripts/generate-mock-games.mjs | 목업 게임 fixture 재생성 (결정론적 시드) |
src/
app/[locale]/ # 로케일 라우팅 (ko·en) — 버블맵 홈 · game/[appid] 상세 · about · privacy
app/sitemap.ts # 동적 sitemap (홈+정적+게임, 로케일별) app/robots.ts
app/api/bubbles/ # 버블맵 스냅샷 API (기간·통화별) app/api/trend/ 게임별 추이 API
app/api/cron/ # players-tier1(10분) · players-tier2(30분) · players-tier3(3시간) · details · universe · maintenance · healthcheck
components/bubble-map/ # PixiJS + d3-force 버블맵 렌더러 (탭=선택 / 드래그=버블 이동 / hover=툴팁)
components/app/ # 상단 바(언어·통화·필터), 모달, 랭킹 테이블, 앱 셸
lib/ # types(계약), fetch-util(백오프+서킷브레이커), circuit(DB 지속화), steam, format, site
lib/data/ # 데이터 프로바이더 — index(스위치) / mock / db
mocks/ # 목업 fixture (games.json 1,000개, genres.json)
i18n/ # 로케일·통화 정책 (locales.ts — OPEN_LOCALES), 라우팅, 요청 설정
db/ # Drizzle 스키마(schema.ts) + Neon 클라이언트
middleware.ts # next-intl 로케일 미들웨어 (언어 감지)
messages/ # UI 문자열 사전 — ko.json / en.json
drizzle/ # 생성된 SQL 마이그레이션
scripts/ # 목업 fixture 생성기
각 Phase 완료 시 프로덕션 배포. 상세 기준은 CLAUDE.md 6번, Phase별 체크리스트는 GitHub 이슈로 추적. Phase 1~5 전부 라이브 — Launch 슬라이스 완료 (노출 우선 전략으로 Phase 4를 3보다 먼저 진행).
job_runsplayers-tier1 수집 + 데드맨스위치 헬스체크 핸들러ALERT_WEBHOOK_URL) → 중단 알림 활성화cubic-bezier(0.23,1,0.32,1)) · 버튼 press 피드백(active scale) · @starting-style + reduced-motion 분기. 버블맵 캔버스는 성능상 제외GetGamesByConcurrentPlayers 실테스트(→ Tier 1 1콜 최적화) · CLAUDE.md 기록/[locale]/game/[id] — 게임 소개(Steam short_description, 로케일별) + 데이터 대시보드(현재 동접 히어로·24h 피크·순위·스팀 점유율·가격/할인·평점 긍정률 바·출시일) + 추이·장르·Steam 링크. 동접 수치는 줄글 대신 데이터로 (소개 미수집 시 순위·평점·가격 폴백 문장)short_description·release_date 파싱 추가(추가 API 콜 0) → apps.desc_ko/desc_en/release_date. HTML 엔티티·태그 정리(수집·렌더 양쪽)router.back() 위치·스크롤 복원 / SEO 직접 유입=홈 push)/[locale]/og 동적 OG 이미지 — next/og로 top 7 동접 리더보드(1200×630) + 홈 openGraph/twitter 연결<Analytics/> — 배포 환경 수집)Phase 1~5 라이브 이후 추가된 증분. 전부 프로덕션 반영됨. 세 해자(ko SEO · 히스토리 · 공유 포맷)에 기여하는 것만.
/[locale]/og/movers, next/og 1200×630) — 순위 · 게임 썸네일(서버 프리페치 → data URI, 실패 시 이니셜 폴백으로 우아한 강등) · Δ · 동접. 공유 버튼은 이미지 미리보기 모달로 열려 다운로드 · 복사 · Web Share 제공(모바일)/api/refresh/[appid]). 3중 게이트(추적 대상만 · 6h 쿨다운 · store 서킷브레이커)로 남용/과금 방지 — "본 만큼 신선". 수집 로직은 details 크론과 lib/collect.ts 공용[1, 3000] clamp · 뒤집힘 정규화 · max>1,000이면 deep 스냅샷 승급). 스팬 상한은 전체 3,000까지 허용/icon 라우트를 로케일 리다이렉트로 깨뜨리던 버그 수정ja/zh·유럽어는 동결 (트리거 대기)ja/zh 로케일, 유럽어, 세일 감지 트리거, Tier 3 sitemap 등재, 수익화 전체. (Tier 3 수집·표시는 2026-07 오픈됨) 해제 트리거는 CLAUDE.md 8번 참조.