# Thread-Master / 巡樓後端 — 架構導覽 這份文件幫助你**快速理解整個 monorepo 在幹什麼**,以及程式碼該從哪裡讀。 更細的 agent 規則見根目錄 `AGENTS.md`;產品方向(文案流重做)見 `docs/post-project-plan.md`。 --- ## 1. 這是什麼專案? **巡樓 Console + 後端**:給 Threads 經營者用的工作台。 | 能力 | 白話 | |------|------| | 帳號 / OAuth | 綁 Threads 帳號、token 刷新、連線診斷 | | 人設 (Persona) | 風格分析(8D)、語調、知識素材 | | 文案 / 任務 (Missions) | 主題發想、矩陣產稿、草稿排程(過渡期實作) | | 海巡 (Patrol) | 依品牌/主題找貼文、知識圖譜、外展草稿 | | 發布 (Publish) | 排程 queue、護欄、成效、提及回覆 | | Job 系統 | 所有長任務:爬蟲、AI 產稿、token 刷新等 | 技術主幹: ```text Go (go-zero) API + Mongo + Redis + Go workers(吃 Redis job queue) + Node/Playwright workers(8D 風格分析、關鍵字搜尋工具) + React 正式前端(backend/web) + Chrome extension(Threads session,目前前端同步刻意關閉) ``` --- ## 2. 目錄地圖 ```text thread-master/ ├── AGENTS.md # 寫碼/分層/時間/錯誤碼規範 ├── Makefile # 全 repo 指令入口 ├── docs/ # 產品與架構文件(本檔) ├── scripts/dev-all.sh # 一鍵起本機完整 stack ├── infra/ # Mongo/Redis、nginx、systemd ├── deploy/ # 正式 compose、env 範本 ├── extension/ # Chrome 擴充 └── backend/ # ★ 主產品(模組名 haixun-backend) ├── gateway.go # API 程序入口 ├── cmd/worker/ # Go worker 程序入口 ├── cmd/tool/ # init(索引、admin) ├── generate/api/*.api # API 契約(goctl) ├── etc/*.yaml # 設定 ├── internal/ │ ├── handler/ # HTTP 進出口 │ ├── logic/ # API 編排(不碰 Mongo 直接存取) │ ├── model/ # domain + usecase + repository │ ├── worker/job/ # step handler、scheduler、reaper │ ├── library/ # 共用能力(threads、placement、viral…) │ ├── middleware/ # JWT、RBAC、worker secret │ ├── svc/ # DI 組裝 ServiceContext │ └── response/ # JSON envelope ├── web/ # 正式 React Console ├── worker/ # Node/Playwright └── docs/ # job-system、gap 等後端計劃 ``` > 文件裡有時寫 `haixun-backend/`,在 monorepo 裡就是 **`backend/`**。 --- ## 3. 怎麼跑起來 ```bash # 1. 環境 cp deploy/.env.dev.example deploy/.env.dev # 填 Mongo/Redis/JWT/Worker secret # 2. 資料庫 make dev-infra # 3. 一鍵:API + Go workers + Node tools/worker + 前端 make dev-all # 或拆開 make run # API :8890 make web-dev # Vite :5173,proxy 到 API ``` | 服務 | 埠 | |------|-----| | API gateway | 8890 | | 前端 Vite | 5173–5199 | | keyword-search tool | 9101 | | resolve-media tool | 9102 | 健康檢查:`curl http://127.0.0.1:8890/api/v1/health` 首次帳號:`make init`(建索引、權限、admin)。註冊一般會員需 **admin JWT**(封閉註冊)。 --- ## 4. 請求怎麼走 ```text Browser / Worker → (nginx 可選) → go-zero Server (gateway.go) → middleware(JWT / MemberAuth / WorkerSecret) → handler(parse + validate) → logic(讀 actor、組 request) → model/usecase(業務) → repository(Mongo / Redis)或 library adapter → response.Write { code, message, data, error } ``` ### 分層規則(必守) | 層 | 可以做 | 不可以做 | |----|--------|----------| | handler | parse、validate、呼叫 logic | 業務判斷、直接 Mongo | | logic | 編排 usecase、組 payload | import `model/*/repository` | | model/usecase | 可重用業務 | 知道 HTTP | | AI provider adapter | 呼叫外部 AI | 讀 setting、Mongo、HTTP context | | worker step | 透過 job usecase 更新進度 | 裸 Update 蓋 job 狀態 | ### Auth 重點 | 路由類型 | Header | |----------|--------| | 一般保護 API | `Authorization: Bearer <會員 JWT>` | | AI(provider key 占 Authorization) | `X-Member-Authorization` + `Authorization: ` | | 內部 worker | `X-Worker-Secret` | Access token 由 `/api/v1/auth/login|refresh` 簽發。AI key **每次 request 帶入**,不寫進 config。 ### 時間與列表 - 儲存/API 時間欄位:**unix nanoseconds(UTC)** - 列表:`?page=&pageSize=`,回傳 `data.pagination` + `data.list`(部分舊 API 仍用 `limit`,屬技術債) --- ## 5. Job 系統(最重要的背景機制) 長任務一律走 job,不要在 HTTP request 裡跑 Playwright / 長 LLM。 ```text CreateRun(API 或內部) → Mongo 寫 run(pending) → Redis 佇列 jobs:queue: Worker ClaimNext → BRPOP → TryLock(jobID, workerID) → status → running → 依 template steps 執行 handler → Heartbeat 續 lock → CompleteRun / FailRun / AcknowledgeCancel ``` | 元件 | 檔案 | |------|------| | 建立 / claim / 完成 | `internal/model/job/usecase/usecase.go` | | Redis queue/lock | `internal/model/job/repository/redis_queue.go` | | Go runner | `internal/worker/job/runner.go` | | 排程 / reaper | `scheduler.go` / `reaper.go` | | 設計文件 | `backend/docs/job-system-plan.md` | **規則:** 狀態轉移用 guarded update;lock value = `workerID`;release 必須檢查 owner。 ### 程序角色 | 程序 | 職責 | |------|------| | Gateway | HTTP;可跑 scheduler/reaper/token/publish sweeper;**通常不 claim job** | | Go worker(一 type 一 process) | 消費對應 queue、跑 step handler | | Node style-8d | 經 **HTTP internal API** claim,Playwright 爬公開頁 | | Node keyword/media | 被 Go 呼叫的 HTTP 工具,不是 job consumer | Gateway 在 `JobWorker.Enabled=false` 時,仍可能 **inline** 起 topic/formula/rewrite 三個 copy worker(見 `internal/svc/job_workers.go`)。 --- ## 6. 產品功能地圖(前端 ↔ 後端) 前端是 **hash 路由**(`App.tsx`),沒有 React Router。 | Hash | 頁面 | 主要後端域 | |------|------|------------| | `#dashboard` | 總覽 | accounts、jobs、publish summary | | `#accounts` | Threads 帳號 | threads_account、OAuth、guard | | `#brands` | 品牌 / 產品 | brand | | `#personas` | 人設 / 8D | persona、style_preset、style-8d job | | `#missions` | 文案工作台 | inspire、content_ops、copy_draft、matrix/formula/rewrite jobs | | `#patrol` | 海巡獲客 | placement_topic、knowledge_graph、scan_post、outreach | | `#publish` | 發布 / 回覆 / 自家貼 | publish_queue、mention_inbox、own_post_formula | | `#jobs` | 任務監控 | job runs / schedules / events | | `#settings` | 會員 / AI | member、placement settings | | `#gaps` | 靜態路線圖 | **無 API** | | `#register` | 管理員建會員 | auth register(需 admin) | API client:`backend/web/src/api/haixun.ts` + `client.ts`(envelope、refresh、502 retry)。 ### 兩條產品流 ```text Flow A 文案營運(過渡) MissionsPage → inspire / content plans / matrix / drafts → publish_queue 舊 copy_mission 完整 pipeline 已半拆(見 post-project-plan) Flow B 海巡獲客 Brands + PatrolPage → 主題 → 圖譜 → 掃描貼文 → outreach 草稿 → 發布 ``` `docs/post-project-plan.md` 計劃用 **Post Project** 取代 Flow A 舊 pipeline。 --- ## 7. 後端 model 一覽(讀碼用) | model | 用途 | 前端是否主用 | |-------|------|----------------| | auth / member / permission | 登入與 RBAC | 是 | | setting | 通用 KV | 弱(多半用 typed settings) | | ai | provider 抽象 + SSE | 設定頁 / AI 路由 | | job | 模板 / run / schedule / event | Jobs + 各頁輪詢 | | threads_account | 帳號、OAuth、token | 是 | | persona / style_preset | 人設 | 是 | | content_ops | 主題候補、content plan、知識、feedback | Missions | | content_formula / own_post_formula | 公式 / 自家貼分析 | Publish / Missions | | copy_draft | 文案草稿 | Missions | | copy_mission | 舊文案任務實體 | **幾乎不用**(僅邊角耦合) | | brand / placement_topic | 品牌與海巡主題 | Brands / Patrol | | knowledge_graph | 知識圖譜 | Patrol | | scan_post / outreach_draft | 掃描貼文與外展 | Patrol | | publish_* | queue / guard / inventory / analytics / events | Publish / Dashboard | | mention_inbox | 提及收件 | Publish | | (已移除)crm_contact / publish_draft scaffold | 見 `docs/cleanup-log.md` | — | 業務重邏輯常在 `internal/library/`(`placement`、`viral`、`threadsapi`、`prompt`…),不是 `model/`。 --- ## 8. 建議閱讀順序 1. 本文件 + `AGENTS.md` 核心原則 2. `backend/gateway.go` → `internal/svc/service_context.go`(DI 全貌) 3. `internal/handler/routes.go`(有哪些 API) 4. 挑一條線跟到底,例如: - 登入:`logic/auth` → `model/auth` - 建 job:`logic/job` → `model/job/usecase` → Redis - 海巡掃描:`logic/placement_topic` → worker `scan_placement.go` 5. 前端:`web/src/App.tsx` → 某一頁 → `api/haixun.ts` 6. Job 細節:`backend/docs/job-system-plan.md` --- ## 9. 常見陷阱 1. **路徑名**:repo 是 `backend/`,文件可能寫 `haixun-backend/`。 2. **假成功**:歷史上部分 goctl stub 會 `return nil` → HTTP 200;清理後不應再有。 3. **兩個 token**:會員 JWT ≠ AI provider key,header 用途不同。 4. **worker 與 gateway**:gateway 不一定 claim job;少起 worker 時長任務會卡 queued。 5. **inline workers**:本機 gateway 可能偷偷起 3 個 copy worker,prod compose 要自己對齊。 6. **時間**:nano 不是毫秒;Node 端有時是 ms 精度假 ns。 7. **DevHeaderFallback**:本機 yaml 可用 `X-Tenant-ID`/`X-UID` 跳過 JWT,prod 必須關。 --- ## 10. 相關文件 | 文件 | 內容 | |------|------| | `docs/architecture.md` | 本導覽 | | `docs/improvement-notes.md` | 前後端可改進處 | | `docs/cleanup-log.md` | 已清除的死碼紀錄 | | `docs/post-project-plan.md` | 文案流(Flow A)重做計劃 | | `backend/docs/job-system-plan.md` | Job 系統設計 | | `backend/docs/threads-automation-gap-plan.md` | 自動營運 gap(部分已落地) | | `backend/README.md` | 後端 README / API 慣例 | | `AGENTS.md` | Agent / 開發規範 |