按交叉评审对齐文档与代码口径,并挡住 reference 下的密钥文件
表名、配额种子和字段名以产品方案与架构为准;文档仓库补 .gitignore,避免 git add -A 把 API Key 推进远端。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+24
-7
@@ -1,6 +1,6 @@
|
||||
# 「美搭」技术架构文档
|
||||
|
||||
> 版本:**v1.3** | 更新日期:2026-08-13 | 状态:待技术评审
|
||||
> 版本:**v1.4** | 更新日期:2026-08-14 | 状态:待技术评审
|
||||
>
|
||||
> **本文的定位**:把产品需求翻译成可直接拆解为开发任务的技术方案。读完这份文档,应该能回答三个问题——系统由哪些部分组成、数据长什么样、每条关键链路怎么跑通。
|
||||
>
|
||||
@@ -185,6 +185,8 @@
|
||||
| `notify` | 推送、应用内消息、Token 管理 | `push()` `notify_task_done()` | — |
|
||||
| `wardrobe` | 我的衣橱(V2) | — | — |
|
||||
|
||||
> **域与包不是一一对应。** 上表按产品职责切(`profile` 含记忆);§16.1 的 `packages/` 按发布与依赖切。记忆有独立表、独立生命周期,且会被 agent / report 同时写入,因此代码上是独立的 `packages/memory`,产品职责仍归 profile 域。跨域只许 import `memory` 的 `service`,不许直接读 `pf_memory`。
|
||||
|
||||
### 4.2 依赖规则
|
||||
|
||||
```
|
||||
@@ -344,11 +346,24 @@ kb ← agent / report(读取)
|
||||
|
||||
| 表 | 关键字段 | V1 | 说明 |
|
||||
| --- | --- | :--: | --- |
|
||||
| `bl_quota` | `user_id`, `quota_key`, `period_key`, `used`, **`bonus_granted`**, `updated_at`;UNIQUE(`user_id`,`quota_key`,`period_key`) | ✅ | **V1 扣减判定的唯一依据**。周期配额计量(日/月/终身),按 `period_key` 自然重置,**不要写定时清零任务**。`bonus_granted` 物化本周期已获任务奖励,避免每次判定都聚合流水 |
|
||||
| `bl_quota_rule` | `quota_key`, `period_type`, `base_limit`, `task_bonus_max`, `hard_cap` | ✅ | 配额规则配置化(`FR-BILL-04`),改配置不发版。数值来源:产品方案 §3.2 配额表(唯一事实源) |
|
||||
| `bl_quota` | `user_id`, `quota_key`, `period_key`, `used`, **`limit_value`**, **`bonus_granted`**, `updated_at`;UNIQUE(`user_id`,`quota_key`,`period_key`) | ✅ | **V1 扣减判定的唯一依据**。周期配额计量(日/月/终身),按 `period_key` 自然重置,**不要写定时清零任务**。`limit_value` 是本周期创建时从规则拷下的 `base_limit` 快照(规则中途被改,本周期仍按快照判定);`bonus_granted` 物化本周期已获任务奖励,避免每次判定都聚合流水 |
|
||||
| `bl_quota_rule` | `quota_key`, `period_type`, `base_limit`, `task_bonus_max`, `hard_cap` | ✅ | 配额规则配置化(`FR-BILL-04`),改配置不发版。数值与 `quota_key` 映射见下表,**一律引用产品方案 §3.2,禁止在种子里另写一套** |
|
||||
| `bl_ledger` | `tx_id`, `user_id`, `delta`, `tx_type`, `status`, `reason`, `ref_type`, `ref_id`, `balance_after`, `idempotency_key` UNIQUE, `created_at` | ✅ | **流水是真相**,但**不参与 V1 的判定**(判定看 `bl_quota`)。`tx_type` V1 用 `system_grant`/`consume`/`refund` **三种**,V2 增加 `purchase`/`gift` —— 这是 V1→V2 免迁移的关键 |
|
||||
| `bl_wallet` | `user_id` PK, `balance`, `version`(乐观锁) | ✅ | ⚠️ **V1 仅用于「跨周期不清零」的额度**(如首次终身报告);周期类额度一律走 `bl_quota`。V2 语义扩展为点数余额,**同一张表,不改结构** |
|
||||
|
||||
**`bl_quota_rule.quota_key` 与产品方案 §3.2 的对应**(种子必须与此表一致):
|
||||
|
||||
| `quota_key` | 对应 §3.2 行 | `period_type` | `base` / `task_bonus_max` / `hard_cap` |
|
||||
| --- | --- | --- | --- |
|
||||
| `agent_chat` | AI 对话 | day | 10 / 10 / 40 |
|
||||
| `tryon` | 换装试穿 | day | 3 / 3 / 8 |
|
||||
| `hairstyle` | 发型 / 发色试戴 | day | 3 / 2 / 6 |
|
||||
| `hd_export` | 高清导出 | day | 1 / 0 / 3 |
|
||||
| `report_basic` | 初级美学报告(首次) | lifetime | 1 / 0 / 1 |
|
||||
| `report_regen` | 报告重新生成 | month | 1 / 1 / 2 |
|
||||
|
||||
「每日 ≤ 2」在月额度上限为 2 时自然满足,不必再拆一条日配额。**记忆条数 200 是存储上限,不是消耗型配额,不进本表。** 游客额度按设备维度计量,依赖 `id_guest`;游客合并链路未建之前**不写入 `guest_*` key**,避免种子里出现没人读的第二套口径。
|
||||
|
||||
> 🔑 **四张表的职责边界见 §7.4 开头**。这是最容易实现成"两套并行扣减逻辑"的地方,务必先读那一段。
|
||||
| `bl_membership` | `user_id`, `level`, `valid_from`, `valid_to`, `source_order_id`, `auto_renew` | ❌ V2 | 会员 |
|
||||
| `bl_order` | `order_id`, `user_id`, `product_id`, `product_type`, `price_cents`, `platform`('huawei_iap'), `purchase_token` UNIQUE, `status`, `verified_at`, `raw_receipt` JSONB | ❌ V2 | `purchase_token` 唯一约束防重复发货(`TD-16`) |
|
||||
@@ -368,7 +383,7 @@ kb ← agent / report(读取)
|
||||
|
||||
| 表 | 关键字段 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `ob_ai_call` | `call_id`, `user_id`, `scene`, `provider`, `model`, `prompt_id`, `prompt_version`, `tokens_in/out/cached`, `tokens_reasoning`, `latency_ms`, `cost_cents`, `rate_tier`, `success`, `error_code`, `ref_type`, `ref_id`, `created_at` | **成本归因的唯一数据源**,按月分区。`prompt_id`/`prompt_version` 使每次调用可复现(§8.1 要求 Prompt 版本化,缺这两列就无法回答「上周的报告是哪版 Prompt 生成的」);`tokens_reasoning` 单独记思考模式 token(按输出价计费,混进 `tokens_out` 会掩盖开关思考模式的成本差异);`rate_tier` 记录该次调用适用的峰谷档位,否则事后无法复核 `cost_cents` |
|
||||
| `ob_ai_call` | `call_id`, `user_id`, `scene`, `provider`, `model`, `prompt_id`, `prompt_version`, `tokens_in/out/cached`, `tokens_reasoning`, `latency_ms`, `cost_cents`, `rate_tier`, `success`, `error_code`, `ref_type`, `ref_id`, `created_at` | **成本归因的唯一数据源**,按月分区。`prompt_id`/`prompt_version` 使每次调用可复现(§8.1 要求 Prompt 版本化,缺这两列就无法回答「上周的报告是哪版 Prompt 生成的」);`tokens_reasoning` 单独记思考模式 token(按输出价计费,混进 `tokens_out` 会掩盖开关思考模式的成本差异);`rate_tier` 记录该次调用适用的峰谷档位,否则事后无法复核 `cost_cents`。**保留口径**:明细至少保留到 V2 定价完成(`T-P6-16`);满 12 个月的分区可迁冷存储,**不可按常规日志周期删除** —— 删了就失去定价依据 |
|
||||
| `ob_event` | `event_id`, `user_id`, `event_name`, `props` JSONB, `client_ts`, `server_ts` | 埋点事件,按月分区(`TD-23`) |
|
||||
|
||||
### 6.3 诊断维度的存储形态
|
||||
@@ -996,7 +1011,7 @@ get_memory_snapshot(user_id, budget_tokens)
|
||||
### 16.1 仓库结构
|
||||
|
||||
```
|
||||
meida/
|
||||
meida_backend/ # 后端仓库。文档在独立仓库 meida,鸿蒙端尚未建库
|
||||
├─ apps/
|
||||
│ ├─ api/ # FastAPI 应用(路由、依赖注入、中间件)
|
||||
│ ├─ worker/ # Celery 任务定义
|
||||
@@ -1031,10 +1046,11 @@ meida/
|
||||
│ ├─ integration/ # 带 DB/Redis(testcontainers)
|
||||
│ └─ golden/ # 黄金集回归(检索/规则/报告)
|
||||
├─ deploy/ # Dockerfile / compose / CI 配置
|
||||
├─ docs/ # 本文档集
|
||||
└─ client-harmony/ # 鸿蒙 ArkTS 工程
|
||||
└─ scripts/
|
||||
```
|
||||
|
||||
文档集在 `meida` 仓库(`docs/`),不进本仓库。鸿蒙客户端独立建库,不预置空目录。
|
||||
|
||||
**包内约定**:每个业务域包统一为 `service.py`(用例编排,对外唯一入口)+ `repo.py`(该域自己的表访问)
|
||||
+ 可选 `schemas.py`。§4.2 的「禁止直接查对方的表」因此落为一条可机检规则:
|
||||
**跨域只允许 import 对方的 `service`,不允许 import 对方的 `repo`。**
|
||||
@@ -1149,6 +1165,7 @@ meida/
|
||||
|
||||
| 日期 | 版本 | 变更 |
|
||||
| --- | --- | --- |
|
||||
| 2026-08-14 | v1.4 | **文档 ↔ 代码交叉评审回写**。① §16.1 根目录 `meida/` → `meida_backend`,并去掉本仓库并不存在的 `docs/`、`client-harmony/`。② §4.1 补「域与包不是一一对应」:产品职责上记忆归 profile,代码上独立 `packages/memory`。③ `bl_quota` 列清单补 `limit_value`(本周期 base_limit 快照),并给出 `quota_key` 与产品方案 §3.2 的一一映射;游客 key 与记忆条数明确不进种子。④ `ob_ai_call` 补保留口径(定价完成前不可按日志周期删除) |
|
||||
| 2026-08-13 | v1.3 | **脚手架落地后按实现回写,五处修正**。① **§16.1 仓库结构补全 11 个业务域包** —— 原树只列了 7 个 `packages/`,§4.1 定义的 11 个业务域在树里无处安放,实现时只能猜;现补全并加「包内约定」(每域 `service.py` + `repo.py`,跨域只许 import 对方 `service`)与三层判别标准表。② **§6.2 `ob_ai_call` 补 `prompt_id`/`prompt_version`/`tokens_reasoning`/`rate_tier` 四列** —— §8.1 要求 Prompt 版本化可复现,但表里没有版本列,等于要求做不到的事;思考 token 混进 `tokens_out` 会掩盖开关思考模式的成本差异。③ **§9.1 澄清基础路径** —— 正文写 `/api/v1`、任务描述写 `/v1`,实现两者都要能用;现明确 `/api/v1` 为规范写法、`/v1/*` 仅作兼容别名。④ **§13.2 新增峰谷计价约束** —— DeepSeek 自 8-17 起高峰单价翻倍且新价目输出侧涨 2.25~4.5 倍,成本须在调用当时算好落库(不可事后回算),§13.1 的预算与熔断阈值需按新价重算;Agent 单轮成本注明思考模式须显式关闭。⑤ **§13.3 补「关键场景显式豁免」** —— 意图识别这类调用失败会让链路整体不可用,须标记 `critical` 不受熔断拒绝,但仍计入成本;豁免清单必须极短,否则熔断被绕空 |
|
||||
| 2026-08-13 | v1.2 | **文档一致性评审修订,其中三处是会直接卡住开发的实质缺陷**。① **§7.4 补齐 `billing` 域四张表的职责边界** —— `bl_quota` 与 `bl_wallet` 此前看起来像两套重复机制,`task_bonus` 的来源也没定义;现明确「V1 判定看 `bl_quota`、V2 判定看 `bl_wallet`、`bl_ledger` 两版都只是流水」,并把 `task_bonus` 物化为 `bl_quota.bonus_granted` 字段(避免每次判定聚合流水),补充三处最易写错的地方(熔断须在预扣之前、`used` 增减须与流水同事务、周期重置靠 `period_key` 而非定时清零)。② **§13 成本模型重写** —— 推翻「月度成本上限 = MAU × 单用户配额上限」这个错误论证(配额约束单用户,总成本 = MAU × 人均,MAU 无上限),改为「理论最坏 / 预期成本 / 真实封顶」三口径,并新增 **§13.3 四档熔断降级**(含在途任务放行、被熔断请求不得扣配额、可人工解除)。③ **§7.2 token 预算改为嵌套表**,合计 3700→**4200**(原表漏算会话近轮原文 400),并明确硬禁忌永不裁剪。另:`pf_memory.status`/`source`、`id_consent.consent_type` 枚举与用户系统对齐(`personalization` 不可省略,否则记忆写入无合规依据);手机号存储位置明确为 `id_user_identity`;诊断维度 34→**32**;`points_reserved`→**`quota_reserved`**;外部依赖表补入腾讯云短信并说明登录双通道不得互相依赖;§12.2 说明 1 万 DAU 基线与 MAU 15 万目标的口径关系 |
|
||||
| 2026-08-13 | v1.1 | 按业务决策收口调整。**billing 域降级为「配额与计量」**:V1 移除支付、订单、会员、IAP;`bl_point_tx` 改名 `bl_ledger` 并新增 `tx_type` 字段,使 V1 配额账本与 V2 点数账本共用同一张表(V2 免数据迁移);新增 `bl_quota_rule` 配额规则表。§7.4 拆为「V1 配额三段式」与「V2 IAP 支付」。§13 成本模型补充「V1 成本上限可事前算准」的公式,并强调 `ob_ai_call` 是 V2 定价的唯一数据来源、不允许后补。§19 风险登记:备案风险关闭,新增备案范围一致性、素材自采产能、顾问到岗三项风险 |
|
||||
|
||||
Reference in New Issue
Block a user