13 KiB
Post Project 計劃(文案任務 Flow A 砍掉重做)
取代
backend/docs/threads-automation-gap-plan.md中文案自動營運閉環的舊版 Flow A。Flow B(海巡獲客:brand / placement_topic / outreach_drafts / PatrolPage)不在本計劃範圍。
1. 動機
舊版文案任務(Flow A)流程過重:
-
一個任務跑 5 個 worker(analyze → expand-graph → scan-viral → matrix → copy-draft),加上 refill-publish-inventory 自動補庫存旁路。
-
中間產 research map、knowledge graph、scan_posts、相似帳號 / 受眾樣本等中介資料,前端被 pipeline 狀態綁住。
-
使用者真正要的是:
單純 po 文、相似貼文模仿、發想主題、AI 找網路資料、矩陣產 N 篇、定時發送、可選人設、可貼參考貼文讓 AI 學風格。
本計劃把 Flow A 整包砍掉重做,換成線性可操作的「發文計畫(Post Project)」。
2. 範圍
砍
- Persona 文案流(copy_mission / copy_draft 全部)
- refill-publish-inventory worker 與其 publish_inventory policy 接面
- 5 個文案 worker(analyze-copy-mission / expand-copy-mission-graph / generate-copy-matrix / generate-copy-draft / refill-publish-inventory)
library/copymission/、library/matrix/copy_generate.go、library/viral/mission_*.go、library/viral/research_map.go- prompt files
matrix_copy.* - 前端 MissionsPage +
pages/missions/ copy_missions/copy_drafts兩個 MongoDB collection(drop)
不動
- Flow B(brand / placement_topic outreach_drafts、PatrolPage 海巡獲客)
outreach_draftsmodel / library/outreach /generate-outreach-draftworkerknowledge_graphmodel(brand / placement_topic 共用)scan_post通用 viral 採樓能力(移除CopyMissionID欄位即可)publish_queue/publish_analytics通用發布與量測- scheduler / reaper / sweeper / token-sweeper / refresh-threads-token 通用 worker
- Persona model / API(沿用)
新增
- 兩個 collection:
post_projects/post_drafts - 一個 worker:
go-generate-post-matrix - 三個同步 LLM endpoint:research-topics / analyze-style / generate-matrix
- 一條線性的前端 wizard 頁面
- 三份 prompt files(post_matrix_generate / analyze_style / research_topics)
3. 資料模型
post_projects
| 欄位 | 型態 | 說明 |
|---|---|---|
_id |
ObjectID | |
tenant_id |
string | |
owner_uid |
string | |
persona_id |
ObjectID | 關聯 personas |
label |
string | 使用者自訂專案名 |
topic |
string | 使用者選定 / 編輯後的主題描述 |
web_research_summary |
string | research-topics 回傳的摘要 |
web_research_refs |
[]object | [{url, title, snippet}] |
style_profile |
object | analyze-style 回的結構化風格 |
style_summary |
string | 給前端顯示的風格短述 |
style_references |
[]string | 使用者貼進來的參考貼文原文 |
status |
string | topic_set / style_set / matrix_generating / drafts_ready / archived |
matrix_draft_count |
int | 矩陣產生的草稿數 |
created_at / updated_at |
int64 | unix nanoseconds(UTC+0) |
style_profile 建議結構:
{
"tone": "親切、口語、像跟朋友聊天",
"length": "短至中(80-180 字)",
"structure": ["hook", "故事", "takeaway", "互動問句"],
"emoji_usage": "少量,平均 1-2 顆,放結尾",
"hook_style": "提問或反差句",
"avoid": ["過度口號", "廉價 emoji 疊字"]
}
post_drafts
| 欄位 | 型態 | 說明 |
|---|---|---|
_id |
ObjectID | |
tenant_id |
string | |
project_id |
ObjectID | 關聯 post_project |
persona_id |
ObjectID | |
topic |
string | snapshot 主題(生成時) |
angle |
string | AI 給該篇的角度標籤 |
hook |
string | AI 給的 hook |
text |
string | 草稿本文 |
rationale |
string | AI 說為何這樣寫 |
sources |
[]object | [{url, title}] 引用網路資料 |
status |
string | draft / scheduled / published |
publish_queue_id |
ObjectID? | 排入佇列後回填 |
scheduled_at |
int64? | 排程時間 |
published_post_id |
string? | 發布後 Threads post id |
created_at / updated_at |
int64 | unix nanoseconds |
publish_queue.queue_item 改欄位
copy_mission_id/copy_draft_id→post_project_id/post_draft_id(可空,舊資料不再解析)- 既有 outreach 排程不受影響(Flow B 不靠這兩欄)
publish_inventory policy
- 移除
copy_mission_id欄位(refill worker 已砍) - publish_inventory 對 outreach 是否仍有用需確認;若只服務文案 refill 則整個 model 一併砍。階段 1 解耦時若發現 inventory 僅供 refill,連 collection 一起 drop。
4. API
新 generate/api/post_project.api,import 至 gateway.api。
Prefix: /api/v1/personas (scope) 與 /api/v1/post-projects (資源)
POST /api/v1/personas/:personaId/post-projects
GET /api/v1/personas/:personaId/post-projects
GET /api/v1/post-projects/:projectId
PATCH /api/v1/post-projects/:projectId (label / topic / status)
DELETE /api/v1/post-projects/:projectId
POST /api/v1/post-projects/:projectId/research-topics sync: { seed } -> { suggestions[], refs[] }
POST /api/v1/post-projects/:projectId/analyze-style sync: { references:[{text}] } -> { style_profile, style_summary }
POST /api/v1/post-projects/:projectId/generate-matrix async job: enqueue generate-post-matrix
POST /api/v1/post-projects/:projectId/drafts/:draftId/regenerate async job: 重生單篇
GET /api/v1/post-projects/:projectId/drafts
PATCH /api/v1/post-projects/:projectId/drafts/:draftId (text / angle / sources)
DELETE /api/v1/post-projects/:projectId/drafts/:draftId
POST /api/v1/post-projects/:projectId/drafts/schedule body: [{draft_id, send_at}] -> publish_queue.Create
Envelope:code/message/data/error;列表用 page/pageSize + pagination/list。
5. Worker
internal/worker/job/generate_post_matrix.go
workerType = "go-generate-post-matrix"step = "post_matrix_generate"- 讀
project.topic+project.style_profile+persona+project.web_research_refs - 組 prompt → LLM 一次吐 N 篇(N=5 預設)
- 寫 N 個
post_draftsdoc - 更新
project.status = drafts_ready、matrix_draft_count = N - 過程中
RefreshRunLock+Heartbeat,不做 cancel 自行設狀態
regenerate 走同一個 worker 同一 template,payload 帶 target_draft_id:
- 有 → 刪舊 draft / 重生一篇覆蓋
- 無 → 全新矩陣
6. Library
新 internal/library/post_matrix/(取代 library/copymission/):
analyze_style.go:貼文 → LLM → 吐style_profileJSON +style_summaryresearch_topics.go:seed → 內部 websearch(node-tool-keyword-search或library/viral/crawler_search) → LLM 摘要 + 主題候選generate.go:組 prompt → LLM → N 篇 post_drafts
prompt files(internal/library/prompt/files/):
post_matrix_generate.system.md/.user.mdanalyze_style.system.md/.user.mdresearch_topics.system.md/.user.md
7. 前端
7.1 新頁面 web/src/pages/PostProjectsPage.tsx
取代 MissionsPage,5-step wizard(沿用 PageTitle / Card / Field / Input / Textarea / Button / Badge):
- 人設:下拉選 Persona
- 主題:
- Textarea 輸入 seed 或想法
- 按鈕「給我主題靈感」→
research-topics(同步) → 顯示 3-5 張主題卡(含摘要 + 來源) - 點卡片自動填 Textarea,或手動編輯
- 「再查一次」換一批
- 風格(可選):
- Textarea 貼 1~N 篇參考貼文(空行分隔)
- 按鈕「分析風格」→
analyze-style(同步) → 顯示style_profile條列 - 可重貼、重新分析
- 矩陣:
- 按鈕「產生 5 篇草稿」→
generate-matrixjob → polling 進度 - 顯示 N 張草稿卡(Hook / Text / Angle / Sources)
- 每張可:編輯 / 刪除 / 重生單篇
- 按鈕「產生 5 篇草稿」→
- 排程:
- 勾選草稿 → 展開 datetime-local 輸入
- 「排入佇列」→
drafts/schedule - 顯示排程清單(沿用 publish_queue 顯示元件)
7.2 路由 / 導覽
App.tsx:case "posts": return <PostProjectsPage />,加進validPages/accountRequiredPagesacAssets.tsnavApps:把原missions換成posts(label「發文計畫」,sublabelPOST)mobileNavKeys同步替換AcIcon:mission換postsSVG(鉛筆 + 對話框 stack 線條稿)validPages/accountRequiredPages移除"missions"
7.3 API client
api/haixun.ts:
- 刪 types
CopyMission、ContentInboxItem、CopyMissionID等相關 - 刪 endpoints
copyMissions/createCopyMission/inspireCopyMission/startCopyMissionAnalyze/startCopyMissionMatrix/scheduleMissionDrafts/ persona copy-drafts 系列 - 新 types
PostProject/PostDraft/StyleProfile - 新 endpoints
createPostProject/listPostProjects/researchTopics/analyzeStyle/generateMatrix/regenerateDraft/listPostDrafts/updatePostDraft/deletePostDraft/schedulePostDrafts - 保留 outreach_drafts endpoints(Flow B)
8. Infra / deploy
deploy/docker-compose.yml:
- 刪
worker-copy-mission-analyze/worker-copy-mission-expand-graph/worker-copy-matrix/worker-copy-draft/worker-refill-publish-inventory五個 service - 新
worker-post-matrix:HAIXUN_JOB_WORKER_TYPE=go-generate-post-matrix/HAIXUN_JOB_WORKER_ID=go-generate-post-matrix - 保留:
worker-scan-viral、worker-outreach-draft、其餘通用 worker
9. Migration
internal/bootstrap/init.go 加 idempotent migration block:
db.RunCommand({dropIndexes: "publish_queue"})必要時重 EnsureIndexes- 寫一個
toolsubcommand(沿用backend/cmd/tool)或 init runtime 做一次性:- drop
copy_missionscollection(忽略 not exist) - drop
copy_draftscollection(忽略 not exist) - rename
publish_queue.copy_mission_id→post_project_id、copy_draft_id→post_draft_id(對存量資料,若有人 queue 還沒發) - 移除
publish_inventory.policy.copy_mission_id欄位(或整 droppublish_inventoriescollection,階段 1 確認後決定)
- drop
- 新 EnsureIndexes
post_projects(tenant+owner+status)、post_drafts(project_id+status)
執行:首次 make prod-install 跑 init,後續 make prod-rebuild 即可。
10. 執行階段
| 階段 | 動作 | 驗證 |
|---|---|---|
| 1. 後端解耦 | scan_viral 拔 CopyMission/CopyDraft 依賴;刪 refill_publish_inventory.go;service_context 對應移除;publish_queue / publish_inventory entity 改欄位 | go test ./... Flow B 仍綠 |
| 2. 刪除 Flow A 後端 | api / handler / logic / model / worker template / library / prompt 全砍;make gen-api 重產 |
go test ./... 通過 |
| 3. 前端清 Flow A | MissionsPage / missions 目錄 / App.tsx / Layout / acAssets / haixun.ts 清 off | make web-build 通過 |
| 4. Infra 清理 | docker-compose.yml 刪 5 個 worker service | docker compose config 過 |
| 5. 新後端實作 | post_project / post_draft model + usecase + repository;post_project.api + generate_post_matrix.go worker + library/post_matrix + prompt files;job template 註冊 | go test ./... 通過 |
| 6. 新前端 | PostProjectsPage + 5-step wizard;AcIcon 新 icon | make web-build 通過 |
| 7. DB migration | bootstrap init drop / rename / EnsureIndexes | docker run init 過 |
| 8. 煙霧測試 | 開 project → 靈感 → 風格 → 矩陣 → 排程 → sweeper 發;Flow B outreach 仍可;JobsPage 顯示新 type | 部署在 dev 環境實測 |
每階段結束跑 go mod tidy && make fmt && go test ./... && make web-build。
11. 風險 / 開放問題
- websearch 串接:
library/viral/crawler_search.go與node-tool-keyword-search服務是否適合 research-topics 用?實作時驗證呼叫 path;不順則直接打內部 node-tool-keyword-search HTTP。 - publish_queue rename 對存量資料:先做 null-tolerant(舊資料視為已發 / 忽略),降低遷移負擔;正式上線前可一次性 rename script。
- publish_inventory 是否完全沒用:階段 1 確認;若 Flow B 不依賴,整包砍。
- style_profile 形態:採 JSON 結構化(語氣 / 長度 / 結構 / emoji / hook_style / avoid),方便前端顯示;prompt 需校調測試。
- 矩陣批次數:MVP 固定 N=5;後續可加
countquery 參數,受 persona 配額上限保護。 - regenerate 是否保留 sources:MVP 整篇重來,不保留;後續可加「保留 sources」選項。
12. 不在本計劃範圍
- Flow B 重做(若日後需要另開計劃)
- Persona model 改造(沿用)
- publish_queue_sweeper 行為修改(沿用)
- A/B 測試、自動成效優化(屬另一個閉環計劃)