YiBi Dev Docs
架構決策 (ADR)

Admin 生成 endpoint 獨立於家長端(不複用 /v1/contents/generate)

Context

Admin 後台需要讓內容管理員直接生成「YiBi 精選(curated)故事」並上架,不需要綁定任何家庭或孩子。 家長端已有 POST /v1/contents/generate,但其設計前提是:

  1. 強制要求 child_profile_id(無法接受 null)
  2. 生成後進入 DRAFT_READY 狀態等待家長批准
  3. Celery task 用 child profile 的年齡參數 + 家長 context 構建 prompt

Admin curated 生成的語意完全不同:無家庭綁定、admin 直接審閱草稿、最終由 admin 呼叫 approve 上架。

Decision

結論:新建獨立的 admin/generate.py router,提供三個獨立 endpoint:

  • POST /api/v1/admin/generation-jobs — 觸發 curated 生成
  • GET /api/v1/admin/generation-jobs/{job_id} — 查詢進度
  • POST /api/v1/admin/generation-jobs/{job_id}/approve — Admin 審閱後上架

不修改家長端 POST /v1/contents/generate,兩個路徑完全獨立。

Alternatives Considered

  • 複用家長端 /v1/contents/generate,加 optional child_profile_id — 考慮過。問題是 task 邏輯會累積大量 if is_curated 判斷,污染家長端路徑,且 DRAFT_READY 狀態機對 admin 流程無意義。
  • 在家長端 generate 加 admin override flag — 考慮過。flag 會讓安全邊界模糊,admin 端 vs 家長端的授權邏輯難以獨立審計。

Consequences

  • 家長端與 admin 端語意完全隔離,各自可獨立演進
  • 安全邊界清晰(admin route 有獨立 auth check)
  • Celery task 的 curated path 加 is_curated=True 旗標,不影響既有家長路徑

壞 / 代償

  • GenerationJob model 需要允許 family_idchild_profile_id 為 NULL(見 ADR-0002)
  • 兩套 endpoint 有部分重複邏輯(job status polling),需小心保持一致

中性

  • Admin frontend 用獨立的 generate-curated.tsx 頁面
  • Polling 策略相同(3 秒 interval,5 分鐘 timeout)

On this page