docs: 交接文档三件套(接手总览+后端地图+差距路线图)+补全env模板
Some checks failed
Clover CI / backend (push) Has been cancelled
Clover CI / frontend (push) Has been cancelled
Clover CI / python-audit (push) Has been cancelled

- HANDOVER.md: 守印接手第一入口,全景+上手路径+文档地图
- backend/BACKEND_MAP.md: 后端接手地图(路由/模型/AI引擎/评分维度)
- 路线图.md: 现状vs目标差距(三视角×双目标矩阵+7/15倒排冲刺)
- .env.example x3: 补全 MODEL_VISION/CLAUDE_API_URL 及本地SSE示例

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
yangqianqian
2026-07-01 18:49:51 +08:00
parent e26f53608b
commit de6466737b
6 changed files with 576 additions and 0 deletions

283
backend/BACKEND_MAP.md Normal file
View File

@@ -0,0 +1,283 @@
# Clover 后端接手地图
> 受众:守印(新接手后端,不了解北哥产品背景)
> 最后更新2026-07-01
> 基于真实代码分析,所有文件名/类名/函数名/行号均来自实际代码,请直接跳转核实。
---
## 产品背景(守印必读)
Clover 是给北哥团队做的**小红书种草内容生产中台**,帮助运营团队批量生产高质量小红书笔记。
完整链路:
```
填产品卖点(产品档案)
→ 上传标杆笔记AI拆解爆款特征
→ 发起任务AI生成3套文案 × A痛点先行/B场景先行/C成分背书
→ 运营选文案 + 选配图(每步触发飞轮信号学偏好)
→ 组长审核(通过/打回带原因)
→ 打包下载 ZIP发给达人分发
→ 爆款笔记可触发"裂变"再出N套变体
```
**三个角色:**
- `operator`(运营):选文案/选图/改稿
- `supervisor`(组长):审核通过/打回
- `admin`(管理员):管用户/管词库/删候选
**两大特色机制:**
- **AI评分门禁**:文案必须 ≥80分才入库低分直接过滤不展示给运营
- **飞轮**:每次选择/改稿/打回都是信号,下次生成自动学偏好
---
## 目录
1. [整体目录结构与技术栈](#1-整体目录结构与技术栈)
2. [API 路由全清单](#2-api-路由全清单)
3. [数据模型](#3-数据模型)
4. [AI 引擎模块清单](#4-ai-引擎模块清单)
5. [Celery 异步任务](#5-celery-异步任务)
6. [飞轮机制](#6-飞轮机制)
7. [门禁可配置性现状](#7-门禁可配置性现状)
8. [鉴权与 SSE](#8-鉴权与-sse)
9. [改动快速索引](#9-改动快速索引)
---
## 1. 整体目录结构与技术栈
**技术栈:** FastAPI + Celery + PostgreSQL + RedisPython 3.11+Alembic 做迁移pytest 做测试。
```
backend/
├── app/
│ ├── api/v1/ # 路由层16个文件统一前缀 /api/v1/
│ ├── models/ # SQLAlchemy ORM 模型6个文件
│ ├── repositories/ # DB 查询封装Repository 模式)
│ ├── services/ # 业务逻辑层
│ │ ├── ai_engine/ # AI 引擎24个模块核心
│ │ ├── flywheel_service.py # 飞轮信号写入
│ │ ├── fission_service.py # 裂变任务创建
│ │ ├── fission_pipeline.py # 裂变执行主流程
│ │ └── fission_images.py # 裂变生图
│ ├── workers/ # Celery 任务层5个文件
│ ├── constants/
│ │ └── enums.py # 枚举定义(状态机、信号类型、角色等)
│ ├── core/
│ │ ├── config.py # 环境变量读取Settings 类)
│ │ ├── database.py # DB session 工厂
│ │ ├── security.py # JWT 签发/验证 + Fernet 加解密
│ │ └── sse_ticket.py # SSE 一次性票据Redis 存储)
│ └── middleware/
│ └── workspace_guard.py # 鉴权依赖注入4个级别
├── alembic/versions/ # 19 个数据库迁移文件
├── tests/ # 单元测试pytest
├── docker-compose.yml # 本地开发启动
└── requirements.txt # Python 依赖
```
---
## 2. API 路由全清单
所有路由统一挂在 `app/main.py`,前缀 `/api/v1/`。路由文件在 `app/api/v1/`
### auth.py — 认证
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/auth/login` | 用户名密码登录,返回 JWT access_token |
| POST | `/auth/change-password` | 修改密码(首次登录强制走此端点) |
| GET | `/auth/me` | 当前用户信息 + 所属 workspace + role |
### workspaces.py / users.py / api_keys.py
| 方法 | 路径 | 作用 |
|------|------|------|
| GET/POST | `/workspaces` | 查/建工作区 |
| GET/POST/PUT | `/users` | 成员管理admin |
| POST/GET/DELETE | `/api-keys` | API Key 录入/查看/删除(只返回 provider+last4不返密文 |
### products.py — 产品档案
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/products` | 新建产品档案 |
| GET | `/products` | 列出当前 workspace 产品 |
| GET | `/products/{id}` | 查单个产品(含参考图) |
| PUT | `/products/{id}` | 更新卖点/风格/角度等 |
| DELETE | `/products/{id}` | 软删除is_active=False |
### product_images.py — 产品多图R5规格
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/products/{id}/images` | 上传参考图,按 scene 分类primary/scene/texture/ingredient/model |
| GET | `/products/{id}/images` | 列出所有参考图 |
| DELETE | `/products/{id}/images/{img_id}` | 删除某张 |
### benchmarks.py — 标杆笔记链路第2环
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/products/{pid}/benchmarks/upload` | 上传截图10MB 限制magic bytes 校验) |
| GET | `/products/{pid}/benchmarks` | 列出该产品标杆笔记 |
| POST | `/benchmarks/{bid}/analyze` | 触发 AI 拆解8维爆款特征写入 features_json |
| GET/POST/PUT/DELETE | `/banned-words` | 违禁词 CRUD写操作需 admin |
| GET | `/products/export` | 产品档案 JSON 导出 |
| GET | `/benchmarks/export` | 标杆笔记 JSON/CSV 导出 |
### tasks.py — 任务查询层
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/tasks` | 发起生成任务(校验有无 key推入 Celery queue |
| GET | `/tasks` | 任务列表(多状态/日期/product_id 过滤 + 分页,可混入裂变条目) |
| GET | `/tasks/{task_id}` | 任务详情(含所有文案候选 + 图片候选) |
| DELETE | `/tasks/{task_id}` | 删除任务admin有成品转 archived无成品物理删 |
### task_actions.py — 任务操作层(飞轮信号入口)
> 所有飞轮信号都在这里触发,是行为核心。
| 方法 | 路径 | 作用 | 飞轮信号 |
|------|------|------|---------|
| POST | `/tasks/{id}/text-candidates/select` | 选文案(同套单选,清旧选) | text_select +3 |
| POST | `/tasks/{id}/image-candidates/select` | 选图(同套同角色单选) | image_select +3 |
| POST | `/tasks/{id}/import-text` | 导入外部文案(客户验证过的范本,最强信号) | text_import +8 |
| POST | `/tasks/{id}/generate-images` | 导入轨去生图(复用已导入文案,不重生文案) | 无 |
| POST | `/tasks/{id}/regenerate` | 重生成(支持整体/单套/单张 + custom_prompt | regenerate -1 |
| POST | `/tasks/{id}/submit-review` | 提交审核至少1文案+1图才能提 | 无 |
| GET | `/tasks/{id}/preference/context` | 查飞轮偏好上下文(前端展示"已学习N条信号" | 无 |
| POST | `/tasks/{id}/text-candidates/{cid}/edit` | 改稿(真改字,回写 content + edited=True | text_edit +5 |
| DELETE | `/tasks/{id}/text-candidates/{cid}` | 删文案候选admin | 无 |
| DELETE | `/tasks/{id}/image-candidates/{cid}` | 删图片候选admin | 无 |
### review.py — 审核路由supervisor 权限)
| 方法 | 路径 | 作用 | 飞轮信号 |
|------|------|------|---------|
| GET | `/review/queue` | 待审队列pending_review按时间升序 | 无 |
| POST | `/review/{task_id}/approve` | 通过状态→approved | approve +5 |
| POST | `/review/{task_id}/reject` | 打回(原因原文存 preference_events.reason | reject_with_reason -3 |
### stream.py — SSE 实时推送安全红线ticket 机制)
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/tasks/{id}/sse-ticket` | 用 JWT 换一次性 ticket60s 有效) |
| GET | `/tasks/{id}/stream?ticket=<ticket>` | SSE 流(断线重连支持 `?last_seq=` |
### fission.py — 裂变链路第11环
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/fission` | 触发裂变1套爆款→N套完整笔记包 |
| GET | `/fission/{id}` | 查进度x/N 完成) |
| GET | `/fission/{id}/notes` | 取 N 套完整笔记包 |
| GET | `/fission/{id}/download` | 下载裂变结果 zip |
| POST | `/fission/{id}/notes/{seq}/retry-images` | 对某套失败分镜补图 |
### delivery.py — 交付打包
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/tasks/{id}/package` | 触发打包(异步 Celery |
| GET | `/tasks/{id}/package` | 查包状态 + 下载链接 |
---
## 3. 数据模型
模型文件在 `app/models/`,共 6 个文件。
### user.py
- `User``id, username(唯一), email(唯一), hashed_password, is_active, must_change_password(首登强制改密)`
- `LoginRecord`:登录记录,`user_id FK→users, ip, user_agent`
- `UserPreference`UI 设置,`preferences_json`Text 存 JSON
### workspace.py
- `Workspace``id, name, slug(唯一), is_active`
- `WorkspaceMember``workspace_id + user_id 联合唯一, role 枚举(admin/supervisor/operator)`
- `UserApiKey``user_id + workspace_id + provider 三联唯一, encrypted_key(Fernet 密文), key_last4`;绝不存明文
### product.py
- `Product``workspace_id FK, name, category, selling_points(JSON数组), style_tone, text_angles(JSON数组), custom_prompt, image_path(主图路径兼容旧), brand_keyword, target_audience, is_active`
- `ProductImage`R5多图`product_id FK, path(绝对路径), scene(primary/scene/texture/ingredient/model), is_primary, sort_order`
- `BenchmarkNote``workspace_id+product_id FK, screenshot_url, highlights(手填), link_url, features_json(AI解析8维), analyze_status(pending/analyzing/done/failed)`
- `BannedWord``workspace_id FK, word, level(auto_fix/soft_warn/hard_block), replacement, updatable`
### task.py
- `GenerationTask``workspace_id FK, product_id FK, operator_id FK, theme, text_count(1-20), image_count(1-20), track(ai/import), need_product_image, status 7态(见下), review_status, reviewer_id, reject_reason, source_fission_id`
- 状态机:`pending → generating → pending_selection → pending_review → approved/rejected`;另有 `archived`(有成品软删)、`failed`(重试耗尽终态)
- `TextCandidate``task_id FK, source(ai/import), angle_label, strategy(A/B/C), content(JSON含title/content/tags/imageBrief), score_json(7维评分), banned_word_status, eval_score(一期留NULL), is_selected, edited(改稿标记)`
- `ImageCandidate``task_id FK, role, url, strategy(A/B/C), seq(分镜序号), is_selected, is_regen, eval_score(一期留NULL), ai_visual_score(展示用不进飞轮权重)`
- `DeliveryPackage``task_id FK, status(pending/ready/downloaded), package_path, download_url, expires_at`
### flywheel.py
- `PreferenceEvent`preference_events 表):飞轮信号日志
- 关键字段:`workspace_id, product_id, task_id FK, user_id FK, signal_type, signal_weight, candidate_id, angle_label, reason(打回原因原文), signal_meta(JSON), data_ownership(固定=client_data数据归客户)`
- 索引:`(workspace_id, product_id, created_at)` 三联复合索引
- `AiCallLog`ai_call_logs 表):`key_id(不含明文), provider, model, call_type, prompt_tokens, completion_tokens, success, error_code, latency_ms`
### fission.py
- `FissionTask``workspace_id FK, source_note(源笔记JSON), source_task_id FK, reference_level(low/mid/high), fanout_count(默认3), status(pending/generating/done/failed)`
- `FissionNote``fission_id FK, workspace_id FK, seq(第几套), note_json(含title/content/tags/imagePlan/dimension), images_json(生图结果列表), score, passed(>=80), dimension(换角度/换痛点/换人群), status`
**表间主要外键:**
- workspace → products / generation_tasks / fission_tasks / preference_events / banned_wordsworkspace_id 隔离多租户)
- generation_task → text_candidates / image_candidates / delivery_packages / preference_events
---
## 4. AI 引擎模块清单
全部在 `app/services/ai_engine/`,共 24 个文件。
| 模块文件 | 一句话职责 |
|---------|----------|
| `constants.py` | 所有可调常量中心:违禁词默认库、评分权重、合格线(80)、叙事策略文本、图片重试参数、飞轮权重 |
| `_score_prompt.py` | AI评委 prompt 模板7维评判标准+输出格式约束JSON与 constants.py 三处同步 |
| `_scoring_dims.py` | 机械合规打分score_compliance用于轨B导入文案或AI评委降级兜底 |
| `llm_scorer.py` | AI评委入口调 LLM 打7维分合规机械硬拦两通道挂时抛 ScoringUnavailableError |
| `text_scoring.py` | 文案评分聚合:整合 AI 评委分 + 机械合规分,输出 score_json |
| `text_variants.py` | 按 A/B/C 三套叙事策略调 LLM 生成多条文案变体 |
| `_text_prompt.py` | 文案生成 prompt 模板(含叙事策略差异化段落) |
| `prompt_composer.py` | 组装最终文案生成 prompt拼飞轮片段+产品信息+标杆特征+叙事策略) |
| `storyboard.py` | 按图数和叙事策略规划分镜列表,返回 storyboard + base_prompt |
| `storyboard_templates.py` | 各套叙事策略的分镜模板数据 |
| `_storyboard_data.py` | 分镜角色的默认视觉参数 |
| `image_gen.py` | 生图主入口asyncio.gather 并发多张主备通道切换指数退避重试3次 |
| `image_postprocessor.py` | 图片去AI化后处理SynthID破除(缩2px裁1px边+亮度/饱和微调)+高保真重编码(jpeg q=100)+尺寸处理 |
| `image_scorer.py` | AI评图0-100分ai_visual_score+ai_visual_note仅展示不进飞轮权重 |
| `banned_word_checker.py` | 三级违禁词扫描auto_fix/soft_warn/hard_block优先 DB 词库,兜底默认词库 |
| `preference_aggregator.py` | 飞轮偏好聚合取最近50条 events → 按权重统计高频角度 → 拼 prompt 片段注入文案生成 |
| `benchmark_analyzer.py` | 标杆笔记爆款8维特征 AI 解析链路第2环 |
| `_benchmark_prompt.py` | 标杆分析 prompt 模板 |
| `fission_prompt.py` | 裂变专用 prompt一次 LLM 出 N 套笔记) |
| `fission_fallback.py` | 裂变引擎降级兜底逻辑 |
| `gemini_factory.py` | Gemini 客户端工厂(生图备用通道) |
| `package_exporter.py` | AI引擎层的素材包打包辅助 |
| `beige_color_grade.py` | 小红书米色调色滤镜去AI化可选后处理 |
### 评分维度详细7维 + 合规机械)
**AI评委7维**,定义在 `_score_prompt.py: SCORING_DIMENSIONS` 字符串 + `llm_scorer.py: _DIM_MAX` dict + `constants.py: AI_DIM_WEIGHTS` dict**三处必须同步**
| 维度 | 满分 | 核心判断标准 |
|-----|-----|------------|
| 痛点人群精准 | 16 | "说的就是我"——处境/困扰让目标用户对号入座 |
| 情绪张力 | 16 | 过去痛(后果)+ 未来好(成果)双向情绪 |
| 买点转化 | 16 | 卖点翻译成用户能感知的场景化利益(人话) |
| 开头钩子 | 13 | 第一句直击痛处/场景,让人停下来继续读 |
| 标题点击力 | 13 | 悬念/反差/疑问钩子 + 广覆盖不锁死窄人群 |
| 真实感 | 11 | 像真人分享前70%干货后30%软性推荐 |
| 标签精准度 | 10 | 精准购买意向埋词,非泛流量词 |
| 合规(机械) | 5 | 机械硬拦不进AI评委打分 |
| **合计** | **100** | |
**合格线**`constants.py` 第47行 `QUALITY_PASS_SCORE = 80`硬编码详见第7节