# 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 + Redis,Python 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 换一次性 ticket(60s 有效) | | GET | `/tasks/{id}/stream?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_words(workspace_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节)。