Files
geo/docs/geo-platform-ops-admin-tech-architecture-v1.md
T
root 5ff2e2e74c refactor(tenant): drop legacy plugin_installations, migrate monitoring to desktop_clients
Hard cutover from the browser-extension plugin flow to desktop clients:
remove plugin_installations/plugin_sessions tables and related service,
handler, router, and generated model code; migrate monitoring quotas
and collector types to desktop_clients (UUID primary_client_id);
recreate platform_access_snapshots keyed by client_id; update dev-seed
and callback types accordingly; mark legacy design docs as historical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 13:52:35 +08:00

1514 lines
58 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.
# GEO 双后台与后端技术架构方案 V1
> 工作记录说明:本文仍保留作为历史架构记录。其中涉及浏览器插件执行链路、`/api/callback/plugin/*`、`plugin_sessions`、`installation_token` 的相关章节,自 2026-04-20 起视为旧版设计;当前实现请以 desktop client 方案和最新代码为准。
## 1. 文档信息
| 项目 | 内容 |
| --- | --- |
| 文档名称 | GEO 双后台与后端技术架构方案 V1 |
| 文档版本 | V1.0 |
| 文档状态 | 待评审 |
| 创建日期 | 2026-03-25 |
| 适用范围 | `admin-web``ops-admin-web` 与 Go 后端整体架构设计 |
| 关联文档 | `docs/geo-platform-prd-v1.md` |
| 关联文档 | `docs/geo-platform-ops-admin-prd-v1.md` |
| 关联文档 | `docs/geo-platform-tech-architecture-v1-50k.md` |
## 2. 目标与结论
### 2.1 建设目标
本方案用于明确 GEO 平台在 V1 阶段的双后台形态与后端落地方式,满足以下目标:
- 面向租户提供独立的业务后台 `admin-web`
- 面向平台内部提供独立的管理后台 `ops-admin-web`
- 后端统一采用 Go 实现,控制复杂度,同时保留后续拆分能力
- 支撑内容生成、知识学习、任务运维、额度管理、平台配置和审计能力
- 在 V1 阶段做到“结构清晰、实现收敛、可持续演进”
### 2.2 核心结论
V1 推荐采用以下架构策略:
- 前端采用 `pnpm workspace + Vue 3 + TypeScript + ant-design-vue + Vite 8(截至 2026-03 官方稳定主线)`
- 前端拆分为两个独立应用:`apps/admin-web``apps/ops-admin-web`
- 公共能力通过 `packages/*` 复用,而不是让两个应用互相引用业务代码
- 后端采用 `Go + Gin + PostgreSQL + Redis + RabbitMQ + Qdrant + 对象存储`
- 对象存储支持双实现:公有云部署推荐 `阿里云 OSS + CDN`,私有化部署推荐 `MinIO + Nginx / CDN`
- 工程脚手架可使用 [`sponge`](https://github.com/go-dev-frame/sponge),但仅用于项目初始化、基础设施接线与简单样板生成;不直接生成业务 `handler/service/dao` 主体代码,领域边界仍以本文的 `transport -> app -> domain -> repository` 分层为准
- 后端拆分为 `gateway + tenant-api + platform-api + scheduler + 多个 Worker`,其中 `gateway` 必须保持超薄
- API 按路由前缀隔离:`/api/tenant/*``/api/platform/*`
- 权限按两层建模:`tenant_role``platform_role`
- 重任务统一异步化,任务进度通过 `SSE` 或短轮询回写
### 2.3 架构边界
| 维度 | `admin-web` | `ops-admin-web` |
| --- | --- | --- |
| 服务对象 | 租户用户 | 平台内部人员 |
| 数据范围 | 当前租户 | 全平台或指定租户 |
| 核心目标 | 生成、发布、查看内容与数据 | 管租户、管配置、管任务、管风险 |
| 权限模型 | `tenant_role` | `platform_role` |
| API 前缀 | `/api/tenant/*` | `/api/platform/*` |
## 3. 仓库结构方案
### 3.1 推荐目录
```text
D:\project\geo
├─ apps
│ ├─ admin-web
│ ├─ ops-admin-web
│ └─ browser-extension
├─ packages
│ ├─ ui
│ ├─ shared-types
│ ├─ http-client
│ ├─ utils
│ ├─ eslint-config
│ └─ tsconfig
├─ server
│ ├─ cmd
│ │ ├─ gateway
│ │ ├─ tenant-api
│ │ ├─ platform-api
│ │ ├─ scheduler
│ │ ├─ worker-generate
│ │ ├─ worker-knowledge
│ │ ├─ worker-analytics
│ │ └─ worker-publish-callback
│ ├─ internal
│ ├─ migrations
│ ├─ sql
│ └─ pkg
├─ deploy
│ ├─ docker-compose
│ └─ k8s
└─ docs
```
### 3.2 前端共享包建议
- `packages/ui`
- 通用布局、表格筛选栏、状态标签、详情抽屉、权限按钮
- `packages/shared-types`
- 前后端共用 DTO、分页结构、状态枚举、角色枚举
- `packages/http-client`
- Axios 实例、鉴权拦截器、错误处理、统一响应解包
- `packages/utils`
- 时间、金额、脱敏、下载、表格导出等工具
- `packages/eslint-config`
- 统一 ESLint 规则
- `packages/tsconfig`
- 统一 TS 配置基线
### 3.3 是否需要第三个前端应用
当前双后台方案覆盖了租户侧和平台侧的控制面,但租户侧 V1 的媒体绑定与手动发布还依赖独立执行面。
因此 V1 建议同步建设:
- `apps/browser-extension`
该应用不属于当前“双后台”主体,但属于 V1 必选执行端,负责真实登录检测、绑定回传、图片上传、手动发布和状态校验。
## 4. 前端完整方案
## 4.1 `apps/admin-web` 定位
租户端后台,主要服务于租户管理员与编辑,负责:
- 工作台
- 文章生成与管理
- 品牌与知识库管理
- 媒体账号绑定与手动发布
- 数据追踪与套餐额度查看
### 4.1.1 路由建议
```text
/login
/workspace
/articles
/articles/:id
/brands
/knowledge
/media
/tracking
/account
```
### 4.1.2 页面特点
- 业务操作多
- 任务状态多
- 详情页和表单较多
- 需要关注生成与发布的过程反馈
## 4.2 `apps/ops-admin-web` 定位
平台管理员端,主要服务于超级管理员、平台运营、客服支持、财务运营、审核风控与技术运维,负责:
- 平台工作台
- 租户中心
- 套餐与额度
- 平台用户与角色
- 模型中心
- 内容配置
- 任务运维
- 监控告警
- 审计中心
### 4.2.1 路由建议
```text
/login
/platform/dashboard
/platform/tenants
/platform/tenants/:id
/platform/plans
/platform/platform-users
/platform/models
/platform/content
/platform/tasks
/platform/monitoring
/platform/audit
```
### 4.2.2 页面特点
- 列表、筛选、统计卡片较多
- 高风险操作较多
- 权限粒度更细
- 更偏运维、审计、治理和配置管理
## 4.3 前端技术栈建议
- `vue`
- `typescript`
- `vite`
- `pnpm`
- `ant-design-vue`
- `vue-router`
- `pinia`
- `@tanstack/vue-query`
- `axios`
- `zod`
- `@vueuse/core`
- `dayjs`
- `vitest`
## 4.4 前端工程规范
- 每个应用独立 `src`,共享能力全部进入 `packages`
- 菜单、按钮、路由权限全部由权限配置表驱动
- 页面模式统一为:`筛选区 + 表格区 + 详情抽屉 / 详情页`
- 长任务状态统一使用 `状态标签 + 默认轮询`,仅在存在运行中任务的活跃页面临时升级为 `SSE`
- 高风险按钮统一带确认弹窗和原因输入框
## 4.5 前端部署建议
- `admin-web``ops-admin-web` 独立构建、独立发布
- 推荐独立域名或子路径:
- `admin.xxx.com`
- `ops.xxx.com`
- 两套前端都走 CDN,后端统一走 API 域名
## 5. 后端完整方案
## 5.1 V1 后端总体策略
V1 推荐:
- `1 个统一网关出口`
- `2 个 Go API 服务`
- `1 个 Scheduler`
- `4 类异步 Worker`
- `1 个浏览器插件执行端`
- `1 套统一基础设施`
其中:
- `tenant-api` 负责租户侧核心业务
- `platform-api` 负责平台治理与内部管理
- `gateway` 负责统一接入、路由转发、公共鉴权、租户级限流与 `request_id` 注入
V1 保留 `gateway`,但必须满足以下硬约束:
- 只做 `route + auth + rate limit + request_id/trace_id 注入 + 错误响应封装`
- 不承载任何 `tenant/*``platform/*` 业务逻辑
- 不直接写 PostgreSQL 业务表,不发 MQ 业务消息,不做任务编排
- 若未来部署环境极简,可由 `Ingress / Nginx` 直接分流到 `tenant-api``platform-api`;本文默认仍保留超薄 `gateway`
这样可以避免:
- 过早微服务化
- 大量跨服务联调
- 权限和数据边界复杂化
- 运维成本提前爆炸
同时,V1 不建议把 `worker-generate / worker-knowledge / worker-analytics / worker-publish-callback` 合并成单一 Worker 进程,因为:
- 交互式生成链路的时延目标高于知识学习和统计聚合
- LLM、Embedding、统计聚合的资源模型不同
- 回调补偿链路需要与用户生成链路故障隔离
- 运维简化更适合通过共享容器基座、统一 Helm 模板和统一日志规范实现,而不是牺牲任务隔离
## 5.2 Go 后端目录结构
```text
server
├─ cmd
│ ├─ gateway
│ ├─ tenant-api
│ ├─ platform-api
│ ├─ scheduler
│ ├─ worker-generate
│ ├─ worker-knowledge
│ ├─ worker-analytics
│ └─ worker-publish-callback
├─ internal
│ ├─ bootstrap
│ ├─ shared
│ │ ├─ auth
│ │ ├─ config
│ │ ├─ middleware
│ │ ├─ observability
│ │ ├─ plugin
│ │ ├─ retrieval
│ │ ├─ scheduler
│ │ ├─ sse
│ │ ├─ repository
│ │ │ ├─ postgres
│ │ │ ├─ redis
│ │ │ ├─ rabbitmq
│ │ │ ├─ qdrant
│ │ │ └─ objectstorage
│ │ └─ dto
│ ├─ tenant
│ │ ├─ transport
│ │ ├─ app
│ │ ├─ domain
│ │ └─ repository
│ ├─ platform
│ │ ├─ transport
│ │ ├─ app
│ │ ├─ domain
│ │ └─ repository
│ ├─ jobs
│ └─ gateway
├─ migrations
├─ sql
└─ pkg
```
## 5.3 API 路由分层建议
### 5.3.1 公共接口
- `/api/health/*`
- `/api/auth/*`
### 5.3.2 租户端接口
- `/api/tenant/workspace/*`
- `/api/tenant/articles/*`
- `/api/tenant/brands/*`
- `/api/tenant/knowledge/*`
- `/api/tenant/media/*`
- `/api/tenant/tracking/*`
- `/api/tenant/account/*`
### 5.3.3 平台管理员端接口
- `/api/platform/dashboard/*`
- `/api/platform/tenants/*`
- `/api/platform/plans/*`
- `/api/platform/platform-users/*`
- `/api/platform/models/*`
- `/api/platform/content/*`
- `/api/platform/integrations/*`
- `/api/platform/tasks/*`
- `/api/platform/monitoring/*`
- `/api/platform/audit/*`
### 5.3.4 回调与内部接口
- `/api/callback/plugin/*`
- `/api/internal/metrics/*`
- `/api/internal/task-events/*`
### 5.3.5 网关转发关系
- `/api/auth/*` -> `gateway` 或共享认证模块
- `/api/tenant/*` -> `tenant-api`
- `/api/platform/*` -> `platform-api`
- `/api/callback/*` -> `tenant-api`
## 5.4 后端二进制职责
| 二进制 | 作用 |
| --- | --- |
| `cmd/gateway` | 统一 API 出口、无状态路由分发、基础鉴权、租户级限流、`request_id/trace_id` 注入与统一错误响应封装 |
| `cmd/tenant-api` | 提供租户端业务接口、任务状态接口、按需 SSE、插件会话与插件回调接口 |
| `cmd/platform-api` | 提供平台管理员端接口、租户治理、模型配置、审计与监控查询 |
| `cmd/scheduler` | 扫描定时生成、数据监控等到期任务,生成调度批次并入队 |
| `cmd/worker-generate` | 处理模板生成、Prompt 生成、批量生成与文章优化任务,并负责 RAG 检索、LLM 超时/限流/并发池控制 |
| `cmd/worker-knowledge` | 处理知识学习、解析、批量 Embedding、Qdrant 写入与 chunk 元数据维护 |
| `cmd/worker-analytics` | 处理问题采集、分析快照、统计聚合、缓存刷新;默认走低优先级模型通道 |
| `cmd/worker-publish-callback` | 处理发布回调、状态回写、失败补偿 |
## 5.5 后端模块职责
### 5.5.1 `shared/auth`
- 登录
- Token 颁发与校验
- 用户身份识别
- 平台角色 / 租户角色装载
### 5.5.2 `shared/retrieval`
- 统一封装 query rewrite、filter 构造、Qdrant 检索、rerank 与上下文拼装
-`worker-generate` 暴露品牌知识 RAG 检索入口
- V1 将 `retrieval_logs` 和 badcase 采样先写文件日志或对象存储,后续再升级为数据库评测体系
### 5.5.3 `tenant`
- 租户基础资料
- 租户状态
- 租户成员与租户角色
### 5.5.4 `platform`
- 平台管理员用户
- 平台角色
- 平台配置与平台级查询
### 5.5.5 `tenant/article` / `tenant/brand` / `tenant/knowledge`
- 租户业务核心能力
- 生成内容、品牌资料、知识库管理
### 5.5.6 `platform/quota` / `platform/plan`
- 套餐配置
- 配额消耗
- 配额补量
- 到期与重置规则
### 5.5.7 `platform/model`
- LLM 配置
- Embedding 配置
- 限流策略
- 默认模型策略
### 5.5.8 `tenant/task` + `platform/task`
- 任务入队
- 状态查询
- 重试与终止
- 死信处理
### 5.5.9 `platform/monitoring`
- 服务健康
- 队列状态
- Worker 状态
- 告警汇总
### 5.5.10 `platform/audit`
- 操作日志
- 配置变更日志
- 额度变更日志
- 风险操作日志
### 5.5.11 `shared/observability`
- 统一结构化日志规范与日志字段
- 统一 `request_id``trace_id``task_batch_id` 透传
- Prometheus 指标、健康检查、慢查询与队列深度观测
- 为 API、MQ、Worker 共用的错误码与告警标签提供基础设施
## 5.6 服务边界建议
### 5.6.1 `tenant-api` 负责
- 租户工作台
- 品牌、文章、知识库
- 媒体绑定与发布记录
- 生成任务提交与状态查询
- 租户侧额度消耗校验
- 发布回调接收
### 5.6.2 `platform-api` 负责
- 平台工作台
- 租户管理
- 套餐与额度策略
- 平台用户与平台角色
- 模型配置与模板规则
- 任务运维查询与重试控制
- 监控告警与审计中心
### 5.6.3 两服务协作原则
- `platform-api` 不直接承载租户高频业务流量
- `tenant-api` 不同步依赖 `platform-api` 完成核心链路
- 平台侧对租户业务的控制,优先通过数据库规则、缓存配置或内部命令完成
- 需要重试或控制任务时,由 `platform-api` 写控制记录并重新入队或调用内部接口
## 6. 认证与权限架构
## 6.1 统一身份模型
建议统一 `users` 主表,但角色绑定拆分:
- `platform_user_roles`
- `tenant_memberships`
这样一个账号可以:
- 既是平台内部用户
- 也可能是某个租户的成员
但两种权限链路必须分开校验。
## 6.2 权限模型
### 6.2.1 平台角色 `platform_role`
- `super_admin`
- `ops`
- `sre`
### 6.2.2 租户角色 `tenant_role`
- `tenant_admin`
- `editor`
### 6.2.3 租户角色能力边界
| 角色 | 主要能力 | 明确限制 |
| --- | --- | --- |
| `tenant_admin` | 租户设置、成员管理、模板/Prompt/品牌/知识/媒体、发布、配额查看、风险操作确认 | 无平台级治理权限 |
| `editor` | 创建与编辑文章、模板、Prompt、品牌、知识、媒体发布、查看追踪数据 | 不能管理成员、套餐策略、平台级配置 |
V1 权限模型按当前产品裁剪口径收敛为 `tenant_admin + editor` 两种租户角色;`viewer` 暂不单列,若后续出现严格只读协作者场景,可再由 `editor` 细分。
### 6.2.4 Prompt 分享身份 `kol_profile`
- `kol` 不是权限角色,而是用户在 Prompt 分享场景下的作者/达人身份
- `kol` 用户可生成分享码,供普通用户导入新的“文章模板类型”
- 分享内容本质上是“模板卡片 + 变量槽位定义 + 使用说明 + 受保护 Prompt 资产引用”的快照,而不是裸 Prompt 文本
- 导入后会在工作台或模板页形成新的模板卡片,作为平台预设模板之外的扩展文章类型
- 公司名、地址、品牌名、联系方式等租户专属字段仍由导入方在变量槽位中自行填写或绑定
- KOL 的原始 Prompt 正文对普通用户不可见,不可导出,不可在前端编辑,用于保护 Prompt 版权
- `kol_profile` 通过 `prompt_share_profiles``prompt_share_codes` 建模,不参与 RBAC 鉴权
## 6.3 鉴权中间件顺序
1. Token 校验
2. 用户身份解析
3. 路由前缀识别
4. 平台角色或租户角色装载
5. 资源范围校验
6. 风险操作校验
7. 审计上下文注入
## 6.4 风险操作要求
以下操作建议统一纳入风险操作:
- 冻结 / 解冻租户
- 调整套餐额度
- 修改模型默认策略
- 修改敏感词规则
- 批量重试任务
- 修改平台适配器配置
这些操作至少具备:
- 二次确认
- 操作原因
- 审计日志
## 7. 数据与中间件方案
## 7.1 PostgreSQL
负责:
- 用户、租户、成员、角色关系
- 品牌、文章、发布记录
- 套餐、额度、账期
- 模型配置、模板配置
- 任务记录
- 告警记录
- 审计日志
- 配额预扣与调度租约
- 知识 chunk 元数据
## 7.2 Redis
负责:
- 登录黑名单
- 高频查询缓存
- 仪表盘热点数据
- 任务短期状态缓存
- 限流计数
- SSE 跨 Pod 广播
## 7.3 RabbitMQ
负责:
- 文章生成任务
- 知识学习任务
- 分析聚合任务
- 发布回调任务
- 死信队列
## 7.4 Qdrant
负责:
- 知识库向量存储
- RAG 检索
## 7.5 对象存储
负责:
- 原始文档
- 图片素材
- 导入导出文件
- 原始抓取结果
- 原始模型回答与插件回调归档
## 8. 双后台与后端交互图
以下为主架构的宏观交互图,细化后的闭环版本以 §13.5.1 为准。
```mermaid
flowchart LR
subgraph FE["前端应用"]
AW["admin-web<br/>租户端"]
OW["ops-admin-web<br/>平台管理员端"]
EXT["browser-extension<br/>V1 发布执行端"]
end
AW --> CDN["CDN / Nginx"]
OW --> CDN
CDN --> ING["Ingress / API Gateway"]
EXT --> ING
ING --> GW["gateway"]
GW --> TA["tenant-api"]
GW --> PA["platform-api"]
SCH["scheduler"] --> PG["PostgreSQL"]
SCH --> MQ["RabbitMQ"]
TA --> PG["PostgreSQL"]
TA --> REDIS["Redis"]
TA --> MQ["RabbitMQ"]
TA --> OBJ["Object Storage"]
TA --> QD["Qdrant"]
PA --> PG
PA --> REDIS
PA --> MQ
MQ --> WG["worker-generate"]
MQ --> WK["worker-knowledge"]
MQ --> WA["worker-analytics"]
MQ --> WP["worker-publish-callback"]
WG --> PG
WG --> REDIS
WG --> QD
WK --> PG
WK --> QD
WK --> OBJ
WA --> PG
WA --> REDIS
WA --> OBJ
WP --> PG
WP --> REDIS
PA --> TA
```
## 9. 后端结构图
以下为主架构的模块示意图;二进制职责、共享模块和运行约束以 §13.5 与 §13.13 为准。
```mermaid
flowchart TB
subgraph CMD["cmd"]
GWBIN["gateway"]
TENBIN["tenant-api"]
PLTBIN["platform-api"]
SCHBIN["scheduler"]
GENBIN["worker-generate"]
KBBIN["worker-knowledge"]
ANABIN["worker-analytics"]
PUBBIN["worker-publish-callback"]
end
subgraph SHARED["internal/shared"]
SAUTH["auth"]
SMIDDLE["middleware"]
SPLUGIN["plugin"]
SRET["retrieval"]
SSCHED["scheduler"]
SREPO["shared repositories"]
SSSE["sse"]
SOBS["observability"]
end
subgraph TENANT["internal/tenant"]
TTRANS["transport"]
TAPP["app"]
TDOMAIN["domain"]
TREPO["repository"]
end
subgraph PLATFORM["internal/platform"]
PTRANS["transport"]
PAPP["app"]
PDOMAIN["domain"]
PREPO["repository"]
end
subgraph JOBS["internal/jobs"]
JGEN["generate job"]
JKB["knowledge job"]
JANA["analytics job"]
JPUB["publish callback job"]
end
subgraph INFRA["infra"]
PGREPO["postgres"]
REDISREPO["redis"]
MQREPO["rabbitmq"]
QDREPO["qdrant"]
OBJREPO["objectstorage"]
end
GWBIN --> SAUTH
GWBIN --> SMIDDLE
TENBIN --> TTRANS
TENBIN --> SAUTH
TENBIN --> SPLUGIN
TENBIN --> SSSE
TENBIN --> SOBS
PLTBIN --> PTRANS
PLTBIN --> SAUTH
PLTBIN --> SOBS
SCHBIN --> SSCHED
SCHBIN --> SOBS
TTRANS --> TAPP
TAPP --> TDOMAIN
TAPP --> TREPO
PTRANS --> PAPP
PAPP --> PDOMAIN
PAPP --> PREPO
GENBIN --> JGEN
KBBIN --> JKB
ANABIN --> JANA
PUBBIN --> JPUB
JGEN --> SRET
JGEN --> TREPO
JKB --> TREPO
JANA --> PREPO
JPUB --> TREPO
JPUB --> PREPO
TREPO --> SREPO
PREPO --> SREPO
SRET --> SREPO
SREPO --> PGREPO
SREPO --> REDISREPO
SREPO --> MQREPO
SREPO --> QDREPO
SREPO --> OBJREPO
```
## 10. 核心链路设计
## 10.1 租户端生成链路
1. `admin-web` 提交生成请求
2. API 校验租户身份、额度、参数
3. `tenant-api` 在同一 PostgreSQL 事务内完成“额度预扣 / 保留 + `generation_tasks` / `task_records` 创建 + 文章占位记录初始化”
4. 事务提交后写入 RabbitMQ
5. `worker-generate` 消费任务,先经 `shared/retrieval` 执行 `query rewrite -> filter -> Qdrant 检索 -> rerank -> 上下文拼装`
6. `worker-generate` 在超时、限流、并发池保护下调用模型
7. 成功时在同一 PostgreSQL 事务内写入 `article_versions`、更新 `articles`、确认额度消耗;失败时写失败状态并按条退还额度
8. 结果写入 Redis,前端通过 SSE 或轮询感知任务进度
## 10.2 平台端额度调整链路
1. `ops-admin-web` 发起额度变更
2. API 校验 `platform_role`
3. 写入额度变更记录
4. 更新租户额度表与缓存
5. 写入审计日志
6. 租户端下一次请求按新额度生效
## 10.3 平台端任务排查链路
1. `ops-admin-web` 查询失败任务列表
2. API 聚合 PostgreSQL 任务信息、错误信息与重试信息
3. 平台人员发起重试
4. API 写入重试记录并重新入队
5. Worker 执行后回写结果
6. 审计中心记录操作人和结果
## 10.4 监控与告警链路
1. Go API 与 Worker 暴露指标
2. 监控系统采集服务、队列、缓存、数据库指标
3. 告警服务生成异常记录
4. `ops-admin-web` 查询并展示告警状态
## 11. 部署建议
## 11.1 本地开发
- 前端:`pnpm` 工作区本地联调
- 基础设施:`docker compose` 仅启动 PostgreSQL、Redis、RabbitMQ、Qdrant、MinIO
- 后端服务建议本地 `go run`,按需启动:
- `go run ./server/cmd/gateway`
- `go run ./server/cmd/tenant-api`
- `go run ./server/cmd/platform-api`
- `go run ./server/cmd/scheduler`
- `go run ./server/cmd/worker-generate`
- `go run ./server/cmd/worker-knowledge`
- `go run ./server/cmd/worker-analytics`
- `go run ./server/cmd/worker-publish-callback`
- 建议提供 `make dev-init` 或等价任务脚本,统一完成:
- 执行 migration
- 创建 RabbitMQ 队列 / exchange / routing key
- 初始化 MinIO bucket
- 写入最小种子数据与本地模型通道配置
## 11.2 测试与预发
- 前端独立构建产物
- API 与 Worker 独立容器
- 使用共享测试基础设施或云托管实例
## 11.3 线上生产
- `admin-web``ops-admin-web` 独立发布到 CDN
- API 与 Worker 部署到 Kubernetes
- PostgreSQL、Redis、RabbitMQ、Qdrant 使用高可用或托管方案
## 12. 演进路线
### 12.1 V1
- 两个前端应用
- 一个浏览器插件执行端
- 一个统一网关出口
- 两个 Go API 服务
- 一个 Scheduler
- 四类 Worker
- 平台端与租户端路由隔离
### 12.2 V1.5
- 抽离统一审计模块
- 抽离模型网关模块
- 增加平台接入配置中心
### 12.3 V2
- 按压力拆分平台 API 与租户 API
- 单独拆出 `ops-bff``platform-api`
- 单独拆出 `analytics-service`
## 13. V1 闭环补齐方案
### 13.1 适用说明
本节结合以下材料对前文进行补齐修订,并作为 V1 详细落地的统一口径:
- `docs/refer/*`
- `docs/geo-platform-prd-v1.md`
- `docs/geo-platform-ops-admin-prd-v1.md`
- `docs/media-binding-and-publish-v1.md`
- `docs/question-driven-monitoring-design-v1.md`
- `docs/Claude_architecture_review.md`
若本节与前文较早的抽象表述存在冲突,以本节为准。
### 13.2 修订结论
为保证 `docs/refer` 中 8 个页面在 V1 阶段形成“页面 -> 路由 -> API -> 对象 -> 任务 -> 存储 -> 状态回传”的完整闭环,V1 对总体架构做如下修订:
- `apps/browser-extension` 从“后续可选”提升为 `V1 必选执行端`
- 后端实际形态明确为:`gateway + tenant-api + platform-api + scheduler + 4 类 Worker + browser-extension`
- `tenant-api` 按业务拆分为 `workspace / template / prompt-rule / schedule / article / optimization / brand / knowledge / media / tracking / account`
- `worker-generate` 同时承载 `模板生成 / Prompt 生成 / 批量生成 / 文章优化`
- 工作台模板卡片支持“平台预设 + 租户自建 + KOL 分享码导入”三种来源,导入后统一物化为租户模板
- `数据追踪` 采用“问题驱动监控”模型,最小采集单元为 `question_version x model x run_time`
- 工作台、数据追踪、任务状态统一提供聚合接口,避免前端首屏发起过多散请求
- 所有长任务统一接入 `task_records + SSE + 轮询兜底`
### 13.3 功能闭环矩阵
| 功能页 | 核心路由 | 核心 API 组 | 核心对象 | 异步/执行组件 |
| --- | --- | --- | --- | --- |
| 工作台 | `/workspace` | `/api/tenant/workspace/*` | `articles` `article_templates` `brands` `platform_accounts` `tenant_plan_subscriptions` | `worker-generate` `worker-publish-callback` |
| 模板创作 | `/articles/template` | `/api/tenant/templates/*` `/api/tenant/prompt-shares/*` `/api/tenant/articles/*` | `article_templates` `prompt_share_codes` `articles` `generation_tasks` | `worker-generate` |
| 自定义生成 | `/articles/custom/*` | `/api/tenant/prompt-rules/*` `/api/tenant/schedules/*` `/api/tenant/articles/*` | `prompt_rules` `schedule_tasks` `generation_tasks` | `scheduler` `worker-generate` |
| 文章优化 | `/articles/optimize` | `/api/tenant/optimizations/*` `/api/tenant/articles/*` | `optimization_tasks` `article_versions` | `worker-generate` |
| 媒体管理 | `/media` | `/api/tenant/media/*` `/api/callback/plugin/*` | `media_platforms` `platform_accounts` `plugin_sessions` `publish_records` | `browser-extension` `worker-publish-callback` |
| 品牌词库 | `/brands` `/brands/:id` | `/api/tenant/brands/*` | `brands` `brand_keywords` `brand_questions` `brand_question_versions` `competitors` | `worker-analytics` |
| 知识库 | `/knowledge` | `/api/tenant/knowledge/*` | `knowledge_groups` `knowledge_items` `knowledge_parse_tasks` | `worker-knowledge` |
| 数据追踪 | `/tracking/overview` `/tracking/detail` | `/api/tenant/tracking/*` | `question_monitor_runs` `question_monitor_parse_results` `keyword_model_daily_metrics` `keyword_model_top_questions_daily` `keyword_model_citation_rank_daily` | `scheduler` `worker-analytics` |
### 13.4 细化前端路由
#### 13.4.1 `admin-web`
```text
/login
/workspace
/articles/template
/articles/template/create
/articles/custom
/articles/custom/instant
/articles/custom/scheduled
/articles/custom/prompts
/articles/optimize
/articles/:id
/articles/:id/publish-records
/brands
/brands/:id
/knowledge
/media
/tracking/overview
/tracking/detail
/account
```
#### 13.4.2 `ops-admin-web`
```text
/login
/platform/dashboard
/platform/tenants
/platform/tenants/:id
/platform/plans
/platform/platform-users
/platform/platform-roles
/platform/models/llm
/platform/models/embedding
/platform/models/channels
/platform/models/limits
/platform/content/templates
/platform/content/prompts
/platform/content/tags
/platform/content/sensitive-rules
/platform/integrations/media-platforms
/platform/integrations/adapters
/platform/integrations/publish-policies
/platform/tasks/generation
/platform/tasks/knowledge
/platform/tasks/publish
/platform/tasks/analytics
/platform/tasks/dead-letter
/platform/monitoring/services
/platform/monitoring/queues
/platform/monitoring/workers
/platform/monitoring/storage
/platform/monitoring/alerts
/platform/audit/operations
/platform/audit/config-changes
/platform/audit/quota-changes
/platform/audit/risk-actions
```
### 13.5 服务、二进制与模块补齐
#### 13.5.1 修订后的整体交互图
```mermaid
flowchart LR
AW["admin-web"] --> CDN["CDN / Nginx"]
OW["ops-admin-web"] --> CDN
EXT["browser-extension"] <---> AW
CDN --> GW["gateway"]
GW --> TA["tenant-api"]
GW --> PA["platform-api"]
SCH["scheduler"] --> PG["PostgreSQL"]
SCH --> MQ["RabbitMQ"]
TA --> PG
TA --> REDIS["Redis"]
TA --> MQ
TA --> OBJ["Object Storage"]
TA --> QD["Qdrant"]
PA --> PG
PA --> REDIS
PA --> MQ
EXT --> CB["/api/callback/plugin/*"]
CB --> TA
MQ --> WG["worker-generate"]
MQ --> WK["worker-knowledge"]
MQ --> WA["worker-analytics"]
MQ --> WP["worker-publish-callback"]
WG --> QD
WA --> OBJ
```
#### 13.5.2 二进制职责补齐
| 二进制/执行端 | 职责 |
| --- | --- |
| `cmd/gateway` | 统一入口、公共鉴权、限流、`request_id/trace_id` 注入与统一错误响应封装;保持无状态,支持水平扩容 |
| `cmd/tenant-api` | 承载租户侧全部业务接口、SSE、插件会话管理、回调落库 |
| `cmd/platform-api` | 承载平台治理、套餐额度、平台用户、模型中心、平台接入、监控审计 |
| `cmd/scheduler` | 扫描 `schedule_tasks` 和数据监控计划,按到期窗口生成调度批次并入队 |
| `cmd/worker-generate` | 执行模板生成、Prompt 生成、批量生成、文章优化;通过 `shared/retrieval` 做 RAG 检索,并使用独立 LLM 并发池控制交互任务 |
| `cmd/worker-knowledge` | 执行文档解析、URL 抓取、文本切片、批量 Embedding、Qdrant 写入、chunk 元数据维护 |
| `cmd/worker-analytics` | 执行问题驱动监控、回答解析、日级聚合、排行榜刷新、缓存刷新;采集任务默认走低优先级模型通道 |
| `cmd/worker-publish-callback` | 处理发布回调补偿、账号状态检测结果、失败重放与死信回写 |
| `apps/browser-extension` | 真实登录检测、账号绑定、图片上传、手动发布、状态检查、本地 adapter 执行 |
#### 13.5.3 租户侧模块补齐
| 模块 | 职责 |
| --- | --- |
| `tenant/workspace` | 工作台聚合指标、最近生成、额度摘要、模板卡片下发;卡片来源支持平台预设、租户自建与 KOL 分享导入 |
| `tenant/template` | 模板定义、模板 schema、模板版本、模板生成入口、KOL 分享模板的变量定制与落库;不向导入方暴露受保护 Prompt 正文 |
| `tenant/prompt-rule` | Prompt 规则 CRUD、启停、默认语气/字数配置、作者身份信息、分享码导出与导入;支持变量槽位定义与版权保护 |
| `tenant/schedule` | 定时生成计划 CRUD、启停、下一次执行时间维护 |
| `tenant/article` | 文章主记录、详情、预览、复制、删除、发布前读取 |
| `tenant/optimization` | 优化任务、优化方向、版本保存、未完成任务入口 |
| `tenant/brand` | 品牌、关键词、问题集、问题版本、竞品库 |
| `tenant/knowledge` | 分组、知识条目、来源类型、学习任务状态 |
| `tenant/media` | 平台清单、平台账号、插件会话、发送记录、状态检测 |
| `tenant/tracking` | 数据概览、趋势图、高频问题、引用排行、品牌关键词模型筛选 |
| `tenant/account` | 套餐、额度、重置时间、升级入口占位 |
#### 13.5.4 平台侧模块补齐
| 模块 | 职责 |
| --- | --- |
| `platform/tenant` | 租户开通、冻结解冻、套餐关联、额度治理 |
| `platform/plan` + `platform/quota` | 套餐档位、额度策略、补量、账期重置 |
| `platform/model` | LLM、Embedding、渠道密钥、限流、默认策略 |
| `platform/content` | 平台级模板、Prompt 规则、分类标签、敏感词规则 |
| `platform/integration` | 媒体平台清单、平台分类、adapter 注册、发布策略 |
| `platform/task` | 任务运维、批量重试、死信处理、执行历史 |
| `platform/monitoring` | 服务、队列、Worker、存储、告警 |
| `platform/audit` | 操作日志、配置变更、额度变更、风险操作 |
### 13.6 核心 API 补齐
#### 13.6.1 租户侧 API
- `/api/tenant/workspace/overview`
- `/api/tenant/workspace/recent-articles`
- `/api/tenant/workspace/quota-summary`
- `/api/tenant/workspace/template-cards`
- `/api/tenant/templates`
- `/api/tenant/templates/{id}`
- `/api/tenant/templates/{id}/schema`
- `/api/tenant/templates/{id}/generate`
- `/api/tenant/prompt-rules`
- `/api/tenant/prompt-rules/{id}`
- `/api/tenant/prompt-rules/{id}/share-code`
- `/api/tenant/prompt-shares/resolve/{shareCode}`
- `/api/tenant/prompt-shares/import`
- `/api/tenant/prompt-share-profiles/me`
- `/api/tenant/schedules`
- `/api/tenant/schedules/{id}`
- `/api/tenant/schedules/{id}/enable`
- `/api/tenant/schedules/{id}/disable`
- `/api/tenant/articles`
- `/api/tenant/articles/{id}`
- `/api/tenant/articles/{id}/versions`
- `/api/tenant/articles/{id}/publish-records`
- `/api/tenant/optimizations`
- `/api/tenant/optimizations/{id}`
- `/api/tenant/brands`
- `/api/tenant/brands/{id}`
- `/api/tenant/brands/{id}/keywords`
- `/api/tenant/brands/{id}/questions`
- `/api/tenant/brands/{id}/competitors`
- `/api/tenant/knowledge/groups`
- `/api/tenant/knowledge/items`
- `/api/tenant/knowledge/parse-tasks`
- `/api/tenant/media/platforms`
- `/api/tenant/media/platform-accounts`
- `/api/tenant/media/platform-accounts/{id}/check`
- `/api/tenant/media/plugin-sessions`
- `/api/tenant/media/publish-records`
- `/api/tenant/tracking/summary`
- `/api/tenant/tracking/trend`
- `/api/tenant/tracking/top-questions`
- `/api/tenant/tracking/citation-rank`
- `/api/tenant/account/plan`
- `/api/tenant/account/quota`
#### 13.6.2 平台侧 API
- `/api/platform/dashboard/*`
- `/api/platform/tenants/*`
- `/api/platform/plans/*`
- `/api/platform/platform-users/*`
- `/api/platform/models/*`
- `/api/platform/content/*`
- `/api/platform/integrations/*`
- `/api/platform/tasks/*`
- `/api/platform/monitoring/*`
- `/api/platform/audit/*`
#### 13.6.3 插件回调与内部接口
- `/api/callback/plugin/bind`
- `/api/callback/plugin/publish`
- `/api/callback/plugin/check`
- `/api/internal/task-events`
- `/api/internal/scheduler/dispatch`
#### 13.6.4 统一错误响应与错误码
所有 API 建议统一返回:
```json
{
"code": 40301,
"message": "quota_insufficient",
"detail": "生成额度不足,请升级套餐或等待额度重置",
"request_id": "req_xxx"
}
```
错误码段建议如下:
| 错误码段 | 含义 |
| --- | --- |
| `400xx` | 参数校验与请求格式错误 |
| `401xx` | 认证失败、Token 失效 |
| `403xx` | 权限不足、额度不足、功能未开通 |
| `404xx` | 资源不存在 |
| `409xx` | 状态冲突、幂等冲突、重复提交 |
| `429xx` | 频率限制、队列拥塞 |
| `500xx` | 内部错误 |
| `503xx` | 下游依赖不可用,如 `LLM / Embedding / Qdrant / ObjectStorage` |
`gateway` 与各 API 服务必须共用同一套错误码枚举和响应封装,避免前后端联调时出现多种格式。
#### 13.6.5 KOL 分享码解析边界
- `/api/tenant/prompt-shares/resolve/{shareCode}` 只返回模板卡片信息、变量槽位、使用说明、作者展示信息,不返回底层 Prompt 正文
- `/api/tenant/prompt-shares/import` 在服务端完成模板物化,前端只提交变量定制结果,不接触受保护 Prompt 资产
- `/api/tenant/templates/{id}``origin_type=kol_share` 的模板仅返回可定制字段与运行配置,不返回 `prompt_template`
- 真正参与生成的受保护 Prompt 仅由 `tenant-api` / `worker-generate` 在服务端读取,前端与浏览器插件都不可见
### 13.7 异步任务、调度与幂等设计
#### 13.7.1 队列与任务类型
| 队列 | 任务类型 | 说明 |
| --- | --- | --- |
| `q.generate.interactive` | `article.generate.template` `article.generate.prompt` `article.optimize` | 交互式任务,高优先级,服务工作台、模板创作、自定义生成即时任务与文章优化 |
| `q.generate.batch` | `article.generate.batch_item` `article.generate.schedule_item` | 批量与定时任务,低优先级,避免堵塞交互任务 |
| `q.knowledge` | `knowledge.parse.file` `knowledge.parse.url` `knowledge.parse.text` | 不同来源共用解析入口,按来源类型走不同解析器 |
| `q.analytics.collect` | `analytics.collect.question` | 采集任务,低于用户直触发生成任务优先级,默认使用独立模型通道或更小并发池 |
| `q.analytics.aggregate` | `analytics.aggregate.daily` `analytics.refresh.cache` | 聚合与缓存刷新任务,不占用 LLM 通道 |
| `q.publish-callback` | `publish.persist` `platform-account.check.persist` | 插件执行结果、账号检测结果入队补偿 |
| `q.dead-letter` | `dead_letter.*` | 统一兜底失败任务 |
#### 13.7.2 调度器设计
- `scheduler` 每分钟扫描一次 `schedule_tasks`,条件为 `status=enabled and next_run_at <= now()`
- 使用数据库行级锁或租约字段 `dispatch_lease_until + lease_owner` 防止多实例重复派发
- 每次派发生成一个 `task_batch_id`,并为批量任务拆分出多个 `generation_tasks`
- 数据追踪监控计划同样由 `scheduler` 生成 `analytics.collect.question` 任务
- 计划任务创建时默认写入 `dispatch_jitter_minutes`,将大批同时到期任务平滑散布到 `5~10 分钟` 窗口内
- `scheduler` 重启后按 `task_batch_id + request_hash` 幂等追回漏派发任务,避免重复投递
- V1 不依赖 RabbitMQ Delay Queue,统一采用“数据库到期扫描 + 普通消息队列”方式,降低实现复杂度
#### 13.7.3 事务、幂等与补偿
- 任务提交路径必须在单个 PostgreSQL 事务内完成“额度预扣 / 保留 + 任务创建 + 任务记录写入”
- Worker 成功路径必须在单个 PostgreSQL 事务内完成“结果写入 + 主记录状态更新 + 额度确认”
- Worker 失败路径必须在单个 PostgreSQL 事务内完成“失败状态更新 + 额度退还 / 释放”
- 批量生成采用“提交时按批次预扣 + 单条失败退款 + 定期对账”模式,批次维度以 `task_batch_id` 管理
- 生成任务按 `tenant_id + source_type + request_hash + schedule_slot` 做幂等
- 插件回调按 `plugin_session_id + callback_stage` 做幂等
- `publish_records` 保留请求与响应摘要,支持补偿重放
- Worker 默认重试 3 次,超过阈值进入死信;平台端允许人工批量重试
### 13.8 浏览器插件执行面闭环
#### 13.8.1 插件会话模型
为避免“页面一关结果丢失”,V1 引入 `plugin_sessions`
1. 前端先调用 `/api/tenant/media/plugin-sessions` 创建一次性会话
2. 后端返回 `plugin_session_id + session_token + expire_at`
3. 前端将会话信息交给 `browser-extension`
4. 插件执行绑定、检测或发布动作
5. 插件将结果:
- 回传给前端用于即时交互
- 同时回调 `/api/callback/plugin/*` 用于可靠落库
6. `tenant-api` 校验 `session_token` 后写入 `platform_accounts``publish_records`
7. 系统通过 SSE 广播结果,列表页和详情页实时刷新
#### 13.8.2 绑定/发布状态流转
- 平台账号状态:`pending -> active -> invalid/expired`
- 发布状态:`unpublished -> publishing -> success/failed/pending_review`
- 回调接口不直接信任浏览器 Cookie,只信任后端签发的短期 `session_token`
#### 13.8.3 安全约束
- 服务端不保存第三方平台 Cookie 与登录态
- 插件仅允许注入受信后台域名
- 所有 `postMessage` / `runtime.sendMessage` 必须校验来源域名与会话 token
- 所有绑定、重检、发布、失败补偿动作写入审计日志
#### 13.8.4 插件检测与降级
- `packages/shared-types` 维护 `MIN_BROWSER_EXTENSION_VERSION` 常量,作为前后端与插件共享的最低兼容版本
- 媒体页加载时,`admin-web` 先通过 `plugin.ping` / `postMessage` 握手检测插件是否安装、版本是否满足要求、能力清单是否齐备
- 未安装、被禁用或版本过低时,页面将“去绑定 / 重新检测 / 发布”按钮置灰,并展示安装或升级引导
- 插件回调会把 `client_version` 回传到 `plugin_sessions` 审计字段,便于排查兼容问题
- 降级场景下不走伪成功逻辑,统一保持前端只读提示,避免产生无法落库的假状态
### 13.9 数据追踪闭环
#### 13.9.1 采集模型
数据追踪采用 `问题驱动监控`,最小采集单元为:
`1 question_version x 1 model x 1 run_time = 1 条原始监控记录`
含义如下:
- `品牌` 是租户下的监控主体
- `关键词` 是问题集合容器与聚合维度
- `问题版本` 保证历史口径稳定
- `模型` 是对比维度
- 页面只查日级聚合表,不直接扫描原始回答
#### 13.9.2 数据链路
1. 用户在品牌词库维护 `brand_keywords``brand_questions`
2. `scheduler` 按每日频率为启用的问题版本和目标模型派发监控任务
3. `worker-analytics` 调用模型得到原始回答,原文写入对象存储
4. 解析回答是否提及品牌、是否首位提及、是否首选推荐、是否正向提及、是否引用文章
5. 结果写入 `question_monitor_runs``question_monitor_parse_results`
6. 日级聚合刷新 `question_model_daily_metrics``keyword_model_daily_metrics``keyword_model_top_questions_daily``keyword_model_citation_rank_daily`
7. Redis 缓存 30 天摘要、趋势图、高频问题、引用排行
8. `/api/tenant/tracking/*` 统一从聚合表和缓存读取
#### 13.9.3 V1 控制策略
- 每个问题每天默认执行 `1 次`
- 重要品牌或更高套餐可配置为 `2 次`
- 同品牌、同模型、同日、相同 `question_hash` 可做采集去重
- 原始回答落对象存储,PostgreSQL 仅保存结构化解析与聚合结果
- 原始运行记录保留 `30 ~ 90 天`,解析结果保留 `90 天`,日级汇总保留 `180 天+`
- `brand_question_versions` 仅在“启用 / 发布新监控口径”时生成新版本;编辑态默认做 `10 分钟` debounce,避免碎片化
### 13.10 SSE 与轮询策略
#### 13.10.1 SSE 适用场景
以下场景在“存在运行中任务”期间可临时升级为 SSE:
- 文章生成进度
- 文章优化进度
- 知识学习状态
- 平台账号检测状态
- 发布状态变更
- 配额刷新提醒
#### 13.10.2 事件类型
- `task.updated`
- `article.generated`
- `article.optimized`
- `knowledge.updated`
- `platform_account.updated`
- `publish.updated`
- `quota.updated`
统一负载字段建议:
- `event_id`
- `tenant_id`
- `event_type`
- `resource_type`
- `resource_id`
- `task_id`
- `status`
- `message`
- `occurred_at`
#### 13.10.3 连接策略
- 工作台、列表页、数据页默认使用 `10s` 轮询
- 仅当页面存在 `queued/running/publishing/checking` 状态的资源时,前端才建立 SSE 连接
- 单用户单租户默认只保留 `1` 条 SSE 连接;页面空闲 `60s` 且无运行中任务时主动关闭
- `tenant-api` 通过 Redis Pub/Sub 做跨 Pod 事件广播,不依赖 Sticky Session;任一 Pod 写事件后,所有订阅 Pod 都能向本地连接转发
- SSE heartbeat 调整为 `30s`
- 客户端断线后按 `3s / 5s / 10s` 退避重连
- 若浏览器或网络环境不支持 SSE,则保持 `10s` 轮询
- 页面不直接监听 RabbitMQ,统一由 `tenant-api` 聚合并对前端推送
### 13.11 核心数据模型与最小 Schema
#### 13.11.1 身份、租户与额度
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `tenants` | `id` `name` `status` `created_at` `frozen_at` | `uk_tenant_name` |
| `users` | `id` `email` `phone` `status` `created_at` | `uk_users_email` |
| `tenant_memberships` | `id` `tenant_id` `user_id` `tenant_role` | `uk_tenant_user` |
| `platform_user_roles` | `id` `user_id` `platform_role` | `uk_platform_user_role` |
| `plans` | `id` `plan_code` `name` `quota_policy_json` `status` | `uk_plan_code` |
| `tenant_plan_subscriptions` | `id` `tenant_id` `plan_id` `start_at` `end_at` `status` | `idx_tenant_plan_active` |
| `tenant_quota_ledgers` | `id` `tenant_id` `quota_type` `delta` `balance_after` `reason` | `idx_tenant_quota_tenant_type_created` |
| `quota_reservations` | `id` `tenant_id` `quota_type` `resource_type` `resource_id` `reserved_amount` `consumed_amount` `refunded_amount` `status` `expire_at` | `idx_quota_reservation_tenant_status` |
#### 13.11.2 模板、Prompt、文章与优化
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `article_templates` | `id` `scope` `tenant_id` `origin_type` `share_code_id` `template_key` `template_name` `schema_json` `prompt_template` `prompt_visibility` `protected_prompt_asset_key` `card_config_json` `status` `version_no` | `uk_template_scope_key_version` |
| `prompt_rules` | `id` `tenant_id` `name` `prompt_content` `scene` `default_tone` `default_word_count` `status` | `idx_prompt_rule_tenant_status` |
| `prompt_share_profiles` | `id` `user_id` `display_name` `bio` `avatar_url` `share_enabled` `status` | `uk_prompt_share_profile_user` |
| `prompt_share_codes` | `id` `tenant_id` `source_template_id` `owner_user_id` `share_code` `snapshot_json` `protected_prompt_asset_key` `status` `expire_at` | `uk_prompt_share_code` |
| `schedule_tasks` | `id` `tenant_id` `prompt_rule_id` `target_platform_id` `cron_expr` `next_run_at` `dispatch_jitter_minutes` `lease_owner` `dispatch_lease_until` `last_dispatch_at` `status` | `idx_schedule_due` |
| `articles` | `id` `tenant_id` `source_type` `template_id` `prompt_rule_id` `current_version_id` `generate_status` `publish_status` | `idx_article_tenant_created` |
| `article_versions` | `id` `article_id` `version_no` `title` `html_content` `markdown_content` `word_count` `source_label` | `uk_article_version_no` |
| `generation_tasks` | `id` `tenant_id` `article_id` `task_batch_id` `quota_reservation_id` `task_type` `request_hash` `status` `error_message` | `idx_generation_task_status_created` |
| `optimization_tasks` | `id` `tenant_id` `article_id` `source_version_id` `target_version_id` `optimization_type` `status` | `idx_optimization_task_status` |
其中:`article_templates.scope=platform``tenant_id` 为空;`scope=tenant``tenant_id` 必填。
导入 KOL 分享码后,系统会把快照物化为当前租户自己的 `article_templates` 记录,并标记 `origin_type=kol_share`
`article_templates.prompt_visibility=sealed` 时,模板的 Prompt 正文只允许服务端读取,前端接口不得返回。
`prompt_share_codes.snapshot_json` 只保存模板卡片信息、变量占位和使用说明;真正的 Prompt 正文通过 `protected_prompt_asset_key` 以受保护资产方式保存,不复制导出方租户的品牌、地址、媒体账号等私有数据。
#### 13.11.3 品牌与问题集
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `brands` | `id` `tenant_id` `name` `description` `status` | `uk_brand_tenant_name` |
| `brand_keywords` | `id` `tenant_id` `brand_id` `name` `status` | `uk_brand_keyword_name` |
| `brand_questions` | `id` `tenant_id` `brand_id` `keyword_id` `current_version_id` `status` | `idx_brand_questions_keyword` |
| `brand_question_versions` | `id` `question_id` `question_text` `question_hash` `version_no` `is_active` | `uk_question_version_no` `idx_question_hash` |
| `competitors` | `id` `tenant_id` `brand_id` `name` `website` `description` `product_lines_json` | `idx_competitor_brand` |
#### 13.11.4 知识库
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `knowledge_groups` | `id` `tenant_id` `name` `parent_id` `sort_order` | `uk_knowledge_group_name` |
| `knowledge_items` | `id` `tenant_id` `group_id` `source_type` `name` `storage_key` `status` `size_bytes` | `idx_knowledge_item_group_status` |
| `knowledge_parse_tasks` | `id` `tenant_id` `knowledge_item_id` `source_type` `status` `error_message` | `idx_parse_task_status` |
| `knowledge_chunks_meta` | `id` `tenant_id` `knowledge_item_id` `chunk_index` `token_count` `qdrant_point_id` `item_version` `status` | `idx_chunk_item_version` |
V1 的 `retrieval_logs``rag_eval_cases` 先不落数据库表,统一写文件日志或对象存储采样归档,待评测体系成熟后再升级。
#### 13.11.5 媒体平台与插件执行
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `media_platforms` | `id` `platform_code` `name` `category` `adapter_key` `status` | `uk_media_platform_code` |
| `platform_accounts` | `id` `tenant_id` `user_id` `platform_id` `platform_uid` `nickname` `avatar_url` `status` `last_check_at` | `uk_platform_account_identity` |
| `plugin_sessions` | `id` `tenant_id` `user_id` `action_type` `platform_id` `session_token` `client_version` `expire_at` `status` | `uk_plugin_session_token` `idx_plugin_session_expire` |
| `publish_records` | `id` `tenant_id` `article_id` `platform_account_id` `platform_id` `status` `external_article_id` `error_message` `request_payload_json` `response_payload_json` | `idx_publish_record_article_created` |
#### 13.11.6 数据追踪
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `question_monitor_runs` | `id` `tenant_id` `brand_id` `keyword_id` `question_id` `question_version_id` `model_id` `run_date` `run_at` `task_batch_id` `status` `raw_answer_storage_key` | `idx_monitor_runs_query` |
| `question_monitor_parse_results` | `id` `run_id` `mentioned_brand` `top1_mentioned` `first_recommended` `positive_mentioned` `citation_article_count` `citation_platform_count` `parser_version` | `uk_parse_result_run` |
| `question_model_daily_metrics` | `tenant_id` `brand_id` `keyword_id` `question_id` `question_version_id` `model_id` `date` `ask_count` `mention_count` `top1_mention_count` `first_recommend_count` `positive_mention_count` `citation_count` | `uk_question_model_daily` |
| `keyword_model_daily_metrics` | `tenant_id` `brand_id` `keyword_id` `model_id` `date` `ask_count` `mention_rate` `positive_mention_rate` | `uk_keyword_model_daily` |
| `keyword_model_top_questions_daily` | `tenant_id` `brand_id` `keyword_id` `model_id` `date` `question_id` `score` | `idx_top_questions_daily` |
| `keyword_model_citation_rank_daily` | `tenant_id` `brand_id` `keyword_id` `model_id` `date` `cited_article_id` `citation_count` | `idx_citation_rank_daily` |
保留策略建议与专项监控方案对齐:原始运行记录 `30 ~ 90 天`、解析结果 `90 天`、日级汇总 `180 天或更久`
#### 13.11.7 平台任务与审计
| 表 | 关键字段 | 关键约束/索引 |
| --- | --- | --- |
| `task_records` | `id` `tenant_id` `task_type` `resource_type` `resource_id` `status` `retry_count` `task_batch_id` | `idx_task_record_status_type` |
| `audit_logs` | `id` `operator_id` `tenant_id` `module` `action` `before_json` `after_json` `result` `created_at` | `idx_audit_module_created` |
| `config_change_logs` | `id` `operator_id` `scope_type` `scope_id` `change_type` `diff_json` | `idx_config_change_scope` |
| `quota_change_logs` | `id` `operator_id` `tenant_id` `quota_type` `delta` `reason` | `idx_quota_change_tenant` |
| `risk_action_logs` | `id` `operator_id` `tenant_id` `risk_type` `reason` `result` | `idx_risk_action_tenant_created` |
### 13.12 闭环验收标准
以下标准满足时,可认为主技术架构已从“宏观方案”补齐为“可开发闭环方案”:
- `工作台` 有独立聚合 API,不依赖前端拼装多个分散接口
- `模板创作` 有模板定义、schema、批量生成和任务状态落点
- `自定义生成` 有 Prompt 规则、定时任务、Scheduler 和幂等派发设计
- `文章优化` 有优化任务、版本表、保存结果与回看路径
- `媒体管理` 有插件执行端、插件会话、绑定回调、发布回调和状态同步
- `品牌词库` 有关键词、问题、问题版本、竞品库与追踪关联
- `知识库` 有分组、多来源解析策略、学习任务和对象存储落点
- `数据追踪` 有明确采集单元、聚合表、缓存策略和查询口径
- 所有长任务都有 `task_records`、SSE 事件和轮询兜底
- 所有高风险操作、配置变更、额度变更、发布失败补偿都有审计记录
### 13.13 面向 5 万并发与简单运维的运行策略
#### 13.13.1 Gateway 水平扩展与负载均衡
- `gateway` 必须保持无状态,允许多实例水平扩展
- 线上入口通过 `Ingress / Nginx` 做 L7 负载均衡,前端无需感知后端实例
- Kubernetes 建议为 `gateway` 配置 HPA,核心观测指标为:`CPU``RPS``active_connections`
- `gateway``tenant-api` / `platform-api` 之间通过集群内部 Service 直连,V1 不引入额外服务网格
- `gateway` 只允许承担统一入口职责,不允许沉淀业务编排、任务控制、数据聚合与数据库业务写入
#### 13.13.2 Scheduler 故障恢复策略
- V1 默认采用 `单活 scheduler + 健康检查 + 自动重启`
- `scheduler` 重启后必须重新扫描 `next_run_at <= now()` 的计划任务,并按幂等键自动追回漏派发任务
- 若计划任务已超出允许追赶窗口,则记录为 `skipped/expired` 并写入审计日志
- 派发状态需保留 `lease_owner``dispatch_lease_until``last_dispatch_at`,便于故障排查和追赶
#### 13.13.3 PostgreSQL 分区、索引与归档
- `audit_logs``config_change_logs``quota_change_logs``risk_action_logs` 按月分区
- `question_monitor_runs``question_monitor_parse_results``question_model_*``keyword_model_*` 按日期分区
- `articles` 至少提供 `(tenant_id, created_at desc)``(tenant_id, generate_status, publish_status, created_at desc)` 复合索引
- 原始回答正文保留在对象存储 `30~90 天`,解析结果保留 `90 天`,聚合表保留 `180 天+`
- V1 先使用单 PostgreSQL 主实例;若读压升高,优先增加只读副本而不是立即拆库
#### 13.13.4 限流、队列保护与熔断
- `gateway` 层增加基于 Redis 的租户级令牌桶限流,维度为 `tenant_id + route_group`
- `tenant-api` 在任务提交前校验:套餐额度、租户当日提交量、当前排队深度、模型通道状态
- `worker-generate` 对下游 LLM 调用统一使用 `context.WithTimeout(30s)`,并以 `semaphore` 控制单 consumer 组最大并发,V1 默认建议 `50`
- 交互式生成、批量生成、监控采集使用独立令牌桶;`worker-analytics` 默认只占用小比例低优先级通道,不能反压用户实时生成
- `worker-generate``worker-analytics` 的上游调用按 `3s / 10s / 30s` 做有限退避重试;熔断打开后只允许少量探测请求恢复
- `worker-knowledge` 的 Embedding 请求按 chunk 批量提交,建议单次 `16 ~ 32` 个 chunk,失败时自动拆批重试
- RabbitMQ 为生成队列配置最大长度和溢出策略,超过阈值时拒绝低优先级批量任务
- 平台端的强制重试、强制补量、限流豁免必须写审计日志
#### 13.13.5 Redis 缓存与对象存储分发策略
- 工作台聚合、趋势图、高频问题、引用排行等热点查询使用 `TTL + 抖动 + 异步刷新`
- 对不存在的数据维度使用空值缓存,避免缓存穿透
- 高热点品牌数据在凌晨批量预热,避免白天冷启动击穿数据库
- 公有云部署推荐 `OSS + CDN`;私有化部署推荐 `MinIO + Nginx / CDN`
- 图片、封面、知识库原文件通过带签名的对象存储 URL 输出,走 CDN 分发
- 已删除知识文档的对象文件按 `T+7` 清理,原始模型回答按监控策略保留 `30 ~ 90 天`
- 发布请求/响应原始 payload 建议按审计需求保留 `30 ~ 90 天`,并由 GC 任务定期扫描孤儿文件
#### 13.13.6 配置管理与动态加载
- V1 配置层级采用:`base YAML -> 环境变量覆盖 -> 动态配置覆盖`
- 动态配置仅用于可热更新项:限流阈值、功能开关、模型通道权重、adapter 开关、轮询/SSE 策略
- 结构性配置如数据库 DSN、MQ 地址、端口等仍通过重启生效,避免隐藏复杂度
- 所有动态配置变更进入 `config_change_logs`
#### 13.13.7 Sponge 使用原则
- `sponge` 仅作为脚手架初始化工具使用,不采用其默认的业务 `handler/service/dao` 全量代码生成
- 如需复用少量样板代码,生成代码也必须按本文分层映射:`handler -> transport``service/logic -> app``dao -> repository``domain` 由业务手工维护
- `tenant``platform` 的双域拆分优先于代码生成习惯,架构设计始终先于框架约束
#### 13.13.8 Migration 与 Schema 变更策略
- V1 推荐统一使用 `golang-migrate` 管理 Schema 版本,目录固定为 `server/migrations/`
- 命名规则建议:`YYYYMMDDHHMMSS_description.up.sql` 与对应 `down.sql`
- 线上 DDL 采用 expand / migrate / contract 三阶段,避免单次发布中直接删列、改类型或重建大索引
- 分区表、索引和长耗时 DDL 必须走预发演练;高风险变更在低峰窗口执行并保留回滚脚本
#### 13.13.9 租户隔离与关键事务边界
- Repository 层必须提供 `TenantScope(ctx)` 或等价封装,租户侧查询默认自动注入 `tenant_id`
- 平台侧跨租户查询只允许出现在 `platform/*` 域;禁止在租户域直接手写绕过租户条件的 SQL
- CI 应增加静态检查或代码评审规则,重点扫描缺少 `tenant_id` 过滤的查询
- 关键事务边界至少包括:任务提交预扣额度、Worker 成功确认额度、Worker 失败退还额度、插件回调幂等落库
#### 13.13.10 错误码、日志与链路追踪
- 所有进程统一使用结构化 JSON 日志,建议使用 `zap`
- `gateway` 为入口请求生成 `request_id`;若上游已带可信 `request_id` 则复用,并同时补充内部 `trace_id`
- API -> MQ -> Worker 全链路透传 `request_id``trace_id``tenant_id``task_batch_id`
- RabbitMQ 消息头必须包含上述追踪字段,Worker 落日志时原样打印
- V1 最低要求是“统一错误码 + 结构化日志 + `request_id` 贯通”;V1.5 再引入 OpenTelemetry / Jaeger
- 所有告警规则统一绑定 `service``queue``tenant_scope``error_code` 标签,便于聚合排查
#### 13.13.11 本地开发、归档与运维模板
- 本地开发默认模式为“中间件容器化,Go 服务本地运行”,避免 `docker compose up` 同时拉起全部业务进程
- 提供统一的 `make dev-init``make dev-api``make dev-workers` 或等价任务入口,降低新人启动门槛
- 4 类 Worker 保持独立二进制,但共享同一套容器基座、健康检查协议、日志格式和 Helm 模板
- 审计表与监控表分区需配套归档脚本或定时作业,按月导出历史分区并清理超期数据
- 对象存储 GC、分区归档、死信队列巡检建议统一纳入 `scheduler` 的低频运维作业或独立运维 CronJob
## 14. 最终建议
如果当前目标是尽快落地并保持后续可扩展,最推荐的方案是:
- 前端采用双应用:`apps/admin-web``apps/ops-admin-web`
- V1 同步建设执行端:`apps/browser-extension`
- 共享能力全部沉淀到 `packages/*`
- 后端采用 `gateway + tenant-api + platform-api + scheduler + 多 Worker` 结构
- 统一使用 `PostgreSQL + Redis + RabbitMQ + Qdrant + 对象存储`
- 权限严格按 `platform_role``tenant_role` 分层
- 高风险操作统一纳入审计
这个方案的优点是:
- 前端边界清晰
- 后端复杂度可控
- 权限模型不混乱
- 既适合 V1,也方便未来演进到更细的服务拆分