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

262 lines
13 KiB
Markdown
Raw Normal View History

# 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 測試、自動成效優化(屬另一個閉環計劃)