계정·클라우드 세이브
아카데미 메타 진행(허브, 도감, 공적, 시길 등)을 Supabase Auth + player_saves 에 동기화합니다. 시련 중 런 상태는 기존처럼 세션 메모리이며, 런 종료 후 메타만 저장됩니다.
흐름 (테트리오식)
- 타이틀에서 플레이어 ID + 비밀번호로 로그인 또는 계정 만들기
- 플레이어 ID는
3~16자, 영문 소문자로 시작,a-z/0-9/_만 허용 - Supabase에는 내부 이메일
{player_id}@player.chaosforge로 저장 (실제 메일 발송 없음) syncAccountSaveForUser— 로컬 캐시와 원격savedAtMs비교 후 최신본 적용- 게임 중
accountStore변경 → 로컬cf_account[:userId]+ debounced cloud push (upsert_player_saveRPC)
Supabase env가 없으면(VITE_SUPABASE_* 미설정) 기존처럼 로컬 전용 cf_account만 사용합니다.
Supabase 설정 (1회)
1. 이메일/비밀번호 로그인 켜기
대시보드: Authentication → Providers → Email
| 설정 | 값 |
|---|---|
| Enable Email provider | ON |
| Confirm email | OFF (필수 — @player.chaosforge 는 실제 메일이 없음) |
Confirm email 이 켜져 있으면 가입은 되어도 로그인이 Invalid login credentials 로 실패합니다.
또는 스크립트 (Management API — mailer_autoconfirm: true):
SUPABASE_ACCESS_TOKEN=sbp_… pnpm supabase:auth-email
SUPABASE_ACCESS_TOKEN: Supabase 대시보드 → Account → Access Tokens (sbp_…, 프로젝트 secret key 아님).
2. DB 마이그레이션
pnpm db:apply-migrations
supabase/migrations/20260711210000_player_saves.sql — auth.users 행당 세이브 1개.
supabase/migrations/20260716130000_player_sessions.sql — auth.users 행당 활성 session_id 1개(단일 기기 로그인). 클라이언트가 claim/heartbeat로 upsert·조회하며, RLS로 본인 행만 접근합니다. 상세: SINGLE_SESSION_PLAN.md.
supabase/migrations/20260717160000_player_save_revisions.sql — 클라우드 upsert는 upsert_player_save RPC 경유. 성공 10회마다 player_save_revisions 스냅샷(reason=stack), 전투 직전·직후는 battle_pre/battle_post, 유저당 최근 20건만 유지. sparse가 rich를 덮으려 하면 적용 거부·자동 복구(restored: true). Admin 보드 Player currencies 탭에서 revision 목록(meta) 조회·수동 복구(POST /admin/players/:userId/revisions/:revisionId/restore). 통화 패치 시 현재 본문은 admin_patch revision으로 남김. 상세: PLAYER_SAVE_HISTORY_PLAN.md.
3. 클라이언트 env
packages/client/.env:
VITE_SUPABASE_URL=https://….supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=eyJ…
동작 확인
계정 만들기 (내부 이메일):
curl -s -X POST "$VITE_SUPABASE_URL/auth/v1/signup" \
-H "apikey: $VITE_SUPABASE_PUBLISHABLE_KEY" \
-H "Authorization: Bearer $VITE_SUPABASE_PUBLISHABLE_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"testplayer@player.chaosforge","password":"secret12","data":{"username":"testplayer"}}'
signup_disabled / email signups are disabled → §1 Email provider 미설정.
로그인 후 세션이 없고 confirm 메일 안내가 나오면 Confirm email 이 아직 켜져 있는 것.
관련 코드
| 경로 | 역할 |
|---|---|
packages/client/src/auth/playerCredentials.ts |
플레이어 ID 규칙·내부 이메일 매핑 |
packages/client/src/auth/supabaseAuth.ts |
Auth 클라이언트·프로필 |
packages/client/src/auth/playerSave.ts |
pull/merge/push |
packages/client/src/auth/playerSession.ts |
기기 단일 세션 claim/heartbeat |
packages/client/src/auth/tabLeader.ts |
동일 origin 탭 리더(BroadcastChannel) |
public.player_sessions (Supabase) |
기기당 활성 session_id — 단일 세션 claim/heartbeat |
packages/client/src/components/PlayerAuthForm.tsx |
타이틀 로그인/가입 폼 |
packages/client/src/state/authStore.ts |
bootstrap·로그인/가입/로그아웃 |
scripts/supabase/enable-email-password-auth.mjs |
Email provider + autoconfirm |
마이그레이션·계정 전환
- 세이브 키:
cf_account:<userId>(계정마다 분리). 예전cf_account단일 키는 클라우드 계정에 자동 병합하지 않음 (신규 가입 = Lv1 새 세이브). - 로컬 전용 플레이(
VITE_SUPABASE_*없음)일 때만cf_account를 읽습니다. - 계정 전환 시 해당 유저의 로컬·클라우드 세이브만 로드합니다.
- 이미 잘못 병합된 클라우드 세이브는 Supabase
player_saves에서 해당 행을 지우거나, 새 플레이어 ID로 가입하세요.
리더보드 playerId
로그인 시 Supabase user.id를 사용합니다. 미로그인 시 기존 bp_player_id 로컬 UUID를 유지합니다.
(선택) Google / 게스트
- Google OAuth — 사용 안 함. 필요 시
scripts/supabase/configure-google-auth.mjs - 게스트 익명 — 사용 안 함.
scripts/supabase/enable-anonymous-auth.mjs
스팀 출시 시 SteamID 연동은 STEAM_RELEASE_PLAN.md 참고.