[DB-01] feature_flags · feature_flag_audit_logs 마이그레이션

작업 내용 (설계 의도)

변경 사항

피처 플래그 시스템의 SSOT 테이블 2개를 신규 생성한다. 근거 설계: ../design-db.md(테이블 정의·인덱스 매핑·용량·배포), 근거 TDD: ../TDD.md §ERD. 컬럼·타입·인덱스·COMMENT는 design-db.md가 SSOT이며, 이 티켓은 그 설계를 단일 마이그레이션 파일로 옮기는 작업이다. DDL 전문 작성·로컬 검증은 private-mysql-implementer가 수행한다.

  • 2 테이블 = 1 마이그레이션 파일 (create_feature_flags).
    • feature_flags (SSOT): id, flag_key(UNIQUE), flag_type VARCHAR(32), status VARCHAR(20) DEFAULT 'ACTIVE', description VARCHAR(500) NULL, strategy_config TEXT NOT NULL(JSON 문자열), version BIGINT NOT NULL DEFAULT 0(낙관락, BE-01 @Version Long 정합), created_at/updated_at DATETIME(6), created_by/updated_by BIGINT NULL.
    • feature_flag_audit_logs (append-only): id, flag_key VARCHAR(100), change_type VARCHAR(20), actor_user_id BIGINT, before_snapshot TEXT NULL, after_snapshot TEXT NOT NULL, occurred_at DATETIME(6). updated_*/deleted_* 없음.
  • 인덱스 (design-db 쿼리 매핑 근거):
    • UNIQUE KEY uq_feature_flags_flag_key (flag_key) — 평가·중복검증 조회(findByKey/existsByKey) + 중복 방지.
    • INDEX idx_feature_flag_audit_logs_flag_key_occurred_at (flag_key, occurred_at) — 플래그별 이력 최신순 페이징. ESR: flag_key(Equality 선두)+occurred_at(Sort).
    • status 인덱스는 만들지 않는다 — 저카디널리티(2값)·저볼륨(수백 행)·저빈도로 근거 없는 인덱스 회피(design-db 확정). 필요 시 추후 ALGORITHM=INPLACE, LOCK=NONE으로 온라인 추가.
  • 컨벤션: FK 컬럼 금지(created_by/actor_user_id 등 일반 컬럼), ENUM 금지(→VARCHAR), JSON 컬럼 금지(→TEXT), BOOLEAN 미사용, DATETIME(6), 전 컬럼·테이블 COMMENT 필수, PK id. 인덱스는 CREATE TABLE 인라인 정의(사후 ALTER 아님).
  • 마이그레이션 번호: 권고 V43__create_feature_flags.sql(잠정). V38~V42는 형제 과제(B2B 파트너 V38-40 · limited_drops V41 · alerts V42)가 문서상으로만 점유한 잠정 배정이다. 구현 시점에 origin/dev 기준 워크트리에서 최신 버전을 실측해 확정한다(“먼저 머지되는 쪽이 순차 점유, 나중 쪽 재배정” 공통 방침, MEMORY worktree 구버전 분기 이슈 직결).

롤백

신규 테이블 순수 가산(expand-contract 1단계, 스키마 먼저). 참조 코드 미배포 상태에서 역방향 DROP TABLE feature_flag_audit_logs; DROP TABLE feature_flags; 안전(데이터·의존 없음). CREATE TABLE은 기존 테이블 무락(온라인 안전).

의존

  • 없음 (스키마 선행 티켓 — BE-02가 이 티켓을 병행 선행으로 참조)

테스트 / 검증 케이스

  • 로컬 MySQL 8.0(docker 또는 Testcontainers)에서 마이그레이션이 오류 없이 적용된다(exit code 0).
  • 기존 마이그레이션 전체(V8~최신) → 신규 순서로 적용해 순서·버전 충돌이 없다.
  • feature_flags에 동일 flag_key로 2건 INSERT 시 UNIQUE 제약(uq_feature_flags_flag_key)으로 두 번째가 거부된다.
  • SHOW INDEXuq_feature_flags_flag_key·idx_feature_flag_audit_logs_flag_key_occurred_at 2개 인덱스만 존재하고 status 인덱스는 없음을 확인한다.
  • strategy_config/before_snapshot/after_snapshot TEXT 컬럼에 JSON 문자열 저장/조회가 손실 없이 round-trip된다.
  • 역방향 DROP TABLE 2개 실행 후 두 테이블이 사라짐을 확인한다(롤백 재현).