thread-master/old/docs/post-project-plan.md

262 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 個 workeranalyze → 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 個文案 workeranalyze-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 collectiondrop
### 不動
- Flow Bbrand / placement_topic outreach_drafts、PatrolPage 海巡獲客)
- `outreach_drafts` model / library/outreach / `generate-outreach-draft` worker
- `knowledge_graph` modelbrand / 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 endpointresearch-topics / analyze-style / generate-matrix
- 一條線性的前端 wizard 頁面
- 三份 prompt filespost_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 nanosecondsUTC+0 |
`style_profile` 建議結構:
```json
{
"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_drafts` doc
- 更新 `project.status = drafts_ready`、`matrix_draft_count = N`
- 過程中 `RefreshRunLock` + `Heartbeat`,不做 cancel 自行設狀態
regenerate 走同一個 worker 同一 templatepayload 帶 `target_draft_id`
- 有 → 刪舊 draft / 重生一篇覆蓋
- 無 → 全新矩陣
## 6. Library
`internal/library/post_matrix/`(取代 `library/copymission/`
- `analyze_style.go`:貼文 → LLM → 吐 `style_profile` JSON + `style_summary`
- `research_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.md`
- `analyze_style.system.md` / `.user.md`
- `research_topics.system.md` / `.user.md`
## 7. 前端
### 7.1 新頁面 `web/src/pages/PostProjectsPage.tsx`
取代 MissionsPage5-step wizard沿用 `PageTitle` / `Card` / `Field` / `Input` / `Textarea` / `Button` / `Badge`
1. **人設**:下拉選 Persona
2. **主題**
- Textarea 輸入 seed 或想法
- 按鈕「給我主題靈感」→ `research-topics`(同步) → 顯示 3-5 張主題卡(含摘要 + 來源)
- 點卡片自動填 Textarea或手動編輯
- 「再查一次」換一批
3. **風格**(可選):
- Textarea 貼 1~N 篇參考貼文(空行分隔)
- 按鈕「分析風格」→ `analyze-style`(同步) → 顯示 `style_profile` 條列
- 可重貼、重新分析
4. **矩陣**
- 按鈕「產生 5 篇草稿」→ `generate-matrix` job → polling 進度
- 顯示 N 張草稿卡Hook / Text / Angle / Sources
- 每張可:編輯 / 刪除 / 重生單篇
5. **排程**
- 勾選草稿 → 展開 datetime-local 輸入
- 「排入佇列」→ `drafts/schedule`
- 顯示排程清單(沿用 publish_queue 顯示元件)
### 7.2 路由 / 導覽
- `App.tsx``case "posts": return <PostProjectsPage />`,加進 `validPages` / `accountRequiredPages`
- `acAssets.ts` `navApps`:把原 `missions` 換成 `posts`label「發文計畫」sublabel `POST`
- `mobileNavKeys` 同步替換
- `AcIcon``mission` 換 `posts` SVG鉛筆 + 對話框 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 endpointsFlow 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
- 寫一個 `tool` subcommand沿用 `backend/cmd/tool`)或 init runtime 做一次性:
- drop `copy_missions` collection忽略 not exist
- drop `copy_drafts` collection忽略 not exist
- rename `publish_queue.copy_mission_id``post_project_id`、`copy_draft_id` → `post_draft_id`(對存量資料,若有人 queue 還沒發)
- 移除 `publish_inventory.policy.copy_mission_id` 欄位(或整 drop `publish_inventories` collection階段 1 確認後決定)
- 新 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.goservice_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 + repositorypost_project.api + generate_post_matrix.go worker + library/post_matrix + prompt filesjob template 註冊 | `go test ./...` 通過 |
| **6. 新前端** | PostProjectsPage + 5-step wizardAcIcon 新 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. 風險 / 開放問題
1. **websearch 串接**`library/viral/crawler_search.go` 與 `node-tool-keyword-search` 服務是否適合 research-topics 用?實作時驗證呼叫 path不順則直接打內部 node-tool-keyword-search HTTP。
2. **publish_queue rename 對存量資料**:先做 null-tolerant舊資料視為已發 / 忽略),降低遷移負擔;正式上線前可一次性 rename script。
3. **publish_inventory 是否完全沒用**:階段 1 確認;若 Flow B 不依賴,整包砍。
4. **style_profile 形態**:採 JSON 結構化(語氣 / 長度 / 結構 / emoji / hook_style / avoid方便前端顯示prompt 需校調測試。
5. **矩陣批次數**MVP 固定 N=5後續可加 `count` query 參數,受 persona 配額上限保護。
6. **regenerate 是否保留 sources**MVP 整篇重來,不保留;後續可加「保留 sources」選項。
## 12. 不在本計劃範圍
- Flow B 重做(若日後需要另開計劃)
- Persona model 改造(沿用)
- publish_queue_sweeper 行為修改(沿用)
- A/B 測試、自動成效優化(屬另一個閉環計劃)