[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_typeVARCHAR(32),statusVARCHAR(20) DEFAULT'ACTIVE',descriptionVARCHAR(500) NULL,strategy_configTEXT NOT NULL(JSON 문자열),versionBIGINT NOT NULL DEFAULT 0(낙관락, BE-01@VersionLong 정합),created_at/updated_atDATETIME(6),created_by/updated_byBIGINT NULL.feature_flag_audit_logs(append-only):id,flag_keyVARCHAR(100),change_typeVARCHAR(20),actor_user_idBIGINT,before_snapshotTEXT NULL,after_snapshotTEXT NOT NULL,occurred_atDATETIME(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 필수, PKid. 인덱스는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 INDEX로uq_feature_flags_flag_key·idx_feature_flag_audit_logs_flag_key_occurred_at2개 인덱스만 존재하고status인덱스는 없음을 확인한다.strategy_config/before_snapshot/after_snapshotTEXT 컬럼에 JSON 문자열 저장/조회가 손실 없이 round-trip된다.- 역방향
DROP TABLE2개 실행 후 두 테이블이 사라짐을 확인한다(롤백 재현).