架構決策 (ADR)
GenerationJob 允許 family_id 與 child_profile_id 為 NULL(curated 生成用)
Context
GenerationJob model 原本假設每個 job 都有對應的家庭與孩子(family_id NOT NULL、child_profile_id NOT NULL)。
Admin curated 生成不綁定任何家庭或孩子,但共用同一個 GenerationJob model 與 Celery task pipeline。
Decision
結論:修改 GenerationJob model,讓 family_id 與 child_profile_id 兩個欄位可為 NULL。
並在 input_params JSON 欄位加入 is_curated: true 旗標,讓 Celery task 知道:
- 用
age_min/age_max替代 child profile 年齡參數構建 prompt - 跳過 DRAFT_READY 等待,完成 TTS 後直接設
status=completed,等 admin 呼叫 approve 需要一個 Alembic migration 移除 NOT NULL 約束。
Alternatives Considered
- 為 curated 生成建立獨立的
CuratedGenerationJobmodel — 考慮過。會複製整個 Celery task pipeline,且 admin 查詢 job status 的邏輯要分兩套維護,得不償失。 - 用 sentinel family_id(如
ADMIN_FAMILY_ID) — 考慮過。sentinel 值污染 DB 查詢,且對未來開發者不透明。
Consequences
好:
- 共用
GenerationJobmodel 和 Celery worker,不重複基礎設施 is_curatedflag 清楚標記語意,task 邏輯一眼可辨
壞 / 代償:
- Alembic migration 須處理 NOT NULL → nullable(若有既有資料需先設 default 值再移除約束)
- Celery task
generate_content_task加 curated path 判斷,需 unit test 保護兩個路徑(見 ADR-0001 Consequences) - 查詢「家庭的所有 job」時 WHERE 條件要加
family_id IS NOT NULL
中性:
- Admin approve endpoint 在 job 完成後設
is_approved=True,is_active=True,source_type="curated" - 若 audio_url 為空(TTS 失敗),approve 時重新 trigger TTS