# 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.md,PRD 仅保留业务语义("租户进入暂停态后所有用户登录被拒绝")。 - **责任角色**: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` 字段。 - **改进方向**:技术方案选定 TOTP(pyotp)方案;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 类,未与组件清单中的 `