# life-helper 데이터 모델 (v1) > **목적**: 본 프로젝트의 3개 마크다운 SoT(`huberman-protocols.md`, `habit-todo-methodologies.md`, `habit-breaking-protocols.md`)와 메모리 원칙(`feedback_sustainable_minimal.md`, `feedback_reward_ladder.md`, `feedback_positive_framing.md`)을 앱에서 쓸 수 있는 데이터 구조로 정형화. > > **선택된 형식**: JSON Schema (Draft 2020-12). SQL/TS 변환은 추후. user_id 기반 → 단일 사용자 local-first와 멀티 사용자 클라우드 모두 호환. > > **machine-readable schema**: `./schema/*.json` (엔티티별 분리) > **본 문서**: 엔티티 관계 + 설계 의도 + 운영 규칙 + 사용 예시 --- ## §1. 엔티티 분류 ### Catalog (read-only seed data, 앱에 번들) | 엔티티 | SoT 원본 | 설명 | |--------|---------|------| | `protocol` | `huberman-protocols.md` + `nutrition/diet-protocols.md` | 원자 프로토콜 (category로 health/meditation/motivation/habit/learning/diet 구분) | | `break_protocol` | `habit-breaking-protocols.md` §2 | 끊기 카테고리 8개 | | `common_frame` | `habit-breaking-protocols.md` §1 | 끊기 공통 프레임 5개 (Dopamine Reset 등) | | `methodology` | `habit-todo-methodologies.md` | 21개 습관/투두 방법론 | | `frame_pattern` | 동 문서 §"언어 프레이밍" | L0→L1/L2/L3 변환 예시 | | `reward_menu_item` | 동 문서 §"리워드 시스템" | 추천 보상 메뉴 | | `reference` | 모든 SoT의 출처 필드 | DOI/URL/책 인용 | | `diet_pattern` | `nutrition/diet-protocols.md` §2 | 식이 패턴 5개 (지중해/저탄수/IF/Plant-Based/한식) — 의견 분열 영역, 사용자 선택 메뉴 | ### User Data (사용자가 생성·변경) | 엔티티 | 설명 | 핵심 제약 | |--------|------|----------| | `user` | 사용자 (단일/멀티 호환) | `id` 필수 | | `phase` | 6주 사이클 1개 | user당 동시 active 1개 | | `habit` | 사용자 습관 (build 또는 break) | active build ≤ 3, active break ≤ 1 | | `tracker_entry` | 일일 ○/공백 체크 | (habit_id, date) unique | | `if_then_rule` | Implementation Intentions | habit당 ≤ 3개 권장 | | `lapse_log` | LEARN 5필드 (재발 일지) | break 습관 위주 | | `urge_log` | 충동 발생/통과 기록 (선택) | break 습관 위주 | | `reward_declaration` | 사전 선언 보상 (T0~T4) | phase 시작 시점에만 | | `reward_claim` | 실제 milestone 달성 기록 | declaration 참조 | | `reflection` | 주/월 회고 텍스트 | 자유 | --- ## §2. 관계 다이어그램 ``` user (1) ├─< phase (n) -- 시점별 6주 사이클 │ └─< reward_declaration (n) -- 이 phase 동안의 T0~T4 사전 선언 │ └─< habit (n) ├── protocol_id or break_protocol_id (catalog 참조, XOR) ├── frame {level, original_text, framed_text} -- L2 또는 L3 강제 ├── anchor {when, after_what, where} -- Tiny Habits ├── stack_position -- after-this-then-that 순서 (선택) ├─< if_then_rule (n) ├─< tracker_entry (n, daily) ├─< lapse_log (n) -- break 위주 ├─< urge_log (n, 선택) -- break 위주 └─< reward_claim (n) -- milestone 달성 시 ``` **catalog 측**: ``` protocol ──< protocol_reference >── reference (M:N) break_protocol ──< break_reference >── reference methodology ──< methodology_reference >── reference ``` --- ## §3. 운영 규칙 (DB level constraint로 적용) 본 프로젝트 메모리에서 도출된 가드레일을 schema에 박는다. | ID | 규칙 | 적용 위치 | 출처 | |----|------|----------|------| | R1 | `user`당 동시 active build habit ≤ 3 | `habit.status='active' AND type='build'` 집계 | `feedback_sustainable_minimal.md` | | R2 | `user`당 동시 active break habit ≤ 1 | `habit.status='active' AND type='break'` 집계 | `project_habit_breaking_module.md` | | R3 | `habit.frame.level` ∈ {`L2`, `L3`} 강제 (L0 거부) | enum 제약 | `feedback_positive_framing.md` | | R4 | `reward_declaration`은 `phase.started_at` 후 7일 안에만 생성 | timestamp 검증 | `feedback_reward_ladder.md` (사전성) | | R5 | `tracker_entry.value` ∈ {`done`, `blank`} 2값만 | enum (×·이모지 X) | 6 가드레일 #6 | | R6 | `phase.duration_weeks` = 6 (default), 6주 전 anchor 변동 X | 변경 시 warning | 6 가드레일 #5 | | R7 | `if_then_rule.then_action` 회피 키워드 감지 시 warning | 클라이언트 검증 | 코끼리 회피 UX | | R8 | `habit` 일일 운영 ≤ 2분 (tracker UI 30~60초) | UX 제약 (DB X) | 6 가드레일 #2 | | R9 | `habit.dose_variants[]` 개수 제한 없음. 단 체크인 화면은 "장소 1탭 + 컨디션 1탭 → 추천 + override" 흐름으로 R8 유지. `is_minimum=true` variant는 0개 이상 허용 (강제 X). | application + UI | `docs/adr/0001-dose-variants.md` | | R10 | `reflection.scope='weekly'`은 `minimum_ratio` (해당 주 done 중 is_minimum 비율) 표시. 강제 임계값 없음 — hint 용도. | application 계산 | `docs/adr/0001-dose-variants.md` | --- ## §4. 핵심 enum 정의 ```yaml HabitType: ["build", "break"] HabitStatus: ["active", "paused", "completed", "abandoned"] FrameLevel: ["L0", "L1", "L2", "L3"] # L0/L1은 입력 차단 (warning + 변환 제안) TrackerValue: ["done", "blank"] # ○/공백 2값 RewardTier: ["T0", "T1", "T2", "T3", "T4"] # T0=매일 / T1=3회 스트릭 / T2=7일 / T3=30일 / T4=42일(6주) LapseFieldHALT: ["hungry", "angry", "lonely", "tired", "none"] ProtocolCategory: ["health", "meditation", "motivation", "habit", "learning", "diet"] # huberman-protocols.md §1~§5 + nutrition/diet-protocols.md (별도 모듈) BreakCategory: ["alcohol", "nicotine", "porn_masturbation", "social_media", "sugar", "caffeine", "cannabis", "behavioral"] CommonFrameId: ["dopamine_reset", "urge_surf", "environment_design", "relapse_recovery", "recovery_stack"] ``` --- ## §5. JSON Schema 파일 목록 (`./schema/`) ### Catalog - `protocol.schema.json` — Huberman atomic protocol - `break_protocol.schema.json` — 끊기 카테고리 - `common_frame.schema.json` — 끊기 공통 프레임 5개 - `methodology.schema.json` — 21개 방법론 - `frame_pattern.schema.json` — L0→L2/L3 변환표 - `reward_menu_item.schema.json` — 보상 메뉴 - `reference.schema.json` — DOI/URL/책 ### User - `user.schema.json` - `phase.schema.json` - `habit.schema.json` - `if_then_rule.schema.json` - `tracker_entry.schema.json` - `lapse_log.schema.json` - `urge_log.schema.json` - `reward_declaration.schema.json` - `reward_claim.schema.json` - `reflection.schema.json` ### 메타 - `enums.schema.json` — 위 §4 enum 통합 정의 ($ref로 재사용) - `_index.json` — 전체 스키마 인덱스 + 운영 규칙 메타 --- ## §6. 사용 예시 (단일 사용자, build 습관 1개) ### habit (build, L2 프레임) ```json { "id": "hb_01J9...", "user_id": "u_local_default", "type": "build", "status": "active", "title": "아침 햇빛 10분", "protocol_id": "huberman_1_1_morning_sunlight", "break_protocol_id": null, "frame": { "level": "L2", "original_text": "햇빛 안 빼먹기", "framed_text": "기상 직후 야외에서 햇빛 10분 받기" }, "anchor": { "when": "06:30", "after_what": "기상 직후", "where": "현관 앞 야외" }, "if_then_rules": [ { "if": "비 오는 날이면", "then": "20분으로 늘려서 우산 쓰고 나간다" } ], "started_at": "2026-06-04", "phase_id": "ph_2026Q2_1", "stack_position": 1 } ``` ### tracker_entry (일일) ```json { "id": "te_...", "habit_id": "hb_01J9...", "date": "2026-06-04", "value": "done", "logged_at": "2026-06-04T06:42:00+09:00" } ``` ### reward_declaration (phase 시작 시 사전 선언) ```json { "id": "rd_...", "phase_id": "ph_2026Q2_1", "habit_id": "hb_01J9...", "tier": "T3", "milestone_rule": "30일 중 24일 이상 done", "reward_text": "주말 1박 단기 여행", "estimated_cost_krw": 150000, "declared_at": "2026-06-04T20:00:00+09:00" } ``` ### habit (break, L3 프레임) ```json { "id": "hb_brk_01...", "user_id": "u_local_default", "type": "break", "status": "active", "title": "평일 무알콜", "protocol_id": null, "break_protocol_id": "alcohol", "common_frame_ids": ["dopamine_reset", "environment_design", "recovery_stack"], "frame": { "level": "L3", "original_text": "술 끊기", "framed_text": "나는 평일 무알콜인 사람이다" }, "anchor": { "when": "18:00", "after_what": "퇴근", "where": "집 거실" }, "phase_id": "ph_2026Q2_1" } ``` ### lapse_log (LEARN 5) ```json { "id": "ll_...", "habit_id": "hb_brk_01...", "date": "2026-06-10", "label_text": "회식에서 맥주 2잔. 데이터로 처리.", "examine_halt": ["tired", "lonely"], "antecedent": ["회식 자리", "20시 늦은 식사", "동료 권유"], "replan": "If 회식 공지 받으면, then 첫잔 무알콜 사전 선언 + 동료에게 알림", "next_action": "다음 평일은 즉시 정상 진행. Never miss twice." } ``` --- ## §7. 단일 vs 멀티 사용자 호환 전략 - 모든 user data 엔티티에 `user_id` 필수 필드. - 단일 사용자 local 앱: `user_id = "u_local_default"` 고정. - 클라우드 멀티 사용자: auth 서비스의 sub/uid를 그대로 `user_id`로 매핑. - catalog 엔티티에는 `user_id` 없음 (모든 사용자 공유). - ID 형식: ULID 권장 (`hb_01J9...`). prefix는 엔티티 타입. --- ## §8. 마이그레이션 노트 - v1은 minimal viable. 다음 항목은 v2 이후 고려: - `habit_stack` (Atomic Habits #5 — 여러 habit 묶음 운영) - `dashboard_preference` (사용자별 트래커 UI 옵션) - `notification_rule` (알림/cron 트리거) - `social_link` (Recovery Stack의 "1-person check-in" 파트너) - `integration_*` (Apple Health / Google Fit / Notion sync) - enum 추가는 backward compatible. enum 제거/이름 변경은 마이그레이션 스크립트 필수. --- ## §9. 다음 단계 제안 1. 본 문서 + `./schema/*.json` 리뷰. 2. seed catalog 데이터 채우기 (Huberman 29개 + break 8개 + methodology 21개) — `./seed/*.json`. 3. 검증기(Ajv 등)로 schema 적합성 확인. 4. UI 와이어프레임 (트래커 30초, 대시보드 1화면 등) — 별도 문서. 5. 백엔드 결정 (SQLite local-first 권장 → 추후 Supabase 등으로 확장).