# Clover PRD-后端

> 后端技术框架。**本文是"承接层"**：架构决策见 `../Clover架构方案.md`(v0.3,金标准)，本文只做①引用架构决策②补PRD独有工程细节③承接扒包上线版新事实。
> 技术栈：FastAPI + Celery + MySQL + MongoDB + Redis（栈范式扒自banana，全新重建）
> 🔴 源码只读复制：扒**上线版** `万牛会L1准备/worker/src`(非旧版产品包) + banana。

## 0. 怎么读这份PRD
- 数据模型16表/基石ABCDEF/三期构建顺序/复用复活新造清单 → **见架构方案 §三/§〇.5/§五/§四**，本文不复制。
- 本文重点：第3章API契约细节、第9章环境变量、第10章工程规范（这些架构方案没细化）。
- 与架构方案冲突时：**以架构方案v0.3 + CLAUDE.md为准**。

## 1. 后端架构总览
- 分层：API层 / Service层(AI引擎) / Model层(双库) / 队列层(Celery+SSE) —— 详见架构方案§一
- AIProvider抽象层(扒banana)：**gpt-image-2主/Gemini备**，由环境变量 IMAGE_PROVIDER_PRIMARY 配置(不写死)
- 🔴 三条铁律入口(详见架构方案§〇.5)：A业务参数不写死 / B key不进Celery+Fernet加密 / C workspace逻辑隔离

## 2. 数据模型
- **完整16表清单+字段+Alembic001-004分批 → 见架构方案§三**，本文不重抄。
- 🔴 PRD骨架旧表名修正(以架构方案为准)：
  - api_keys→**user_api_keys**(UNIQUE user_id+workspace_id+provider)
  - tasks→**generation_tasks**(审核字段平铺:review_status/reviewer_id/reviewed_at/reject_reason/approved_at/archived_at)
  - 无assets表→实为 **text_candidates + image_candidates**(text_candidates有source=ai/import区分双轨)
  - 补 **login_records**(扒banana) / 补 **ai_call_logs**(usage记录,按key计费排障基础,一期必做)
  - data_ownership是**preference_events的字段**(client_data/platform_asset)，不是独立表
- 任务状态机7态：pending→generating→pending_selection→pending_review→approved/rejected→archived(打回回pending_selection)
- MongoDB**只存AI debug trace**(业务不依赖)；可调prompt在 products 表字段，**不在Mongo**
- 关键索引(架构没列,PRD补)：generation_tasks(workspace_id,status) / preference_events(workspace_id,product_id,created_at)

## 3. API 契约 → 唯一冻结源：`启动包/API契约.md`

> ⚠️ 契约统一：本 PRD **不再另写一套契约**。端点/响应包络/错误码/SSE事件/分页，
> 全部以 `Clover/启动包/API契约.md` 为唯一冻结源（避免前后端分叉，外部AI审核P0-1/2/8）。
> 开工首步：Lead 据 API契约.md 生成并冻结 `Clover/contracts/openapi.yaml`（"契约优先"落地，非口号）。

本 PRD 第3章只补**契约文档未覆盖的后端实现约定**（不重复端点定义）：
- 任务软删用标记位不物理删；DELETE /tasks/{id} 走 archived 态。
- 限流：同用户并发生成任务数上限（建议2，可配）；生图每张~4min 异步不占连接。
- SSE token 走 header（Authorization），不走 query（对齐契约，纠 banana 旧法）。
- preference 写入**不暴露独立埋点端点**：选择/审核业务接口内部写 events，前端只调业务动作（外部AI审核P1-14）。
- preference 读：GET /preference/context 已列入 API契约端点清单（外部AI审核P2-13）。

## 4. AI 引擎（扒上线版 worker/src 重写Python·核心）
> 算法逻辑整体扒上线版copy.js/image.js/split.js重写为Python，逻辑照搬防走样(TDD对照)。

### 4.1 文案引擎（扒copy.js上线版）
- **轨A**：一次调强模型返**N角度JSON**(N=用户设定text_count，不串行不并发，新造generate_text_variants)——这是去同质化关键，勿照抄旧版单条循环。数量不写死(基石A)。
- **轨B**：导入外部文案(豆包等)直接进候选池跳过AI(text_import_handler,text_candidates.source=import,洞2)
- 保留(扒上线版重写Python集成进轨A)：三层兜底Claude→Gemini→本地 / 五维打分90过线 / 自动优化循环 / **正文+开头去重(splitPublishableContent/contentSignature)** / **角度槽位(angleSlotsForCategory,作可迁移数据非代码常量)** / 内部提示剥离(content只放可发布正文)
- 可调prompt：products表字段，北哥可配(等北哥优质样本+判断标准注入,质量责任在北哥侧)

### 4.2 生图引擎（扒image.js上线版+改造）
- 扒保留：storyboard 10角色分镜 / getNarrativeRoles(3/6/8张链路) / 6品类proofStrategy / 素材路由 / buildVisualSystem成组视觉
- 🔴 生图通道(扒上线版已成熟,直接用)：
  - 主备由 IMAGE_PROVIDER_PRIMARY=gpt/FALLBACK=gemini 配置(imageProviderOrder)
  - GPT走 **edits带产品参考图**(requestGptImageWithReferences)，**禁纯文生图防跑偏**(无产品图报错)
  - 产品图=**不可修改商品锚点**,禁改包装/换产品/混历史产品(防串货)
- 🔴 补(上线版仍缺)：**生图通道加重试退避**(gpt-image-2实测502,baseline验证必要)
- 🔴 一期执行模型(纠正混淆,外部AI审核P0-3/4)：
  - **一期只做 storyboard 分镜图**：一篇笔记出 N 张叙事图(N=用户设定image_count，默认3，**合法1-8**，对齐worker getNarrativeRoles 3/6/8档链路，**不是固定10选3**)
  - 每张 storyboard 图走 provider 主备(gpt edits→gemini fallback) + 重试退避
  - **A/B/C 三策略不在一期主链路**：A/B/C 是"同一目标图的三种改图策略"，留给二期的"单图重生成/改图"功能，不与 storyboard 分镜混跑(否则任务数×UI 爆)
  - getNarrativeRoles 角色框架(hook/pain_scene/applied_proof/texture/scenario/tutorial/social_proof/closer)是可迁移数据，按 image_count 取前 N 个角色

### 4.3 裂变引擎（扒split.js上线版）
- 1爆款→N完整笔记包(标题+正文+标签+imagePlan分镜+维度+人群+场景+痛点)
- 爆款参考度调节(低30/中/高85防抄袭) ; generateImages=true串生图
- _combine_benchmarks：1-5篇标杆合并成综合reference(新造)

### 4.4 去水印（image_postprocessor·新造·洞3）
- 🔴 主方案=**重编码去C2PA元数据+转JPG+轻重采样削像素水印+压缩**(Pillow,对客户透明)；保留可视质量，**C2PA元数据可去除，私有像素水印只能削弱不保证100%清除**(诚实表述,外部AI审核P1-9)
- 备选=banana remove_watermark(Gemini重绘)——⚠️对海报中文大字有改字风险,仅特殊场景用,非主通道
- eval_score：**一期留NULL**,不接banana假评分(88分污染飞轮),等组长标准蒸馏真评分(三期)

## 5. 异步队列（扒banana骨架）
- Celery任务：生图异步(每张~4min) / **只传task_id绝不传key(基石B)** / worker内查库取encrypted_key→FERNET_KEY解密→局部变量,不落盘不打日志
- gemini_factory：每任务用自己key构建实例(新造,解决全局单例)
- 失败处理：Celery task失败→更新任务状态→SSE推task_failed(带code) ; 生图502重试退避
- SSE：Redis Pub/Sub推进度(扒banana event_bus)

## 6. 多租户与安全（基石BC,扒banana JWT）
- JWT HS256每请求验签,放user_id/workspace_id/role加速字段
- 🔴 读写分层(基石C，外部AI审核P1-7细化)：
  - **写操作+切workspace**：必须查 workspace_members 校验权限
  - **列表读**：用 JWT 的 current_workspace_id 过滤即可(加速)
  - **单资源读**(任务详情/候选详情/下载包)：仍须校验 resource.workspace_id == current_workspace_id，不能笼统信JWT(防越权读他人资源)
- base_workspace_repo：所有workspace相关Repo继承,强制带workspace_id过滤(新造,防串数据)
- workspace_guard中间件：FastAPI依赖注入,所有业务接口强制注入workspace_id
- token-url收口：统一自家中转站endpoint；**账号表只存encrypted_key不存url字段**(旧"兼容任意url"已废止)
- 上传安全(扒banana)：magic number校验+扩展名白名单+路径穿越防护

## 7. 存档打包（package_exporter·新造·洞6）
- 达人素材交付包：按笔记分文件夹+图(01/02/03命名防错序)+文案.txt(标题+正文+标签)+📋发布清单.txt+✅合规说明.txt(违禁词已过/已去水印)
- delivery_packages表:status(pending/ready/downloaded)/package_path
- 数据可导出(归客户,client_data) ; 飞轮偏好归平台(platform_asset)

## 8. 偏好飞轮（新造·灵魂·开放测试即启动）
- 三信号入口(preference_collector写events)：选文案+3/选图+3/通过+5/打回-3/重生成-1(初始默认权重,北哥可校准)
- 实时聚合(preference_aggregator)：查最近50条→最常选角度+打回原因近3条原文拼进prompt;不足5条用产品档案冷启动
- 三层继承：L1品牌基线>L2人设(二期)>L3个人手感;⚠️按产品维度分开学(素颜霜不串精华)
- 🔴 飞轮MVP验收四点(基石E,全过才达标)：events正确写入✓ / aggregator返回明确prompt片段✓ / 下次prompt trace含该片段✓ / UI显示"本次已注入:最近偏好/打回原因"✓

## 9. 配置与环境（架构没列,PRD补）
- 环境变量完整清单(必填项启动时校验,缺失则启动失败报错不静默)：
  - FERNET_KEY(必填,key解密,绝不进代码库) / JWT_SECRET(必填≥32字符) / DATABASE_URL / MONGO_URI / REDIS_URL
  - IMAGE_PROVIDER_PRIMARY=gpt / IMAGE_PROVIDER_FALLBACK=gemini / IMAGE_API_BASE(自家中转站url) / IMAGE_MODEL=gpt-image-2
  - CLAUDE_API_URL / GEMINI_API_URL(都收口自家站)
- 6容器Docker Compose(扒banana,调环境变量名) ; 文件存储:交付包路径规则uploads/packages/{workspace}/{task}/

## 10. 工程规范与可观测
- 健康检查 GET /health(Docker健康检查用)
- Alembic迁移：001-004按序;回滚策略;FERNET_KEY缺失启动保护
- 可观测：每次AI调用记ai_call_logs(谁/多少token,失败归因到个人key) ; MongoDB存调用trace排障
- 错误处理：统一错误码(§3.2) ; Celery失败SSE推送

