Phase D: 닉네임 기반 DB 세이브 동기화
- villages 테이블(pg-jskim): nickname PK + 보호 토큰 + JSONB 세이브 - API: /api/village/check(중복)·register(선점)·save(토큰 검증 업서트)·load - 닉네임 모달: 촌장 냥이 인사 직후 게임 차단, 입력 멈춘 1초 후 자동 중복 체크(디바운스), 사용 가능할 때만 결정 버튼 활성화 한글·영문·숫자 2~12자 검증, 서버 불가 시 로컬 시작 후 재시도 - 동기화: 30초마다 자동 push + 종료 시 push, 부팅 시 서버가 더 최신이면 교체(replaceState → 마이그레이션·오프라인 정산 재수행) - 기존 세이브도 닉네임 미설정이면 모달 표시 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
이 커밋은 다음에 포함됨:
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { useGame } from "@/hooks/useGame";
|
||||
import VillageView, { type PlacingState } from "@/components/game/VillageView";
|
||||
import DbStatus from "@/components/DbStatus";
|
||||
import NicknameModal from "@/components/game/NicknameModal";
|
||||
import {
|
||||
engine,
|
||||
effectiveRate,
|
||||
@@ -231,6 +232,11 @@ export default function Game() {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* ── 닉네임 입력 (인사 후, 미입력 시 게임 차단) ── */}
|
||||
{!state.nickname && (state.tutorialStep ?? TUTORIAL_DONE) >= 1 && (
|
||||
<NicknameModal onDone={() => dispatch(() => undefined)} />
|
||||
)}
|
||||
|
||||
{/* ── 배치 모드 힌트 ── */}
|
||||
{placing && (
|
||||
<div className="wood-plank font-jua absolute bottom-6 left-1/2 z-40 flex -translate-x-1/2 items-center gap-3 px-5 py-2.5 text-sm">
|
||||
|
||||
새 이슈에서 참조
사용자 차단