Files
life-helper/docs/design/204-flutter-bootstrap/05-seed-data.md
joungmin 29befe4d97 [Architect] Refs #204 — apply OQ decisions: diet_pattern (19th), ADR-0002 normalize dose_variants
- OQ-1: dose_variants 정규화 결정을 ADR-0002 로 승격 (ADR-0001 = 왜, ADR-0002 = 어떻게).
- OQ-3: nutrition diet 패턴 5개를 별도 diet_pattern 카탈로그(19번째 SoT)로 분리.
  · 02-catalog §8 신규, 인덱스 IDX_diet_patterns_evidence / IDX_diet_patterns_kfit.
  · 05-seed: diet_patterns.json (5행) 추가, 로딩 순서 끝에 배치.
  · 04-migrations: v1 테이블 합계 = Catalog 8 + User 11 + 부속 1 + meta_kv = 21.
- README §2/§3/§6/§11 갱신: 18→19 SoT, AC-2 에 diet_pattern=5 검증 추가.
- README §12 OQ → Resolved Open Questions 표 (OQ-1~OQ-8 결정 결과).
- habit_dose_variant → habit_dose_variants 표기 통일.
- fn-weekly-minimum-ratio, 03-drift-schema-user 의 ADR-0002 cross-link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-11 17:13:04 +09:00

6.0 KiB

05 — 시드 데이터 전략 (#204)

부모 설계서: README.md

1. 전략 결정: build-time 번들 + first-run JSON import

검토한 대안

옵션 장점 단점 채택
A. build-time codegen (*.dart 생성) 컴파일 타임 안전, JSON parse 실패 0 시드 변경 시 codegen 강제. PR diff 가 dart 자동 생성.
B. asset 번들 JSON + 첫 실행 import SoT schema/*.json 호환 형식 그대로. 사람이 읽기 쉬움. diff 명료. 첫 실행 시 ~1 초 추가 시간. parse 실패 가능성 (테스트로 커버)
C. 원격 fetch 동적 업데이트 네트워크 의존 (Phase 1 out of scope)

2. 파일 배치

app/assets/seed/
├── protocols.json            # Array<Protocol> — ~34 항목
├── break_protocols.json      # Array<BreakProtocol> — 8 항목
├── common_frames.json        # Array<CommonFrame> — 5 항목
├── methodologies.json        # Array<Methodology> — 21 항목
├── frame_patterns.json       # Array<FramePattern> — ~30 항목
├── reward_menu_items.json    # Array<RewardMenuItem> — ~30 항목
├── diet_patterns.json        # Array<DietPattern> — 5 항목 (OQ-3 결정)
└── references.json           # Array<Reference> — ~50 항목

8 시드 파일 (Catalog 카탈로그 1:1). user-data 테이블은 시드 없음.

  • 각 파일 형식 = schema/<entity>.schema.json 을 만족하는 객체 배열.
  • 인코딩 = UTF-8 (한국어 텍스트).
  • pubspec.yamlflutter.assets:assets/seed/ 등록.

3. 로딩 순서 (참조 무결성)

1. references.json        ← 다른 시드가 reference_ids 로 참조
2. protocols.json         ← diet_patterns 가 linked_protocol_ids 로 참조
3. break_protocols.json
4. common_frames.json
5. methodologies.json
6. frame_patterns.json
7. reward_menu_items.json
8. diet_patterns.json     ← protocols + references 참조 (마지막)
  • 각 파일 batch insert 는 단일 트랜잭션.
  • 전체 시드 import 도 단일 transaction. 1 파일이라도 실패하면 rollback.

4. 첫 실행 감지

meta_kv 테이블에 key='seeded_v1' 행 존재 여부로 판단.

Future<bool> _alreadySeeded(AppDatabase db) async {
  final row = await db.metaKvDao.find('seeded_v1');
  return row?.value == 'true';
}

5. import 시퀀스 (의사코드 — fn-seed-importer.md 참조)

Future<void> importIfNeeded() async {
  if (await _alreadySeeded(db)) return;
  await db.transaction(() async {
    for (final entry in _seedOrder) {
      final raw = await rootBundle.loadString(entry.assetPath);
      final list = jsonDecode(raw) as List;
      for (final json in list) {
        final adapted = entry.adapter(json as Map<String, dynamic>);
        await entry.dao.insertAll(adapted);
      }
    }
    await _ensureLocalDefaultUser();
    await db.metaKvDao.put('seeded_v1', 'true');
  });
}

6. 시드 데이터 출처 ↔ 카탈로그 매핑 (검증용)

시드 파일 SoT 마크다운 추출 단위 추산 행
protocols.json huberman-protocols.md §1~§5 + nutrition/diet-protocols.md §1 ### 헤더 단위 ~34
break_protocols.json habit-breaking-protocols.md §2 ### 헤더 단위 (8 카테고리) 8
common_frames.json habit-breaking-protocols.md §1 ### 5 개 5
methodologies.json habit-todo-methodologies.md §1~§21 ### 헤더 단위 21
frame_patterns.json habit-todo-methodologies.md "흔한 끊기 목표 변환 30선" 표 row 단위 ~30
reward_menu_items.json habit-todo-methodologies.md "권장 리워드 메뉴 30선" 표 row 단위 ~30
diet_patterns.json nutrition/diet-protocols.md §2 5 개 식이 패턴 (### 헤더 단위) 5
references.json 4 SoT 의 각 출처 섹션 합계 인용 1 건 ~50

diet_patterns.json 시드 5 행 (예시 id)

id name 비고
mediterranean 지중해 식단 PREDIMED RCT — evidence_strength=strong
low_carb_keto 저탄수/케토 당뇨 약물 복용자 medical_warning
tre_if TRE / 간헐적 단식 huberman §1.5 linked_protocol
plant_based 식물성 k_diet 와 starter_levers 일부 공유
k_diet 한식 기반 korean_context_fit=high, starter '첫 끼 단백질 +30g'

7. 손 작성 vs 자동 추출

본 Phase 는 손 작성 (Developer 가 SoT 마크다운을 보고 JSON 작성). 이유:

  • 자동 추출 파서가 또 다른 코드 (스크립트) 의 SoT 가 됨 — 본 Phase 범위 초과.
  • 손 작성으로 카탈로그 schema 의 비논리적 누락을 발견할 수 있음 (피드백 루프).

Phase 2 에서 scripts/extract_seed.py 검토 (OQ-2).

8. user 기본 row 생성

Future<void> _ensureLocalDefaultUser() async {
  await db.users.insertOnConflictUpdate(UsersCompanion.insert(
    id: 'u_local_default',
    createdAt: DateTime.now().toIso8601String(),
    locale: const Value('ko-KR'),
    timezone: const Value('Asia/Seoul'),
  ));
}

9. 테스트 fixture

test/fixtures/seed/
├── protocols_small.json       # 2 항목 (1 health + 1 diet)
├── break_protocols_small.json # 1 항목
├── common_frames_small.json   # 1 항목
├── methodologies_small.json   # 3 항목 (core engine 3 개)
├── frame_patterns_small.json  # 2 항목
├── reward_menu_items_small.json # 5 항목 (T0~T4 각 1)
├── diet_patterns_small.json   # 2 항목 (k_diet + mediterranean)
└── references_small.json      # 2 항목
  • SeedImporter 의 단위 테스트는 fixture 디렉토리로 path override.

10. 운영 메모

  • 시드 변경 시 (v1 출시 후 카탈로그 한 행 추가): asset JSON 수정 → schemaVersion 그대로 → migration 으로 신규 row insert 별도 처리. 자동 import 는 seeded_v1 flag 가 true 라 다시 안 돔.
  • 카탈로그 갱신은 별도 메커니즘 (v2 또는 seeded_v2 플래그 신설) — Phase 2 결정.