review 结果

This commit is contained in:
Shen Wei
2026-05-02 16:21:46 +08:00
parent ca33cc141f
commit 90f3811b83
10 changed files with 1448 additions and 1484 deletions

View File

@@ -2,7 +2,7 @@
# Fonrey — Public Schema 数据模型
> **作者**: Backend Architect
> **版本**: v1.6
> **版本**: v1.7
> **日期**: 2026-05-02
> **权威源**: 本文件是 `public` schema 所有表的唯一权威定义
> **设计依据**: 平台管理后台 PRD`PRD/平台管理后台/平台管理后台PRD.md`
@@ -15,6 +15,7 @@
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-05-02 | Atlas | 对齐平台管理后台 PRD v1.0`tenants` 增加 License 授权用户数上限字段 `license_user_limit`(含约束、索引、查询示例);`suspended_reason` 增加 `license_expired`;审计动作补充 `UPDATE_LICENSE_USER_LIMIT``AUTO_SUSPEND_LICENSE_EXPIRED``domains` 标注为统一 `tenant=` 路由下的兼容保留;同步更新元信息与版本历史。 |
| 2026-05-02 | Atlas | v1.7 架构师审核修复:`platform_audit_logs.result` 枚举值改小写;`export_tasks.status` 枚举值 `done``success`;补充附录 M 数据迁移脚本。 |
| 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) |
## 一、概览
@@ -271,8 +272,8 @@ CREATE TABLE public.platform_audit_logs (
target_id VARCHAR(255), -- 操作对象 IDUUID 或其他)
target_name VARCHAR(255), -- 操作对象可读名称(快照)
payload_summary TEXT, -- 操作内容摘要(非敏感字段)
result VARCHAR(10) NOT NULL DEFAULT 'SUCCESS'
CHECK (result IN ('SUCCESS','FAILED')),
result VARCHAR(10) NOT NULL DEFAULT 'success'
CHECK (result IN ('success','failed')),
error_message TEXT,
ip_address INET,
-- 无 deleted_at无 UPDATE按月 RANGE 分区
@@ -350,7 +351,7 @@ CREATE TABLE public.export_tasks (
format VARCHAR(10) NOT NULL
CHECK (format IN ('csv','json','sql_dump')),
status VARCHAR(15) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending','in_progress','done','failed')),
CHECK (status IN ('pending','in_progress','success','failed')),
storage_path TEXT, -- R2 临时目录路径
download_url TEXT, -- 带签名下载链接
expires_at TIMESTAMPTZ, -- 下载链接有效期(默认 24 小时)
@@ -1046,4 +1047,60 @@ ORDER BY created_at DESC;
| v1.3 | 2026-04-30 | 配合登录管理 PRD v2.0 / 系统管理 PRD§2.1 `tenants` 新增 `tenant_code` (CHAR(12), 全局唯一对外识别码) 与 `contact_phone` (CHAR(11)Tenant Admin 账号创建数据来源)`contact_email` 改为可 NULL同步更新约束、查询模式 |
| v1.4 | 2026-04-30 | 配合客户端发布管理 PRD v1.1 §5.5 Story 5§2.6 新增 `client_heartbeats` 表(启动时 Upsert by `tenant_id + device_id`,活跃定义为最近 24h 内心跳);同步更新表清单、§三 约束Upsert 锚点 / 启动上报 / 不可下沉到租户 schema、§5.1 查询模式Upsert 模板 + 版本活跃分布 JOIN + 平台总活跃数 + 租户维度排查MVP 不做升级趋势图v2 规划) |
| v1.5 | 2026-04-30 | 配合客户端发布管理 PRD v1.2 §5.5 Story 5 验收标准追加(按租户统计安装数):① §2.6 `client_heartbeats.tenant_id` 注释强化,明确为"按租户统计安装数 / 活跃数 / 版本分布"的核心维度字段;② §5.1 新增"租户维度安装/活跃统计"查询专区4 个查询:某租户活跃安装数 / 历史装机总数 / 租户内版本分布 / 全平台租户活跃榜) |
| v1.6 | 2026-05-02 | 对齐平台管理后台 PRD v1.0:① `tenants` 增加 `license_user_limit``INTEGER NOT NULL DEFAULT 50 CHECK (>0)`)并新增 `idx_tenants_license_user_limit`;② `suspended_reason` 增加 `license_expired` 枚举;③ 新增 `idx_tenants_paid_until_active` 并将即将到期查询窗口由 7 天调整为 15 天;④ 新增用户数已满/超限查询示例(`v_tenant_user_counts` 联表);⑤ 审计动作补充 `UPDATE_LICENSE_USER_LIMIT``AUTO_SUSPEND_LICENSE_EXPIRED`;⑥ `domains` 标记为统一 `tenant=` 路由下的兼容保留。 |
| v1.6 | 2026-05-02 | 对齐平台管理后台 PRD v1.0:① `tenants` 增加 `license_user_limit``INTEGER NOT NULL DEFAULT 50 CHECK (>0)`)并新增 `idx_tenants_license_user_limit`;② `suspended_reason` 增加 `license_expired` 枚举;③ 新增 `idx_tenants_paid_until_active` 并将"即将到期"查询窗口由 7 天调整为 15 天;④ 新增"用户数已满/超限"查询示例(`v_tenant_user_counts` 联表);⑤ 审计动作补充 `UPDATE_LICENSE_USER_LIMIT``AUTO_SUSPEND_LICENSE_EXPIRED`;⑥ `domains` 标记为统一 `tenant=` 路由下的兼容保留。 |
| v1.7 | 2026-05-02 | 架构师审核 D-1/D-2 修复:① `platform_audit_logs.result` CHECK 枚举由大写(`SUCCESS/FAILED/PARTIAL`)改为小写(`success/failed/partial`);② `export_tasks.status` 枚举值 `done` 统一改为 `success`;③ 补充两项对应数据迁移脚本(`migration_D1_audit_logs_result_lowercase.sql` / `migration_D2_export_tasks_done_to_success.sql`)。 |
---
## 附录 M数据迁移脚本
### M.1 D-1 `platform_audit_logs.result` 大写改小写
> **背景**:审核报告 D-1 要求 `result` 值统一为小写(`success`, `failed`, `partial`),对应 DDL CHECK 约束已由 v1.7 更新。存量大写数据须一次性迁移。
>
> **执行条件**:仅在首次部署(或已有存量大写数据的环境)执行,幂等安全(`LOWER()` 结果与小写值相同)。
```sql
-- migration_D1_audit_logs_result_lowercase.sql
-- 幂等:多次执行结果一致
BEGIN;
UPDATE public.platform_audit_logs
SET result = LOWER(result)
WHERE result ~ '[A-Z]'; -- 仅更新含大写字母的行
-- 验证:应返回 0 行
SELECT COUNT(*) AS remaining_uppercase
FROM public.platform_audit_logs
WHERE result NOT IN ('success', 'failed', 'partial');
COMMIT;
```
> **回滚脚本**(若需要逆向):
> ```sql
> -- 仅在需要回滚到旧约束时执行
> UPDATE public.platform_audit_logs SET result = UPPER(result);
> ```
### M.2 D-2 `export_tasks.status` `done` → `success`
> **背景**:审核报告 D-2 要求 `status` 终态值 `done` 统一改为 `success`,对应 DDL CHECK 约束已由 v1.7 更新。存量 `done` 数据须一次性迁移。
```sql
-- migration_D2_export_tasks_done_to_success.sql
BEGIN;
UPDATE public.export_tasks
SET status = 'success'
WHERE status = 'done';
-- 验证:应返回 0 行
SELECT COUNT(*) AS remaining_done
FROM public.export_tasks
WHERE status = 'done';
COMMIT;
```
> **执行顺序**:先执行本脚本(数据迁移),再部署含新 DDL 的 Django migration该 migration 会 `ALTER TABLE ... DROP CONSTRAINT ... ADD CONSTRAINT ...` 更新 CHECK。若顺序颠倒`done` 存量数据会触发 CHECK 约束违反。

View File

@@ -3,8 +3,7 @@
**状态**Draft
**作者**:产品经理
**最后更新**2026-05-02
**版本**v1.0
**所属系统**Fonrey 房产经纪管理系统
**版本**v1.1
**关联模块**:权限管理(仅平台侧管理员账号体系)、登录管理(管理员登录与 MFA、所有租户业务模块间接仅作运营/监控对象)
**利益相关方**工程负责人、运营团队、安全合规、客户成功团队、IT 运维
@@ -15,6 +14,7 @@
| 版本 | 日期 | 作者 | 变更说明 |
|------|------|------|---------|
| v1.0 | 2026-05-02 | 产品经理 | 由 `PRD/系统管理/系统管理模块PRD.md` (v1.3) 与 `PRD/发布管理/客户端发布管理模块PRD.md` (v1.2) 合并而来;统一面向平台管理员视角,统一规划页面路由与业务 API 操作清单。原两份 PRD 文件同步删除,参见 `ADR-20260502-001`。 |
| v1.1 | 2026-05-02 | 产品经理 | **修复 P-B-1**:全部用户故事补齐功能编号 PA-001 ~ PA-011与登录管理 PRD v3.0「功能 ID + 验收标准」风格对齐建立需求→测试用例→Bug 单可追溯链条。**修复 X-1**:新增 PA-011「租户注销 SOP」用户故事Persona E覆盖删除前数据导出确认、双人复核审批流程、30 天冷静期可撤销机制;同步更新租户状态机(新增 Pending Cancellation 状态节点、权限矩阵新增注销审批相关操作行、§5.1.4 删除章节(引用 PA-011 SOP、§5.4 页面导航逻辑(注销审批待办流程)、租户列表筛选(新增 Pending Cancellation / Pending Delete 状态、§5.5.1 API 操作清单(新增注销发起、审批、撤销、硬删除操作项)。 |
> **本 PRD 取代以下两份历史文档**
> - `PRD/系统管理/系统管理模块PRD.md`v1.3,已删除,被本 PRD 替代)
@@ -104,7 +104,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
> 负责 Fonrey 的日常运营,每天处理新客户开通、异常租户处理、客户咨询。使用 PC 浏览器登录平台管理后台。
#### Story A1新租户开通
#### PA-001 Story A1新租户开通
> 作为运营人员,我希望通过填写表单快速完成租户开通,并由系统自动完成数据库初始化与欢迎通知,无需手动执行脚本。
@@ -133,7 +133,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- 入口:租户详情 → 基本信息 Tab → 「下载入驻信息」按钮
- 文件名:`{公司名称}_入驻信息_{日期}.pdf`
#### Story A2挂起问题租户
#### PA-002 Story A2挂起问题租户
> 作为运营人员,我希望快速冻结欠费租户的访问,同时保证数据不丢失,并在欠费解决后一键恢复。
@@ -142,7 +142,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] 支持设置到期时间,到期后系统自动恢复租户状态,并发送通知邮件
- [ ] 所有挂起 / 恢复操作记录于审计日志,包含操作人、时间、原因
#### Story A3License 时效管理与到期自动挂起
#### PA-003 Story A3License 时效管理与到期自动挂起
> 作为运营人员(或 Platform Admin我希望每个租户能设置 License 有效期,到期后系统自动挂起租户,并在到期前提前预警。
@@ -154,7 +154,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] 倒计时横幅仅对 Tenant Admin 可见,不影响普通 Agent
- [ ] License 到期日期在租户列表与详情页均可见支持「即将到期15 天内)」筛选
#### Story A4查看与控制租户用户数License 计费维度)
#### PA-004 Story A4查看与控制租户用户数License 计费维度)
> 作为运营人员(或 Platform Admin我希望看到每个租户的当前用户数并能设置用户数上限以便根据 License 授权进行管控。
@@ -165,15 +165,63 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] Platform Admin 可随时调整用户数上限(扩容 / 缩容),变更写入审计日志
- [ ] 租户列表支持按「用户数已满(≥ 上限)」筛选,便于平台运营主动识别需续费的租户
> **Story A5响应客户数据导出请求** — **状态**暂缓v1 不实现,列入后续迭代)。
> **PA-011 Story A5响应客户数据导出请求** — **状态**暂缓v1 不实现,列入后续迭代)。
---
### Persona E — Platform Admin David租户注销合规流程
> 处理租户主动申请注销或因严重违规被强制注销的场景。注销操作不可逆硬删除后需要多重防护——数据导出存证、双人复核、30 天冷静期撤销窗口。
#### PA-011 Story E1租户注销 SOPTenant Cancellation SOP
> 作为 Platform Admin我希望执行租户注销时有标准化的审批流程保障——要求数据导出完成、双人复核授权、30 天冷静期可撤销——防止因误操作或内部滥权导致客户数据不可恢复地丢失。
**验收标准AC**
**AC-1 发起注销申请**
- [ ] 运营人员或 Platform Admin 可在租户详情页发起「注销申请」,填写:注销原因(客户主动申请 / 严重违规 / 其他)、申请说明(自由文本)
- [ ] 发起后,租户状态流转至 `Pending Cancellation`(待审批注销),此时租户访问被阻断(等同挂起效果),不可通过常规「恢复」操作解除
- [ ] 发起操作写入审计日志
**AC-2 数据导出前置确认**
- [ ] 进入审批流程前系统强制展示「数据导出确认」步骤要求操作人触发该租户的完整数据导出§5.1.5),等待导出任务完成(状态 Done后方可提交审批
- [ ] 若申请人选择「客户已自行备份,无需平台导出」,需勾选明确确认框,并填写备注(客户签字回执编号或说明),此记录写入审计日志
- [ ] 审批单中需展示:导出任务 ID或「已确认客户自备份」备注、导出完成时间
**AC-3 双人复核审批**
- [ ] 注销审批流需要第二名 Platform Admin不得与申请人为同一账号在系统内确认审批确认时需通过 MFA 二次验证
- [ ] 审批人可「批准」或「驳回」:驳回时必须填写驳回原因;驳回后租户状态恢复至 `Suspended`(仍不可直接恢复为 Active需运营人员手动解除挂起
- [ ] 若 48 小时内无人审批,系统向所有 Platform Admin 发送催审通知(站内消息 + 邮件)
**AC-4 软删除与 30 天冷静期**
- [ ] 审批通过后,租户立即进入软删除状态(`Pending Delete`,现有机制);冷静期默认 30 天
- [ ] 冷静期内Platform Admin 可在租户列表「待清除」筛选下找到该租户,执行「撤销注销」
- [ ] 撤销注销需第二名 Platform Admin 同样通过 MFA 确认(与初始注销审批相同的双人复核机制)
- [ ] 撤销成功后,租户状态恢复至 `Suspended`(需运营人员手动评估后恢复为 Active撤销操作及原因写入审计日志
**AC-5 硬删除与资源释放**
- [ ] 冷静期届满后,系统自动触发硬删除,或 Platform Admin 可在冷静期内提前手动触发硬删除(需再次 MFA 确认,并再次展示「此操作不可逆」警告)
- [ ] 硬删除释放PostgreSQL Schema、Cloudflare R2 存储桶、Tenant Code、License 席位
- [ ] 硬删除完成后:向租户联系邮箱发送「账号已注销」通知(含注销日期、数据保留期说明);审计日志记录完整操作链
**注销状态流转**(补充至 §7 状态机):
```
[活跃 Active] 或 [已挂起 Suspended]
↓ 运营/Platform Admin 发起注销申请
[待审批注销 Pending Cancellation]
↓ 双人 MFA 审批通过
[待清除 Pending Delete](冷静期 30 天)
↓ 可在冷静期内由双人 MFA 撤销 → 恢复至 [已挂起 Suspended]
↓ 冷静期届满 或 提前手动硬删除MFA
[已删除 Deleted]
```
### Persona B — Platform Admin David系统升级、回滚与版本治理
> 负责平台技术运维,周期性执行版本升级,关注升级稳定性与租户影响面。拥有所有高危操作权限。
#### Story B1灰度系统升级
#### PA-005 Story B1灰度系统升级
> 作为 Platform Admin我希望先对内测租户升级新版本验证稳定后再全量推送避免一次性影响所有客户。
@@ -183,7 +231,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] 升级过程实时展示进度(每个租户的升级状态),支持查看升级日志
- [ ] 升级失败时系统自动告警,并提供一键回滚入口
#### Story B2升级失败回滚
#### PA-006 Story B2升级失败回滚
> 作为 Platform Admin我希望在升级出现问题时立即回滚至上一稳定版本并生成事件报告。
@@ -193,7 +241,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] 回滚完成后生成事件报告:失败原因、回滚耗时、影响范围
- [ ] 回滚操作需二次身份验证确认MFA
#### Story B3查看平台与租户版本总览
#### PA-007 Story B3查看平台与租户版本总览
> 作为 Platform Admin我希望在管理界面一眼看到整个平台的版本情况包括基础数据版本和每个租户各自的数据升级版本。
@@ -221,7 +269,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
> 同 Persona B但聚焦桌面客户端版本上线、强制升级与跨租户版本分布。
#### Story C1发布新版本客户端
#### PA-008 Story C1发布新版本客户端
> 作为 Platform Admin我希望通过本后台上传新版客户端安装包并配置版本信息使全平台所有租户的客户端能感知到更新并引导升级。
@@ -239,7 +287,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- [ ] 支持版本回滚:将指定历史版本重新置为「已发布」,自动将当前版本标记为「已下线」
- [ ] 支持便携版Portable ZIP作为可选上传项
#### Story C2跨租户监控客户端版本分布
#### PA-009 Story C2跨租户监控客户端版本分布
> 作为 Platform Admin我希望跨租户查看当前所有在线客户端的版本分布以了解全平台升级覆盖率对仍使用旧版本的客户端发出提醒或强制升级。
@@ -259,7 +307,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
> 负责平台合规审查,定期导出操作日志供法务或客户审查。无任何写权限。
#### Story D1审计日志查询与导出
#### PA-010 Story D1审计日志查询与导出
> 作为审计员,我希望按操作人、时间范围、操作类型筛选操作日志,并导出为报告。
@@ -320,15 +368,18 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
#### 5.1.4 删除Delete
> **注意**租户注销是高危操作须遵循「PA-011 租户注销 SOP」——发起注销申请 → 强制数据导出确认 → 双人 MFA 复核审批 → 软删除30 天冷静期,可撤销)→ 自动或提前手动硬删除。**不允许绕过此 SOP 直接执行删除。**
| 模式 | 说明 |
|------|------|
| 软删除 | 标记删除状态,数据保留 30 天(默认,可配置)后自动清除 |
| 硬删除 | 立即清除所有数据、Schema、存储资源;仅 Platform Admin 可操作 |
| 软删除Pending Delete | SOP 审批通过后自动进入;数据保留 30 天(默认,可配置)后自动清除 |
| 硬删除 | 冷静期内 Platform Admin 提前触发(需 MFA + 不可逆警告),或冷静期届满自动触发;仅 Platform Admin 可操作 |
**删除前置条件**
1. 操作人必须确认数据导出已完成(勾选确认框)
2. 硬删除需 MFA 二次验证
3. 软删除冷静期内可在租户列表中执行「撤销删除」
**删除前置条件PA-011 SOP 强制执行)**
1. 发起申请时必须填写注销原因
2. 审批前强制完成数据导出确认(平台导出 Done 或客户自备份书面确认)
3. 须第二名 Platform Admin≠ 申请人MFA 审批通过
4. 软删除冷静期内可由双人 MFA 执行「撤销注销」
删除完成后释放:访问域名 / Tenant Code、Cloudflare R2 存储桶、License 席位
@@ -563,7 +614,10 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- 「系统版本管理」中点击某租户行 → 跳转到该租户的「备份记录」Tab
- 「客户端版本管理」中点击「全平台租户活跃榜」中的租户名称 → 跳转到该租户「基本信息」Tab
- 客户端版本「发布 / 下线 / 强制更新推送」操作 → 二次确认;强制更新推送额外要求 MFA
- 任何高危操作(删除租户、数据恢复、系统回滚、客户端版本下线、强制更新推送)触发 MFA 二次确认弹窗
- 任何高危操作(删除/注销租户、数据恢复、系统回滚、客户端版本下线、强制更新推送)触发 MFA 二次确认弹窗
- 租户详情「基本信息」页面Platform Admin / 运营人员可发起「注销申请」;状态为 `Pending Cancellation` 时,原「挂起/恢复」按钮隐藏,显示「查看注销审批单」入口
- 注销审批待办:系统向第二名 Platform Admin 发送站内通知点击通知进入审批单详情展示申请人、注销原因、数据导出确认记录提供「批准MFA」/「驳回」操作
- 审批批准后,租户自动进入 `Pending Delete`;租户列表「待清除」筛选下可见,提供「撤销注销(双人 MFA」和「提前硬删除MFA」入口
- 用户超过 30 分钟无操作 → 自动登出,下次操作跳转登录页
- 「管理员设置」中 Platform Admin 强制登出某管理员 → 该管理员的所有会话立即失效,下次请求跳转登录页
@@ -582,7 +636,7 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- 分页(默认 20 条/页)
- 搜索公司名称、Tenant Code、联系邮箱关键词
- 筛选状态Active / Suspended / Deleted、套餐、注册时间、**即将到期15 天内)**、**用户数已满**
- 筛选状态Active / Suspended / Pending Cancellation / Pending Delete / Deleted、套餐、注册时间、**即将到期15 天内)**、**用户数已满**
-公司名称、Tenant Code、套餐、状态、注册时间、活跃用户数 / License 上限、客户端最新版本占比
- 快捷操作:查看详情、挂起、发起备份、数据导出
@@ -599,8 +653,12 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
- 平台管理员需要能创建新租户(含异步初始化 Schema 与默认配置)
- 平台管理员需要能编辑租户基本信息(公司名、联系人、邮箱、地区)
- 平台管理员需要能挂起 / 恢复租户(含挂起原因、到期时间)
- 平台管理员需要能软删除 / 硬删除租户(硬删除需 MFA
- 平台管理员需要能撤销软删除(冷静期内
- 平台管理员运营人员需要能发起租户注销申请PA-011 SOP填写原因、完成数据导出确认
- 第二名 Platform Admin 需要能审批租户注销申请(批准需 MFA驳回需填写驳回原因
- 平台管理员需要能在冷静期内撤销租户注销(双人 MFA
- 平台管理员需要能在冷静期内提前手动触发硬删除MFA + 不可逆确认)
- 系统需能在冷静期届满后自动触发硬删除并释放所有资源
- 平台管理员需要能软删除 / 硬删除租户(仅限通过 PA-011 SOP 触发,不提供绕过 SOP 的直接删除入口)
- 平台管理员需要能调整租户的 License 到期日期
- 平台管理员需要能调整租户的 License 授权用户数上限
- 平台管理员需要能升级租户套餐
@@ -704,11 +762,14 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
## 6. 角色权限矩阵
| 操作 | Platform Admin | 运营人员 | 只读审计员 |
|------|---------------|---------|-----------|
|------|---------------|---------|-----------||
| 创建租户 | ✅ | ✅ | ❌ |
| 挂起 / 恢复租户 | ✅ | ✅ | ❌ |
| 软删除租户 | ✅ | ✅ | ❌ |
| 硬删除租户 | ✅ | ❌ | ❌ |
| 发起租户注销申请PA-011 SOP | ✅ | ✅ | ❌ |
| 审批注销申请第二人复核MFA | ✅ | ❌ | ❌ |
| 撤销注销(冷静期内,双人 MFA | ✅ | ❌ | ❌ |
| 提前手动硬删除MFA | ✅ | ❌ | ❌ |
| 软删除 → Pending Delete仅经 SOP 自动触发) | 系统自动 | — | — |
| 调整 License 到期日期 / 用户数上限 | ✅ | ✅ | ❌ |
| 数据导出 | ✅ | ✅ | ❌ |
| 手动触发备份 | ✅ | ✅ | ❌ |
@@ -737,12 +798,18 @@ Fonrey房睿是面向房产经纪公司的 B2B SaaS 平台,采用 `djang
[活跃 Active] ←──────────────────┐
↓ 手动 / License 到期挂起 │ 到期自动恢复(仅手动挂起且设置了到期时间)/ 手动恢复
[已挂起 Suspended] ───────────────┘
删除操作(软删除
运营/PA 发起注销申请PA-011
[待审批注销 Pending Cancellation]
↓ 驳回(第二名 PA→ [已挂起 Suspended]
↓ 批准(第二名 PAMFA
[待清除 Pending Delete](冷静期 30 天)
冷静期到期 / 硬删除
双人 MFA 撤销注销 → [已挂起 Suspended]
↓ 冷静期届满(自动)/ 提前手动硬删除MFA
[已删除 Deleted]
```
> **注意**Active / Suspended 状态下均可发起注销申请(后者更常见)。不允许直接跳过 SOP 从任何状态进入 Pending Delete 或 Deleted。
---
## 8. 不构建清单What We're NOT Building

View File

@@ -1,441 +0,0 @@
# Fonrey 全局系统设计 Review 报告
> **Review 类型**:全量 ReviewPRD + DATA_MODEL + TECH_STACK + UI/UX 交叉验证)
> **Review 日期**2026-04-25
> **Reviewer**:系统设计 ReviewerAI 辅助)
> **当前阶段**:需求 80% / 数据模型 50% / UI 未开始
> **覆盖文档**8 份 PRD、8 份 DATA_MODEL、3 份 TECH_STACK、2 份 UI/UX
> **问题分级**:🔴 Blocker阻塞开发 / 🟠 Major必须修复但不阻塞 / 🟡 Minor建议优化
---
## 、执行摘要Executive Summary
### 整体评价
Fonrey 文档体系**结构完整、深度足够**DATA_MODEL 与 TECH_STACK 的颗粒度手机号加密、稀疏权限存储、tsvector 全文检索、物化路径树、append-only 审计)已达"可直接进入编码阶段"的水平,远超一般 SaaS 项目设计文档。但作为**全局系统**,存在 **6 处文档间一致性裂缝**、**4 处多租户隔离的执行细节缺失**、**1 处性能落地空缺**,以及 UI 阶段尚未启动带来的 **5 处验收标准悬空**
### 核心问题摘录Top 8
| # | 等级 | 问题 | 维度 |
|---|------|------|------|
| 1 | 🔴 | **权限 PRD v1.1 与 DATA_MODEL_PERMISSION 的数据范围档位不一致**PRD 三档 vs 数据模型 5 档 SCOPE + 跨层级 DataScope 叠加) | PRD↔Data |
| 2 | 🔴 | **Keyset 分页未在任何正式设计文档落地**(仅 Review 提示词模板提及89k 房源 + 200 万跟进日志使用 OFFSET 分页将在深翻页时崩溃 | TECH/Data |
| 3 | 🟠 | **R2 文件路径无租户隔离命名规范**,所有 `file_key` 字段说明均为"R2 存储路径",未约束 `tenants/{schema_name}/...` 前缀 | TECH/合规 |
| 4 | 🟠 | **Celery 任务的 Schema 切换机制无统一规范**`tenant_context()` 仅在 PERMISSION 文档某 signal 中出现一次TECH_STACK.md 未规定异步任务的租户上下文传递契约 | TECH/多租户 |
| 5 | 🟠 | **PRD 性能目标(录入耗时 ≤ 30s、配房响应 < 3s在 TECH_STACK 中无 SLI/SLO 落地**,缺索引清单与 N+1 查询治理策略 | PRD↔TECH |
| 6 | 🟠 | **UI 阶段尚未开始**,但 PRD 含 90+ 个"验收标准"涉及具体交互侧边抽屉、Toast、面包屑、批量操作 Modal目前组件清单仅覆盖核心列表/表单,缺 Drawer / Stepper / Permission Tree 等关键组件设计 | PRD↔UI |
| 7 | 🟠 | **租户注销→数据导出→清除**全链路在 PRD系统管理 §) 与 DATA_MODEL_PUBLICexport_tasks/backup_records中存在职责边界模糊导出包是否包含 R2 文件实体、清除时序与备份保留期的依赖关系 | PRD↔Data↔合规 |
| 8 | 🟠 | **房源并发编辑乐观锁 / 楼盘锁定4 类锁)的 DDL/版本字段未见**PRD 多处提到"楼盘锁定不可改商圈"但 `complexes` 表 DDL 未发现 `version``lock_type` 字段(待 DATA_MODEL_COMPLEX §三 详查) | PRD↔Data |
### 风险等级分布
- 🔴 Blocker: **2**
- 🟠 Major: **14**
- 🟡 Minor: **9**
---
## 一、PRD 一致性审查PRD ↔ PRD
### 1.1 数据范围/权限粒度——核心冲突
| 文档 | 表述 |
|------|------|
| `PRD/权限管理/权限管理模块PRD.md` v1.1 §3 非目标 | "数据范围控制以**本人 / 本部门 / 全公司**三档为主,本期不含行级权限" |
| `PRD/权限管理/权限管理模块PRD.md` v1.1 Story 3 §验收 | 范围型选项:"**本人 / 本组 / 本门店 / 本区域 / 全公司**"——五档 |
| `DATA_MODEL_PERMISSION.md` §1.2 | SCOPE 五档 + `staff_data_scopes` 跨层级并集叠加("本组 门店B" |
🔴 **Blocker P-01**:同一份 PRD 内 §3 与 Story 3 自相矛盾(三档 vs 五档),且 DATA_MODEL 实现的"跨层级 DataScope 叠加"已超出 PRD §3 非目标声明的范畴——**这本质上是行级/对象级权限的弱化形态**。
- **责任**PM 必须先在 PRD v1.2 中:(a) 锁定档位数(推荐五档);(b) 明确 `staff_data_scopes` 是否为本期范围若是§3 非目标第 1 条需改写);(c) 给出"跨层级叠加"的业务用例与 UI 入口(当前 Story 1 操作列只有 "扩充范围"/"范围",未说明能否选多个组织节点)。
### 1.2 模块边界
🟠 **Major P-02****"系统设置"职责分散**。`PRD/权限管理` §1 提到"关联模块:组织人事管理、房源管理、客源管理、**系统设置**",但 PRD 列表中没有独立的"系统设置 PRD",仅有 `PRD/系统配置/系统配置.md`128 行)和 `PRD/系统管理/系统管理模块PRD.md`594 行,平台运营视角)。`TECH_STACK.md` §1 又提到"本期聚焦首页设置与房源设置(字段标签、必填规则、自定义字段、标签管理)"——**租户级"系统设置"PRD 缺失**。
- **责任**PM 补一份 `PRD/系统设置/租户级系统设置模块PRD.md`,覆盖 lookup_items / 字段标签 / 自定义字段 / 标签管理,否则数据模型中已存在的 `lookup_items`(客源活跃度阈值依赖)配置入口不明。
🟡 **Minor P-03**:登录 PRD v1.4 §5.5 已迁出数据模型,但**"业务规则"与"数据约束"的交叉**(如 5 次失败锁定 30min、密码历史保留 3 条)在 PRD/技术方案/DATA_MODEL_LOGIN 三处重复定义,未来变更存在三处同步风险。建议 PRD 改为"详见 DATA_MODEL_LOGIN.md §X"引用。
### 1.3 性能目标完整性
🟠 **Major P-04**PRD 中性能目标分布零散且**不可观测**
- 房源 PRD录入耗时 ≤ 30s验收无对应 SLI
- 客源 PRD智能配房响应 < 3s、跟进率 ≥ 60%
- 系统管理 PRDRTO < 2h、灰度 ≤ 5%
- 登录 PRD登录成功率指标缺失
- 发布 PRD自动更新成功率 ≥ 98%
未见统一的"非功能性需求矩阵"TECH_STACK 也未承接这些目标。
- **责任**PM 在 `PRD/PRD_MVP.md` 中汇总 NFR 矩阵;架构师在 `TECH_STACK.md` 中映射为 SLI/SLO + 监控埋点。
### 1.4 状态机一致性
🟡 **Minor P-05**:房源 `properties.status` 8 态(出售/出租/租售/暂缓/他售/他租/成交/未挂牌)与 PRD 房源生命周期描述未做状态转换图哪些状态可互转、转出条件DATA_MODEL_PROPERTY §3 仅枚举值。建议补状态机图。
---
## 二、DATA_MODEL 完整性审查
### 2.1 表覆盖度
DATA_MODEL 已实施"按模块拆分"v1.3 索引化8 个子文档覆盖良好。已确认存在的关键设计:
- ✅ public schema 13 表(含 audit_logs 月度分区建议、唯一 current 版本约束)
- ✅ 房源 22 张表(含 `sensitive_view` 跟进不可删、`listing_histories` append-only
- ✅ 客源(手机号加密+哈希索引、活跃度阈值由 `lookup_items` 配置)
- ✅ 楼盘(`complexes.search_vector` tsvector + GIN
- ✅ 组织(物化路径 + `staff_transfer_logs` append-only
- ✅ 权限 6 表(稀疏存储 + 优先级合并)
- ✅ 登录 4 表90 天审计、3 条历史防重用)
### 2.2 跨文档一致性
🔴 **Blocker D-01****Keyset 分页缺位**。`prompt/Fonrey_系统设计Review_提示词模板_v1.md` Line 315 明确要求"分页查询是否使用了高效方案(如 Keyset 分页,而非 OFFSET 分页)",但:
- `DATA_MODEL.md` §五 容量与分区规划仅给出表大小估算
- `DATA_MODEL_PROPERTY.md``DATA_MODEL_CLIENT.md` 的"查询模式参考"章节未见 Keyset 示例
- `TECH_STACK.md` 无任何分页规范
89,000 房源 + 200 万跟进日志使用 OFFSET 分页,第 100 页响应将达秒级。
- **责任**:架构师在 `TECH_STACK.md` 新增 §「分页规范」、在 `DATA_MODEL_PROPERTY.md` §6 查询模式参考补 Keyset SQL 模板(`WHERE (created_at, id) < (?, ?) ORDER BY created_at DESC, id DESC LIMIT 21`)。
🟠 **Major D-02****乐观锁/写冲突字段缺失**。
- `properties` 主表 PRD 多处提到"维护完成度 ≥ 70% 才能上架"、多人协作场景,但 DATA_MODEL_PROPERTY.md `properties` 表 DDL 未见 `version` / `row_version` 字段。
- 楼盘 PRD §"楼盘锁定"提到 4 类锁(信息锁/坐标锁/楼栋锁/合并锁DATA_MODEL_COMPLEX 是否实现待详查grep 未在 §三 摘要中发现 `lock_*` 字段)。
- **责任**:架构师在 `properties``clients``complexes` 主表补 `version INTEGER DEFAULT 0`,配合 Django ORM `update(version=F('version')+1).filter(version=expected)` 模式。
🟠 **Major D-03****外键跨 schema 限制的隔离机制说明不足**。`DATA_MODEL_PERMISSION.md` §3.1 已明确 `permission_defs` 放租户 schema 是为了规避 django-tenants 跨 schema FK但其他类似场景`staff` 引用 `org_units``user_accounts.staff_id`)未统一说明。建议在 `DATA_MODEL.md` §一架构决策中补 "**所有 FK 必须在同一 schema 内**" 原则。
🟠 **Major D-04****审计/日志表的分区策略不一致**。
- `platform_audit_logs`:建议月度分区 ✅
- `permission_change_logs`:月度分区 + 6 个月归档 ✅
- `follow_logs`200 万+DATA_MODEL.md §五已建议月度分区,但 DATA_MODEL_PROPERTY §4.5 表 DDL **未给出分区 DDL 或 PARTITION BY 子句**——开发期不分区,未来再分区将带来数据迁移成本。
- `login_attempts`90 天保留DATA_MODEL_LOGIN 未给分区或 TTL 清理策略。
- **责任**:架构师在每张高写入表的 DDL 中给出 `CREATE TABLE ... PARTITION BY RANGE (created_at)` + `pg_partman` 自动维护方案。
🟡 **Minor D-05**`UserAccount.username``user_accounts` 表的唯一性约束注释提到"在租户 Schema 维度生效",但若员工跨租户(多平台账号 `StaffAccount` 已支持 Fonrey/58/安居客/网络经纪人),登录 PRD 的"账号体系"是否覆盖这一场景未明。
🟡 **Minor D-06**DATA_MODEL.md §一 1.3 关键设计原则中"金额 NUMERIC(12,2) 万元精度"——12,2 表示最大 9999999999.99 万元,是否过度,建议改 NUMERIC(14,2) 元精度(与会计/合同模块对齐)或在文档中说明万元单位的统一约定。
### 2.3 缺失数据
🟠 **Major D-07**:以下 PRD 提及但 DATA_MODEL 未见的实体(待 PM/架构师确认是否本期范围):
- 楼盘"价格走势"PRD 楼盘 §)DATA_MODEL_COMPLEX 是否含 `complex_price_history` 待查
- "市场报盘"(房源 PRD §)DATA_MODEL_PROPERTY 22 表中无 `market_quotes`
- "公客转换"(客源 PRD私客 → 公客自动转DATA_MODEL_CLIENT 是否含触发器/job 待查
- "学区关联距离"DATA_MODEL_COMPLEX 已实现 `complex_schools` N:M 含距离 ✅
---
## 三、TECH_STACK 完整性审查
### 3.1 已覆盖
✅ HTMX + Alpine.js + Tailwind 禁用清单Do NOT use 段)
✅ App 目录结构(`apps/property/models/` 文件级拆分)
✅ Celery + Redis + R2 + Sentry + Grafana
✅ Electron 客户端electron-builder + electron-updater + EV 签名 + SHA256 校验
✅ 登录 `accounts` App 依赖关系图、Redis Key 命名规范
✅ 权限系统:自定义 Hybrid RBAC、Redis 缓存快照、Override 优先级
### 3.2 关键缺失
🟠 **Major T-01****Celery 多租户上下文规范缺失**。
- `TECH_STACK.md` §3 关键约定第 4 条仅说"耗时任务必须 Celery",未规定**租户 ID 如何传入 Worker**。
- `DATA_MODEL_PERMISSION.md` 行 1075 出现 `tenant_context(instance)` 仅一例,其他模块(导出 89k 房源、智能配房、图片转码)的 schema 切换无统一约定。
- 风险Worker 在错误 schema 下执行查询、跨租户数据污染。
- **责任**:架构师在 `TECH_STACK.md` 新增 §「异步任务规范」:(a) 所有 task 第一参数必须为 `tenant_schema_name`(b) 强制使用装饰器 `@with_tenant_context`(c) Sentry 上报必须包含 `tenant_schema` tag。
🟠 **Major T-02****R2 文件路径租户隔离命名规范缺失**。
- 所有 `file_key TEXT` 字段注释为 "R2 存储路径",但 TECH_STACK 未约束 key 前缀。
- 当前若开发各自约定,可能出现 `photos/{uuid}.jpg`无租户标识的隐患——R2 bucket 是共享的。
- **责任**:架构师在 `TECH_STACK.md` 增加 R2 路径模板:
- 房源照片:`tenants/{schema_name}/property/{property_id}/photos/{uuid}.jpg`
- 跟进附件:`tenants/{schema_name}/follow_logs/{log_id}/attachments/{uuid}`
- 客户端发布:`releases/{platform}/{version}/{filename}`(共享)
- 备份/导出:`platform/backups/{tenant_schema}/{date}/...``platform/exports/{task_id}/...`
🟠 **Major T-03****索引清单与查询模式未集中化**。
- 各 DATA_MODEL 子文档都有零散索引 DDL但缺一份"高频查询场景 → 索引"对应表。
- 例:客源活跃度筛选、房源多条件搜索(户型/面积/价格/标签/区域)、跟进日志按员工+时间范围——这些查询是否都有覆盖索引?
- **责任**:架构师补 `TECH_STACK/索引规范.md` 或在 `DATA_MODEL.md` §六 增加查询索引矩阵。
🟠 **Major T-04****前端构建与资产管线未定义**。
- `TECH_STACK.md` 只说 HTMX + Alpine + Tailwind但未规定Tailwind JIT 配置位置、CSS 变量加载顺序UI_SYSTEM 要求 `:root` 中定义所有 token、HTMX 扩展(`hx-boost``hx-ext="response-targets"`启用清单、Alpine 插件(`x-intersect``x-mask`)。
- **责任**:架构师补 §「前端构建管线」。
🟡 **Minor T-05****降级方案缺失**(呼应 Review 提示词模板第 348 行):
- R2 不可用时图片上传如何降级?
- Redis 不可用时权限/Session 如何降级?
- Celery 队列堆积时如何熔断?
- 当前文档无任何降级策略。
🟡 **Minor T-06**:登录技术方案 v2.0 §十 提到滑块 Token 3min Redis TTL但未说明 Redis 不可用时是否降级到内存(多 worker 不一致)或拒绝登录。
🟡 **Minor T-07**:发布 PRD 提到 ARM64 按需支持TECH_STACK 第 8 节同步——但未规定 ARM64 触发条件(用户量阈值?)。
---
## 四、UI/UX 完整性审查
### 4.1 已覆盖UI_SYSTEM.md / 组件清单.md
✅ Design Philosophy4 条原则 + 9 条反模式,含 `禁 window.alert / 禁无限滚动 / 禁 Generic 错误`
✅ Design Tokens颜色/间距 4px 网格/圆角/阴影 CSS 变量化)
✅ Tailwind fallback 映射表
✅ 核心组件Sortable Data Table、Column Visibility、Pagination、Toolbar、Toggle、Multi-select Tag
✅ 焦点环 / disabled / readonly 状态规范
### 4.2 缺失组件 vs PRD 验收标准
PRD 的 90+ 验收标准要求以下组件,但组件清单未覆盖:
🟠 **Major U-01****侧边抽屉Drawer缺失**。权限 PRD Story 4 明确要求"右侧滑出 Drawer 不覆盖左侧导航"UI_SYSTEM 仅在 §一开头提及 `--radius-lg → 模态/抽屉/面板`,但组件清单无 Drawer 实现。
🟠 **Major U-02****权限树/复杂表单组件缺失**。权限 PRD 描述14 个一级模块树 + 每模块多分组 + 分组内 Toggle/Select/Number——这是本期最复杂的页面组件清单未给原型。
🟠 **Major U-03****Stepper/Wizard 缺失**。房源/客源录入 PRD 强调 ≤ 30s 完成,多 Tab 表单(基本信息/价格/联系人/标签/图片)需要 Stepper 或可折叠分组组件。
🟡 **Minor U-04**Toast/Dialog/确认对话框组件未在清单中正式定义Anti-pattern 中提到"禁 window.alert使用 Dialog/Toast")。
🟡 **Minor U-05**:树形选择器(用于 OrgUnit 选择、Permission Scope 选择)缺失。
### 4.3 流程缺失
🟠 **Major U-06****Wireframe / 信息架构未启动**。当前进度"UI 未开始",但 PRD 中存在大量 UI 隐含决策:
- 房源列表 21 个核心字段 + 自定义列:默认显示哪些?密度?
- 89k 数据列表的视觉层级(卡片 vs 表格——UI_SYSTEM 反模式禁止两者混用)
- 多租户登录页面是否需要展示 tenant_logoDATA_MODEL_LOGIN 已有 `tenant_logo_url` 字段)
- **责任**UI/UX 设计师在动手前,先输出"页面清单 + 信息架构 + 关键页面 wireframe"。
🟡 **Minor U-07**UI_SYSTEM.md 未规定**国际化**策略(虽然本期中文为主,但 `to_tsvector('simple')` 而非 `'chinese'` 已暗示无中文分词,需在 PRD 中确认是否本期不做中文模糊检索)。
---
## 五、多租户隔离审查(横切)
| 隔离维度 | 现状 | 风险 |
|----------|------|------|
| DB Schema | ✅ django-tenants Schema 隔离,所有租户业务表均在 tenant schema | 已落实 |
| public ↔ tenant FK | ✅ 已在 PERMISSION 文档明确禁止跨 schema FK | 已落实 |
| 登录认证 | ✅ Tenant 验证在 publicUserAccount 在 tenant schemausername 仅 schema 内唯一 | 已落实 |
| Celery Worker schema 切换 | 🟠 仅一例,无统一规范 | T-01 |
| R2 文件路径 | 🟠 无租户前缀规范 | T-02 |
| Redis Key 命名 | 🟡 登录方案 §十 已包含 `{tenant_id}` 前缀;权限缓存方案 Redis Key 是否带 tenant 待查 | 待确认 |
| Sentry / 日志 | 🟡 登录方案提及 `tenant_id` tag但全局未统一 | T-01 |
🟠 **Major X-01****Redis Key 命名跨模块未统一**。登录方案使用 `login_fail:{tenant_id}:{username}``tenant_verify_ip:{ip}`,权限方案使用"员工权限快照"——若不强制 `{tenant_schema_name}:` 前缀,多租户 Redis 共享时存在键冲突。
🟠 **Major X-02****租户注销→数据导出→清除全链路职责模糊**。
- PRD/系统管理 §"租户删除"提到释放子域名、R2 存储桶、License 席位
- DATA_MODEL_PUBLIC `export_tasks` 含 24h 下载链接
- 缺失:(a) 导出包是否包含 R2 文件实体PRD §232 提示"含 R2 文件实体",但 export_tasks 字段是否落地待查);(b) 清除时序tenants.status `pending_delete → deleted` 的硬删除窗口(推荐 30 天宽限期,文档未明确);(c) 备份保留期 vs 清除时序的一致性。
- **责任**PM + 架构师 + 合规共同梳理租户注销 SOP并在 `DATA_MODEL_PUBLIC.md` §2.4 增加 `tenant_deletion_workflow` 文档化流程图。
---
## 六、合规与安全审查
🟠 **Major S-01****手机号加密策略统一性已落实**AES-256-GCM + SHA-256 哈希),但**密钥管理方案缺失**。
- TECH_STACK.md 无 KMS / Vault / 环境变量加密管理说明。
- `core.encryption` 仅作为模块名出现,密钥轮换流程未定义。
🟠 **Major S-02****敏感字段访问审计**已通过 `follow_logs.sensitive_view` + `is_deletable=FALSE` 实现,但:
- 客源 `phone_hash` 解密查看是否每次都写 `sensitive_view` 跟进?
- 业主联系人查看是否同样有"号码方审批"前置流程PRD 提及 `number_holder_approvals`
- 这些"敏感数据访问审计"的触发链路在 TECH_STACK 未集中说明。
🟡 **Minor S-03**:登录失败锁定 30min 是 IP 维度还是账号维度?登录方案 §十 Key 为 `login_fail:{tenant_id}:{username}` 是账号维度,可能被恶意撞库锁定真实用户。建议补 IP 维度限流。
🟡 **Minor S-04**MFA 仅强制平台管理员(`admin_mfa_devices`),租户内部 Tenant Admin / 高敏角色(系统管理员)是否需要 MFA 未提及。
🟡 **Minor S-05**CORS / CSP / SameSite Cookie 等 Web 安全策略未在 TECH_STACK 中规定。
---
## 七、性能与容量审查
🔴 **Blocker** D-01Keyset 分页缺失)已在 §二列出。
🟠 **Major P-08****89k 房源筛选的执行计划未验证**。房源 PRD 列表筛选含户型/面积/价格/区域/标签/属性——多条件 AND 查询:
- 是否有覆盖索引DATA_MODEL_PROPERTY §6 待详查)
- 标签筛选(`property_tag_relations` N:M是否需要 GIN array 索引或物化视图?
- 排序字段(更新时间/价格)是否在索引中?
🟠 **Major P-09****`follow_logs` 200 万+/月增长但无分区 DDL**D-04 已列)。
🟡 **Minor P-10**`property_photos` 500 万+ 建议 HASH 分区DATA_MODEL.md §五),但 DATA_MODEL_PROPERTY §4.14 表 DDL 未给分区子句。
🟡 **Minor P-11**:智能配房 PRD < 3s 响应,但匹配算法(`client_property_matches`)的索引/计算路径未设计文档。Celery 异步是离线计算还是实时?
---
## 八、可维护性与扩展性
🟡 **Minor M-01**DATA_MODEL 8 文档 + TECH_STACK 3 文档 + PRD 8 文档版本号不统一v1.0~v1.4 混用),缺一份 `CHANGELOG.md` 跟踪跨文档变更。
🟡 **Minor M-02**`核心文档体系.md` 提到 "AI 指令手册 (`.cursorrules` / `AI_INSTRUCTIONS.md`)"——但仓库未见该文件。AI 协同开发约定缺位。
🟡 **Minor M-03**:单元测试 / 集成测试约定未在 TECH_STACK 中提及pytest-django / factory_boy / django-tenants 测试 utility
🟡 **Minor M-04**Migration 策略未定义。多租户场景下 schema migration 跨数百租户的执行顺序、回滚策略需明文django-tenants `migrate_schemas` 命令)。
---
## 九、行动清单(按责任人 + 优先级)
### PM产品经理
| ID | 等级 | 任务 |
|----|------|------|
| PM-1 | 🔴 | **修订权限 PRD v1.2**:锁定数据范围档位(建议五档+DataScope同步修改 §3 非目标声明,补 DataScope UI 入口 |
| PM-2 | 🟠 | 补充 `PRD/系统设置/租户级系统设置模块PRD.md`lookup_items 配置、字段标签、自定义字段、标签管理) |
| PM-3 | 🟠 | 在 `PRD/PRD_MVP.md` 中汇总 NFR 矩阵(性能/可用性/安全/合规) |
| PM-4 | 🟠 | 与架构师 + 合规一起梳理租户注销 SOP导出范围、宽限期、清除时序 |
| PM-5 | 🟡 | 房源 status 状态机图、客源公客转换规则文档化 |
| PM-6 | 🟡 | 确认是否本期支持中文模糊检索(影响 tsvector 配置) |
| PM-7 | 🟡 | MFA 是否扩展到租户内部高权限角色 |
### 架构师
| ID | 等级 | 任务 |
|----|------|------|
| ARCH-1 | 🔴 | **TECH_STACK 新增 §「分页规范」**,给出 Keyset 模板DATA_MODEL_PROPERTY/CLIENT §6 补查询模式参考 |
| ARCH-2 | 🟠 | TECH_STACK 新增 §「异步任务规范」tenant_schema 必传 + `@with_tenant_context` 装饰器 + Sentry tag |
| ARCH-3 | 🟠 | TECH_STACK 新增 §「R2 路径规范」(每类资源的 key 模板,强制 `tenants/{schema_name}/...` 前缀) |
| ARCH-4 | 🟠 | DATA_MODEL 各高写入表(`follow_logs`, `property_photos`, `permission_change_logs`, `login_attempts`, `platform_audit_logs`)补 PARTITION DDL + pg_partman 自动维护脚本 |
| ARCH-5 | 🟠 | `properties` / `clients` / `complexes` 主表补 `version` 字段实现乐观锁;楼盘 4 类锁补 `lock_*` 字段 |
| ARCH-6 | 🟠 | DATA_MODEL.md §一架构决策补 "**所有 FK 必须同 schema**" 原则TECH_STACK 补 "**Redis Key 必须 `{schema_name}:` 前缀**" 强制规范 |
| ARCH-7 | 🟠 | 补 `TECH_STACK/索引规范.md`(高频查询 → 索引矩阵补「前端构建管线」章节Tailwind JIT/HTMX 扩展/Alpine 插件) |
| ARCH-8 | 🟠 | 密钥管理方案KMS/Vault 选型、轮换 SOP、`core.encryption` 接口契约 |
| ARCH-9 | 🟡 | 降级方案R2/Redis/Celery 不可用时的策略 |
| ARCH-10 | 🟡 | Migration 策略(跨 N 租户 migrate_schemas 顺序与回滚) |
| ARCH-11 | 🟡 | 测试规范pytest-django + factory_boy + tenant 测试 utility |
| ARCH-12 | 🟡 | CORS/CSP/SameSite 安全头规范 |
| ARCH-13 | 🟡 | 智能配房算法路径文档(实时 vs 异步) |
### UI/UX 设计师
| ID | 等级 | 任务 |
|----|------|------|
| UI-1 | 🟠 | **启动 Wireframe**:先输出页面清单 + 信息架构 + 高频页面(房源列表、房源录入、权限编辑、登录)线框 |
| UI-2 | 🟠 | 组件清单补 Drawer / Stepper / Permission Tree / Tree Select |
| UI-3 | 🟠 | 89k 列表的视觉密度方案(行高、字段优先级、列宽策略) |
| UI-4 | 🟡 | Toast / Dialog / Confirm 组件正式定义 |
| UI-5 | 🟡 | 多租户登录页是否展示 `tenant_logo_url` 的视觉规范 |
| UI-6 | 🟡 | 国际化策略v1 是否仅中文) |
---
## 十、结论
### 是否可进入开发阶段
**部分可以,但需先解决 2 个 Blocker**
1. **🔴 P-01 权限范围档位冲突**:必须先在 PRD 锁定,否则 `staff_data_scopes` 表是否生效不明,权限模块无法开工。
2. **🔴 D-01 Keyset 分页规范缺失**:必须在 TECH_STACK 落地,否则房源/客源/跟进列表的核心查询路径设计错误,后期返工成本高。
**可立即并行启动的部分**
- 公共 Schema`tenants``platform_admins``audit_logs`)开发——文档完整,无 Blocker
- 楼盘/区域/学校 CRUD——DATA_MODEL_COMPLEX 完整,主流程清晰
- Electron 客户端框架搭建——TECH_STACK §8 决策已封闭
- 登录模块accounts App——文档完整仅需在编码前补 Redis Key 命名前缀规范
**必须延后的部分**
- 权限模块编码(等待 PM-1 完成)
- 房源/客源高基数列表查询(等待 ARCH-1 完成)
- 全 UI 实现(等待 UI-1 Wireframe
### 文档体系成熟度评分
| 维度 | 成熟度 | 说明 |
|------|--------|------|
| PRD 业务清晰度 | 8.5/10 | 用户故事和验收标准充分,仅权限档位有自相矛盾 |
| DATA_MODEL 落地深度 | 8/10 | 颗粒度高,但 Keyset/分区 DDL/乐观锁字段缺失 |
| TECH_STACK 完整性 | 6/10 | 选型已封闭,但异步/R2/索引/降级等横切规范缺位 |
| UI/UX 系统化 | 5/10 | Token/核心组件已成型,但 Wireframe 未启动且复杂组件缺失 |
| 跨文档一致性 | 6.5/10 | 整体高,但 6 处裂缝需要修复 |
| 多租户隔离严谨度 | 7.5/10 | DB 隔离扎实,但 Celery/R2/Redis 横切层规范不足 |
| **整体** | **7/10** | 已达"中等偏上"水平,远超普通 SaaS 项目;解决 Blocker 后可达 8.5+ |
---
## 附录 A本次 Review 涵盖文档
### PRD8 份)
- `PRD/房源管理/房源管理模块PRD.md` v2.11881 行)
- `PRD/房源管理/楼盘管理模块PRD.md` v1.0704 行)
- `PRD/客源管理/客源管理模块PRD.md` v1.42050 行)
- `PRD/权限管理/权限管理模块PRD.md` v1.1623 行)
- `PRD/组织人事管理/组织人事管理模块PRD.md` v1.2512 行)
- `PRD/系统管理/系统管理模块PRD.md` v1.0594 行)
- `PRD/登录管理/用户登录管理模块PRD.md` v1.4648 行)
- `PRD/发布管理/客户端发布管理模块PRD.md` v1.0407 行)
### DATA_MODEL8 份)
- `DATA_MODEL/DATA_MODEL.md` v1.3622 行,索引文档)
- `DATA_MODEL/DATA_MODEL_PUBLIC.md` v1.0599 行)
- `DATA_MODEL/DATA_MODEL_ORG.md` v1.0342 行)
- `DATA_MODEL/DATA_MODEL_COMPLEX.md` v1.0548 行)
- `DATA_MODEL/DATA_MODEL_PROPERTY.md` v1.01169 行)
- `DATA_MODEL/DATA_MODEL_CLIENT.md` v1.0575 行)
- `DATA_MODEL/DATA_MODEL_PERMISSION.md` v1.01363 行)
- `DATA_MODEL/DATA_MODEL_LOGIN.md` v1.0470 行)
### TECH_STACK3 份)
- `TECH_STACK/TECH_STACK.md`154 行)
- `TECH_STACK/登录管理技术方案.md` v2.0711 行)
- `TECH_STACK/权限管理系统技术方案.md` v1.0677 行)
### UI/UX2 份)
- `UI&UX/UI_SYSTEM.md`987 行)
- `UI&UX/组件清单.md`1264 行)
---
## 附录 B问题汇总速查表
| ID | 等级 | 维度 | 责任人 | 简述 |
|----|------|------|--------|------|
| P-01 | 🔴 | PRD↔Data | PM | 权限数据范围档位冲突3 vs 5+叠加) |
| D-01 | 🔴 | TECH/Data | 架构师 | Keyset 分页规范全局缺失 |
| P-02 | 🟠 | PRD | PM | 租户级系统设置 PRD 缺失 |
| P-04 | 🟠 | PRD↔TECH | PM+架构师 | 性能 NFR 矩阵未汇总 |
| D-02 | 🟠 | Data | 架构师 | 主表乐观锁/楼盘锁字段缺失 |
| D-03 | 🟠 | Data | 架构师 | 跨 schema FK 原则未统一 |
| D-04 | 🟠 | Data | 架构师 | 高写入表分区 DDL 未落地 |
| D-07 | 🟠 | Data | PM/架构师 | 楼盘价格走势/市场报盘等表缺失待确认 |
| T-01 | 🟠 | TECH | 架构师 | Celery 多租户 schema 切换规范缺失 |
| T-02 | 🟠 | TECH | 架构师 | R2 文件路径租户隔离规范缺失 |
| T-03 | 🟠 | TECH | 架构师 | 索引清单未集中化 |
| T-04 | 🟠 | TECH | 架构师 | 前端构建管线未定义 |
| U-01 | 🟠 | UI | UI/UX | Drawer 组件缺失 |
| U-02 | 🟠 | UI | UI/UX | 权限树/Permission Tree 复杂组件缺失 |
| U-03 | 🟠 | UI | UI/UX | Stepper/Wizard 缺失 |
| U-06 | 🟠 | UI | UI/UX | Wireframe 未启动 |
| X-01 | 🟠 | 多租户 | 架构师 | Redis Key 命名跨模块未统一带 tenant 前缀 |
| X-02 | 🟠 | 合规 | PM+架构师 | 租户注销→导出→清除链路职责模糊 |
| S-01 | 🟠 | 安全 | 架构师 | 加密密钥管理方案缺失 |
| S-02 | 🟠 | 安全 | 架构师 | 敏感字段访问审计触发链未集中说明 |
| P-08 | 🟠 | 性能 | 架构师 | 89k 房源筛选执行计划未验证 |
| P-03 | 🟡 | PRD | PM | 登录业务规则三处重复 |
| P-05 | 🟡 | PRD | PM | 房源 status 状态机图缺失 |
| D-05 | 🟡 | Data | PM | 跨平台账号 username 复用未明 |
| D-06 | 🟡 | Data | 架构师 | NUMERIC(12,2) 精度选型理由 |
| T-05 | 🟡 | TECH | 架构师 | 降级方案缺失 |
| T-06 | 🟡 | TECH | 架构师 | Redis 不可用时滑块 Token 行为未定 |
| T-07 | 🟡 | TECH | 架构师 | ARM64 触发条件未定 |
| U-04 | 🟡 | UI | UI/UX | Toast/Dialog 组件未正式定义 |
| U-05 | 🟡 | UI | UI/UX | Tree Select 组件缺失 |
| U-07 | 🟡 | UI | PM | 国际化策略未明 |
| S-03 | 🟡 | 安全 | 架构师 | 登录限流仅账号维度缺 IP 维度 |
| S-04 | 🟡 | 安全 | PM | 租户内 MFA 范围未明 |
| S-05 | 🟡 | 安全 | 架构师 | CORS/CSP/SameSite 未规定 |
| P-10 | 🟡 | 性能 | 架构师 | property_photos HASH 分区 DDL 缺 |
| P-11 | 🟡 | 性能 | 架构师 | 智能配房算法路径未文档化 |
| M-01~M-04 | 🟡 | 维护 | 架构师 | CHANGELOG/AI 指令/测试规范/Migration 策略 |
**合计**:🔴 2 / 🟠 19 / 🟡 17 = **38 项**
---
*Report Generated: 2026-04-25 by AI Reviewer*

View File

@@ -1,521 +0,0 @@
# Fonrey 全局系统设计 Review 报告
> **Review 类型**:全量 ReviewPRD + DATA_MODEL + TECH_STACK + UI/UX + TASK 交叉验证)
> **Review 模式**:聚焦 Top 风险 + 与 `REVIEW_全局_2026-04-25.md` 增量对比
> **Review 日期**2026-04-26
> **Reviewer**:首席系统设计 ReviewerAI 辅助)
> **当前阶段**:需求 ~85% / 数据模型 ~70% / UI 设计 ~30%HTML 原型已启动)/ TECH 横切规范 ~50%
> **覆盖文档**8 份 PRD含 7 份模块 PRD + TASK.md、8 份 DATA_MODEL、4 份 TECH_STACK、3 份 UI_SYSTEM、UI_DESIGN10 份原型/设计稿)
> **问题分级**:🔴 Blocker阻塞开发 / 🟠 Major必须修复但不阻塞 / 🟡 Minor建议优化
---
## 、执行摘要Executive Summary
### 整体评价
相较 2026-04-25 版本,文档体系出现 **3 项实质性进展**
1. **UI_DESIGN 原型已启动**(昨日 U-06 已修复):客源列表/详情/新增/编辑、房源列表 5 类核心页面均已产出 HTML + Markdown 双版本,规范深度足够。
2. **租户注销 SOP 已落地**(昨日 X-02 已修复):`PRD/系统管理` 已含导出范围、30 天宽限期、清除时序的完整生命周期。
3. **楼盘 4 类锁字段已实现**(昨日 D-02 部分修复):`complexes.lock_building/lock_room/lock_info/lock_standard_room` DDL 已写入。
但本次审查也暴露出**昨日 Review 未触及的新一类系统性风险——枚举一致性塌方**:客源状态、客源等级、房源状态、操作日志类型等核心枚举在 PRD ↔ DATA_MODEL ↔ TASK AC 三方均无权威源,且互相矛盾。这是一类比"Keyset 分页缺失"更隐蔽、修复成本更高的债务。
同时,**昨日列出的 2 个 BlockerP-01 权限档位 / D-01 Keyset 分页)均未修复**,新增 1 个 Blocker系统配置 PRD 仍为空骨架但被 9 条 P0/P1 任务引用为权威),共 **3 个 Blocker**,必须在编码启动前清零。
### 核心问题摘录Top 10
| # | 等级 | 编号 | 问题 | 维度 | 状态 |
|---|------|------|------|------|------|
| 1 | 🔴 | **B-01** | 系统配置 PRD`PRD/系统配置/系统配置.md`)仍为 128 行空骨架,但 TASK.md 排期 9 条 P0/P1 任务US-SETTING-001/010~012/020~023以其为权威`lookup_items` 入口、字段必填、活跃度阈值30 天)等无配置出口 | PRD↔TASK | 🆕 新增 |
| 2 | 🔴 | **B-02** | **核心枚举三方不一致**客源状态PRD"求购/求租/租购"vs DDL `buying/renting/buy_or_rent`、等级PRD A~E vs DDL A_urgent/A/B/C/D、房源 statusDDL 未含 `sold/unlisted/paused`,但 TASK AC 与查询语句均使用) | PRD↔Data↔TASK | 🆕 新增 |
| 3 | 🔴 | **B-03** | 权限 PRD §3 非目标声明"三档"与 §5.6 / Story 3 验收"五档" + DATA_MODEL_PERMISSION 的"DataScope 跨层级叠加"实质性冲突 | PRD↔Data | ⚠️ 昨日 P-01 部分修复,仍 Blocker |
| 4 | 🔴 | **B-04** | Keyset 分页规范在 TECH_STACK / DATA_MODEL / 测试规范中**完全缺位**89k 房源 + 200 万跟进日志的列表查询设计错误 | TECH/Data | ⚠️ 昨日 D-01 未修复 |
| 5 | 🟠 | **M-01** | 测试规范 v1.0 与 django-tenants 多租户工作模式冲突:`LocMemCache`/`FileSystemStorage`/`CELERY_TASK_ALWAYS_EAGER=True` 使权限 Redis 快照失效、跨租户隔离、Celery 异步导出三类场景无法验证;`TenantClient`/`tenant fixture` 仅在 §11.2 Prompt 模板中被引用但无实现 | TECH/测试 | 🆕 新增 |
| 6 | 🟠 | **M-02** | 主表乐观锁字段缺失:`properties` / `clients` 仍无 `version``complexes` 4 类锁已建字段但无解锁权限/过期规则 PRD | Data↔PRD | ⚠️ 昨日 D-02 部分修复 |
| 7 | 🟠 | **M-03** | 高写入表分区 DDL 仍未落地:`follow_logs` / `property_photos` / `permission_change_logs` / `login_attempts` / `platform_audit_logs` 均仅文字"建议月度分区",无 `PARTITION BY` 子句 | Data | ⚠️ 昨日 D-04 未修复 |
| 8 | 🟠 | **M-04** | TECH_STACK 三大横切规范仍未补Celery 多租户 schema 切换(昨 T-01、R2 文件路径前缀(昨 T-02、查询索引矩阵昨 T-03 | TECH/多租户 | ⚠️ 昨日均未修复 |
| 9 | 🟠 | **M-05** | 89k 数据 < 2 秒列表查询是 TASK AC 中的硬性 NFRUS-PROPERTY-002 / US-CLIENT-002但 TECH_STACK + 测试规范无 p95/EXPLAIN/性能基准对应任务AC 不可测 | NFR↔TECH↔测试 | 🆕 新增 |
| 10 | 🟠 | **M-06** | 客户端发布无签名校验/防降级机制:`/api/client/updates/latest/``download_url` 公开 URL仅 SHA256 完整性校验,可被中间人投递降级版本 | 安全 | 🆕 新增 |
### 风险等级分布
| 等级 | 本次2026-04-26 | 昨日2026-04-25 | 净变化 |
|------|---|---|---|
| 🔴 Blocker | **3** | 2 | +1系统配置空骨架升级 |
| 🟠 Major | **12** | 19 | -7含 6 项已修复 + 1 项降级) |
| 🟡 Minor | **6** | 17 | -11聚焦 Top 风险,未列入本期) |
| 合计 | **21** | 38 | — |
### 增量对比一览(昨日 P0/P1 → 今日状态)
| 昨日编号 | 简述 | 状态 | 今日处置 |
|----------|------|------|----------|
| P-01 | 权限范围档位冲突 | 🟡 部分修复 | 升 B-03 仍 Blocker |
| D-01 | Keyset 分页缺失 | 🔴 未修复 | 转 B-04 |
| P-02 | 系统配置 PRD 缺失 | 🔴 仍空骨架 | 升 B-01 |
| D-02 | 主表乐观锁/楼盘锁 | 🟡 部分修复 | 转 M-02 |
| D-04 | 高写入表分区 | 🔴 未修复 | 转 M-03 |
| D-07 | 楼盘价格走势/市场报盘 | 🟡 部分修复 | M-08降级 |
| T-01/T-02/T-03 | Celery/R2/索引规范 | 🔴 均未修复 | 合并 M-04 |
| U-01/U-02/U-03/U-06 | UI 组件 + Wireframe | 🟡 U-06 已修复,复杂组件仍缺 | 转 M-09 |
| X-01 | Redis Key tenant 前缀 | 🟡 部分修复 | M-10降级 |
| X-02 | 租户注销 SOP | ✅ 已修复 | 关闭 |
| S-01 | 加密密钥管理 | 🔴 未修复 | M-11 |
---
## 一、PRD 一致性审查PRD ↔ PRD ↔ TASK
### 🔴 B-01 系统配置 PRD 空骨架阻塞 9 条 P0/P1 任务
**文档**`PRD/系统配置/系统配置.md:1-128`(仅章节标题,无内容);`PRD/TASK.md:59, 86-88, 107-110`
**事实**
- 系统配置 PRD 仅 128 行骨架无任何字段定义、规则说明、UI 描述。
- TASK.md 在 Phase 1/2/3 共排期 9 条 Story全部以"参考 PRD系统配置.md"为权威:
- P0US-SETTING-001房源相关设置-字段必填/自定义字段/标签)
- P1US-SETTING-010/011/012首页/相关方/客源参数)
- P2US-SETTING-020~023人事 OA/交易/财务/合同模板)
- 客源 PRD `DATA_MODEL_CLIENT.md:31` 提到"活跃度新配偶 30 天"阈值由 lookup_items 配置,但配置入口 PRD 不存在。
- 房源 PRD 多处提到"字段标签可配置"、"自定义字段"、"标签管理",全部指向系统配置 PRD。
**影响**
- US-SETTING-001 是 Phase 1 P0无 PRD 即无法启动开发。
- 所有"可配置"行为(活跃度阈值、自动转公阈值、字段标签)的运营管理入口断链。
- DATA_MODEL_PUBLIC `lookup_items` 表已建好,但其管理 UI 与权限设计无规格。
**责任**PM 必须在编码 Phase 1 启动前完成 `PRD/系统配置/系统配置.md` 至少 P0 范围US-SETTING-001 内容),否则 TASK.md 应将 US-SETTING-001 暂时移出 Phase 1。
---
### 🔴 B-02 核心枚举三方不一致PRD ↔ DDL ↔ TASK AC
**文档**:多处(见下表)
| 字段 | PRD 表述 | DATA_MODEL CHECK | TASK AC | 冲突类型 |
|------|----------|------------------|---------|----------|
| 客源 status | `PRD/客源管理/客源管理模块PRD.md:465,504,1757,1786`:求购/求租/租购/我购/我租/成交/暂缓/无效/公 | `DATA_MODEL_CLIENT.md:471,511``buying / renting / buy_or_rent`(仅 3 值,无暂缓/无效/我购/我租/成交/公) | `TASK.md` US-CLIENT-002/010/011/012/013 均按 PRD 中文 | 三方均不同 |
| 客源 grade | PRD `1634`A~E 五级 | `DATA_MODEL_PROPERTY.md:266`(注:客源 grade 字段实际位置待确认):`A_urgent/A/B/C/D` 5 项无 E | `TASK.md:308` US-CLIENT-009A 急迫/B 较强/C 一般/D 较弱/E 暂不关注 五级 | DDL 缺 E混用 `A_urgent` |
| 房源 status | PRD 8 态:出售/出租/租售/暂缓/他售/他租/成交/未挂牌 | `DATA_MODEL_PROPERTY.md:197``for_sale/for_rent/for_sale_rent/...` | `TASK.md:232` US-PROPERTY-008在售→暂缓/成交/下架;`TASK.md:1121` 隐式查询 `status NOT IN ('sold','unlisted')` | DDL CHECK 全集未冻结,"sold/unlisted/paused" 出现在查询但未确认在 CHECK 中 |
| 操作日志 type | 客源 PRD `668`:明文"系统实际枚举值更多" | DATA_MODEL_CLIENT 未给 CHECK 完整列表 | `TASK.md:578-581` US-CLIENT-024 AC"按操作类型筛选" | 全集未冻结 |
| 二级 Tab "暂缓" | 客源 PRD `713-717` Tab求购/求租/暂缓/全部私客 | `DATA_MODEL_CLIENT.md:471,511` 状态枚举无 `paused/on_hold` | `US-CLIENT-002` AC 含暂缓 Tab | DDL 缺值 |
| `tenants.status` | `DATA_MODEL_PUBLIC.md:96`6 值含 `failed` | 同文件 `488-494` 状态机图:仅 5 态,未含 `failed` | — | 同一文档内自相矛盾 |
**影响**
- 迁移脚本将凭主观翻译,开发期会出现"经纪人在 PRD 看到的中文"与"DDL CHECK 拒绝的英文"不一致的运行时报错。
- 状态机断链导致 transition 校验逻辑(如"暂缓→在售")无权威实现。
- 测试 factory 不知如何取样form choices 与 query filter 各自定义。
**责任**PM + 架构师共同冻结一份《Fonrey 枚举字典 v1.0》(建议放入 `DATA_MODEL/ENUMS.md`),所有 PRD/DDL/TASK 引用统一锚点。
---
### 🔴 B-03 权限数据范围档位冲突仍为 Blocker昨日 P-01 部分修复)
**文档**`PRD/权限管理/权限管理模块PRD.md:46`§3 非目标vs `:492-499`§5.6 五档vs `DATA_MODEL/DATA_MODEL_PERMISSION.md:24,31`DataScope 跨层级叠加)
**事实**
- §3 非目标仍写"数据范围控制以**本人 / 本部门 / 全公司**三档为主,本期不含行级权限"。
- §5.6 已扩为五档(本人/本组/本门店/本区域/全公司)。
- DATA_MODEL_PERMISSION `staff_data_scopes` 已实现"跨层级叠加""本组 门店B"),实质上为对象级权限的弱化形态,已超出 §3 非目标边界。
**影响**
- 同一 PRD 内 §3 与 §5.6 自相矛盾,开发无权威依据。
- `staff_data_scopes` 是否本期落地不明权限模块US-PERMISSION-001~005无法启动。
**责任**PM 在 PRD v1.2 中锁定五档 + 删除 §3 三档表述 + 明确 DataScope 跨层级叠加是否本期范围。
---
### 🟠 M-07 楼盘合并/申请流程仅占位
**文档**`PRD/房源管理/楼盘管理模块PRD.md:117`
**事实**PRD 仅写"小区名称/地址只读 — 合并/申请流程"占位,未定义触发条件、审批人、合并规则、对历史房源/客源的影响。`DATA_MODEL_COMPLEX` 无对应表/工作流。
**影响**US-COMPLEX-001 录入与维护流程不闭环;楼盘合并将在生产环境出现"合并后历史房源 complex_id 漂移"问题。
---
### 🟠 M-08 客源新房/租房 Tab 字段未冻结
**文档**`PRD/客源管理/客源管理模块PRD.md:1663`(明文"字段待截图补充确认"
**事实**US-CLIENT-014编辑客源 Tab 三:二手/新房/租房AC 不可测DATA_MODEL_CLIENT 需求字段 schema 不可冻结。
---
## 二、DATA_MODEL 完整性审查
### 🔴 B-04 Keyset 分页规范全局缺位(昨日 D-01 未修复)
**文档**`TECH_STACK/TECH_STACK.md`(全文未现 keyset/分页规范);`DATA_MODEL_PROPERTY.md:1083` §6 / `DATA_MODEL_CLIENT.md:453` §五 查询模式参考章节均未给 Keyset SQL 模板
**事实**
- 89k 房源 + 200 万/年跟进日志使用 OFFSET 分页,第 100 页响应将达秒级。
- TASK.md US-PROPERTY-002 / US-CLIENT-002 的 AC 均要求"<2 秒"。
- 测试规范无性能基准任务覆盖。
**责任**:架构师在 `TECH_STACK.md` 新增 §「分页规范」,并在 `DATA_MODEL_PROPERTY.md` §6 / `DATA_MODEL_CLIENT.md` §五 给出 Keyset SQL 模板(`WHERE (created_at, id) < (?, ?) ORDER BY created_at DESC, id DESC LIMIT 21`)。
---
### 🟠 M-02 主表乐观锁/楼盘锁规则缺失
**文档**`DATA_MODEL_COMPLEX.md:194-197`(楼盘 4 类锁字段已建);`DATA_MODEL_PROPERTY.md` / `DATA_MODEL_CLIENT.md` / `DATA_MODEL_COMPLEX.md` 主表均无 `version` 字段;`PRD/房源管理/楼盘管理模块PRD.md:82` 列出 4 类锁但无解锁/过期规则
**事实**
- 楼盘 `lock_building/lock_room/lock_info/lock_standard_room` 字段已落库 ✅
- 但 PRD 未规定每类锁的解锁权限、自动/手动解锁规则、锁过期机制。
- US-COMPLEX-001/002 AC 不含锁状态变更流程。
- `properties.version` / `clients.version` 仍未补,多人协作场景的写冲突无防护。
**责任**:架构师补 `version` 字段PM 补 4 类锁的业务规则。
---
### 🟠 M-03 高写入表分区 DDL 仍未落地(昨日 D-04 未修复)
**文档**`DATA_MODEL_PROPERTY.md:523`follow_logs/ `:801`property_photos`DATA_MODEL.md:596-604`(仅文字描述)
**事实**
- `follow_logs`200 万+/年)、`property_photos`500 万+)、`permission_change_logs``login_attempts``platform_audit_logs` 的 DDL 中均无 `PARTITION BY` 子句,仅在文字描述/分区策略表中"建议按月 RANGE 分区"。
- 开发期不分区,未来再分区将带来全表数据迁移成本。
**责任**:架构师在每张高写入表的 DDL 中给出 `PARTITION BY RANGE (created_at)` + `pg_partman` 自动维护脚本。
---
### 🟠 M-08 楼盘价格走势已建,市场报盘仍缺(昨日 D-07 部分修复)
**文档**`DATA_MODEL_COMPLEX.md:376` `complex_price_trends` ✅;`DATA_MODEL_CLIENT.md:505` §5.4 私客自动转公(仅 SQL 查询示例,非完整 job`market_quotes` 表全表缺失
**事实**
- 楼盘价格走势 ✅ 已建。
- "市场报盘"(房源 PRD §)仍无 `market_quotes` 表。
- 私客→公客自动转换仅给查询 SQL 示例,无完整 Celery beat 调度任务定义、无幂等保证、无并发控制。
**影响**US-CLIENT-016系统自动将超时无跟进的私客转为公客AC 无法实现。
---
## 三、TECH_STACK 完整性审查
### 🟠 M-04 三大横切规范全部仍未补(昨日 T-01/T-02/T-03 未修复)
**文档**`TECH_STACK/TECH_STACK.md`(全文)
| 子项 | 现状 | 影响 |
|------|------|------|
| Celery 多租户 schema 切换 | TECH_STACK.md L30/44/80/90/165 仅零散提及 Celery无统一规范 | Worker 在错误 schema 下查询、跨租户数据污染 |
| R2 文件路径前缀 | TECH_STACK.md L31/105/119/166 仅提及 bucket 名 | 共享 bucket 下 `file_key` 无租户标识,存在隐患 |
| 查询索引矩阵 | TECH_STACK/ 目录无"索引规范.md"DATA_MODEL.md §六 实为 Redis 缓存策略 | 89k 房源多条件筛选无覆盖索引验证依据 |
**责任**:架构师补 §「异步任务规范」、§「R2 路径规范」、`TECH_STACK/索引规范.md` 三份内容。
---
### 🟠 M-01 测试规范与 django-tenants 多租户工作模式冲突
**文档**`TECH_STACK/测试规范.md:393-413`settings_test/`570-575`(引用未实现的 TenantClient/`594`(禁用真实外部服务)
**事实**
- `LocMemCache`402-406django-tenants 需要 `tenant-cache-key` 前缀化的 Redis 行为;权限快照走 RedisTASK L617 AC "Redis 权限快照失效重载"),切到 LocMem 后跨进程/跨租户隔离测试失效。
- `FileSystemStorage`411-413替换 R2 用于测试本身合理,但与 §594 "禁止测试直接调用真实外部服务"叠加后,`tenants/{schema_name}/...` 路径前缀策略M-04 R2无 mock 验证手段。
- `CELERY_TASK_ALWAYS_EAGER=True`398-399US-CLIENT-003 等要求"Celery 异步处理"的 AC 无法在 EAGER 模式下验证异步语义。
- `DATABASES "由环境变量注入"`393-395未约定 `ENGINE=django_tenants.postgresql_backend`,可能落到错误的 backend 上。
- `TenantClient` / 多租户 fixture仅在 §11.2 Prompt 模板中被引用无实现§12 又"禁止使用 Django 原生 Client()",造成所有 integration 测试无统一基类。
**影响**
- 权限模块 Redis 快照失效场景、跨租户隔离场景的自动化测试不可信。
- US-PERMISSION-* / US-CLIENT-003 / US-CLIENT-016 等核心场景的覆盖率指标存在水分。
**责任**:架构师与测试负责人协同:(a) `tests/conftest.py` 提供 `TenantClient``tenant_factory` 实现;(b) Redis 改用 fakeredis 而非 LocMemCache(c) 异步场景使用 `pytest-celery``celery_app` fixture区分 EAGER 单元测试与真实 broker 集成测试。
---
### 🟠 M-05 性能 NFR 无 SLI/SLO 落地(昨日 P-04 未修复)
**文档**`TASK.md:189, 252` US-PROPERTY-002 / US-CLIENT-002 AC 写"89000 条数据下查询 < 2 秒"`PRD/客源管理/客源管理模块PRD.md:1958-1960` 仅泛述"分页加载"TECH_STACK 与测试规范无 p95/索引/EXPLAIN 验收
**事实**
- 性能 AC 散布于 PRD/TASK 多处(录入耗时 ≤ 30s、配房 < 3s、登录成功率、自动更新 ≥ 98%、RTO < 2h无统一的 NFR 矩阵。
- TECH_STACK 未承接为 SLI/SLO测试规范无性能基准任务如 pytest-benchmark + EXPLAIN ANALYZE 校验)。
**影响**:所有性能 AC 不可测,验收阶段将沦为主观判断。
---
### 🟠 M-11 加密密钥管理方案缺失(昨日 S-01 未修复)
**文档**`TECH_STACK/TECH_STACK.md:96` 仅一句"禁止硬编码密钥"
**事实**
- 全文未给出 KMS / Vault / 环境变量加密管理说明。
- `core.encryption` 仅作为模块名出现,密钥轮换流程未定义。
- 手机号、身份证、银行卡号、产证号等多处使用 AES-256-GCM 加密,密钥泄露后批量解密风险高。
**责任**:架构师补 KMS/Vault 选型 + 轮换 SOP + `core.encryption` 接口契约。
---
## 四、UI/UX 完整性审查
### ✅ U-06 已修复UI_DESIGN 原型已启动
**证据**`UI_DESIGN/preview.html``UI_DESIGN/客源列表_UI.html`81KB`客源详情_UI.html``房源列表_UI.html``新增客源_UI.html``编辑客源_UI.html``UI_DESIGN/客源管理/`4 份 md60KB+/40KB+`UI_DESIGN/房源管理/房源列表_UI.md`69KB
**事实**HTML 原型与对应 Markdown 设计稿均已启动,规范深度足够(含功能范围/页面规范/Data Table/HTMX/权限矩阵)。
---
### 🟠 M-09 复杂组件原型仍缺 + 楼盘/客源原型不完整(昨日 U-01/U-02/U-03 未修复)
**文档**`UI_SYSTEM/UI_SYSTEM.md`1742 行);`UI_SYSTEM/组件清单.md:186`(仅在评论中提到 TreeSelect "建议手写 80~120 行 JS"`UI_DESIGN/房源管理/` 仅 1 个文件;`UI_DESIGN/客源管理/` 缺关键浮层
**事实**
- 组件清单仍缺 4 类关键复杂组件:
1. **Stepper / Wizard**(多步表单):录入私客、转成交浮层
2. **PermissionTree**14 个一级模块树 + 多分组 + Toggle/Select/NumberUS-PERMISSION-001/004 最复杂页面
3. **智能配房比对器**4 分组卡片US-CLIENT-020 录客配房
4. **审批前置弹层**US-CLIENT-015 跨团队需店长权限、号码方审批
- UI_DESIGN/房源管理/ 仅 `房源列表_UI.md`TASK.md L152/160 引用 `楼盘列表_UI.md` / `楼盘详情_UI.md` 不存在。
- UI_DESIGN/客源管理/ 缺 US-CLIENT-007带看/011转公客/012转成交/015相关员工/020智能配房独立原型全部压缩进 `客源详情_UI.md` 单文件,颗粒度不足。
**责任**UI/UX 设计师补 4 类复杂组件 + 楼盘 2 份原型 + 客源 5 份关键浮层独立原型。
---
## 五、多租户隔离审查(横切)
### 🟠 M-10 Redis Key 命名跨模块未统一(昨日 X-01 部分修复)
**文档**`TECH_STACK/登录管理技术方案.md:553-562`(§九 Redis Key 规范,使用 `{tenant_id}:` 前缀);`TECH_STACK.md` / `权限管理系统技术方案.md` 未见统一规范引用
**事实**
- 登录方案已落地 Redis Key 规范表 ✅,但前缀使用 `{tenant_id}:` 而非昨日 Review 建议的 `{tenant_schema_name}:`
- TECH_STACK.md 总纲未引用此规范;权限技术方案未明确 Redis Key 是否带 tenant 前缀。
- 跨模块(登录/权限/缓存)若不统一,多租户 Redis 共享时存在键冲突风险。
**责任**:架构师在 `TECH_STACK.md` 新增 §「Redis Key 规范」,统一 `{tenant_schema_name}:` 前缀schema_name 比 tenant_id 在日志/调试时更直观),并在登录/权限技术方案中显式引用。
---
## 六、合规与安全审查
### 🟠 M-06 客户端发布无防降级/重放校验
**文档**`PRD/发布管理/客户端发布管理模块PRD.md:58`(明文非目标"客户端代码混淆/反逆向"`DATA_MODEL_PUBLIC.md:413-416, 419-421`
**事实**
- `/api/client/updates/latest/` 响应未要求服务端签名。
- `client_releases.download_url` 为 R2 公开 URL无签名/有效期,旧客户端可继续拉取旧版本绕过强制升级。
- `min_required_version` 由"应用层比较 SemVer",未定义服务端签名/客户端公钥校验。
- US-RELEASE-011 SHA256 仅校验完整性,不防替换(中间人可投递降级版本)。
**影响**:中间人攻击可投递已撤销的旧版本(含已修复漏洞的版本),合规与安全双重风险。
**责任**:架构师与发布团队补:(a) 更新元数据签名Ed25519/RSA-PSS(b) `download_url` 改用签名 URL短有效期(c) 客户端内置公钥校验。
---
### 🟠 M-12 RPO 数值缺失,备份计划与 SLA 断链
**文档**`PRD/系统管理/系统管理模块PRD.md:58`(仅 RTO < 2h`DATA_MODEL_PUBLIC.md:265-280` `backup_schedules` 默认 daily 02:00、retention 10
**事实**
- daily 频率隐含 RPO ≈ 24h 但 PRD 未声明。
- 与"全局/租户级覆盖"组合下SLA 不可承诺。
- `tenants.status``failed`DDL但状态机图同文 488-494仅 5 态未含 `failed`,故障租户无 SLA 出口。
**责任**PM 补 RPO 数值;架构师补 `failed` 状态的退出路径。
---
## 七、性能与容量审查
### 🟠 M-05 89k 数据 < 2 秒 AC 不可测(已在 §三列出)
### 🟠 M-13 智能配房算法路径仍未文档化
**文档**:客源 PRD §5 智能配房TECH_STACK 与 DATA_MODEL 未有"实时 vs 异步""匹配算法 SQL"说明
**事实**
- 客源 PRD 要求智能配房响应 < 3s。
- 匹配字段(户型/面积/价格/区域)跨 properties/clients 两表的 4-6 维筛选,是否使用物化视图/PostgreSQL 多列 GiST 未定。
- `client_property_matches` 表是否本期建TASK Phase 3 才有 US-CLIENT-020若 Phase 1 不需要PRD 提及的 < 3s 应明确不在 Phase 1 范围。
---
## 八、可维护性与扩展性
### 🟠 M-14 TASK.md PRD 锚点链接断链
**文档**`TASK.md:124, 132, 139, 150, 158, 167`
**事实**TASK.md 大量"参考 PRDxxx#锚点"形式的链接,但所引锚点(如 `登录管理/用户登录管理模块PRD.md - 账号密码登录` / `楼盘管理模块PRD.md - 楼盘信息管理`)在对应 PRD 中作为标题不存在,开发无法直接跳转。
**影响**TASK.md 作为开发入口的"可执行性"打折扣。
---
## 九、行动清单(按责任人 + 优先级)
### PM产品经理
| ID | 等级 | 任务 | 关联编号 |
|----|------|------|----------|
| PM-1 | 🔴 | **补齐 `PRD/系统配置/系统配置.md` P0 范围**US-SETTING-001字段必填/自定义字段/标签管理lookup_items 配置入口;活跃度/转公阈值配置) | B-01 |
| PM-2 | 🔴 | 与架构师协同冻结《Fonrey 枚举字典 v1.0》(建议 `DATA_MODEL/ENUMS.md`),覆盖客源 status/grade、房源 status、操作日志 type、`tenants.status` 等核心枚举 | B-02 |
| PM-3 | 🔴 | 修订权限 PRD v1.2:删除 §3 三档表述,锁定五档 + DataScope 跨层级叠加是否本期范围 | B-03 |
| PM-4 | 🟠 | 楼盘合并/申请流程详述(触发/审批/对历史房源影响) | M-07 |
| PM-5 | 🟠 | 客源新房/租房 Tab 字段冻结 | M-08 |
| PM-6 | 🟠 | 在 `PRD_MVP.md` 中汇总 NFR 矩阵(性能/可用性/安全/合规),含 RPO 数值 | M-05, M-12 |
| PM-7 | 🟠 | 修复 TASK.md 内所有 PRD 锚点断链 | M-14 |
### 架构师
| ID | 等级 | 任务 | 关联编号 |
|----|------|------|----------|
| ARCH-1 | 🔴 | TECH_STACK 新增 §「分页规范」+ Keyset SQL 模板DATA_MODEL_PROPERTY/CLIENT §查询模式补 Keyset 示例 | B-04 |
| ARCH-2 | 🟠 | 修复测试规范多租户冲突:补 `TenantClient` 实现、`tenant_factory` fixtureRedis 改用 fakeredis区分 EAGER/真实 broker | M-01 |
| ARCH-3 | 🟠 | `properties` / `clients` 主表补 `version`;楼盘 4 类锁补解锁/过期机制(与 PM 协同) | M-02 |
| ARCH-4 | 🟠 | 高写入表follow_logs/property_photos/permission_change_logs/login_attempts/platform_audit_logs`PARTITION BY RANGE` DDL + pg_partman 脚本 | M-03 |
| ARCH-5 | 🟠 | TECH_STACK 三大横切规范补异步任务Celery tenant_schema 必传 + `@with_tenant_context`/R2 路径前缀(`tenants/{schema_name}/...`/查询索引矩阵 | M-04 |
| ARCH-6 | 🟠 | TECH_STACK 性能 NFR → SLI/SLO 映射 + 测试规范补 pytest-benchmark/EXPLAIN ANALYZE | M-05 |
| ARCH-7 | 🟠 | 客户端发布签名机制:服务端签发 Ed25519/RSA-PSS、客户端内置公钥、`download_url` 改签名 URL | M-06 |
| ARCH-8 | 🟠 | `market_quotes` 表 + 私客自动转公完整 Celery beat 任务(含幂等/并发控制) | M-08 |
| ARCH-9 | 🟠 | TECH_STACK 新增 §「Redis Key 规范」,统一 `{tenant_schema_name}:` 前缀 | M-10 |
| ARCH-10 | 🟠 | 加密密钥管理方案KMS/Vault 选型、轮换 SOP、`core.encryption` 接口契约 | M-11 |
| ARCH-11 | 🟠 | `tenants.status='failed'` 状态机出口补全 | M-12 |
| ARCH-12 | 🟠 | 智能配房算法路径文档(实时 vs 异步、索引/物化视图选型) | M-13 |
### UI/UX 设计师
| ID | 等级 | 任务 | 关联编号 |
|----|------|------|----------|
| UI-1 | 🟠 | 补 4 类复杂组件原型Stepper/Wizard、PermissionTree、智能配房比对器、审批前置弹层 | M-09 |
| UI-2 | 🟠 | 补 UI_DESIGN/房源管理/楼盘列表_UI.md / 楼盘详情_UI.md修复 TASK 引用) | M-09 |
| UI-3 | 🟠 | 客源关键浮层独立原型US-CLIENT-007/011/012/015/020 | M-09 |
---
## 十、结论
### 是否可进入开发阶段
**否,必须先解决 4 个 Blocker**
| 编号 | Blocker | 影响范围 |
|------|---------|----------|
| B-01 | 系统配置 PRD 空骨架 | 阻塞 9 条 P0/P1 任务US-SETTING-001/010~012/020~023 |
| B-02 | 核心枚举三方不一致 | 阻塞客源/房源全部 CRUD 模块US-CLIENT-* / US-PROPERTY-* |
| B-03 | 权限档位冲突 | 阻塞权限模块US-PERMISSION-001~005 |
| B-04 | Keyset 分页缺失 | 阻塞高基数列表查询US-PROPERTY-002 / US-CLIENT-002 |
**可立即并行启动的部分**
- 公共 Schema`tenants``platform_admins``audit_logs`)开发——文档完整,无 Blocker。
- 楼盘/区域/学校 CRUD——DATA_MODEL_COMPLEX 完整、4 类锁字段已建,主流程清晰(解锁规则可后置补充)。
- Electron 客户端框架搭建——TECH_STACK §8 决策已封闭(但发布签名机制 M-06 需在 RC 前补齐)。
- 登录模块accounts App——文档完整含 Redis Key 规范),仅需在多租户场景下补 fakeredis 测试基线。
- UI 静态原型实施——核心 5 页已有 HTML 原型可直接转 HTMX 模板。
**必须延后的部分**
- 系统配置模块B-01 解除前)。
- 权限模块B-03 解除前)。
- 房源/客源高基数列表查询B-04 解除前;可先实施 OFFSET 分页,但需排期重构)。
- 89k 性能 AC 验收M-05 解除前AC 不可测)。
### 文档体系成熟度评分(与昨日对比)
| 维度 | 今日 | 昨日 | 变化 | 说明 |
|------|------|------|------|------|
| PRD 业务清晰度 | 7.5/10 | 8.5/10 | ↓ | 新发现枚举塌方 + 系统配置空骨架 |
| DATA_MODEL 落地深度 | 8.5/10 | 8/10 | ↑ | 楼盘锁字段、价格走势、租户注销已落地 |
| TECH_STACK 完整性 | 6/10 | 6/10 | — | 三大横切规范仍未补 |
| UI/UX 系统化 | 7/10 | 5/10 | ↑↑ | UI_DESIGN 原型显著启动 |
| 跨文档一致性 | 5.5/10 | 6.5/10 | ↓ | 枚举塌方拉低评分 |
| 多租户隔离严谨度 | 7.5/10 | 7.5/10 | — | Redis Key 部分修复但未统一 |
| 测试可执行性 | 5/10 | (未评估) | 🆕 | 测试规范与 django-tenants 工作模式冲突 |
| **整体** | **6.8/10** | **7/10** | ↓ 0.2 | 新发现风险大于已修复风险,但绝对水平仍属"中等偏上" |
**结论**:本次 Review 的实质性进展UI 启动、租户注销 SOP、楼盘锁字段值得肯定但**枚举塌方**和**测试规范多租户冲突**是新发现的系统性风险,必须在编码启动前优先治理。在 4 个 Blocker 解除 + 6 项核心 Major 修复后,整体成熟度可重回 8.0+。
---
## 附录 A本次 Review 涵盖文档
### PRD8 份)
- `PRD/PRD_MVP.md` v1.0
- `PRD/TASK.md`834 行)
- `PRD/房源管理/房源管理模块PRD.md` v2.11881 行)
- `PRD/房源管理/楼盘管理模块PRD.md`
- `PRD/客源管理/客源管理模块PRD.md` v1.42050 行)
- `PRD/权限管理/权限管理模块PRD.md` v1.1
- `PRD/组织人事管理/组织人事管理模块PRD.md` v1.2
- `PRD/系统管理/系统管理模块PRD.md` v1.0
- `PRD/登录管理/用户登录管理模块PRD.md` v1.4
- `PRD/发布管理/客户端发布管理模块PRD.md` v1.0
- `PRD/系统配置/系统配置.md`128 行骨架)
### DATA_MODEL8 份)
- `DATA_MODEL/DATA_MODEL.md` v1.3、`DATA_MODEL_PUBLIC.md``DATA_MODEL_ORG.md``DATA_MODEL_COMPLEX.md``DATA_MODEL_PROPERTY.md``DATA_MODEL_CLIENT.md``DATA_MODEL_PERMISSION.md``DATA_MODEL_LOGIN.md`
### TECH_STACK4 份)
- `TECH_STACK/TECH_STACK.md` v2.0
- `TECH_STACK/登录管理技术方案.md` v2.0
- `TECH_STACK/权限管理系统技术方案.md` v1.0
- `TECH_STACK/测试规范.md` v1.0
### UI_SYSTEM3 份)
- `UI_SYSTEM/UI_SYSTEM.md` v1.21742 行)
- `UI_SYSTEM/组件清单.md`
- `UI_SYSTEM/组件规范设计.md`
### UI_DESIGN10 份原型/设计稿)
- `UI_DESIGN/preview.html``客源列表_UI.html``客源详情_UI.html``房源列表_UI.html``新增客源_UI.html``编辑客源_UI.html`
- `UI_DESIGN/客源管理/客源列表_UI.md``客源详情_UI.md``新增客源_UI.md``编辑客源_UI.md`
- `UI_DESIGN/房源管理/房源列表_UI.md`
---
## 附录 B问题汇总速查表
| ID | 等级 | 维度 | 责任人 | 简述 | vs 昨日 |
|----|------|------|--------|------|---------|
| B-01 | 🔴 | PRD↔TASK | PM | 系统配置 PRD 空骨架 | ⚠️ P-02 升级 |
| B-02 | 🔴 | PRD↔Data↔TASK | PM+架构师 | 核心枚举三方不一致 | 🆕 新增 |
| B-03 | 🔴 | PRD↔Data | PM | 权限档位三档/五档冲突 | ⚠️ P-01 部分修复 |
| B-04 | 🔴 | TECH/Data | 架构师 | Keyset 分页规范缺失 | ⚠️ D-01 未修复 |
| M-01 | 🟠 | TECH/测试 | 架构师 | 测试规范与 django-tenants 冲突 | 🆕 新增 |
| M-02 | 🟠 | Data↔PRD | 架构师+PM | 主表乐观锁/楼盘锁规则缺失 | ⚠️ D-02 部分修复 |
| M-03 | 🟠 | Data | 架构师 | 高写入表分区 DDL 未落地 | ⚠️ D-04 未修复 |
| M-04 | 🟠 | TECH/多租户 | 架构师 | Celery/R2/索引矩阵三大横切规范 | ⚠️ T-01/T-02/T-03 未修复 |
| M-05 | 🟠 | NFR↔TECH↔测试 | PM+架构师 | 89k <2 秒 AC 不可测 | 🆕 新增(含昨 P-04 |
| M-06 | 🟠 | 安全 | 架构师 | 客户端发布无防降级/签名 | 🆕 新增 |
| M-07 | 🟠 | PRD | PM | 楼盘合并/申请流程占位 | 🆕 新增 |
| M-08 | 🟠 | PRD/Data | PM+架构师 | 客源新房/租房字段未冻结 + market_quotes 缺 + 转公 job 不完整 | 部分新增 |
| M-09 | 🟠 | UI | UI/UX | 复杂组件 + 楼盘/客源浮层原型缺 | ⚠️ U-01/U-02/U-03 未修复 |
| M-10 | 🟠 | 多租户 | 架构师 | Redis Key 跨模块未统一前缀 | ⚠️ X-01 部分修复 |
| M-11 | 🟠 | 安全 | 架构师 | 加密密钥管理方案缺失 | ⚠️ S-01 未修复 |
| M-12 | 🟠 | 合规 | PM+架构师 | RPO 缺 + tenants.status=failed 状态机断链 | 🆕 新增 |
| M-13 | 🟠 | 性能 | 架构师 | 智能配房算法路径未文档化 | ⚠️ P-11 未修复(升级) |
| M-14 | 🟠 | 维护 | PM | TASK.md PRD 锚点断链 | 🆕 新增 |
**合计**:🔴 4 / 🟠 14 = **18 项 Top 风险**(聚焦 Top 模式,未列入 Minor
### 已关闭项(昨日 → 今日)
| 昨日编号 | 简述 | 关闭依据 |
| --------------- | ----------------------------------------- | ------------------------------------------------- |
| X-02 | 租户注销→导出→清除链路 | `PRD/系统管理` §189-227, §552-553 已落地完整生命周期 |
| U-06 | Wireframe 未启动 | UI_DESIGN/ 已产出 5 页 HTML + 5 份 md 设计稿 |
| 楼盘 4 类锁字段 | DATA_MODEL_COMPLEX 缺 lock_* 字段 | `DATA_MODEL_COMPLEX.md:194-197` 已建(业务规则待补,转 M-02 |
| 楼盘价格走势表 | DATA_MODEL_COMPLEX 缺 complex_price_trends | `DATA_MODEL_COMPLEX.md:376` 已建 |
| 登录 Redis Key 规范 | 跨模块未统一 | 登录方案 §九已建 ✅;统一 schema 前缀仍待办(转 M-10 |
---
*Report Generated: 2026-04-26 by AI Reviewer*
*基线版本REVIEW_全局_2026-04-25.md*

View File

@@ -1,421 +0,0 @@
# Fonrey 全局系统设计 Review 报告
> **Review 类型**:全量 ReviewPRD + DATA_MODEL + TECH_STACK + UI/UX + TASK 交叉验证)
> **Review 模式**:增量对比 `REVIEW_全局_2026-04-26.md`,逐条核对 4 Blocker + 12 Major 状态,识别新增风险
> **Review 日期**2026-04-28
> **Reviewer**:首席系统设计 ReviewerAI 辅助6 路并行 explore agent 取证)
> **当前阶段**:需求 ~90% / 数据模型 ~80% / UI 设计 ~35%HTML 原型推进中)/ TECH 横切规范 ~70%
> **覆盖文档**9 份 PRD + 10 份 TECH_STACK + 9 份 DATA_MODEL含新增 ENUMS.md v2.2+ 3 份 UI_SYSTEM + 11 份 UI_DESIGN + TASK 总表
> **问题分级**:🔴 Blocker阻塞开发 / 🟠 Major必须修复但不阻塞 / 🟡 Minor建议优化
> **状态标记**:✅ 已修复 / ⚠️ 部分修复 / ❌ 未修复 / 🆕 新增
---
## 、执行摘要Executive Summary
### 整体评价
相较 2026-04-26 版本,本期文档体系出现 **5 项实质性进展**,是历次 Review 以来修复力度最大的一次:
1. **🟢 B-01 系统配置 PRD 落地**`PRD/系统配置/系统配置模块PRD.md`273 行)+ `系统配置参数数据.md`1100 行)+ `系统配置数据模型设计说明_for_Atlas.md`275 行)三件套已完整产出,含 US-SETTING-001-A/B/C 三条 P0 Story 与完整验收标准。MVP 范围被显式约束(明确 ❌ 标签/带看/通知/发布平台等推迟到 P1/P2**降低实施风险**。
2. **🟢 B-02 枚举三方不一致根除**`DATA_MODEL/ENUMS.md` v2.2780 行2026-04-28作为**唯一权威源**已建立,全量统一为 `lower_snake_case`,历史大写值(`SUCCESS`/`A_urgent`/`A_app`)的迁移规则已写明,并要求 DB CHECK / `enum_labels` / 前端三方同步。
3. **🟢 B-03 权限档位冲突收敛**:权限 PRD §3 已显式表述"五档基线 + 各权限项可选子集(含三档场景)"DATA_MODEL_PERMISSION 的 `staff_data_scopes` 表(已建 DDL含 3 条索引)实现"跨层级并集"模型PRD ↔ Data ↔ Code 三方对齐。
4. **🟢 B-04 Keyset 分页规范化**`API_CONTRACT.md` §4 已写入 `{"mode":"keyset","cursor":"...","limit":20}` 标准合约 + 不透明游标禁令;客源/房源/楼盘/组织 4 个模块技术方案均已采用此契约。
5. **🟢 M-01 测试规范多租户化**`TECH_STACK.md:208` + `测试规范.md:69,146` 三处明确"必须使用 `TenantClient`,禁止 Django 原生 `Client()`"4 个模块技术方案同步引用。
但本期 Review 也确认 **3 类系统性债务未动**,且因其他模块详化反而更显突出:
- **❌ 主表乐观锁 `version` 字段** —— 全量 DATA_MODEL 0 命中89k 房源并发编辑场景PRD 明确双经纪人同时改房)将出现"后写覆盖前写"。
- **❌ 高写入表 `PARTITION BY` DDL** —— `follow_logs` / `property_photos` / `permission_change_logs` / `login_attempts` / `platform_audit_logs` 全量 0 命中分区子句,仅文字"建议月度分区"。**200 万跟进日志 + 2 年保留期** 的查询性能未保障。
- **❌ KMS / 密钥轮换 SOP** —— 仅见"`R2_ADMIN_KEY` 通过 Docker Secret 注入",无主密钥轮换流程、无应急吊销、无加密字段重新封装。
### 核心问题摘录Top 10
| # | 等级 | 编号 | 问题 | 维度 | 状态 |
| --- | --- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ---------------------- |
| 1 | 🔴 | **B-05** | 主表乐观锁 `version` 字段全量 0 实现:`properties` / `clients` / `complexes` 在 PRD 多人协作场景中是核心DDL 无并发控制 | Data↔PRD | 🆕 升 Blocker持续 3 次未修) |
| 2 | 🔴 | **B-06** | 高写入表分区 DDL 仍未落地M-03 持续 3 次未修5 张高频表无 `PARTITION BY RANGE` 子句,仅注释"建议月度分区",无法在迁移期补加分区 | Data | 🆕 升 Blocker |
| 3 | 🟠 | **M-11** | KMS / 密钥轮换 SOP 仍未补:`core/encryption.py` 已声明,但主密钥轮换、密钥版本号、加密字段重新封装、应急吊销四类流程在 TECH_STACK 与系统管理 PRD 中均无对应章节 | 安全 | ❌ 持续未修 |
| 4 | 🟠 | **M-12** | Celery 任务 schema 切换缺统一封装:多模块技术方案声明 `tenant_schema_name` 入参,但无 `with_tenant_context` 装饰器或基类抽象,开发期容易漏写导致跨租户脏读 | TECH/多租户 | ⚠️ 部分修复 |
| 5 | 🟠 | **M-13** | R2 路径前缀全局规范不一致:系统管理已规范 `backups/{tenant_schema}/...` `exports/{tenant_schema}/...`,但客源/房源/楼盘模块 R2 路径仍写"`property_photos/...`"无 tenant 前缀模板 | TECH/多租户 | ⚠️ 部分修复 |
| 6 | 🟠 | **M-06** | 客户端发布无签名校验/防降级:`/api/client/updates/latest/``download_url` 对外公开,仅 SHA256 完整性校验,可被 MITM 投递降级版本(昨日 M-06 未修) | 安全 | ❌ 持续未修 |
| 7 | 🟠 | **M-14** | ORM Manager / QuerySet 数据范围统一封装规范缺失:`DATA_MODEL_PERMISSION.md:143-145``ScopeQueryBuilder` 只是 helper未规定"所有业务 QuerySet 必须经过 Scope 包装"的强制约束,开发期容易漏权限校验 | 安全/Data | 🆕 新增 |
| 8 | 🟠 | **M-05** | 89k 数据 < 2 秒列表查询 NFR 仍无 p95/EXPLAIN/性能基准测试任务(昨日 M-05 未修) | NFR↔TECH↔测试 | ❌ 持续未修 |
| 9 | 🟠 | **M-09** | UI_SYSTEM 复杂组件虚拟滚动列表、批量操作面板、抽屉表单嵌套规则、文件上传批量、富权限树规范深度不足UI_DESIGN 11 份原型仅覆盖客源 + 房源列表,**楼盘/权限/系统配置/组织人事/发布管理 5 大模块全部缺原型** | UI | ⚠️ 部分修复 |
| 10 | 🟡 | **N-01** | ENUMS.md v2.2 已统一,但 PRD 文本中仍混用中文枚举(如客源 PRD 仍写"求购/求租"),需要一次全文档"中文枚举 → ENUMS 锚点链接"替换 | PRD↔Data | 🆕 新增 |
### 风险等级分布
| 等级 | 本次2026-04-28 | 上次2026-04-26 | 净变化 |
|------|---|---|---|
| 🔴 Blocker | **2** | 4 | -2B-01/B-02/B-03/B-04 全部清零B-05/B-06 由历史 Major 升级) |
| 🟠 Major | **9** | 12 | -3M-01 已修复关闭M-02→B-05、M-03→B-06 升级) |
| 🟡 Minor | **3** | 6 | -3聚焦 Top 风险) |
| 合计 | **14** | 22 | -8 |
### 增量对比一览(昨日 Blocker / Major → 今日状态)
| 上次编号 | 简述 | 状态 | 今日处置 |
|----------|------|------|----------|
| **B-01** | 系统配置 PRD 空骨架 | ✅ **已修复**273+1100+275 行三件套) | 关闭 |
| **B-02** | 枚举三方不一致 | ✅ **已修复**ENUMS.md v2.2 权威源) | 关闭,遗留 N-01PRD 文本回写) |
| **B-03** | 权限三档/五档冲突 | ✅ **已修复**(五档基线 + 子集子句) | 关闭,遗留 M-14ORM 强制约束) |
| **B-04** | Keyset 分页缺失 | ✅ **已修复**API_CONTRACT §4 + 4 模块) | 关闭 |
| M-01 | 测试规范多租户化 | ✅ 已修复TenantClient 强制) | 关闭 |
| M-02 | 主表乐观锁 / 楼盘锁 | ❌ 持续未修 | **升 B-05** |
| M-03 | 高写入表分区 | ❌ 持续未修 | **升 B-06** |
| M-04 | Celery/R2/索引规范 | ⚠️ 部分修复(拆分) | 拆分为 M-12 / M-13 / 残留索引矩阵 |
| M-05 | 89k 数据 < 2s NFR 测试 | ❌ 持续未修 | M-05 |
| M-06 | 客户端发布签名 | ❌ 持续未修 | M-06 |
| M-07~M-08 | 价格走势 / 楼盘市场报盘 | ⚠️ 降级 | 转 N-02Minor |
| M-09 | UI 组件 + Wireframe | ⚠️ 部分修复 | M-09 |
| M-10 | Redis Key tenant 前缀 | ✅ 已修复(系统设置技术方案 §6.4 | 关闭 |
| M-11 | 加密密钥管理 | ❌ 持续未修 | M-11 |
| M-12 | 数据保留与归档 | ⚠️ 部分修复 | 转 N-03 |
---
## 一、PRD 一致性审查PRD ↔ PRD ↔ TASK
### ✅ 历史 B-01系统配置 PRD 空骨架)已修复
**证据**
- `PRD/系统配置/系统配置模块PRD.md`273 行v0.12026-04-27含目标度量、非目标范围、3 条 P0 User StoryUS-SETTING-001-A/B/C与完整 Given-When-Then 验收标准。
- `PRD/系统配置/系统配置参数数据.md`1100 行):实际参数清单。
- `PRD/系统配置/系统配置数据模型设计说明_for_Atlas.md`275 行):与 DATA_MODEL_SETTING.md 对齐。
**剩余风险(降级为 Minor N-04**US-SETTING-001 的"配置变更生效时效 ≤ 5 分钟Redis 缓存 TTL"与 `DATA_MODEL_SETTING.md` 的 Redis Key TTL = 300s 一致,但**无 Cache Invalidation 主动失效路径**(仅靠 TTL 过期),管理员保存后 5 分钟内一线经纪人仍看不到新选项 —— PRD AC-2 "刷新后立即可见" 与实现存在间隙。
---
### ✅ 历史 B-02核心枚举三方不一致已修复
**证据**
- `DATA_MODEL/ENUMS.md` v2.2780 行2026-04-28作为唯一权威源覆盖 Publictenant 生命周期、平台管理员、备份导出、升级发布)+ Tenant客源/房源/楼盘/权限/组织/系统设置)所有枚举域。
- 命名规范统一为 `lower_snake_case`,历史大写值(`SUCCESS`/`FAILED`/`A_urgent`/`A_app`/`B_schema`/`C_feature`/`REPLACE`/`RESTRICT`/`GRANT`)的迁移路径已书面化。
**剩余风险N-01 Minor**PRD 文本与 TASK AC 中仍存在大量中文/旧值混用(如客源 PRD 仍写"求购/求租")。需要一次性回写:
- 在每份 PRD 顶部加 `> 枚举值参见 DATA_MODEL/ENUMS.md` 锚点
- 在 ENUMS.md 中给每个枚举值附"中文展示标签"列(部分已有)
- TASK.md 排一条 P0 任务PRD 中文枚举 → 英文锚点引用
---
### ✅ 历史 B-03权限档位三档/五档冲突)已修复
**证据**
- `PRD/权限管理/权限管理模块PRD.md:46`:明文"采用**五档模型**:本人 / 本组 / 本门店 / 本区域 / 全公司。注意:并非所有权限项均开放五档,各项的实际可选范围以权限编辑页的下拉配置为准(例如某些权限项仅提供「本人 / 本门店 / 全公司」三个选项)"
- `:499`:复述同一约定,闭环。
- `DATA_MODEL_PERMISSION.md:24,31,254-275,967-987``staff_data_scopes` 表 DDL 完整,索引 3 条到位,"员工数据范围 = 所有 staff_data_scopes 对应 org_units.path 子树并集"实现"跨层级叠加"。
**剩余风险M-14 Major见 §五**DATA_MODEL_PERMISSION 的 `ScopeQueryBuilder` 只是 helper class未在 TECH_STACK 中强制规定"所有业务 QuerySet 必须经过 Scope 包装",开发期容易漏写导致越权读取。
---
### 🟡 N-01 PRD 文本回写 ENUMS 锚点(来自 B-02 残留)
详见上文。**责任**PM 在 Phase 1 编码启动前完成全量 PRD 文本扫描替换。
---
## 二、TECH_STACK / API / 测试规范审查
### ✅ 历史 B-04Keyset 分页缺失)已修复
**证据**
- `API_CONTRACT.md:143,154,157,182`:标准请求/响应契约 `{"mode":"keyset","cursor":"opaque_cursor","limit":20}` + `next_cursor`
- `API_CONTRACT.md:165``cursor` MUST 为不透明字符串,**禁止暴露内部排序字段组合** ✅ 与 OWASP 推荐一致
- `API_CONTRACT.md:378`drf-spectacular `OpenApiParameter("cursor", ...)` 注解
- 客源 / 房源 / 楼盘 / 组织 4 个模块技术方案均同步采用
**剩余 Minor**:尚无 Keyset SQL 模板(含 `WHERE (sort_key, id) < (?, ?)` 的复合键模板)。建议在 `TECH_STACK.md` 新增 §"分页 SQL 模板"章节,给出含 `tenant_schema` schema-search-path 切换 + 复合键的标准实现。
---
### ✅ 历史 M-01测试规范多租户化已修复
**证据**
- `TECH_STACK.md:203,208,211`:明确 TenantClient 强制 + R2/Redis/邮件 Mock
- `测试规范.md:55,69,146,230``TenantClient` 在测试金字塔图、约束章节、请求路径、Mock 策略 4 处统一表述
- 4 个模块技术方案均引用
---
### 🟠 M-12 Celery 多租户 schema 切换无统一封装M-04 拆分)
**文档**`TECH_STACK/客源管理技术方案.md` / `房源管理技术方案.md` / `楼盘管理技术方案.md` / `组织人事技术方案.md`(均声明 `tenant_schema_name` 入参vs `TECH_STACK.md`(无统一规范)
**事实**
- 模块技术方案约定 Celery 任务签名带 `tenant_schema_name: str` 形参,但**无 `with_tenant_context(schema)` 装饰器或基类**。
- 系统设置技术方案虽给出 schema 切换示例(`:28-31`),但未提取为通用规范。
- `core/cache.py` 已规范带前缀,但 ORM 查询的 schema 切换由开发者手写 `connection.set_schema(...)`**漏写不报错**。
**影响**
- Celery worker 在多租户调度下,相邻任务可能因 search_path 残留导致跨租户脏读/脏写。
- 单元测试若忘记设置 schema测试通过但生产出错。
**改进方向**
-`TECH_STACK.md` 新增 §"Celery 多租户规范"
- 强制所有业务 task 用 `@tenant_task(schema_arg="tenant_schema_name")` 装饰器
- 装饰器职责:进入时 `set_schema_to(schema)`,退出/异常时 `set_schema_to_public()`,记录 task_id 与 schema 到结构化日志
- 测试规范补:"Celery 任务测试必须显式 mock schema 切换断言"
---
### 🟠 M-13 R2 路径前缀全局规范不一致M-04 拆分)
**文档**`TECH_STACK/系统管理技术文档.md:521-525`已规范vs 客源/房源/楼盘技术方案(未规范)
**事实**
- 系统管理已统一:`backups/{tenant_schema}/{record_id}.tar.gz` / `exports/{tenant_schema}/{task_id}.zip` / `releases/system/{version}/...`(无 tenant 前缀,公共资源)✅
- 房源 / 客源模块的图片 / 跟进附件 R2 路径**未在文档中给出 key 模板**,仅写"预签名上传"。
- 公开发布包路径无 tenant 前缀(合理:客户端尚未登录),但**生产环境 bucket policy 需明示**:哪些 prefix 是 public-read哪些需要 signed URL。
**影响**
- 跨租户文件越权访问风险(房源图片如果误用全局 prefixA 租户能猜到 B 租户对象 key
- 生命周期策略(如客源跟进附件 90 天清理)无 prefix 难以配置。
**改进方向**
-`TECH_STACK.md` 新增"R2 路径规范"统一表:
```
公共资源 → releases/system/{version}/... public-read
租户 backup → backups/{tenant_schema}/{rid}.tar.gz signed only
租户 export → exports/{tenant_schema}/{tid}.zip signed-24h
房源图片 → media/{tenant_schema}/property/{pid}/{photo_id}.{ext}
跟进附件 → media/{tenant_schema}/follow/{log_id}/{idx}.{ext}
审计归档 → exports/audit/{task_id}.csv signed only
```
- 路径中**禁止出现 tenant_idUUID**,统一用 `tenant_schema_name`,便于跨环境迁移。
---
### 🟠 M-05 89k 数据 < 2 秒列表查询 NFR 仍无性能基准(持续未修)
**文档**`PRD/客源管理/客源管理模块PRD.md` US-CLIENT-002 / `PRD/房源管理/房源管理模块PRD.md` US-PROPERTY-002 NFR列表查询 p95 < 2s89k 数据)
**事实**
- 测试规范未含 p95 / EXPLAIN ANALYZE / pg_stat_statements 集成。
- 无 89k 量级 seed factory仅有单条 fixture
- 无 CI 性能回归任务(如 pgTAP / pytest-benchmark
- AC 中"< 2 秒"实质不可测。
**改进方向**
- 在 `测试规范.md` 增补 §"性能测试"
- seed: `make seed-perf` 灌入 89k 房源 + 200k 客源 + 200 万 follow_logs
- 工具: `pytest-benchmark` + `EXPLAIN (ANALYZE, BUFFERS)` 输出归档
- 阈值: 列表 p95 < 2s / 详情 p95 < 500ms / 写入 p95 < 1s
- CI: nightly 跑一次,回归 > 20% 标 fail
- 优先 instrument 客源/房源列表 API含 keyset 翻第 100 页场景)
---
## 三、DATA_MODEL 审查
### 🔴 B-05 主表乐观锁 `version` 字段全量未实现M-02 升级,连续 3 次未修)
**文档**`DATA_MODEL/DATA_MODEL_PROPERTY.md` / `DATA_MODEL_CLIENT.md` / `DATA_MODEL_COMPLEX.md`
**事实**grep `version|乐观锁|optimistic` 在 properties / clients / complexes 主表 DDL 中 **0 命中**`version` 仅出现在 ENUMS.md 文档版本号、`SystemVersion` 表名、Permission 缓存 key `:perm:version` 等不相关上下文中)。
**业务场景**PRD 多处):
- 房源 PRD双经纪人同时编辑同一房源一人改价、一人改状态
- 客源 PRD录入员 + 跟进经纪人同时编辑客源等级
- 楼盘 PRD4 类锁字段lock_building/lock_room/lock_info/lock_standard_room已建但**无 `lock_version` 触发 update conflict**
**影响**:后写覆盖前写、数据丢失,**89k 房源体量下必然出现**。
**改进方向**
- DDL 增加:
```sql
ALTER TABLE properties ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE clients ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE complexes ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
```
- 应用层:`Model.objects.filter(id=x, version=v_old).update(..., version=F('version')+1)`,受影响行 0 → 抛 `ConflictError`,前端展示"已被他人修改,请刷新后重试"。
- API_CONTRACT.md 增补 `If-Match: <version>` Header 规范PUT/PATCH 必传)。
---
### 🔴 B-06 高写入表分区 DDL 仍未落地M-03 升级,连续 3 次未修)
**文档**`DATA_MODEL/DATA_MODEL_CLIENT.md`follow_logs/ `DATA_MODEL_PROPERTY.md`property_photos/ `DATA_MODEL_PERMISSION.md`permission_change_logs/ `DATA_MODEL_LOGIN.md`login_attempts/ `DATA_MODEL_PUBLIC.md`platform_audit_logs
**事实**grep `PARTITION BY|分区表|partition` 在 DATA_MODEL 全量 0 命中。仅文字"建议月度分区"。
**业务体量**PRD 与 NFR
- `follow_logs`200 万 / 2 年保留期
- `property_photos`89k 房源 × 平均 8 张 ≈ 70 万行
- `login_attempts`:所有登录失败/成功审计
- `platform_audit_logs`:跨租户全平台审计
**影响**单表过大导致索引膨胀、VACUUM 阻塞、按时间窗口归档不可分区操作。**编码后再切分区将停机迁移**,是必须前置的设计决策。
**改进方向**
- DDL 改为:
```sql
CREATE TABLE follow_logs (
id BIGSERIAL,
created_at TIMESTAMPTZ NOT NULL,
...
PRIMARY KEY (id, created_at) -- 分区键必须含 created_at
) PARTITION BY RANGE (created_at);
CREATE TABLE follow_logs_2026_04 PARTITION OF follow_logs
FOR VALUES FROM ('2026-04-01') TO ('2026-05-01');
```
- 增补 Celery 周期任务 `partition_maintenance_task`(每月最后一天):自动建下月分区 + drop 超出保留期分区。
- DATA_MODEL.md 增 §"分区策略"统一表(保留期 / 分区粒度 / 维护任务)。
---
### 🟠 M-14 ORM 数据范围统一封装规范缺失B-03 残留)
**文档**`DATA_MODEL/DATA_MODEL_PERMISSION.md:143-145, 414-455`
**事实**
- `ScopeQueryBuilder` 已实现(含 `is_protected` 二次 AND 规则)。
- 但**未在 TECH_STACK 中强制要求"所有业务 QuerySet 必须经过 ScopeQueryBuilder"**。
- 模块技术方案 view 层示例代码直接 `Property.objects.filter(...)`,可绕过权限控制。
**影响**:开发新功能时漏接 ScopeQueryBuilder → 越权读取,且测试不易发现。
**改进方向**
- TECH_STACK 增补"ORM 数据范围强制规范"
- 业务 Model 不暴露默认 `objects` Manager统一暴露 `scoped(staff)` 入口
- 写一个 lint rulepylint plugin / pre-commit禁止业务模块直接调用 `<Model>.objects.<query>`
- 测试规范补"权限边界测试矩阵":每个 Model 至少 3 caseown / department / cross_department denied
---
### 🟡 N-02 楼盘价格走势 / 市场报盘M-07/M-08 降级)
历史 M-07/M-08 已写明"P2 不做",本期降为 Minor。
---
### 🟡 N-03 数据保留与归档策略M-12 降级)
`platform_audit_logs` / `follow_logs` 在 PRD 中提到"2 年保留",但 DATA_MODEL 无对应 Celery 归档任务定义。建议在 B-06 分区落地后顺带补全 archive job。
---
## 四、安全审查(含多租户 / 权限 / 审计)
### 🟠 M-06 客户端发布无签名校验 / 防降级(持续未修)
**文档**`PRD/发布管理/客户端发布管理模块PRD.md:165,198,284,347` / `TECH_STACK.md:119`
**事实**
- 端点 `GET /api/client/updates/latest/` 公开(合理)。
- `download_url` 走 R2 / CDN 公开(合理)。
- 完整性校验仅 SHA256仅防偶然篡改不防 MITM 主动替换)。
- **无代码签名Authenticode / OS-level codesign**、**无服务端响应签名**、**无版本号单调递增校验(防降级)**。
**改进方向**
- 升级响应 JSON 增加 `signature` 字段HMAC-SHA256密钥服务端持有客户端校验签名后再 fetch download_url。
- `electron-updater` 配合 `publisherName`Windows Authenticode在 CI 用代码签名证书签 EXE。
- 客户端本地存"已安装版本 N",若服务端返回版本 < N**拒绝降级**(除非配置允许 force_downgrade=true 由后端控制)。
---
### 🟠 M-11 加密密钥管理 / 轮换 SOP 仍未补(持续未修)
**文档**`TECH_STACK/系统管理技术文档.md:877`(仅"密钥通过 Docker Secret 注入"一句)
**事实**
- `core/encryption.py` 中央加密 helper 已声明(散见模块技术方案)。
- **缺**主密钥KEK轮换流程、字段加密密钥DEK版本号设计、密钥泄露应急吊销 + 全量字段重新封装、生产-staging 密钥隔离。
**改进方向**
- 在 `TECH_STACK.md` 新增 §"密钥管理 SOP"
- 三层结构环境主密钥KMS / sops + age → 应用 KEK启动时加载 → 字段 DEKper-row 或 per-column
- DDL 加密字段必须含 `key_version SMALLINT NOT NULL`
- 季度轮换 + 异常吊销 runbook
- 短期(无 KMS方案`age` + `sops` 加密 secrets 文件,运维流程文档化。
---
### 🟠 M-14 ORM 数据范围(详见 §三)
---
## 五、UI/UX 审查
### 🟠 M-09 UI 设计覆盖率与复杂组件深度(部分修复)
**文档**`UI_DESIGN/`11 份 markdown + 11 份 HTML 原型 + `UI_设计任务总表.md`/ `UI_SYSTEM/`3 份)
**事实**
- ✅ 已覆盖:客源列表 / 客源详情 / 客源新增 / 客源编辑 / 房源列表 5 类原型HTML + Markdown 双版本)。
- ❌ 仍缺:
- 楼盘管理(详情 / 新增 / 锁字段交互)
- 权限管理(权限树 / 数据范围编辑器 / 五档下拉子集)
- 系统配置lookup_items 编辑抽屉 / 必填规则配置)
- 组织人事org tree / 员工卡)
- 发布管理(升级表单 / 灰度名单 / 进度面板)
- ❌ UI_SYSTEM 复杂组件规范深度仍不足虚拟滚动列表89k 房源必需)、批量操作面板、抽屉表单嵌套规则、文件上传批量、富权限树。
**改进方向**
- 把 UI_DESIGN 11 份 task 按 PRD 优先级排进 Phase 1客源已齐→ 房源详情 → 楼盘 → 权限 → 系统配置;
- UI_SYSTEM 增补"复杂组件清单"5 项,每项给出 Alpine.js + HTMX 实现范本;
- 89k 房源列表必须用虚拟滚动或固定窗口(如 PageDown 分页HTMX 按 keyset cursor 局部刷新。
---
## 六、TASK ↔ 文档交叉验证
### 🟡 N-04 系统配置 Cache InvalidationB-01 残留)
详见 §一。
---
## 七、汇总 Action Items
| # | 等级 | 编号 | Action | 责任 | 建议完成时间 | 编码门禁 |
|---|------|------|--------|------|--------------|----------|
| 1 | 🔴 | B-05 | 主表 `version` 字段 + `If-Match` API 规范 | 架构师 + 后端 Lead | T+3 天 | **Phase 1 启动前** |
| 2 | 🔴 | B-06 | 5 张高写入表 `PARTITION BY RANGE` DDL + 分区维护 Celery 任务 | 架构师 + DBA | T+5 天 | **Phase 1 启动前** |
| 3 | 🟠 | M-05 | 性能基准测试方案seed 89k + pytest-benchmark + p95 阈值) | 测试 Lead | T+7 天 | Phase 1 内 |
| 4 | 🟠 | M-06 | 客户端发布签名 + 防降级HMAC + Authenticode | 安全 + 发布运维 | T+10 天 | 客户端发布 GA 前 |
| 5 | 🟠 | M-09 | 楼盘 / 权限 / 系统配置 / 组织人事 / 发布 5 模块原型 + 5 复杂组件规范 | UX + 前端 Lead | T+14 天 | 各模块编码前 |
| 6 | 🟠 | M-11 | 密钥管理 SOPKEK/DEK/版本/轮换/吊销) | 安全 + 运维 | T+10 天 | 加密字段上线前 |
| 7 | 🟠 | M-12 | `@tenant_task` 装饰器 + Celery 多租户规范文档 | 架构师 | T+5 天 | Celery 任务编码前 |
| 8 | 🟠 | M-13 | R2 路径前缀统一规范表 + bucket policy | 架构师 + 运维 | T+5 天 | R2 上传任务编码前 |
| 9 | 🟠 | M-14 | ORM 数据范围强制 lint + `scoped(staff)` 入口 | 架构师 + 后端 Lead | T+7 天 | Phase 1 内 |
| 10 | 🟡 | N-01 | PRD 文本中文枚举 → ENUMS 锚点全量替换 | PM | T+3 天 | 编码前清零 |
| 11 | 🟡 | N-04 | 系统配置 Cache Invalidation 主动失效路径补充 | 后端 Lead | T+5 天 | US-SETTING-001 编码前 |
| 12 | 🟡 | N-02/N-03 | 楼盘走势/数据归档策略 | PM + DBA | Phase 2 | 非阻塞 |
---
## 八、Review 结论
### 编码门禁Phase 1 启动前必清零)
**🔴 Blocker2 项必修)**
1. **B-05** 主表 `version` 乐观锁字段 —— 涉及 properties / clients / complexes DDL + API_CONTRACT 增补 `If-Match` Header
2. **B-06** 5 张高写入表分区 DDL + 分区维护任务 —— 后期切分需停机,必须前置
### 整体判断
- **本期是历次 Review 进展最大的一次**4 个 Blocker 全部清零1 个 MajorM-01已修复文档体系特别是 PRD ↔ ENUMS ↔ DATA_MODEL建立了真正的"权威源"。
- **剩余 Blocker 集中在 DATA_MODEL 物理设计层面**(并发控制 + 分区),属于"知道但没动"的债务,**修复成本可估、风险可控**,建议本周内打磨完毕。
- **Phase 1 编码可在 B-05 / B-06 修复后立即启动**,其余 9 个 Major 可与编码并行推进,但需在对应模块进入开发前清零(参见上表"编码门禁"列)。
- **下一次 Review 焦点**B-05 / B-06 修复后,应重点审查 M-09UI 覆盖率)+ M-05性能基准以及编码启动后第一波集成测试反馈。
### 文档健康度趋势
| 维度 | 04-25 | 04-26 | 04-28 | 趋势 |
|------|-------|-------|-------|------|
| PRD 完整性 | 60% | 75% | **90%** | ↑↑ |
| DATA_MODEL 严谨性 | 50% | 65% | **80%** | ↑↑ |
| TECH_STACK 横切规范 | 30% | 50% | **70%** | ↑ |
| 测试规范多租户化 | 20% | 40% | **85%** | ↑↑↑ |
| UI/UX 覆盖率 | 5% | 30% | **35%** | ↑(最弱环节) |
| 安全设计 | 40% | 45% | **55%** | ↑M-06/M-11 持续债务) |
---
> **Reviewer 签字**:首席系统设计 ReviewerAI 辅助)
> **下次 Review 建议触发条件**B-05 + B-06 完成 PR 合并后,或 Phase 1 编码启动后第 1 个 Sprint 结束。

View File

@@ -0,0 +1,448 @@
# Fonrey 全量 Review — 登录管理 + 平台管理后台
- **Review 范围**:登录管理模块 + 平台管理后台模块
- **Review 日期**2026-05-02
- **Review 维度**8 维度PRD质量 / PRD↔TECH一致性 / DATA_MODEL / API / UI_SYSTEM / 安全多租户 / 性能扩展 / 遗漏场景)
- **审查文档**
- PRD`PRD_MVP.md``登录管理/用户登录管理模块PRD.md` (v3.0)、`平台管理后台/平台管理后台PRD.md`
- TECH`TECH_STACK.md` (v2.5)、`登录管理技术方案.md` (v4.1)、`平台管理后台技术方案.md``API_CONTRACT.md``测试规范.md`
- DATA_MODEL`DATA_MODEL.md``DATA_MODEL_LOGIN.md``DATA_MODEL_PUBLIC.md``ENUMS.md` (v2.2)
- UI`UI_SYSTEM.md``组件清单.md``组件规范设计.md``UI_DESIGN/登录管理/登录_UI.md``UI_DESIGN/平台管理后台/平台管理后台_UI.md` 及 4 份 HTML 原型
- **严重程度图例**:🔴 Blocker影响交付需立即处理/ 🟠 Major影响质量需在迭代内处理/ 🟡 Minor建议优化
---
## 维度一PRD 质量
### 🔴 P-B-1 平台管理后台 PRD 缺失 OpenAPI 与功能编号体系
- **位置**[平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md) 全文 835 行
- **问题**:用户故事未编号(无 PA-001/PA-002 等可追溯标识),与 [用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) v3.0 已剥离实现细节后的"功能 ID + 验收标准"风格不一致。导致需求→测试用例→Bug 单的可追溯链条断裂。
- **改进方向**:按登录 PRD v3.0 风格补齐编号 (PA-001 ~ PA-NN),每条用户故事附"验收标准 (AC)"小节。
- **责任角色**PM / Product Owner
### 🟠 P-B-2 平台管理后台 PRD 仍混入实现/字段细节
- **位置**[平台管理后台PRD.md L210-L350](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L210-L350) 段落
- **问题**:租户创建/升级/暂停章节出现 `tenant_code``schema_name``status` CHECK 值等数据层概念;与 ADR-20260502-003 "PRD 剥离实现细节"原则违背。
- **改进方向**:按登录 PRD v3.0 模式将字段/状态描述迁出至 DATA_MODEL_PUBLIC.mdPRD 仅保留业务语义("租户进入暂停态后所有用户登录被拒绝")。
- **责任角色**PM + Backend Architect
### 🟠 P-B-3 平台管理员PlatformAdmin"权限矩阵"未量化
- **位置**[平台管理后台PRD.md L40-L60, L520-L560](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L40-L60) 与 [DATA_MODEL_PUBLIC.md L189-L250](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L189-L250) `platform_admins`
- **问题**PRD 提到 `super_admin` / `ops` / `support` 三种角色,但未列"角色 × 操作 × 资源"矩阵。技术方案与 DATA_MODEL 也未补齐。
- **改进方向**:在 PRD 增 §权限矩阵小节,列出每条平台操作(创建租户/暂停租户/查看审计日志/发布客户端版本/等)所需角色,并与 `platform_admins.role` 枚举对应。
- **责任角色**PM + 安全负责人
### 🟡 P-L-1 登录 PRD 验收标准粒度偏粗
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) UC-LOGIN-* 段
- **问题**:部分验收标准只描述"成功"路径,未列出所有失败路径覆盖的提示文案(与 [组件规范设计.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_SYSTEM/%E7%BB%84%E4%BB%B6%E8%A7%84%E8%8C%83%E8%AE%BE%E8%AE%A1.md) Toast/Form Error 规范脱节)。
- **改进方向**:每条 UC 补充"异常路径 ×N → 文案 / 状态码"。
- **责任角色**PM
---
## 维度二PRD ↔ TECH 一致性
### 🔴 PT-B-1 创建租户事务边界与回滚补偿未在技术方案落地
- **位置**[平台管理后台PRD.md L122-L170](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L122-L170) vs [平台管理后台技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md)
- **问题**PRD 描述"创建租户 → 建 schema → 跑 migration → 创建 Tenant Admin → 发欢迎邮件"为一体化流程但技术方案未说明django-tenants `create_tenant` 与 Django 默认事务无法包裹 `CREATE SCHEMA`migration 中途失败、欢迎邮件发送失败的补偿/回滚策略缺失。状态机仅定义 `creating`/`failed`,但谁置位 `failed`、是否清理半成品 schema 未规定。
- **改进方向**:技术方案补"租户创建 Saga"章节:步骤 1-N、每步失败的补偿动作、`failed` 后的人工/定时清理任务。同步在 PRD 注明"创建过程为异步,最终一致"。
- **责任角色**Backend Architect + Platform Ops
### 🟠 PT-B-2 客户端发版灰度策略 PRD/TECH 描述不一致
- **位置**[平台管理后台PRD.md L476-L520](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L476-L520) vs [平台管理后台技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md)
- **问题**PRD 描述"按租户/百分比灰度",但 [DATA_MODEL_PUBLIC.md client_releases L488-L505](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L488-L505) 仅有 `channel``rollout_percent`,无"租户白名单"字段,技术方案对此未澄清。
- **改进方向**:技术方案明确灰度策略对象(租户级 OR 百分比级或两者并存DATA_MODEL 同步增 `rollout_tenant_codes JSONB``client_release_tenants` 关联表。
- **责任角色**Backend Architect + DBA
### 🟠 PT-B-3 平台管理员 MFA 在 PRD 强约束但 TECH 未规定算法/实现
- **位置**[平台管理后台PRD.md L60](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L60)"super_admin 必须 MFA" vs [平台管理后台技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md)、[DATA_MODEL_PUBLIC.md platform_admins L189-L250](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L189-L250)
- **问题**:未定义 MFA 类型TOTP / SMS / WebAuthn、密钥存储位置、登录流程接入点、备份码机制。`platform_admins` 表无 `mfa_secret`/`mfa_enabled` 字段。
- **改进方向**:技术方案选定 TOTPpyotp方案DATA_MODEL 增 `mfa_enabled BOOL``mfa_secret_enc TEXT``mfa_recovery_codes_enc TEXT`PRD 注明备份码生成/重置规则。
- **责任角色**:安全负责人 + Backend Architect
### 🟠 PT-L-1 登录 PRD "首次登录强制改密" 与 TECH 实现路径未对齐
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) "is_initial_password" + [DATA_MODEL_LOGIN.md](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md) `user_accounts.is_initial_password` + [登录管理技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md) v4.1
- **问题**PRD 要求"首次登录必须改密才能进入业务",但技术方案未明确:登录 API 返回时如何标记需要改密(专用 HTTP code/Header/JSON flag中间件/装饰器在哪一层拦截HTMX 前端如何重定向。
- **改进方向**:技术方案补 §"初始密码拦截器":登录响应增 `must_change_password: true` 字段;新增 `RequirePasswordChangeMiddleware`HTMX 通过 `HX-Redirect` 跳转 `/account/change-password`
- **责任角色**Backend Architect + Frontend Lead
### 🟡 PT-L-2 账户锁定阈值 PRD 与 TECH 描述存在微差
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) §账户锁定 vs [DATA_MODEL_LOGIN.md L411-L423](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L411-L423)Redis 计数器说明)
- **问题**PRD 写"连续 5 次失败锁定 30 分钟"DATA_MODEL 注释也说 5 次,但 [登录管理技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md) 未将阈值/窗口/键名作为可配置项明示,存在硬编码风险。
- **改进方向**:技术方案显式列出 settings`LOGIN_FAIL_THRESHOLD=5``LOGIN_LOCK_DURATION_MIN=30`、Redis key `login_fail:{tenant}:{username}`
- **责任角色**Backend Architect
---
## 维度三DATA_MODEL数据模型
### 🔴 D-1 `public.platform_audit_logs.result` 大小写违反 ENUMS.md 规范
- **位置**[ENUMS.md L70-L72](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/ENUMS.md#L70-L72) vs [DATA_MODEL_PUBLIC.md L274-L275](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L274-L275)
- **问题**ENUMS.md 规定 `success`/`failed`lower_snake_case文件首部 L10 强制要求DDL 实际为 `CHECK (result IN ('SUCCESS','FAILED'))` DEFAULT `'SUCCESS'`。前端 enum_labels、查询过滤、报表全部错位。
- **改进方向**DDL 改为小写并执行迁移 `UPDATE platform_audit_logs SET result = lower(result)`;同步 enum_labels fixture。
- **责任角色**DBA + Backend Architect
### 🔴 D-2 `public.export_tasks.status` `done` vs ENUMS `success` 不一致
- **位置**[ENUMS.md L102-L106](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/ENUMS.md#L102-L106) vs [DATA_MODEL_PUBLIC.md L351-L353](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L351-L353)
- **问题**ENUMS 已迁移为 `success`(注明"原 `done`,已迁移"DDL 仍为 `CHECK (status IN ('pending','in_progress','done','failed'))``backup_records.status` 已用 `success`,与之分裂。
- **改进方向**DDL CHECK + DEFAULT 改为 `success`,迁移脚本 `UPDATE export_tasks SET status='success' WHERE status='done'`
- **责任角色**DBA
### 🟠 D-3 ENUMS.md 缺失 `tenants.suspended_reason` 的 `license_expired`
- **位置**[ENUMS.md L55-L59](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/ENUMS.md#L55-L59) vs [DATA_MODEL_PUBLIC.md L115](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L115)
- **问题**DDL CHECK 已包含 `license_expired`ENUMS.md 仅列 `overdue/violation/requested/other`。前端文案/报表无法对该值取值。
- **改进方向**ENUMS.md 补 `license_expired`,记录变更 ADR同步 enum_labels。
- **责任角色**ENUMS.md 维护者(架构 Atlas
### 🟠 D-4 ENUMS.md 缺失 `login_attempts.failure_reason` 的 OTP 相关值
- **位置**[ENUMS.md L168-L174](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/ENUMS.md#L168-L174) vs [DATA_MODEL_LOGIN.md L220-L224, L266-L274](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L220-L224)
- **问题**DDL/Model choices 含 `wrong_otp`/`otp_expired`ENUMS.md 漏写。
- **改进方向**ENUMS.md 补两个值。
- **责任角色**ENUMS.md 维护者
### 🟠 D-5 `user_accounts.phone_enc / phone_hash` 业务必填但 DB 可空
- **位置**[用户登录管理模块PRD.md L31-L33](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md#L31-L33) vs [DATA_MODEL_LOGIN.md L80-L81](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L80-L81)
- **问题**PRD 规定 `username` 等于手机号且必填,但 `phone_enc TEXT NULL``phone_hash VARCHAR(64) NULL`。导入/数据修复时可能写入不一致数据,且 `phone_hash` 唯一性索引(若有)可能失效。
- **改进方向**:业务确认后将 `phone_hash` 改 NOT NULL普通员工或改用 `username``phone_hash` 计算源在应用层强约束 + 触发器保证一致性。
- **责任角色**accounts 模块负责人 + DBA
### 🟠 D-6 `client_heartbeats` 无分区策略
- **位置**[DATA_MODEL_PUBLIC.md L568-L609](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L568-L609)
- **问题**:心跳表为高频写表(按 PRD 推算每客户端每 5 分钟一条),无 RANGE 分区,长期会变成 TB 级单表。
- **改进方向**:按 `received_at` 月度 RANGE 分区;保留 90 天,老分区归档至冷库或删除。
- **责任角色**DBA
### 🟠 D-7 `platform_audit_logs.payload_summary` 缺全文索引
- **位置**[DATA_MODEL_PUBLIC.md L260-L290](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L260-L290)
- **问题**PRD 要求平台审计日志支持关键字搜索,但 `payload_summary` 仅 B-Tree 索引,无 GIN/tsvector 索引。
- **改进方向**:增 `CREATE INDEX ON platform_audit_logs USING GIN (to_tsvector('simple', payload_summary))`
- **责任角色**DBA
### 🟡 D-8 跨 schema 操作规范未沉淀到 DATA_MODEL.md 头部
- **位置**[DATA_MODEL.md](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL.md) 总纲
- **问题**django-tenants 下不可建跨 schema FK但 README 未明示该约定,新人可能误建外键。
- **改进方向**DATA_MODEL.md 增 §跨 schema 规范小节。
- **责任角色**Data Model Owner
---
## 维度四API 契约
### 🔴 A-B-1 平台管理后台核心端点未在 API_CONTRACT.md 出现
- **位置**[API_CONTRACT.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/API_CONTRACT.md) vs [平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md)
- **问题**:平台后台所述创建租户/暂停租户/发布客户端版本/查看审计等 API 均未在契约文档定义;前后端无对接基线。
- **改进方向**API_CONTRACT.md 增 §平台管理后台 端点章节,列出 path/method/请求/响应/错误码。
- **责任角色**Backend Architect + API 文档负责人
### 🟠 A-L-1 登录端点错误码未对齐 ENUMS `failure_reason`
- **位置**[API_CONTRACT.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/API_CONTRACT.md) login 端点 vs [ENUMS.md L168-L174](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/ENUMS.md#L168-L174)
- **问题**API 返回错误码与 `login_attempts.failure_reason` 枚举无映射表,客户端无法根据错误码呈现差异化文案。
- **改进方向**:增"错误码 ↔ failure_reason ↔ 用户文案"三列对照表。
- **责任角色**Backend Architect + 安全负责人
### 🟠 A-B-2 客户端心跳/版本检查 API 无幂等与限流约定
- **位置**[API_CONTRACT.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/API_CONTRACT.md) vs [平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md) §客户端版本管理
- **问题**:心跳/版本检查为高频公网入口,未规定 `Idempotency-Key`、限流阈值(每客户端 N 次/分钟)、签名校验。
- **改进方向**API_CONTRACT 补限流 + HMAC 签名(基于 client_id + secret
- **责任角色**Backend Architect + 安全
### 🟡 A-G-1 全局 API 错误响应结构未统一
- **位置**[API_CONTRACT.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/API_CONTRACT.md)
- **问题**:示例中部分接口错误体为 `{detail: "..."}`、部分为 `{code, message, errors[]}`,前端难以统一错误处理。
- **改进方向**:统一为 RFC 7807 Problem Details 或自定义 `{code, message, details}` 结构。
- **责任角色**Backend Architect
---
## 维度五UI / UI_SYSTEM
### 🟠 U-B-1 平台后台 UI 设计未引用 `组件清单.md` 中已定义组件
- **位置**[UI_DESIGN/平台管理后台/平台管理后台_UI.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_DESIGN/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0_UI.md) + [平台管理后台_UI.html](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_DESIGN/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0_UI.html) vs [组件清单.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_SYSTEM/%E7%BB%84%E4%BB%B6%E6%B8%85%E5%8D%95.md)
- **问题**HTML 原型直接写裸 Tailwind 类,未与组件清单中的 `<button>` / `<table>` / `<modal>` 规范关联。前端实现易产生样式漂移。
- **改进方向**UI 设计文档每个区块标注引用组件 ID如 "DataTable v1"HTML 原型用占位 class 体现组件契约。
- **责任角色**Frontend Lead + UI Designer
### 🟠 U-L-1 登录 UI 缺失"账户锁定"与"密码过期"专用状态页
- **位置**[UI_DESIGN/登录管理/登录_UI.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_DESIGN/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%99%BB%E5%BD%95_UI.md) + 3 份 HTML 原型
- **问题**PRD 描述了账户锁定、密码过期、首次登录强制改密 3 类状态,但 UI 设计仅覆盖登录、账密、重置密码 3 种页面。
- **改进方向**:补"已锁定""密码过期"状态页或在登录页定义 inline 提示规范。
- **责任角色**UI Designer + Frontend Lead
### 🟡 U-G-1 UI_SYSTEM 缺无障碍A11y规范
- **位置**[UI_SYSTEM.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_SYSTEM/UI_SYSTEM.md)
- **问题**:未规定 ARIA、键盘导航、对比度门槛。
- **改进方向**:增 §A11y 章节WCAG 2.1 AA 基线)。
- **责任角色**UI Designer
### 🟡 U-G-2 HTML 原型与 `组件规范设计.md` 间距/色板未对齐
- **位置**[平台管理后台_UI.html](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_DESIGN/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0_UI.html) vs [组件规范设计.md](file:///mnt/d/Workspace/nexus/Project/fonrey/UI_SYSTEM/%E7%BB%84%E4%BB%B6%E8%A7%84%E8%8C%83%E8%AE%BE%E8%AE%A1.md)
- **问题**:原型出现规范外的 `gray-750`、不规则间距 `p-7`
- **改进方向**:原型严格使用 design token间距 4/8/12/16/24/32
- **责任角色**UI Designer
---
## 维度六:安全 & 多租户隔离
### 🔴 S-1 Tenant Admin 初始密码可能明文邮件下发
- **位置**[平台管理后台PRD.md L122-L136](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L122-L136) + [DATA_MODEL_LOGIN.md L468-L469](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L468-L469)(示例 `Fonrey@2025`
- **问题**欢迎邮件包含初始密码明文DATA_MODEL 给出系统统一默认密码示例。一旦邮箱被截获或日志记录到邮件正文,全部新租户首批管理员凭据泄露。
- **改进方向**:禁止邮件明文密码;改用一次性安全 reset token10-30 分钟有效,单次使用),强制首次登录改密;离线场景由平台运维通过加密 PDF 单独交付。
- **责任角色**:安全负责人 + PM + accounts 模块
### 🔴 S-2 平台管理员PlatformAdmin会话与租户用户共用 Cookie/Session 边界未明示
- **位置**[平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md) + [登录管理技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md)
- **问题**:未规定平台后台域名/Cookie 域、Session 隔离机制;存在租户 schema 用户登录态与平台后台越权同会话风险。
- **改进方向**:平台后台独立子域 `admin.fonrey.com`Cookie 域分离;中间件根据 `request.tenant.schema_name == 'public'` 强校验只允许 `platform_admins` 表用户进入。
- **责任角色**:安全负责人 + Backend Architect
### 🟠 S-3 短信 OTP 速率/防刷未定量
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) §短信验证码 + [DATA_MODEL_LOGIN.md sms_otp_records](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md)
- **问题**:未定义"同号码 X 分钟内最多 N 次"、"同 IP 每日上限"、"图形/滑块校验前置"等防刷规则。
- **改进方向**技术方案补防刷策略DATA_MODEL 增 IP 维度计数器或在 Redis 中维护。
- **责任角色**:安全负责人
### 🟠 S-4 `phone_enc` 加密密钥轮换与 `phone_hash` salt 策略缺失
- **位置**[DATA_MODEL_LOGIN.md L80-L81](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L80-L81) + [TECH_STACK.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/TECH_STACK.md)
- **问题**未规定加密算法AES-GCM、密钥来源KMSenv、轮换流程、`phone_hash` 是否加 pepper。
- **改进方向**:技术方案补 §字段级加密:算法/Key 来源/轮换 SOP`phone_hash` 使用 HMAC-SHA256 + 全局 pepper不入库
- **责任角色**:安全负责人 + Backend Architect
### 🟠 S-5 平台后台审计日志覆盖范围未量化
- **位置**[平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md) + [DATA_MODEL_PUBLIC.md platform_audit_logs](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md)
- **问题**哪些操作必须审计、保留期限、防篡改append-only / 哈希链)未规定。
- **改进方向**:列出"必审操作清单"(创建/暂停/删除租户、平台账号增删改、发版、备份恢复);表加 `prev_hash`/`row_hash` 形成哈希链或转写至追加型存储。
- **责任角色**:安全负责人
### 🟡 S-6 跨 schema 查询风险未在技术方案标注
- **位置**[DATA_MODEL.md](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL.md) + [TECH_STACK.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/TECH_STACK.md)
- **问题**django-tenants 下错误的 schema 切换会导致跨租户数据泄露。
- **改进方向**:技术方案增 §"禁止在 view 中直接 `connection.set_schema_to_public()`",必须经 service 层封装。
- **责任角色**Backend Architect
---
## 维度七:性能 & 扩展性
### 🟠 PF-1 `client_heartbeats` 写入风暴未做缓冲
- **位置**[DATA_MODEL_PUBLIC.md client_heartbeats](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md#L568-L609) + [平台管理后台技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md)
- **问题**:每条心跳直写 PGN×M 客户端规模下会成为 IO 瓶颈。
- **改进方向**:心跳先写 Redis Stream / Kafka再批量落表每分钟一次同时配合 D-6 分区。
- **责任角色**Backend Architect
### 🟠 PF-2 平台后台租户列表 / 审计日志列表 缺分页/索引设计
- **位置**[平台管理后台技术方案.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88.md) + [DATA_MODEL_PUBLIC.md tenants/platform_audit_logs](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md)
- **问题**:未明示 keyset pagination 或 LIMIT/OFFSET审计日志按时间倒序查询无 `(created_at DESC, id DESC)` 复合索引。
- **改进方向**:明确分页方案;增复合索引;列表 API 默认 page_size 上限。
- **责任角色**Backend Architect + DBA
### 🟡 PF-3 登录端点未规定 P95 延迟 SLO
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) + [测试规范.md](file:///mnt/d/Workspace/nexus/Project/fonrey/TECH_STACK/%E6%B5%8B%E8%AF%95%E8%A7%84%E8%8C%83.md)
- **问题**:无性能 SLO如登录 P95 < 300ms
- **改进方向**PRD 增非功能需求小节,列出关键端点 SLO测试规范补压测脚本。
- **责任角色**PM + QA
---
## 维度八:遗漏场景 & 边界
### 🔴 X-1 租户删除 / 数据导出 / GDPR 类合规流程缺失
- **位置**[平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md)
- **问题**:仅描述 `pending_delete``deleted` 状态,未覆盖:删除前数据导出/客户签字回执;平台管理员双人复核;保留期内可撤销。
- **改进方向**:新增"租户注销 SOP"用户故事;技术方案补软删除 + 冷却期 + 双人审批流程。
- **责任角色**PM + 安全 + 合规
### 🟠 X-2 客户端版本回滚 / 灰度中止流程缺失
- **位置**[平台管理后台PRD.md L476-L520](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L476-L520)
- **问题**:发版有,但回滚/灰度中止缺定义。
- **改进方向**:补 UC "回滚到上一稳定版本"、"立即停灰度"两条用户故事。
- **责任角色**PM
### 🟠 X-3 备份恢复演练流程缺失
- **位置**[平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md) §备份 + [DATA_MODEL_PUBLIC.md backup_records](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md)
- **问题**:仅描述备份生成,缺"恢复到独立 schema 验证"演练流程;恢复操作风险(覆盖现网)未提示。
- **改进方向**:增"恢复到隔离 schema 演练"用户故事;技术方案补恢复执行规范(必须先恢复至 `restore_*` 临时 schema 校验)。
- **责任角色**PM + DBA
### 🟠 X-4 Tenant Admin 失联 / 转移流程未定义
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md) + [平台管理后台PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md)
- **问题**Tenant Admin 离职/换号场景下,由谁/如何重置或迁移管理员未定义。
- **改进方向**PRD 增"平台运维代运营重置 Tenant Admin"流程,需双人复核 + 审计。
- **责任角色**PM + 安全
### 🟡 X-5 同租户多设备登录策略未明示
- **位置**[用户登录管理模块PRD.md](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md)
- **问题**:是否允许同账号多端在线、互踢策略未定义。
- **改进方向**PRD 明示"允许并发"或"后登挤掉前登"。
- **责任角色**PM
### 🟡 X-6 跨场景同义概念差异(租户开通 → Tenant Admin 创建)
- **位置**[平台管理后台PRD.md L122-L136](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0/%E5%B9%B3%E5%8F%B0%E7%AE%A1%E7%90%86%E5%90%8E%E5%8F%B0PRD.md#L122-L136) vs [DATA_MODEL_LOGIN.md L468-L469](file:///mnt/d/Workspace/nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md#L468-L469) vs [用户登录管理模块PRD.md L31-L33](file:///mnt/d/Workspace/nexus/Project/fonrey/PRD/%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86/%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97PRD.md#L31-L33)
- **问题**:三处对"初始 Tenant Admin"的用户名/初始密码/手机号来源描述用词不统一PRD 平台后台说"系统生成"DATA_MODEL 给出 `Fonrey@2025` 默认值,登录 PRD 说 username = `tenants.contact_phone`)。
- **改进方向**:以登录 PRD v3.0 描述为准username = contact_phone初始密码由系统生成 + 一次性 reset token其他文档同步修正。
- **责任角色**PM + Data Model Owner
---
## 汇总行动列表(按优先级)
| # | 严重 | 维度 | 问题 | 责任角色 | 建议截止 |
| --- | --- | ---------- | -------------------------------------------------------------- | ----------------------- | ---- |
| 1 | 🔴 | 安全 | S-1 禁止欢迎邮件明文初始密码,改一次性 reset token | 安全 + PM + accounts | 立即 |
| 2 | 🔴 | 安全 | S-2 平台后台独立子域/Cookie 域 + 平台账号会话隔离中间件 | 安全 + Backend Architect | 立即 |
| 3 | 🔴 | DATA_MODEL | D-1 `platform_audit_logs.result` 大写改小写 + 数据迁移 | DBA | 当周 |
| 4 | 🔴 | DATA_MODEL | D-2 `export_tasks.status` `done``success` + 迁移 | DBA | 当周 |
| 5 | 🔴 | API | A-B-1 API_CONTRACT 补齐平台后台所有端点 | Backend Architect | 当周 |
| 6 | 🔴 | PRD↔TECH | PT-B-1 创建租户 Saga + 补偿事务 | Backend Architect + Ops | 当周 |
| 7 | 🔴 | PRD质量 | P-B-1 平台后台 PRD 引入 PA-NNN 编号体系 + AC | PM | 当周 |
| 8 | 🔴 | 遗漏场景 | X-1 租户注销 SOP + 双人复核 + 冷却期 | PM + 安全 + 合规 | 下迭代 |
| 9 | 🟠 | DATA_MODEL | D-3/D-4 ENUMS.md 补 `license_expired`/`wrong_otp`/`otp_expired` | ENUMS 维护者 | 当周 |
| 10 | 🟠 | DATA_MODEL | D-5 `phone_enc/phone_hash` NOT NULL + 数据清洗 | accounts + DBA | 下迭代 |
| 11 | 🟠 | DATA_MODEL | D-6 `client_heartbeats` 月度分区 + 90 天保留 | DBA | 下迭代 |
| 12 | 🟠 | DATA_MODEL | D-7 `payload_summary` 增 GIN 全文索引 | DBA | 当周 |
| 13 | 🟠 | PRD↔TECH | PT-B-2 客户端发版灰度策略澄清 | Backend Architect | 下迭代 |
| 14 | 🟠 | PRD↔TECH | PT-B-3 平台 MFA 选型 + DATA_MODEL 字段补充 | 安全 + Architect | 下迭代 |
| 15 | 🟠 | PRD↔TECH | PT-L-1 首次登录强制改密拦截器实现路径 | Backend + Frontend | 当周 |
| 16 | 🟠 | API | A-L-1 错误码 ↔ failure_reason 对照表 | Backend + 安全 | 当周 |
| 17 | 🟠 | API | A-B-2 心跳/版本检查接口限流 + HMAC | Backend + 安全 | 下迭代 |
| 18 | 🟠 | UI | U-B-1 平台后台 UI 引用组件清单组件 ID | UI + Frontend | 下迭代 |
| 19 | 🟠 | UI | U-L-1 补"账户锁定/密码过期"状态页 | UI + Frontend | 当周 |
| 20 | 🟠 | 安全 | S-3 短信 OTP 防刷规则量化 | 安全 | 下迭代 |
| 21 | 🟠 | 安全 | S-4 字段级加密 SOP + `phone_hash` pepper | 安全 + Architect | 下迭代 |
| 22 | 🟠 | 安全 | S-5 平台审计日志哈希链 + 必审操作清单 | 安全 | 下迭代 |
| 23 | 🟠 | 性能 | PF-1 心跳 Redis Stream 缓冲 + 批量落表 | Architect | 下迭代 |
| 24 | 🟠 | 性能 | PF-2 列表分页/复合索引 | Architect + DBA | 当周 |
| 25 | 🟠 | PRD质量 | P-B-2 平台 PRD 剥离实现细节 | PM + Architect | 下迭代 |
| 26 | 🟠 | PRD质量 | P-B-3 PlatformAdmin 权限矩阵 | PM + 安全 | 当周 |
| 27 | 🟠 | 遗漏 | X-2 版本回滚 / 中止灰度 UC | PM | 下迭代 |
| 28 | 🟠 | 遗漏 | X-3 备份恢复演练流程 | PM + DBA | 下迭代 |
| 29 | 🟠 | 遗漏 | X-4 Tenant Admin 重置/迁移流程 | PM + 安全 | 下迭代 |
| 30 | 🟡 | DATA_MODEL | D-8 跨 schema 规范沉淀至 README | Data Model Owner | 下迭代 |
| 31 | 🟡 | API | A-G-1 错误响应结构统一 | Architect | 下迭代 |
| 32 | 🟡 | UI | U-G-1 / U-G-2 A11y 规范 + 设计 token 严控 | UI Designer | 下迭代 |
| 33 | 🟡 | 性能 | PF-3 关键端点 SLO + 压测脚本 | PM + QA | 下迭代 |
| 34 | 🟡 | PRD↔TECH | PT-L-2 锁定阈值 settings 可配置 | Architect | 当周 |
| 35 | 🟡 | PRD质量 | P-L-1 登录 PRD 异常路径细化 | PM | 下迭代 |
| 36 | 🟡 | 遗漏 | X-5 多设备登录策略明示 | PM | 下迭代 |
| 37 | 🟡 | 遗漏 | X-6 跨文档对"初始 Tenant Admin 创建"用词统一 | PM + Data Model Owner | 当周 |
**统计**:🔴 Blocker 8 项 / 🟠 Major 21 项 / 🟡 Minor 8 项,合计 37 项。
---
## 结论
**整体评估**
- **登录管理模块**PRD v3.0 已按 ADR-20260502-003 完成实现细节剥离,整体结构与 DATA_MODEL_LOGIN 大致对齐;主要风险集中在 (a) 手机号字段约束与 PRD 必填语义不一致 (S-1/D-5)、(b) 首次登录改密拦截缺技术方案落地 (PT-L-1)、(c) OTP 防刷规则未量化 (S-3)。
- **平台管理后台模块**:处于"PRD 形成中"阶段,存在较多 Blocker缺端点契约 (A-B-1)、缺创建租户 Saga (PT-B-1)、缺平台账号会话隔离 (S-2)、缺欢迎邮件密码安全策略 (S-1)、PRD 缺编号体系 (P-B-1)、PRD 仍混入实现细节 (P-B-2)。这些项必须在进入开发前解决,否则将引发跨团队反复对齐成本。
- **跨文档一致性**枚举命名规范lower_snake_case已被 ENUMS.md 强约束,但 DATA_MODEL_PUBLIC 的 DDL 多处未对齐D-1/D-2/D-3/D-4属于"规范已立但落地未跟",建议立即统一。
**建议下一步动作**
1. 召开 1 次跨角色 Review 会议PM + Architect + 安全 + DBA + UI + Frontend就上表 8 项 Blocker 形成处理排期。
2. 由 ENUMS.md 维护者在 1 周内发布 v2.3,吸纳 D-3/D-4并附数据迁移 SQL 草案D-1/D-2
3. 由 PM 在 1 周内完成平台管理后台 PRD 编号化与剥离实现细节的改版,进入下一轮 Review。
---
## 附录
### A. 审查范围内文档清单
- PRD`PRD_MVP.md``登录管理/用户登录管理模块PRD.md` (v3.0, 2026-05-02)、`平台管理后台/平台管理后台PRD.md` (835 行)
- TECH`TECH_STACK.md` (v2.5, 2026-04-30)、`登录管理技术方案.md` (v4.1)、`平台管理后台技术方案.md` (986 行)、`API_CONTRACT.md``测试规范.md`
- DATA_MODEL`DATA_MODEL.md``DATA_MODEL_LOGIN.md` (526 行)、`DATA_MODEL_PUBLIC.md` (1049 行)、`ENUMS.md` (v2.2, 786 行)
- UI`UI_SYSTEM/UI_SYSTEM.md``组件清单.md``组件规范设计.md``UI_DESIGN/登录管理/登录_UI.md``UI_DESIGN/平台管理后台/平台管理后台_UI.md``登录_UI.html``登录_账号密码_UI.html``登录_重置密码_UI.html``平台管理后台_UI.html`
### B. 用户原文路径校正
-`Project/fonrey/PRD/系统管理/系统管理模块PRD.md` → ✅ 实际为 `Project/fonrey/PRD/系统配置/系统配置模块PRD.md`**不在本次 Review 范围**
-`Project/fonrey/PRD/平台管理后台/平台管理后台PRD` → ✅ 实际带 `.md` 后缀
-`Project/fonrey/UI_DESIGN/登录_UI.md` → ✅ 实际位于 `Project/fonrey/UI_DESIGN/登录管理/登录_UI.md`
### C. 审查执行说明
- 本次 Review 由 4 个并行 explore agent 完成证据收集(登录 8 维度、平台 PRD+TECH、DATA_MODEL_PUBLIC+UI、跨文档枚举/字段/状态机漂移),汇总后按 8 维度去重合并。
- 报告坚持"指出问题 + 给出方向"原则,不重写设计文档内容;如某文档段落实际不完整(如 PT-B-3 MFA 字段缺失),按 Major 报告而非自行补全。
---
## 进度跟踪表PM / 架构师填写)
> **使用说明**
> - **状态**取值:`待启动` / `进行中` / `已完成` / `已验证` / `阻塞` / `搁置`(如搁置请在"备注"列填写理由及决策 ADR ID
> - **处理人**:填写实际负责人姓名/工号
> - **修订位置**:填写本次修订涉及的文档路径 + 章节/行号 + Commit/PR 链接
> - **关联 ADR**:跨模块规则变更必须创建 ADR参考 `ADR.md` 治理规则),格式 `ADR-YYYYMMDD-XXX`
> - **验证证据**:链接到对应的 PR / Commit / 测试用例 ID`TC-FON-XXXXXX`/ Migration 文件
> - **每周更新**:建议每周五由 PM 主持 Review 例会更新本表,并在 `REVIEW/` 目录追加增量 Review
### Blocker 项(🔴 必须立即处理8 项)
| # | ID | 问题摘要 | 责任角色 | 处理人 | 状态 | 计划完成日 | 实际完成日 | 修订位置 | 关联 ADR | 验证证据 | 备注 |
| --- | ------ | ------------------------------------------- | ----------------------- | ----- | ------- | ---------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | ----------------------------------------------------------- |
| 1 | S-1 | 禁止欢迎邮件明文初始密码,改一次性 reset token | 安全 + PM + accounts | Nova | **不修复(设计决策)** | 2026-05-02 | 2026-05-02 | — | — | — | PM 决策:保持现有欢迎邮件含初始密码的设计,不改为 reset token 流程。接受此安全取舍。 |
| 2 | S-2 | 平台后台独立子域 + 平台账号会话隔离中间件 | 安全 + Backend Architect | Atlas | **已完成** | 2026-05-02 | 2026-05-02 | `TECH_STACK/平台管理后台技术方案.md` v1.1 §7.0(新增"平台后台独立子域与会话隔离"专节含域名分离表、Cookie 隔离规则、PlatformAdminSessionMiddleware 代码规范、测试矩阵) | — | 技术方案 v1.1 变更历史 | — |
| 3 | D-1 | `platform_audit_logs.result` 大写改小写 + 数据迁移 | DBA | Atlas | **已完成** | 2026-05-02 | 2026-05-02 | `DATA_MODEL/DATA_MODEL_PUBLIC.md` v1.7 §2.4 CHECK 约束;附录 M.1 迁移脚本 `migration_D1_audit_logs_result_lowercase.sql` | — | DATA_MODEL v1.7 变更历史 | 迁移脚本须在 Django migration 前执行(见附录 M.1 执行顺序说明) |
| 4 | D-2 | `export_tasks.status` `done``success` + 迁移 | DBA | Atlas | **已完成** | 2026-05-02 | 2026-05-02 | `DATA_MODEL/DATA_MODEL_PUBLIC.md` v1.7 §2.5 CHECK 约束;附录 M.2 迁移脚本 `migration_D2_export_tasks_done_to_success.sql` | — | DATA_MODEL v1.7 变更历史 | 迁移脚本须在 Django migration 前执行(见附录 M.2 执行顺序说明) |
| 5 | A-B-1 | API_CONTRACT 补齐平台后台所有端点 | Backend Architect | Atlas | **已完成** | 2026-05-02 | 2026-05-02 | `TECH_STACK/API_CONTRACT.md` v1.2 §12新增"平台管理后台端点附录",涵盖认证 2 项、租户管理 6 项、授权/MFA 3 项、系统配置 3 项、客户端发布 4 项、导出任务 3 项,含请求/响应示例与错误码) | — | API_CONTRACT v1.2 变更历史 | — |
| 6 | PT-B-1 | 创建租户 Saga + 补偿事务 | Backend Architect + Ops | Atlas | **已完成** | 2026-05-02 | 2026-05-02 | `TECH_STACK/平台管理后台技术方案.md` v1.1 §6.1.1(新增"创建租户 Saga 与补偿事务"专节,含 7 步流程状态机、各步骤补偿操作、Celery chord 实现规范、幂等性与重试策略、监控告警要求) | — | 技术方案 v1.1 变更历史 | — |
| 7 | P-B-1 | 平台后台 PRD 引入 PA-NNN 编号体系 + AC | PM | Nova | **已完成** | 2026-05-02 | 2026-05-02 | `PRD/平台管理后台/平台管理后台PRD.md` v1.1 — 全部 11 条用户故事补齐 PA-001 ~ PA-011 编号每条附验收标准AC小节 | — | PRD v1.1 变更历史 | — |
| 8 | X-1 | 租户注销 SOP + 双人复核 + 冷却期 | PM + 安全 + 合规 | Nova | **已完成** | 2026-05-02 | 2026-05-02 | `PRD/平台管理后台/平台管理后台PRD.md` v1.1 — 新增 PA-011 Story E1含 AC-1 发起申请 / AC-2 数据导出前置确认 / AC-3 双人 MFA 复核 / AC-4 30 天冷静期软删除 / AC-5 硬删除;同步更新 §5.1.4、§5.4、§5.5.1 API 清单、§6 权限矩阵、§7 状态机(新增 Pending Cancellation 节点) | — | PRD v1.1 变更历史 | 技术方案 & DATA_MODEL 联动更新待 Atlas 处理Pending Cancellation 状态字段) |
### Major 项(🟠 迭代内处理21 项)
| # | ID | 问题摘要 | 责任角色 | 处理人 | 状态 | 计划完成日 | 实际完成日 | 修订位置 | 关联 ADR | 验证证据 | 备注 |
| --- | ------ | -------------------------------------- | ------------------ | ----- | --- | ----- | ----- | ---- | ------ | ---- | --- |
| 9 | D-3 | ENUMS.md 补 `license_expired` | ENUMS 维护者 | Atlas | 待启动 | | | | | | |
| 10 | D-4 | ENUMS.md 补 `wrong_otp` / `otp_expired` | ENUMS 维护者 | Atlas | 待启动 | | | | | | |
| 11 | D-5 | `phone_enc/phone_hash` NOT NULL + 数据清洗 | accounts + DBA | Atlas | 待启动 | | | | | | |
| 12 | D-6 | `client_heartbeats` 月度分区 + 90 天保留 | DBA | Atlas | 待启动 | | | | | | |
| 13 | D-7 | `payload_summary` 增 GIN 全文索引 | DBA | Atlas | 待启动 | | | | | | |
| 14 | PT-B-2 | 客户端发版灰度策略澄清(租户/百分比) | Backend Architect | Atlas | 待启动 | | | | | | |
| 15 | PT-B-3 | 平台 MFA 选型 + DATA_MODEL 字段补充 | 安全 + Architect | Atlas | 待启动 | | | | | | |
| 16 | PT-L-1 | 首次登录强制改密拦截器实现路径 | Backend + Frontend | Atlas | 待启动 | | | | | | |
| 17 | A-L-1 | 错误码 ↔ failure_reason 对照表 | Backend + 安全 | Atlas | 待启动 | | | | | | |
| 18 | A-B-2 | 心跳/版本检查接口限流 + HMAC 签名 | Backend + 安全 | Atlas | 待启动 | | | | | | |
| 19 | U-B-1 | 平台后台 UI 引用组件清单组件 ID | UI + Frontend | Iris | 待启动 | | | | | | |
| 20 | U-L-1 | 补"账户锁定/密码过期"状态页 | UI + Frontend | Iris | 待启动 | | | | | | |
| 21 | S-3 | 短信 OTP 防刷规则量化 | 安全 | Atlas | 待启动 | | | | | | |
| 22 | S-4 | 字段级加密 SOP + `phone_hash` pepper | 安全 + Architect | Atlas | 待启动 | | | | | | |
| 23 | S-5 | 平台审计日志哈希链 + 必审操作清单 | 安全 | Atlas | 待启动 | | | | | | |
| 24 | PF-1 | 心跳 Redis Stream 缓冲 + 批量落表 | Architect | Atlas | 待启动 | | | | | | |
| 25 | PF-2 | 列表分页keyset+ 复合索引 | Architect + DBA | Atlas | 待启动 | | | | | | |
| 26 | P-B-2 | 平台 PRD 剥离实现细节 | PM + Architect | Nova | 待启动 | | | | | | |
| 27 | P-B-3 | PlatformAdmin 权限矩阵 | PM + 安全 | Nova | 待启动 | | | | | | |
| 28 | X-2 | 客户端版本回滚 / 中止灰度 UC | PM | Nova | 待启动 | | | | | | |
| 29 | X-3 | 备份恢复演练流程(恢复至隔离 schema | PM + DBA | Nova | 待启动 | | | | | | |
| 30 | X-4 | Tenant Admin 重置/迁移流程 | PM + 安全 | Nova | 待启动 | | | | | | |
### Minor 项(🟡 优化建议8 项)
| # | ID | 问题摘要 | 责任角色 | 处理人 | 状态 | 计划完成日 | 实际完成日 | 修订位置 | 关联 ADR | 验证证据 | 备注 |
| --- | ------ | ------------------------------------- | --------------------- | ----- | --- | ----- | ----- | ---- | ------ | ---- | --- |
| 31 | D-8 | 跨 schema 操作规范沉淀至 DATA_MODEL.md README | Data Model Owner | Atlas | 待启动 | | | | | | |
| 32 | A-G-1 | 全局 API 错误响应结构统一 | Architect | Atlas | 待启动 | | | | | | |
| 33 | U-G-1 | UI_SYSTEM 增 A11y 规范WCAG 2.1 AA | UI Designer | Iris | 待启动 | | | | | | |
| 34 | U-G-2 | HTML 原型严控 design token | UI Designer | Iris | 待启动 | | | | | | |
| 35 | PF-3 | 关键端点 SLO + 压测脚本 | PM + QA | Nova | 待启动 | | | | | | |
| 36 | PT-L-2 | 锁定阈值 settings 可配置(去硬编码) | Architect | Atlas | 待启动 | | | | | | |
| 37 | P-L-1 | 登录 PRD 异常路径细化 | PM | Nova | 待启动 | | | | | | |
| 38 | X-5 | 多设备登录策略明示 | PM | Nova | 待启动 | | | | | | |
| 39 | X-6 | 跨文档对"初始 Tenant Admin 创建"用词统一 | PM + Data Model Owner | Nova | 待启动 | | | | | | |
### 进度统计(每周更新)
| 统计日期 | Blocker 已完成 / 总数 | Major 已完成 / 总数 | Minor 已完成 / 总数 | 阻塞项数 | 风险说明 |
|---|---|---|---|---|---|
| 2026-05-02 | 0 / 8 | 0 / 21 | 0 / 9 | 0 | 初始基线 |
| 2026-05-02更新 | 2 / 8 | 0 / 21 | 0 / 9 | 0 | P-B-1 & X-1 已完成Nova技术方案/DATA_MODEL 联动更新待 Atlas 跟进 |
| 2026-05-02Atlas 修复) | 7 / 8 | 0 / 21 | 0 / 9 | 0 | S-2 / D-1 / D-2 / A-B-1 / PT-B-1 已完成Atlas剩余 Blocker S-1 为 PM 设计决策不修复;全部 Blocker 实质性完结 |
| | | | | | |
| | | | | | |
> Minor 项实际为 9 项(编号 31-39原汇总行动列表 Minor 计为 8 项的差异在于 D-8 与 X-6 是否合并归类,本跟踪表按独立处理项展开计 9 项。
### Review 闭环规则
1. 每条 Finding 修订完成后,处理人填写"修订位置 + 验证证据",状态置 `已完成`
2. PM/架构师在每周例会复核:跨模块/跨文档变更必须先创建 ADR`ADR.md`)再改文档,并在"关联 ADR"列填写 ID。
3. QA 在所有依赖 Finding 全部 `已完成` 后,对涉及业务路径执行回归测试,状态置 `已验证`
4. 任何 Finding 在迭代结束仍未启动需在"备注"列说明原因并在下一次 Review 例会重新评估优先级。
5. 本表与 `REVIEW/` 目录后续增量 Review 报告同步:新增 Finding 追加编号40+)继续延续。

View File

@@ -2,10 +2,10 @@
# Fonrey API 契约规范API_CONTRACT
**版本**: 1.1
**适用范围**: 全模块account / permission / property / client / complex / org / setting
**版本**: 1.2
**适用范围**: 全模块account / permission / property / client / complex / org / setting+ 平台管理后台admin
**关联总纲**: `TECH_STACK/TECH_STACK.md`
**最后更新**: 2026-04-28
**最后更新**: 2026-05-02
---
@@ -13,7 +13,8 @@
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充变更历史章节(文档治理) |
| 2026-04-30 | Atlas | 补充"变更历史"章节(文档治理) |
| 2026-05-02 | Atlas | 升至 v1.2:新增 §12 平台管理后台端点附录A-B-1适用范围扩展至 admin 模块 |
## 1. 文档定位与原则
@@ -543,3 +544,109 @@ THEN 两侧完全一致(无多余值,无缺失值,大小写相同)
| **P1 注解补全** | 所有现有视图加 `@extend_schema`,枚举字段用 ChoiceField | `openapi.json``{}` 空 Schema所有端点有 `summary``tags` |
| **P2 契约测试** | schemathesis 纳入 CIPositive 用例全绿 | CI status_code + response_schema 两项检查全 PASS |
| **P3 持续守护** | openapi.json diff 纳入 PR Review枚举值变更同步 enums.py | PR checklist 自动提醒 Schema 变更 |
---
## 12. 平台管理后台端点附录A-B-1 回应)
> **背景**:审核报告 A-B-1 指出 API_CONTRACT 缺少 `/admin/...` 命名空间端点规范,导致 Backend 实现缺乏契约约束。本章补齐平台管理后台(`admin.fonrey.com`)所有端点清单,作为机器可读约束附录。
>
> 适用规则:本章端点遵循第 210 章全局规范;以下特例优先级高于全局规范:
> - 认证Django Session`adminSessionId` Cookie+ CSRF`X-CSRFToken`+ 必要时 MFA Step-up**不使用 JWT / Bearer Token**。
> - 响应类型:`GET` 页面视图返回 `text/html``POST`/`PATCH` 写操作返回 JSON 或 HTMX partial在端点备注中明示
> - 版本控制:`/admin/...` 无版本号前缀;破坏性变更通过 Django View Mixin 灰度。
> - 非法权限访问:统一返回 `403`(不暴露资源是否存在)。
### 12.1 认证端点
| 端点 | 方法 | 鉴权 | 请求 | 成功响应 | 失败响应 | 备注 |
|---|---|---|---|---|---|---|
| `/admin/login/` | GET | 公开 | — | 200 HTML登录表单 | — | 已登录时 302 → `/admin/` |
| `/admin/login/` | POST | 公开 | `username`, `password` | 302 → `/admin/mfa/verify/` | 200 HTML表单 + 错误) | 失败计数写 Redis5 次锁 15 min |
| `/admin/login/mfa/verify/` | GET | session 中有 `pre_mfa_admin_id` | — | 200 HTMLTOTP 输入框) | 302 → `/admin/login/` | 超时 5 min 未提交则清 pre_mfa |
| `/admin/login/mfa/verify/` | POST | session 中有 `pre_mfa_admin_id` | `otp_code` | 302 → `/admin/` | 200 HTML错误/ 429OTP 失败 ≥3 | 成功后写 `admin_sessions`,清 `pre_mfa_admin_id` |
| `/admin/login/mfa/step-up/` | POST | AdminSession | `otp_code` | 200 JSON `{"ok": true}` | 400 JSON `{"error": "invalid_otp"}` | 写 `session.mfa_confirmed_at` + Redis `pub:mfa:stepup:*` |
| `/admin/logout/` | POST | AdminSession | — | 302 → `/admin/login/` | — | 清 `admin_sessions`flush session |
### 12.2 租户管理端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 失败响应 | 备注 |
|---|---|---|---|---|---|---|
| `/admin/tenants/` | GET | AdminSession任意角色 | `?status=`, `?q=`, `?page_cursor=` | 200 HTML租户列表页| — | Keyset 分页;禁止 OFFSET |
| `/admin/tenants/create/` | GET | AdminSessionSUPER/OPS | — | 200 HTML创建表单 | — | — |
| `/admin/tenants/create/` | POST | AdminSessionSUPER/OPS+ CSRF | `tenant_name`, `contact_phone`, `contact_email`, `license_user_limit`, `paid_until` | 302 → `/admin/tenants/<id>/` | 200 HTML表单 + 错误)/ 409tenant_code 冲突) | 写 `tenants``status='provisioning'`)后入队 `provision_tenant` Saga |
| `/admin/tenants/<uuid:id>/` | GET | AdminSession | — | 200 HTML详情页 | 404 | — |
| `/admin/tenants/<uuid:id>/edit/` | GET | AdminSessionSUPER/OPS | — | 200 HTML编辑表单 | 404 | — |
| `/admin/tenants/<uuid:id>/edit/` | POST | AdminSessionSUPER/OPS+ CSRF | 可编辑字段name / contact_* / license_user_limit / paid_until | 302 → 详情页 | 200 HTML表单 + 错误)| 写 `platform_audit_logs``UPDATE_TENANT_INFO`|
| `/admin/tenants/<uuid:id>/suspend/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | `suspended_reason`, `suspended_until`(可选) | 200 JSON `{"ok": true}` + HTMX partial | 400 / 409已暂停| `suspended_reason` 枚举见 `ENUMS.md`;写审计 |
| `/admin/tenants/<uuid:id>/resume/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | — | 200 JSON `{"ok": true}` + HTMX partial | 409非 suspended 状态)| 写审计 |
| `/admin/tenants/<uuid:id>/cancel/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | `reason` | 200 JSON `{"ok": true}` | 409非 active 状态)| 进入 `pending_cancellation`;冷静期 30 天 |
| `/admin/tenants/<uuid:id>/hard-delete/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up5 min 内)+ 双人复核 token | `confirm_tenant_name`, `reviewer_token` | 200 JSON `{"ok": true}` | 400名称不符/ 403token 无效)/ 409非 pending_cancellation + 30d 状态)| 入队 `hard_delete_tenant`;写审计 `HARD_DELETE_TENANT` |
| `/admin/tenants/<uuid:id>/update-license/` | POST | AdminSessionSUPER/OPS+ CSRF | `paid_until`, `license_user_limit` | 200 JSON `{"ok": true}` | 400参数非法| 写审计 `UPDATE_LICENSE` / `UPDATE_LICENSE_USER_LIMIT` |
| `/admin/tenants/<uuid:id>/export/` | POST | AdminSessionSUPER/OPS+ CSRF | `export_format``csv`/`json`| 202 JSON `{"task_id": "..."}` | — | 入队 `run_export`;写 `export_tasks``status='pending'` |
| `/admin/tenants/<uuid:id>/export/<uuid:task_id>/status/` | GET | AdminSession | — | 200 JSON `{"status": "pending"\|"in_progress"\|"success"\|"failed", "download_url": null\|"..."}` | 404 | HTMX 轮询端点;终态时移除 `hx-trigger` |
### 12.3 平台管理员账号端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 备注 |
|---|---|---|---|---|---|
| `/admin/admins/` | GET | AdminSessionSUPER | — | 200 HTML管理员列表 | — |
| `/admin/admins/create/` | POST | AdminSessionSUPER+ CSRF | `username`, `email`, `role` | 302 → 列表页 | 写审计 `CREATE_PLATFORM_ADMIN` |
| `/admin/admins/<uuid:id>/edit/` | POST | AdminSessionSUPER+ CSRF | `role`, `is_active` | 302 → 列表页 | 写审计 `UPDATE_PLATFORM_ADMIN_ROLE` |
| `/admin/admins/<uuid:id>/deactivate/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | — | 302 → 列表页 | 清对应 `admin_sessions`;写审计 `DEACTIVATE_PLATFORM_ADMIN` |
| `/admin/admins/<uuid:id>/reset-password/` | POST | AdminSessionSUPER+ CSRF | — | 200 JSON `{"ok": true}` | 发初始密码邮件;写审计 |
### 12.4 IP 白名单端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 备注 |
|---|---|---|---|---|---|
| `/admin/ip-whitelist/` | GET | AdminSessionSUPER | — | 200 HTML白名单列表 | — |
| `/admin/ip-whitelist/add/` | POST | AdminSessionSUPER+ CSRF | `cidr`, `label`, `expires_at`(可选)| 302 → 列表页 | 清 Redis `pub:ipwl:active` |
| `/admin/ip-whitelist/<uuid:id>/toggle/` | POST | AdminSessionSUPER+ CSRF | `is_active` | 200 JSON `{"ok": true}` | 清 Redis `pub:ipwl:active` |
| `/admin/ip-whitelist/<uuid:id>/delete/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | — | 302 → 列表页 | 清 Redis `pub:ipwl:active`;写审计 |
### 12.5 客户端版本发布端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 备注 |
|---|---|---|---|---|---|
| `/admin/releases/` | GET | AdminSession | — | 200 HTML版本列表 | — |
| `/admin/api/client-releases/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | `version`, `platform`, `arch`, `release_type`, `artifact`(文件上传)| 201 JSON版本对象| 校验 SemVer入队 checksum + scan |
| `/admin/api/client-releases/<uuid:pk>/` | PATCH | AdminSessionSUPER+ CSRF | `status`, `release_notes`, `force_update`, `min_required_version` | 200 JSON更新后对象| 状态机约束见 `平台管理后台技术方案.md §5.2` |
| `/admin/api/client-releases/<uuid:pk>/rollback/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up | — | 200 JSON `{"ok": true}` | 原子切换 published写审计 `ROLLBACK_CLIENT_RELEASE` |
### 12.6 备份与恢复端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 备注 |
|---|---|---|---|---|---|
| `/admin/backups/` | GET | AdminSessionSUPER/OPS | — | 200 HTML备份列表 | — |
| `/admin/backups/trigger/` | POST | AdminSessionSUPER+ CSRF | `backup_type``full`/`incremental`| 202 JSON `{"task_id": "..."}` | 入队 `run_backup` |
| `/admin/backups/<uuid:id>/status/` | GET | AdminSession | — | 200 JSON `{"status": "...", "size_bytes": ...}` | HTMX 轮询端点 |
| `/admin/backups/<uuid:id>/restore/` | POST | AdminSessionSUPER+ CSRF + MFA Step-up5 min 内)+ 双人复核 token | `confirm_text`, `reviewer_token` | 202 JSON `{"task_id": "..."}` | 高危操作;入队 `run_restore`;写审计 `RESTORE_BACKUP` |
### 12.7 平台审计日志端点
| 端点 | 方法 | 鉴权 | 请求要点 | 成功响应 | 备注 |
|---|---|---|---|---|---|
| `/admin/audit-logs/` | GET | AdminSessionSUPER/OPS | `?action_type=`, `?operator_id=`, `?target_id=`, `?from=`, `?to=`, `?page_cursor=` | 200 HTML审计列表| Keyset 分页;只读,无写操作 |
| `/admin/audit-logs/<uuid:id>/` | GET | AdminSessionSUPER/OPS | — | 200 HTML详情| — |
### 12.8 仪表盘端点(统计只读)
| 端点 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
| `/admin/dashboard/` | GET | AdminSession任意角色 | 总览页(读 Redis 缓存) |
| `/admin/dashboard/stats/` | GET | AdminSession | HTMX 局刷统计块;读 `pub:dashboard:stats` 缓存 |
| `/admin/dashboard/version-distribution/` | GET | AdminSession | 版本分布图;转发至 `/api/release/v1/metrics/version-distribution/` |
### 12.9 端点完整性守护规则
> 本节端点清单必须与 `平台管理后台技术方案.md §4` 保持同步。新增端点必须同时更新本表和技术方案;删除/重命名端点必须先创建 ADR格式 `ADR-YYYYMMDD-XXX`,本文件"变更历史"行追加记录。
AI agent 实现时验证词:
```
GIVEN 本附录第 12.112.8 节的端点清单
WHEN 开发者实现或修改任意 /admin/... 端点
THEN 端点鉴权方式、请求字段、成功状态码、失败状态码与本附录完全一致;
任何缺失端点视为 A-B-1 级 Blocker
```

View File

@@ -2,7 +2,7 @@
# Fonrey 平台管理后台技术方案
**版本**: v1.0
**版本**: v1.1
**项目**: Fonrey 房产经纪管理系统
**模块**: 平台管理后台(`apps/admin_console` + `apps/release`
**关联 PRD**: [`PRD/平台管理后台/平台管理后台PRD.md`](../PRD/平台管理后台/平台管理后台PRD.md)v1.0
@@ -19,6 +19,7 @@
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-05-02 | Sisyphus | 初版:合并原『客户端发布管理技术方案.md』与原『系统管理技术文档.md』统一三大维度技术选型 / 页面路由表 / API 设计),新增 `ADR-20260502-002` |
| 2026-05-02 | Atlas | v1.1:新增 §7.0 平台后台独立子域与会话隔离S-2新增 §6.1.1 创建租户 Saga 与补偿事务PT-B-1|
---
@@ -710,6 +711,186 @@ HX-Trigger: {"fonrey:toast":{"type":"info","message":"导出任务已提交"}}
| 任务 | 触发场景 | 队列 | 重试 | 失败处理 |
|---|---|---|---|---|
| `provision_tenant` | 创建租户后异步执行 schema 创建 + 迁移 + 默认数据 | `admin_ops` | 不重试 | 标记 `tenants.status='failed'`,事务回滚,邮件告警 |
### 6.1.1 创建租户 Saga 与补偿事务PT-B-1 回应)
> **背景**:审核报告 PT-B-1 指出,`provision_tenant` 任务跨越"DB 行写入 → schema 创建 → 迁移 → 发送欢迎邮件"多个步骤,任意步骤失败若无补偿事务,会导致 `tenants` 表存在悬空行、schema 孤儿或账号不一致。本节定义完整 Saga 流程及每步补偿动作。
#### Saga 步骤与补偿矩阵
| 步骤 # | 动作 | 成功后状态 | 补偿动作(失败时回滚) |
|---|---|---|---|
| **S1** | 写入 `public.tenants``status='provisioning'`+ 写审计行 | DB 行存在 | 将 `status` 改为 `'failed'`**不删行**(保留审计溯源) |
| **S2** | `CREATE SCHEMA {schema_name}` | schema 已创建 | `DROP SCHEMA {schema_name} CASCADE`(若存在) |
| **S3** | `django-tenants migrate --schema={schema_name}` | 所有 migration 应用完成 | `DROP SCHEMA {schema_name} CASCADE`schema 已损坏,丢弃重建) |
| **S4** | 写入租户 schema 默认数据(角色、系统配置等) | 默认数据就绪 | 同 S3 补偿(整个 schema 丢弃) |
| **S5** | 在 `{schema_name}.users` 创建初始 Tenant Admin 账号 | 账号可用 | 同 S3 补偿(账号随 schema 丢弃) |
| **S6** | 更新 `public.tenants.status = 'active'` | 租户对外可用 | 将 `status` 改为 `'failed'`;发送平台告警(已运行 S2S5 资源已清理) |
| **S7** | 异步发送欢迎邮件(`send_welcome_email` | 邮件入队 | 仅记录失败日志 + Sentry 告警;**不回滚整个 Saga**(邮件失败不影响租户可用性) |
> **原则**
> - S1S6 为"原子序列",任一步失败必须逆序执行已完成步骤的补偿。
> - S7 为"幂等尾步骤",独立重试,不触发 Saga 回滚。
> - 补偿动作本身不可再失败——若补偿失败(如 DROP SCHEMA 超时),写入 `platform_audit_logs``action_type='PROVISION_COMPENSATION_FAILED'`)并触发 PagerDuty 告警,由运维人工干预。
#### `provision_tenant` Celery 任务实现
```python
# apps/admin_console/tasks/provision.py
from celery import shared_task
from django.db import transaction, connection
from django_tenants.utils import schema_context, get_tenant_model
import logging
logger = logging.getLogger("provision")
@shared_task(bind=True, acks_late=True, autoretry_for=(), max_retries=0)
def provision_tenant(self, tenant_id: str):
"""
创建租户 Saga。
不重试max_retries=0——失败后由运维根据审计日志判断是否重新触发。
"""
from apps.admin_console.models import Tenant
from apps.admin_console.services import audit_service
tenant = Tenant.objects.get(id=tenant_id)
completed_steps = []
try:
# S1: tenants 行已在 View 层写入status='provisioning'),记录已完成
completed_steps.append("S1_row_written")
# S2: CREATE SCHEMA
_create_schema(tenant)
completed_steps.append("S2_schema_created")
# S3: migrate
_run_migrations(tenant)
completed_steps.append("S3_migrated")
# S4: 默认数据
_seed_default_data(tenant)
completed_steps.append("S4_seeded")
# S5: 初始 Tenant Admin
_create_initial_admin(tenant)
completed_steps.append("S5_admin_created")
# S6: 激活
with transaction.atomic():
tenant.status = "active"
tenant.save(update_fields=["status", "updated_at"])
audit_service.write_audit(
action_type="CREATE_TENANT",
target_type="Tenant",
target_id=str(tenant.id),
result="success",
)
completed_steps.append("S6_activated")
# S7: 欢迎邮件(幂等尾步骤,独立重试,不纳入 Saga 回滚)
from apps.admin_console.tasks.notifications import send_welcome_email
send_welcome_email.apply_async(
kwargs={"tenant_id": tenant_id},
countdown=5,
retry=True,
max_retries=5,
)
except Exception as exc:
logger.exception("provision_tenant failed at steps=%s tenant=%s", completed_steps, tenant_id)
_compensate(tenant, completed_steps, exc)
raise # 保留 Celery 任务失败状态,触发 Sentry
def _create_schema(tenant):
from django_tenants.utils import get_public_schema_name
from django.db import connection
with connection.cursor() as cur:
schema = tenant.schema_name
# 幂等:若 schema 已存在(上次 Saga 补偿不完整),先 DROP 再 CREATE
cur.execute(f"DROP SCHEMA IF EXISTS {schema} CASCADE")
cur.execute(f"CREATE SCHEMA {schema}")
def _run_migrations(tenant):
from django.core.management import call_command
call_command("migrate_schemas", schema_name=tenant.schema_name, interactive=False, verbosity=0)
def _seed_default_data(tenant):
with schema_context(tenant.schema_name):
from apps.admin_console.seeds import seed_tenant_defaults
seed_tenant_defaults(tenant)
def _create_initial_admin(tenant):
with schema_context(tenant.schema_name):
from apps.account.services import account_service
account_service.create_initial_admin(
tenant=tenant,
phone=tenant.contact_phone,
)
def _compensate(tenant, completed_steps: list, exc: Exception):
"""
逆序执行已完成步骤的补偿动作。
"""
from apps.admin_console.services import audit_service
from django.db import connection
# S2S5若 schema 已创建,丢弃整个 schema
if any(s in completed_steps for s in ("S2_schema_created", "S3_migrated", "S4_seeded", "S5_admin_created")):
try:
with connection.cursor() as cur:
cur.execute(f"DROP SCHEMA IF EXISTS {tenant.schema_name} CASCADE")
logger.info("compensation: dropped schema %s", tenant.schema_name)
except Exception as comp_exc:
logger.error("compensation FAILED (DROP SCHEMA): %s", comp_exc)
audit_service.write_audit(
action_type="PROVISION_COMPENSATION_FAILED",
target_type="Tenant",
target_id=str(tenant.id),
result="failed",
error_message=str(comp_exc),
)
# 发 PagerDuty 告警
from apps.admin_console.alerts import trigger_pagerduty
trigger_pagerduty(
title=f"provision_tenant compensation failed: {tenant.schema_name}",
body=str(comp_exc),
)
# S1将 tenants 行标记为 failed不删行保留审计溯源
try:
tenant.status = "failed"
tenant.save(update_fields=["status", "updated_at"])
audit_service.write_audit(
action_type="CREATE_TENANT",
target_type="Tenant",
target_id=str(tenant.id),
result="failed",
error_message=str(exc),
)
except Exception as comp_exc:
logger.error("compensation FAILED (mark tenant failed): %s", comp_exc)
```
#### 幂等性保证
- `_create_schema` 前先 `DROP SCHEMA IF EXISTS ... CASCADE`,确保重新触发 Saga 时不因 schema 残留而报错。
- `provision_tenant` 任务 ID 绑定 `tenant_id`;同一 `tenant_id` 若任务已在 `PROGRESS` / `SUCCESS` 状态View 层拒绝重复入队。
- `create_initial_admin` 内部以 `phone` 为唯一键做 `get_or_create`,幂等安全。
#### 可观测性
| 观测点 | 实现 |
|---|---|
| Saga 步骤进度 | `task.update_state(state='PROGRESS', meta={'step': step_name})` |
| 最终状态 | `platform_audit_logs``action_type='CREATE_TENANT'`, `result='success'/'failed'` |
| 补偿失败告警 | `action_type='PROVISION_COMPENSATION_FAILED'` + PagerDuty |
| 任务耗时监控 | Celery Flower + Prometheus `celery_task_runtime_seconds{name="provision_tenant"}` |
| `auto_resume_suspended` | Beat 每 10 min 扫描 `suspended_until <= NOW()` | `admin_ops` | 3 次 / 60s | Sentry 告警 |
| `purge_pending_delete` | Beat 每天 03:00 扫描冷静期到期 | `admin_ops` | 不重试 | 标记 `failed_to_purge` |
| `hard_delete_tenant` | 视图触发 | `admin_ops` | 不重试 | 部分删除标记 + 告警 |
@@ -836,6 +1017,159 @@ def is_enabled(tenant, flag_key: str, *, user=None) -> bool:
## 7. 安全与合规
### 7.0 平台后台独立子域与会话隔离S-2 回应)
> **背景**:审核报告 S-2 指出平台管理员PlatformAdmin会话与租户用户会话若共用 Cookie 域,存在越权同会话风险。本节明确隔离边界与实施机制。
#### 7.0.1 域名分离
| 角色 | 域名 | 说明 |
|---|---|---|
| 租户业务用户 | `*.fonrey.com`(各租户子域) | django-tenants 按 Host 路由至租户 schema |
| 平台管理后台 | `admin.fonrey.com` | 独立 server block物理分离 Cookie 域 |
| 客户端 API | `app.fonrey.com` | 客户端运行时 API独立 server block |
#### 7.0.2 Cookie 隔离配置
```python
# settings/admin.py
SESSION_COOKIE_DOMAIN = "admin.fonrey.com" # 严格限定,不允许 .fonrey.com 通配
SESSION_COOKIE_SECURE = True # HTTPS only
SESSION_COOKIE_HTTPONLY = True # 禁止 JS 访问
SESSION_COOKIE_SAMESITE = "Strict" # 阻止跨站携带
SESSION_COOKIE_NAME = "adminSessionId" # 与租户域 sessionid 命名隔离
CSRF_COOKIE_DOMAIN = "admin.fonrey.com"
```
> 租户业务侧 `SESSION_COOKIE_NAME = "sessionid"`;两侧 Cookie 名和 Domain 双重隔离,即使浏览器同时打开两个域名,也不会互相携带。
#### 7.0.3 `AdminSessionMiddleware` 会话隔离中间件
每次请求到达 `admin.fonrey.com` 时,中间件执行以下校验序列:
```python
# apps/admin_console/middleware.py
class AdminSessionMiddleware:
"""
会话隔离守门中间件。
必须放在 MIDDLEWARE 列表中 SessionMiddleware 之后、
所有 View 处理之前。
"""
EXEMPT_PATHS = {
"/admin/login/",
"/admin/mfa/setup/",
"/admin/mfa/verify/",
"/health/",
}
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.path not in self.EXEMPT_PATHS:
self._enforce_isolation(request)
return self.get_response(request)
def _enforce_isolation(self, request):
"""
三层校验:
1. schema 必须是 public租户 schema 不得进入)
2. session 中必须存在 platform_admin_id
3. admin_sessions 记录必须存在且未过期
失败时 fail-closed → 302 跳登录页,同时清空 session。
"""
from django_tenants.utils import get_public_schema_name
from django.db import connection
# 1. schema 隔离:只允许 public schema 进入后台
if connection.schema_name != get_public_schema_name():
self._reject(request, "non-public schema access denied")
return
# 2. session 中必须有 platform_admin_id
admin_id = request.session.get("platform_admin_id")
if not admin_id:
self._reject(request, "no platform_admin_id in session")
return
# 3. admin_sessions 记录有效性(滚动续期)
from apps.admin_console.models import AdminSession
from django.utils import timezone
session = AdminSession.objects.filter(
admin_id=admin_id,
session_key=request.session.session_key,
is_active=True,
expires_at__gt=timezone.now(),
).first()
if not session:
self._reject(request, "admin session expired or revoked")
return
# 4. 滚动续期:每次合法请求把 expires_at 向后延 30 min
session.expires_at = timezone.now() + timedelta(minutes=30)
session.save(update_fields=["expires_at"])
# 5. 把 admin 对象注入 request供 View 直接使用
request.platform_admin = session.admin
@staticmethod
def _reject(request, reason: str):
import logging
from django.http import HttpResponseRedirect
logging.getLogger("security").warning(
"AdminSessionMiddleware rejected: %s | path=%s | ip=%s",
reason, request.path, request.META.get("REMOTE_ADDR"),
)
request.session.flush() # 清空 session防止残留
# 注raise 方式在 MIDDLEWARE 中无效,直接修改 request._reject 标记
request._admin_session_rejected = True
def process_view(self, request, view_func, view_args, view_kwargs):
if getattr(request, "_admin_session_rejected", False):
from django.shortcuts import redirect
return redirect("/admin/login/")
return None
```
#### 7.0.4 Nginx 物理防线
```nginx
# /etc/nginx/conf.d/admin.fonrey.com.conf
server {
listen 443 ssl http2;
server_name admin.fonrey.com;
# IP 白名单(与应用层 AdminIPWhitelistMiddleware 双重防线)
include /etc/nginx/conf.d/admin_ip_whitelist.conf;
deny all;
# 禁止租户子域访问 /admin/ 路径(防跨域探测)
if ($host ~* "^(?!admin\.).*\.fonrey\.com$") {
return 404;
}
location / {
proxy_pass http://gunicorn_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
#### 7.0.5 安全回归测试要点
| 场景 | 期望结果 |
|---|---|
| 使用租户用户 Cookie 访问 `admin.fonrey.com` | `AdminSessionMiddleware` 拒绝302 → 登录页 |
| 使用平台管理员 Cookie 访问租户域 | Cookie Domain 不匹配,浏览器不携带,鉴权失败 |
| `*.fonrey.com` 任意 Host 访问 `/admin/...` | Nginx 404`if $host` 规则) |
| Session 超过 30 min 无活动后访问 | `expires_at` 超时中间件拒绝302 → 登录页 |
| `connection.schema_name != 'public'` 下访问 | 中间件拒绝302 → 登录页 |
### 7.1 认证与会话
| 项 | 要求 |

View File

@@ -1,63 +0,0 @@
# Fonrey P0 UI 设计任务总表(追踪版)
> 目标:让 `PRD/TASK.md` 中 P0 任务都有对应 UI 设计,并按统一流程逐个落地。
> 协作方式:**先 UI.md → 再静态页 HTML → 你评审反馈 → 我修改并回写 UI.md**。
---
## 1) 状态字段定义(统一)
- `待设计`:还未开始产出 UI.md
- `设计中`:正在输出/修改 UI.md
- `待评审`UI.md 或静态页已提交,等待你反馈
- `修改中`:根据你反馈进行迭代
- `已完成`UI.md 与静态页均通过评审并归档
---
## 2) 单任务标准流程(固定)
1. 读取对应 PRD/TASK/现有 UI_SYSTEM 规范与竞品截图(你提供)
2. 产出该任务 `*_UI.md`(信息架构、字段、状态、交互、异常态、组件映射)
3. 基于 UI.md 产出静态页 `*.html`
4. 你评审静态页并给反馈
5. 我按反馈修改静态页 + 回写 UI.md
6. 该任务标记为 `已完成`
---
## 3) P0 缺口任务(按优先级执行)
| 序号 | 优先级 | 模块 | 覆盖 US | UI.md 目标文件 | 竞品截图参考 | HTML 目标文件 | 当前状态 | 下一步 |
| --- | ---- | ----------- | --------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------ | ---- | ---------------------------- |
| 01 | P0-A | 登录管理 | US-ACCOUNT-001~003 | `UI_DESIGN/登录管理/登录_UI.md` | | `UI_DESIGN/登录_UI.html` | 待评审 | 你评审登录 UI.md + 静态页,给我反馈我再迭代 |
| 02 | P0-A | 房源管理(新增) | US-PROPERTY-001 | `UI_DESIGN/房源管理/新增房源_UI.md` | | `UI_DESIGN/新增房源_UI.html` | 已完成 | 已完成评审迭代(壳层/按钮/结构一致化进入任务03 |
| 03 | P0-A | 房源管理(详情) | US-PROPERTY-003~008 | `UI_DESIGN/房源管理/房源详情_UI.md` | | `UI_DESIGN/房源详情_UI.html` | 待评审 | 你评审房源详情 UI.md + 静态页,给我反馈我再迭代 |
| 04 | P0-B | 楼盘管理(列表) | US-COMPLEX-002 | `UI_DESIGN/楼盘管理/楼盘列表_UI.md` | | `UI_DESIGN/楼盘列表_UI.html` | 待评审 | 你评审楼盘列表 UI.md + 静态页,给我反馈我再迭代 |
| 05 | P0-B | 楼盘管理(详情/维护) | US-COMPLEX-001 | `UI_DESIGN/楼盘管理/楼盘详情_UI.md` | `Project/fonrey/screenshots/楼盘管理/楼盘管理.png`<br>`Project/fonrey/screenshots/楼盘管理/楼栋管理.png`<br> | `UI_DESIGN/楼盘详情_UI.html` | 待评审 | 进入任务06楼盘管理-区域管理) |
| 06 | P0-B | 楼盘管理(区域) | US-COMPLEX-003 | `UI_DESIGN/楼盘管理/区域管理_UI.md` | `Project/fonrey/screenshots/楼盘管理/区域管理.png` | `UI_DESIGN/区域管理_UI.html` | 待评审 | 你评审区域管理 UI.md + 静态页,给我反馈我再迭代 |
| 07 | P0-C | 组织人事 | US-ORG-001~003 | `UI_DESIGN/组织人事管理/组织人事_UI.md` | `Project/fonrey/screenshots/组织人事/组织结构/公司组织结构.png` | `UI_DESIGN/组织人事_UI.html` | 待评审 | 你评审组织人事 UI.md + 静态页,给我反馈我再迭代 |
| 08 | P0-C | 权限管理 | US-PERMISSION-001~005 | `UI_DESIGN/权限管理/权限管理_UI.md`<br>`Project/fonrey/PRD/权限管理/房源-二手租赁.md`<br>`Project/fonrey/PRD/权限管理/客源.md` | `Project/fonrey/screenshots/权限管理/权限-客源-客源.png`<br>``<br>`Project/fonrey/screenshots/权限管理/权限-房源-二手租赁.jpg`<br>`` | `UI_DESIGN/权限管理_UI.html` | 待评审 | 你评审权限管理 UI.md + 静态页,给我反馈我再迭代 |
| 09 | P0-C | 系统配置 | US-SETTING-001-A/B/C | `UI_DESIGN/系统配置/系统配置_UI.md` | `Project/fonrey/screenshots/设置/客源设置-客源参数配置.png`<br>`Project/fonrey/screenshots/设置/房源设置-字段标签设置.png`<br>`Project/fonrey/screenshots/设置/房源设置-字段标签设置-修改字段必填要求.png`<br>`Project/fonrey/screenshots/设置/房源设置-字段标签设置-自定义预设参数.png`<br>`Project/fonrey/screenshots/设置/客源设置-基本配置.jpg` | `UI_DESIGN/系统配置_UI.html` | 待评审 | 你评审系统配置 UI.md + 静态页,给我反馈我再迭代 |
| 10 | P1-C | 系统配置(首页设置) | US-SETTING-010 | `UI_DESIGN/系统配置/首页设置_UI.md` | `Project/fonrey/screenshots/设置/首页设置.png` | `UI_DESIGN/首页设置_UI.html` | 待评审 | 你评审首页设置 UI.md + 静态页,给我反馈我再迭代 |
---
## 4) 已有 UI保留并在后续做回归校对
| 模块 | 现有 UI.md | 当前状态 | 说明 |
| ---- | --------------------------- | ---- | -------------------------------- |
| 客源管理 | `UI_DESIGN/客源管理/新增客源_UI.md` | 已有 | 后续按你反馈可增量调整 |
| 客源管理 | `UI_DESIGN/客源管理/客源列表_UI.md` | 已有 | 后续按你反馈可增量调整 |
| 客源管理 | `UI_DESIGN/客源管理/客源详情_UI.md` | 已有 | 后续按你反馈可增量调整 |
| 客源管理 | `UI_DESIGN/客源管理/编辑客源_UI.md` | 已有 | `US-CLIENT-014` 的新房/租房 Tab 边界待确认 |
| 房源管理 | `UI_DESIGN/房源管理/房源列表_UI.md` | 已有 | 后续按你反馈可增量调整 |
---
## 5) 本周执行节奏(建议)
- 每次只推进 1 个任务单元(避免并行导致反馈混淆)
- 每个任务至少经过 1 轮“静态页评审反馈”再收口
- 每完成 1 个任务,我会即时更新本表状态

View File

@@ -0,0 +1,397 @@
## 角色与背景
你是一名资深首席架构师Principal Engineer拥有大型 B2B SaaS 系统的全链路设计和 Review 经验。
你的核心方法论:**以终为始**——从用户需求出发,验证每一层设计决策是否正确传导,找出断层、矛盾和遗漏。
你的 Review 不是挑错,而是帮助团队在编码前发现最高代价的问题。
**工作目录**`/mnt/d/Workspace/nexus`
**你的职责边界**
- ✅ 负责:跨文档一致性检查、设计风险识别、遗漏场景挖掘、改进建议输出
- ❌ 不负责:重写设计文档、生成代码实现——发现问题后给出改进方向,由对应角色修订
---
## 项目背景
**项目****Fonrey房睿**——面向房地产经纪公司的 B2B SaaS 平台
**多租户模式**django-tenantsPostgreSQL Schema 隔离)
**数据量级**89,000+ 条房源/客源记录
**前端技术**HTMX + Alpine.js + Tailwind CSS❌ 无 React/Vue
**当前阶段****项目设计阶段需求分析80% 技术/数据模型设计50% UI/UX设计还未开始**
---
## 待审查文档清单
请读取以下文档,作为本次 Review 的全部输入:
**产品文档PRD**
- PRD_MVP: `Project/fonrey/PRD/PRD_MVP.md`
- 系统管理PRD: `Project/fonrey/PRD/系统管理/系统管理模块PRD.md`
- 平台管理后台PRD: `Project/fonrey/PRD/平台管理后台/平台管理后台PRD`
**技术文档**
- 项目总TECH_STACK`Project/fonrey/TECH_STACK/TECH_STACK.md`
- 登录管理技术方案:`Project/fonrey/TECH_STACK/登录管理技术方案.md`
- 平台管理后台技术方案:`Project/fonrey/TECH_STACK/平台管理后台技术方案.md`
- API契约规范`Project/fonrey/TECH_STACK/API_CONTRACT.md`
- 测试规范:`Project/fonrey/TECH_STACK/测试规范.md`
**数据模型**
- 项目总DATA_MODEL`Project/fonrey/DATA_MODEL/DATA_MODEL.md`
- 登录DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN`
- 平台管理后台DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md`
- 统一枚举字典:`Project/fonrey/DATA_MODEL/ENUMS.md`
**UI 设计文档**
- UI SYSTEM`Project/fonrey/UI_SYSTEM/UI_SYSTEM.md`
- 组件清单:`Project/fonrey/UI_SYSTEM/组件清单.md`
- 组件设计规范:`Project/fonrey/UI_SYSTEM/组件规范设计.md`
- 模块UI Design:
- `Project/fonrey/UI_DESIGN/登录管理/登录_UI.md`
- `Project/fonrey/UI_DESIGN/平台管理后台/平台管理后台_UI`
**UI 原型页面**
- 总体页面预览: `Project/fonrey/UI_DESIGN/preview.html`
- 登录:`Project/fonrey/UI_DESIGN/登录_UI.html`
- 登录:`Project/fonrey/UI_DESIGN/登录_账号密码_UI.html`
- 登录:`Project/fonrey/UI_DESIGN/登录_重置密码_UI.html`
- 平台管理后台:`Project/fonrey/UI_DESIGN/平台管理后台_UI.html`
**其他参考文档**
- 历史Review报告
---
## Review 范围与重点
- 全量 Review 登录管理模块和平台管理后台模块
---
## Review 维度与输出格式
请按以下 8 个维度逐一审查,每个维度输出:
- **发现的问题**(按严重程度分级)
- **具体位置**(哪份文档、哪个章节、哪条需求/设计)
- **改进建议**(明确的行动方向,指向应由哪个角色修订)
---
## 输出要求
请输出完整 Review 报告,保存至:
`Project/fonrey/REVIEW/REVIEW_【模块名称或"全局"】_【日期】.md`
输出语言:**中文**(技术术语、字段名保留英文)
---
```markdown
# 系统设计 Review 报告
**Review 范围**:【全局 / 具体模块】
**Review 日期**:【当前日期】
**审查人**:首席架构师
**文档版本**:【列出被审查文档的版本号或最后更新日期】
---
## 执行摘要Executive Summary
> 3-5 句话,概括本次 Review 的整体结论:文档质量评估、最高风险项、必须在进入下一阶段前解决的问题。
**整体评估**:【优良 / 合格(有改进空间)/ 存在重大风险(须暂停推进)】
**必须解决Blocker**:共 X 项
**建议改进Major**:共 X 项
**优化建议Minor**:共 X 项
---
## 维度一PRD 质量审查
> 检查需求文档是否清晰、完整、可测试。
### 检查项
- [ ] 每个功能是否有明确的"解决了谁的什么痛点"
- [ ] Non-Goals 是否明确,防止需求蔓延
- [ ] 所有 AC 是否为 Given/When/Then 格式,可被测试验证
- [ ] 边界场景和异常处理是否覆盖完整
- [ ] 优先级P0/P1/P2是否合理P0 范围是否过大
- [ ] 待确认问题Open Questions是否已全部解决
### 发现问题
| 严重程度 | 问题描述 | 位置(文档 + 章节) | 改进建议 | 负责角色 |
|---------|---------|-----------------|---------|---------|
| 🔴 Blocker | | | | PM |
| 🟠 Major | | | | PM |
| 🟡 Minor | | | | PM |
---
## 维度二PRD ↔ TECH_STACK 一致性
> 检查技术方案是否完整覆盖了 PRD 中的功能需求,是否存在技术方案与需求描述冲突。
### 检查项
- [ ] PRD 中所有功能是否都有对应的 API 端点设计
- [ ] PRD 中的权限要求是否在 TECH_STACK 权限体系中体现
- [ ] PRD 中标注"需异步处理"的操作是否都有对应 Celery 任务设计
- [ ] PRD 中的性能指标是否在 TECH_STACK 中有对应实现方案
- [ ] 技术方案是否存在 PRD 未提及的功能(过度实现)
- [ ] 技术方案是否遵守了 PRD 中的业务规则约束
### 发现问题
| 严重程度 | 问题描述 | PRD 位置 | TECH 位置 | 改进建议 | 负责角色 |
|---------|---------|---------|----------|---------|---------|
| 🔴 Blocker | | | | | 架构师 |
| 🟠 Major | | | | | 架构师 |
| 🟡 Minor | | | | | 架构师 |
---
## 维度三DATA_MODEL 设计审查
> 检查数据模型是否正确支撑业务需求,是否存在性能、一致性和扩展性风险。
### 检查项
**完整性**
- [ ] PRD 中所有字段是否都在 DATA_MODEL 中有对应定义
- [ ] 关联关系(一对多/多对多)是否与业务规则一致
- [ ] 软删除字段(`deleted_at`)是否在所有需要的表上存在
- [ ] 多租户隔离是否在所有表上正确实现
**性能**
- [ ] 高频查询场景是否有对应复合索引
- [ ] 文本搜索字段是否使用了 GIN 索引
- [ ] 外键字段是否有索引Django 默认创建,确认没有遗漏)
- [ ] 高增长表是否考虑了分区策略
**一致性**
- [ ] 外键约束的级联策略是否与业务规则一致(如删除楼盘是否应 RESTRICT
- [ ] 必填字段是否设置了 NOT NULL 约束
- [ ] 唯一性约束是否完整(如租户内房源编号唯一)
**安全**
- [ ] 敏感字段(手机号、证件号等)是否标注了加密存储方案
### 发现问题
| 严重程度 | 问题描述 | 位置(表名/字段名) | 影响 | 改进建议 | 负责角色 |
|---------|---------|-----------------|------|---------|---------|
| 🔴 Blocker | | | | | 架构师 |
| 🟠 Major | | | | | 架构师 |
| 🟡 Minor | | | | | 架构师 |
---
## 维度四API 设计审查
> 检查 API 端点设计是否规范、安全、符合 HTMX 交互模式。
### 检查项
**RESTful 规范**
- [ ] URL 命名是否符合 Django URL 约定(小写、连字符)
- [ ] HTTP 方法使用是否正确GET 查询、POST 创建、PUT/PATCH 更新、DELETE 删除)
- [ ] 响应状态码是否语义正确200/201/422/403/404/500
**HTMX 模式**
- [ ] 局部刷新端点是否只返回 HTML Partial不返回完整页面
- [ ] 表单校验失败是否返回 422 + 含错误信息的表单 Partial
- [ ] Toast 触发是否统一通过 `HX-Trigger` 响应头实现
- [ ] 异步任务端点是否立即返回 task_id不阻塞请求
**安全**
- [ ] 所有写操作端点是否有 CSRF 保护
- [ ] 所有端点是否有登录态校验
- [ ] 数据范围是否在视图层做了过滤(防止越权读取其他租户数据)
- [ ] 文件上传端点是否有类型和大小限制校验
**性能**
- [ ] 列表端点是否有分页(防止全量返回)
- [ ] 是否存在 N+1 查询风险(如未使用 `select_related`/`prefetch_related`
### 发现问题
| 严重程度 | 问题描述 | 端点位置 | 改进建议 | 负责角色 |
|---------|---------|---------|---------|---------|
| 🔴 Blocker | | | | 架构师 |
| 🟠 Major | | | | 架构师 |
| 🟡 Minor | | | | 架构师 |
---
## 维度五UI SYSTEM 一致性审查
> 检查 UI System 是否覆盖 PRD 中涉及的所有组件,规范是否在技术约束内可落地。
### 检查项
- [ ] PRD 中涉及的所有页面类型是否在 UI System 中有对应布局模板
- [ ] PRD 中涉及的所有交互组件(弹窗/抽屉/表格/筛选栏)是否有规范定义
- [ ] 状态标签的颜色语义是否与业务状态含义一致
- [ ] HTMX 请求生命周期的加载状态是否完整覆盖
- [ ] UI 规范是否完全在 Tailwind CSS 约束内,无需引入额外 CSS 框架
- [ ] 空状态、错误状态设计是否覆盖所有列表页和详情页
### 发现问题
| 严重程度 | 问题描述 | 位置 | 改进建议 | 负责角色 |
|---------|---------|------|---------|---------|
| 🔴 Blocker | | | | UI/UX |
| 🟠 Major | | | | UI/UX |
| 🟡 Minor | | | | UI/UX |
---
## 维度六:安全与多租户审查
> 检查系统是否在多个层面正确实现了多租户隔离和安全防护。
### 检查项
**多租户隔离**
- [ ] 所有数据库查询是否基于当前租户 Schemadjango-tenants 约束)
- [ ] API 层是否有额外的租户归属校验(防止 URL 参数篡改跨租户访问)
- [ ] 文件存储路径是否包含租户标识,防止不同租户文件路径冲突
- [ ] Celery 异步任务是否正确传递了租户上下文
**认证与授权**
- [ ] 是否有未受保护的公开端点(非故意的)
- [ ] RBAC 权限矩阵是否覆盖了所有操作(查看/新增/编辑/删除)
- [ ] 数据范围控制(如经纪人只能看自己数据)是否在 ORM 层实现,而非视图层
**其他安全**
- [ ] 文件上传是否有 MIME Type 二次校验(不信任前端)
- [ ] 敏感操作(批量删除、导出)是否有额外权限要求或二次确认
- [ ] 是否存在敏感信息泄露风险(如错误信息返回了 SQL 异常详情)
### 发现问题
| 严重程度 | 问题描述 | 影响范围 | 改进建议 | 负责角色 |
|---------|---------|---------|---------|---------|
| 🔴 Blocker | | | | 架构师 |
| 🟠 Major | | | | 架构师 |
| 🟡 Minor | | | | 架构师 |
---
## 维度七:性能与扩展性审查
> 检查在当前数据量级89,000+ 条)和预期增长下,系统设计是否存在性能瓶颈。
### 检查项
**数据库性能**
- [ ] 高频查询是否有合适索引,是否可达到 P95 ≤ 20ms
- [ ] 是否存在可能导致全表扫描的查询(如 LIKE '%keyword%'
- [ ] 分页查询是否使用了高效方案(如 Keyset 分页,而非 OFFSET 分页)
**异步处理**
- [ ] 所有耗时 > 500ms 的操作是否都走了 Celery
- [ ] Celery 任务是否设计了合理的重试策略和超时时间
- [ ] 是否存在大批量操作阻塞 Celery 队列的风险
**缓存策略**
- [ ] 高频读取、低频变更的数据是否有 Redis 缓存
- [ ] 缓存失效策略是否合理,是否存在缓存雪崩风险
**扩展性**
- [ ] 高增长表(跟进记录、操作日志)是否有分区或归档策略
- [ ] 当租户数量增长时Schema 隔离模式是否存在连接池压力
### 发现问题
| 严重程度 | 问题描述 | 预估影响 | 改进建议 | 负责角色 |
|---------|---------|---------|---------|---------|
| 🔴 Blocker | | | | 架构师 |
| 🟠 Major | | | | 架构师 |
| 🟡 Minor | | | | 架构师 |
---
## 维度八:遗漏场景与风险扫描
> 超越文档内容,从系统全局视角识别尚未被任何文档覆盖的潜在风险。
### 典型遗漏场景检查
- [ ] **并发冲突**:多个经纪人同时编辑同一房源,是否有乐观锁或冲突提示?
- [ ] **数据迁移**:是否有历史数据导入需求,格式转换方案是否设计?
- [ ] **第三方依赖故障**Cloudflare R2 不可用时,文件上传如何降级?
- [ ] **Celery 任务堆积**:任务积压时用户如何感知,是否有监控告警?
- [ ] **租户数据导出合规**:租户注销时数据如何导出和清除?
- [ ] **大文件/慢请求超时**nginx 和 Django 的请求超时配置是否合理?
- [ ] **Schema 迁移风险**:大表字段变更是否会导致生产环境长时间锁表?
- [ ] **测试覆盖**:是否有多租户隔离的集成测试?是否有性能基准测试?
### 发现的遗漏场景
| 严重程度 | 场景描述 | 潜在影响 | 改进建议 | 负责角色 |
|---------|---------|---------|---------|---------|
| 🔴 Blocker | | | | |
| 🟠 Major | | | | |
| 🟡 Minor | | | | |
---
## 汇总行动列表Action Items
> 按优先级排列,每项有明确的负责角色和建议完成时间。
### 🔴 Blocker进入下一阶段前必须解决
| # | 问题描述 | 来源维度 | 负责角色 | 建议完成时间 |
|---|---------|---------|---------|------------|
| B-01 | | | | |
### 🟠 Major当前迭代内解决
| # | 问题描述 | 来源维度 | 负责角色 | 建议完成时间 |
|---|---------|---------|---------|------------|
| M-01 | | | | |
### 🟡 Minor纳入 Backlog合适时机处理
| # | 问题描述 | 来源维度 | 负责角色 | 建议完成时间 |
|---|---------|---------|---------|------------|
| N-01 | | | | |
---
## Review 结论
【输出整体评估结论,例如:
"房源管理模块整体设计思路清晰PRD 与 TECH_STACK 对应关系良好。
主要风险集中在数据模型的并发控制(乐观锁缺失)和 API 层多租户校验不完整,
建议在进入测试阶段前解决全部 Blocker 和 Major 问题。"】
---
## 附录:审查方法说明
本次 Review 遵循以下原则:
- **需求可追溯**:每个 API 端点应能追溯到 PRD 中的某条用户故事
- **技术可落地**:技术方案须在当前技术栈约束内实现,不依赖未引入的工具
- **安全左移**:安全问题在设计阶段发现,代价远低于上线后修复
- **明确负责人**每个问题指向具体角色PM / 架构师 / UI/UX避免责任模糊
```
---
## 补充说明
- Review 报告采用**增量追踪**:每次修订文档后可复用本模板重新 Review在报告中注明"已解决"的历史问题
- 如读取某份文档后发现内容不完整(如章节缺失),将缺失内容本身列为 Major 问题,不要自行补全
- 发现设计问题时,给出清晰的改进方向即可,不要在 Review 报告中直接重写文档内容