최종 갱신 (KST)

← 일감 목록
T-146

서버 기동 시 DB 마이그레이션 자동 적용 (`user_version`)

진우 Resolve 우선순위 높음 목표 261024

배경

  • 2026-10-07에 migrations/를 없애고 game.sqlite3만 본체로 두기로 했다. 손으로 돌리는 SQL 파일이 적용되지 않은 채 남았기 때문이다 — 10-06 drop-aptitude-bonus는 미적용, 10-07 응축 컬럼은 로컬 DB에만 있어 pull한 쪽 로그인이 깨질 뻔했다.
  • 2026-10-11 마이그레이션을 다시 두기로 했다 (사용자 결정). 원격 Docker 서버(T-109)에 친구 데이터가 쌓이면 DB를 덮어쓸 수 없다. 이번에는 사람이 돌리지 않고 서버가 기동할 때 적용한다 — 10-07 사고의 원인을 없앤다.
  • Docker 없이도 지금 바로 쓸모 있다 — DB 커밋을 빠뜨려도 받은 쪽 서버가 스스로 맞춘다.

설계 (2026-10-11 결정)

  • 파일: Server/Shared/migrations/0001-<슬러그>.sql — 순번 = PRAGMA user_version
  • 기동 시 user_version을 읽고 그보다 큰 번호를 차례로 적용한다 — 파일 하나 = 트랜잭션 하나, 끝나면 user_version = 그 번호. 적용할 것이 있으면 먼저 DB 파일을 백업 복사한다.
  • DB 판이 서버가 아는 마지막 번호보다 높으면 기동을 멈춘다 — 옛 서버가 새 DB를 조용히 쓰지 않게 (경매장 AuctionStore와 같은 태도).
  • 0001은 지금 스키마 전체를 CREATE TABLE/INDEX IF NOT EXISTS로 — 지금 DB(user_version 0)에 돌려도 판 번호만 1이 된다.
  • game.sqlite3는 git에 그대로 둔다(본체) — 새로 받은 사람이 바로 띄운다. 스키마를 바꾸면 마이그레이션 파일 + 적용된 DB를 같이 커밋한다.
  • 스키마는 마이그레이션으로만 바꾼다 — DB를 직접 고치지 않는다.
  • 데이터를 지우는 마이그레이션(DELETE 등)은 원격에 친구 데이터가 있으니 공지하고 돌린다.
  • 경매장 DB(auction.sqlite3)는 지금 방식(AuctionStore 자체 판 · 단계 변환)을 유지한다.

할 일

  • [x] 0001-baseline.sql — 지금 game.sqlite3 스키마 전체(테이블 15 · 인덱스 6) 덤프 · IF NOT EXISTS
  • [x] 마이그레이션 실행기 DbMigrator — DBManager 초기화 직전(커넥션을 열기 전)에 돈다 · 번호순 · 트랜잭션 · user_version · 백업 · 판이 더 높으면 기동 중단 · 적용 내역을 ServerLog로
  • [x] 마이그레이션 파일을 실행 폴더(Migrations/)로 복사 — csproj Content (Docker 이미지에도 같이 들어간다)
  • [x] 테스트 DbMigratorTest 13개 — 빈 DB · 남은 것만 · 롤백 · 판 유지 · 판이 더 높으면 거절 · 번호 겹침/빈 번호/형식 · 백업 · 저장소 파일 전체 적용
  • [x] game.sqlite3에 적용(→ user_version 1) — 서버를 띄워 확인: 스키마·행 38개 그대로, 두 번째 기동은 "적용할 마이그레이션 없음"
  • [x] SqliteFixture의 손으로 베낀 DDL을 CreateSchema()(마이그레이션 적용)로 바꿨다 — 호출처 12파일
  • [x] 문서 — Server/CLAUDE.md DB 규칙(10-07 규칙 교체) · sqlite-sql-creator 스킬 · 메모리
  • [x] 치트: 해당 없음 — 개발 인프라

발견: 실제 DB의 t_character에 10-06 drop-aptitude-bonus가 적용 안 된 채 적성 보너스 5컬럼이 남아 있다 — 0001에 그대로 들어갔다. 지우려면 0002로.

완료 조건

  • 판이 낮은 DB로 서버를 띄우면 남은 마이그레이션이 적용되고 백업이 남는다. 다시 띄우면 아무것도 하지 않는다.
  • 판이 더 높은 DB로 띄우면 기동이 멈추고 이유가 로그에 남는다.
  • 서버 테스트가 통과하고, game.sqlite3가 user_version 1로 커밋돼 있다.

막고 있는 것 / 선행 일감

  • 없음

관련 커밋

  • 88ab98f — 일감 등록 · T-109 맞춤
  • 4563a42 — DbMigrator · 0001-baseline · SqliteFixture.CreateSchema() · game.sqlite3 판 1