不要讓建置中途的意外消失在滾動歷史裡,請 agent 在發生時記錄每一個偏離計畫的地方——這樣意外就會成為你下次嘗試的輸入。
「在你建置匯出功能時,維護一份實作筆記檔案。如果你遇到邊界情況迫使你偏離計畫,選擇保守的選項,記錄在『偏離』區塊下,然後繼續做。」
在 apps/api/src/exports/exportJob.ts 新增 ExportJob,排入現有的 BullMQ media-tasks queue,用專門的 export job name。Migration 0121_export_jobs 完全符合計畫的 schema(status enum、requested_by、review_id、format)。
POST /api/v1/reviews/:id/export endpointRequest validation 依計畫重用 apps/api/src/validation/ 中的 zod schema。format 接受 mp4-burnin | csv | bundle。回傳 202 加上 job id;polling endpoint 依計畫延到步驟 6。
Review.duration_ms 是反正規化的,偶爾過時三筆 fixture review 的 duration_ms 跟來源素材 probe 資料不符(看起來重新上傳時沒有刷新)。匯出改為從 MediaAsset.probe.duration 讀取——跟 playbackManifest.ts 現有做法一樣。沒有計畫變更,只是給之後碰這塊的人的陷阱提醒。
frame_ts;burn-in renderer 可以排序並把它們都放到時間軸上。annotations 中約 12% 的 row 早於 migration 0087,frame_ts = NULL——它們是 per-frame 註解存在前的一般審閱評論。frame_ts 留空並加上 legacy_comment 標記。匯出 bundle 不會悄悄丟掉任何東西。created_at 對照 review session 推算 timestamp——決定這樣在影片中顯示是否夠誠實。drawtext/drawbox 做註解 burn-in,照計畫Filtergraph builder 在 apps/worker/src/exports/burnin.ts。計畫的 per-annotation overlay windows(enable='between(t,a,b)')可行;在 40 個註解的壓測 fixture 驗證過——worker instance class 上渲染時間是實時的 1.4 倍,在計畫的 2 倍預算內。
Date 物件來回傳成字串ExportJobPayload.requestedAt: Date,傳給 worker 並與 review 的 updated_at 比較以偵測過時的匯出。Date。過時比較在單元測試中悄悄強制轉型通過了,但在整合測試的重新投遞 job 上失敗。requestedAt: string ISO-8601),在 worker 邊界的 exportConsumer.ts 解析一次。不用自訂 serializer。media-tasks payload 可能有一樣的潛在 bug——一個共用的 job payload zod codec 可以修掉這整類問題。archiver 依賴archiver 來把匯出 bundle(影片 + CSV + 縮圖)建成 zip stream 到 S3。packages/media/src/zipStream.ts 已經有 streaming zip 加 backpressure 處理——它驅動批次素材下載功能,從三月就上線了。zipStream.ts。少一個依賴,bundle 匯出也繼承了跟批次下載一樣測試過的 backpressure 行為。zipStream 在 packages/media 但現在被兩個功能用——值得在清理時提升到 packages/shared。轉碼 pipeline 發送 media:progress:{assetId} 事件。遵循同樣的慣例——匯出發送 export:progress:{jobId}——這樣前端可以重用 apps/web/src/hooks/ 的 useProgressChannel(),而不是計畫草擬的 polling UI。polling endpoint 也保留了,作為備用。
guest_reviewer 角色授予 review 存取權但 can_download_assets = false——客戶用它讓外部利害關係人可以評論但不能把素材帶走。只檢查 review ACL 會讓訪客透過匯出洩漏原始影片。guest_reviewer 回傳 403,跟 assetAccess.ts 現有的素材下載檢查一致。最嚴格的防禦解讀。目前行為(來自偏離 4):訪客在所有匯出格式都收到 403。如果你希望訪客可以匯出不含素材的註解 CSV,在 exportPolicy.ts 大約改 10 行加一個測試——但這會改變「無法下載素材」對客戶的意義,所以應該由你決定。不阻擋 merge 或 QA。
計畫沒有指定產生的 bundle 的 TTL。我把它們放在 exports/ S3 prefix 下,7 天 lifecycle rule,跟分享連結到期時間一致——保守做法,沒有對客戶承諾更長時間。但如果合約或資料保留政策另有規定,infra/s3.tf 的 lifecycle rule 是唯一要改的一行。
三行可以貼到下一份計畫或 prompt 的內容,讓下次執行不用重新發現今天的意外。
frame_ts。在開始實作前決定要推算還是放 sidecar,不要在建置中途的 14:41 才決定。Date——而且一個共用的 media-tasks payload zod codec 可以消滅整類 bug。zipStream.ts 和 useProgressChannel() 都已經存在,都比計畫版本好用。在計畫模板加上「搜尋現有方案」步驟,並在下一個碰 ACL 的功能前解決訪客審閱者匯出政策。