{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://life-helper.local/schema/habit.schema.json", "title": "Habit (사용자 습관 — build 또는 break)", "description": "active 상태에서 build ≤ 3, break ≤ 1 (R1/R2). frame.level은 L2/L3만 허용 (R3).", "type": "object", "required": ["id", "user_id", "type", "status", "title", "frame", "anchor", "started_at"], "additionalProperties": false, "properties": { "id": { "type": "string" }, "user_id": { "type": "string" }, "phase_id": { "type": "string", "description": "소속 phase. null이면 phase 외 운영" }, "type": { "$ref": "enums.schema.json#/$defs/HabitType" }, "status": { "$ref": "enums.schema.json#/$defs/HabitStatus" }, "title": { "type": "string", "description": "사용자가 보는 짧은 제목 (≤ 20자 권장)" }, "protocol_id": { "type": ["string", "null"], "description": "catalog protocol 참조 (type=build)" }, "break_protocol_id": { "type": ["string", "null"], "description": "catalog break_protocol 참조 (type=break)" }, "common_frame_ids": { "type": "array", "items": { "$ref": "enums.schema.json#/$defs/CommonFrameId" }, "description": "type=break 시 활성화할 공통 프레임 ID" }, "frame": { "type": "object", "additionalProperties": false, "required": ["level", "framed_text"], "properties": { "level": { "$ref": "enums.schema.json#/$defs/FrameLevelAllowed" }, "original_text": { "type": "string", "description": "사용자의 최초 입력 (L0일 수 있음, 감사 목적)" }, "framed_text": { "type": "string", "description": "L2 또는 L3로 변환된 최종 문장" } } }, "anchor": { "type": "object", "additionalProperties": false, "properties": { "when": { "$ref": "enums.schema.json#/$defs/TimeOfDay" }, "after_what": { "type": "string", "description": "Tiny Habits anchor — 직전 행동" }, "where": { "type": "string" } } }, "stack_position": { "type": "integer", "minimum": 1, "description": "Atomic Habits #5 habit stacking 순서" }, "min_dose": { "type": "string", "description": "시작 doseo (Tiny Habits)" }, "target_dose": { "type": "string" }, "started_at": { "$ref": "enums.schema.json#/$defs/DateString" }, "ended_at": { "$ref": "enums.schema.json#/$defs/DateString" }, "tags": { "type": "array", "items": { "type": "string" } }, "x_constraint": { "description": "참고용 메타 — 검증은 application layer에서 수행 (XOR protocol_id vs break_protocol_id)", "type": "string", "const": "type=build → protocol_id 채움 / type=break → break_protocol_id 채움 (반대쪽은 null)" } } }