# Fonrey 平台管理后台模块测试用例文档(可自动化) > 文档版本:v1.0 > 适用范围:`PRD/平台管理后台/平台管理后台PRD.md` v1.0 > 用例编号范围:`TC-FON-000073` ~ `TC-FON-000152`(全局唯一,共 80 条) > 编号规范:`TEST_CASES/TEST_CASE_ID_SPEC.md` > 关联 ADR:`ADR-20260502-001`(PRD 合并)、`ADR-20260502-002`(TECH 合并)、`ADR-20260430-007`(Heartbeat Upsert + 24h 活跃口径)、`ADR-20260430-008`(SHA-256 强制)、`ADR-20260430-009`(客户端 API 命名空间 `/api/release/...`) --- ## 变更历史 | 日期 | 变更人 | 变更内容 | |---|---|---| | 2026-05-02 | Sisyphus | 初版:覆盖 4 Personas / 11 Stories / 16 页面 / §5.1–§5.7 / §6 角色矩阵 / §7 状态机;登记 TC-FON-000073~000152 | --- ## 1. 目标与原则 1. 本文档用于让工程师直接生成自动化测试代码(HTMX 视图集成测试 + Web E2E + 客户端 API 集成测试)。 2. 每个用例均包含**唯一 ID**与**步骤 ID**(`-SYY`),可直接用于失败定位与报告聚合。 3. 用例覆盖『平台管理后台』PRD 全部 11 条 User Story 的验收标准,并叠加: - §5.6 安全(MFA / IP 白名单 / 会话超时 / 强制登出) - §5.7 审计日志规范(字段、写入、不可变) - §6 角色权限矩阵(Platform Admin / 运营人员 / 只读审计员 三档) - §7 租户状态机(Creating → Active ↔ Suspended → Pending Delete → Deleted) 4. 不覆盖租户业务模块内部(房源/客源/权限)— 那些由各自 TEST_CASES 文档承担。 --- ## 2. 自动化执行与报告要求 - **执行层**: - 后台业务集成(HTMX/JSON 视图):`pytest + pytest-django + TenantClient`(仅 public schema 用例可省略租户切换) - Web E2E:`playwright`(PC 桌面分辨率 ≥ 1280×720) - 客户端 API 集成(`/api/release/...`):`pytest + requests`,使用 device-token 鉴权 - **每步必须输出**:`run_id / test_case_id / step_id / status / expected_result / actual_result / error_message` - **失败时附带**: - Web:截图路径 - 后端:请求/响应快照、SQL 关键日志路径 - Celery:任务 ID 与 Flower 链接 - **CI 门禁**:`TC-FON-000073` ~ `TC-FON-000152` 全量通过才允许合并到主干。 --- ## 3. 端点口径(以 PRD §5.5 + 技术方案 §3/§4 为准) ### 3.1 后台业务命名空间 `/admin/...`(Session + CSRF + TOTP) - 认证/会话:`POST /admin/login/`、`POST /admin/login/mfa/`、`POST /admin/logout/`、`POST /admin/mfa/setup/`、`POST /admin/mfa/confirm/` - 租户:`GET /admin/tenants/`、`POST /admin/tenants/`、`GET /admin/tenants/{id}/`、`PATCH /admin/tenants/{id}/`、`POST /admin/tenants/{id}/suspend/`、`POST /admin/tenants/{id}/resume/`、`POST /admin/tenants/{id}/soft-delete/`、`POST /admin/tenants/{id}/restore/`、`POST /admin/tenants/{id}/hard-delete/`、`POST /admin/tenants/{id}/license/`、`POST /admin/tenants/{id}/license/user-limit/`、`GET /admin/tenants/{id}/onboarding.pdf` - 用户:`GET /admin/tenants/{id}/users/`、`POST /admin/tenants/{id}/users/{uid}/reset-password/`、`POST /admin/tenants/{id}/admins/` - 备份/导出/恢复:`POST /admin/tenants/{id}/backups/`、`GET /admin/tenants/{id}/backups/`、`POST /admin/tenants/{id}/restore/`、`POST /admin/tenants/{id}/exports/` - 升级:`POST /admin/system/versions/upgrade/`、`POST /admin/system/versions/rollback/`、`GET /admin/system/versions/` - 客户端版本:`GET /admin/api/client-releases/`、`POST /admin/api/client-releases/`、`PATCH /admin/api/client-releases/{id}/`、`POST /admin/api/client-releases/{id}/publish/`、`POST /admin/api/client-releases/{id}/offline/`、`POST /admin/api/client-releases/{id}/rollback/`、`POST /admin/api/client-releases/force-update/`、`GET /admin/api/client-releases/distribution/` - 审计:`GET /admin/audit-logs/`、`GET /admin/audit-logs/export.csv` - 管理员:`GET /admin/settings/admins/`、`POST /admin/settings/admins/`、`POST /admin/settings/admins/{id}/deactivate/`、`POST /admin/settings/admins/{id}/force-logout/`、`POST /admin/settings/ip-whitelist/` ### 3.2 客户端运行时命名空间 `/api/release/v1/...`(设备 Token) - `GET /api/release/v1/latest?platform=win32&arch=x64` - `POST /api/release/v1/heartbeat` > 注:测试代码生成与请求构造必须使用以上路径;任何路径偏差视为缺陷。 --- ## 4. 全量测试用例清单(80 条) > 模块前缀:A. 认证与会话|B. 仪表盘|C. 租户列表与筛选|D. 新建租户(Story A1)|E. 挂起/恢复(A2)|F. License 时效(A3)|G. License 用户数(A4)|H. 删除与撤销|I. 数据导出/备份/恢复|J. 套餐升级|K. 租户用户管理|L. 监控/告警|M. 平台升级(B1)|N. 升级回滚(B2)|O. 版本总览(B3)|P. 客户端发布(C1)|Q. 客户端分布与活跃榜(C2)|R. 强制更新|S. 审计日志(D1)|T. 安全(MFA / IP / 会话 / 强制登出)|U. 角色矩阵交叉|V. 状态机非法跃迁 --- ## A. 认证与会话(PRD §5.6 / §5.4.1 #1) ### TC-FON-000073 平台后台登录页强制 IP 白名单 - 级别:API - 前置:来源 IP 不在 `ip_whitelist` 表 - 步骤: - `TC-FON-000073-S01` `GET /admin/login/` - `TC-FON-000073-S02` 校验 HTTP 403 - `TC-FON-000073-S03` 校验 `IpWhitelistMiddleware` 命中日志 - 预期:未在白名单的 IP 一律 403,不返回登录表单。 ### TC-FON-000074 首次登录强制 MFA 配置向导 - 级别:E2E - 前置:管理员 `mfa_enabled=false` - 步骤: - `TC-FON-000074-S01` 提交账号密码登录成功 - `TC-FON-000074-S02` 校验自动跳转 `/admin/mfa/setup/`,无法绕过 - `TC-FON-000074-S03` 完成 TOTP 绑定后跳转仪表盘 - 预期:MFA 未配置则一切受保护页面均跳 setup。 ### TC-FON-000075 登录失败 5 次锁定 15 分钟 - 级别:API - 步骤: - `TC-FON-000075-S01` 同账号连续 5 次错误密码 - `TC-FON-000075-S02` 第 6 次返回 `ADMIN_ACCOUNT_LOCKED` - `TC-FON-000075-S03` 15 分钟后自动解锁 - 预期:阈值与解锁窗口与 PRD §5.6 + 技术方案 §7.1 一致。 ### TC-FON-000076 同 IP 登录尝试 20 次/小时限流 - 级别:API - 步骤:`S01` 同 IP 不同账号 20 次错误;`S02` 第 21 次 429;`S03` 1 小时后恢复 - 预期:IP 级限流独立于账号级锁定。 ### TC-FON-000077 会话 30 分钟无操作自动登出 - 级别:E2E - 步骤:`S01` 登录后挂起 31 分钟;`S02` 任意请求;`S03` 跳转登录页且 Session 失效 - 预期:滚动续期 30 分钟超时口径生效。 ### TC-FON-000078 高危操作 step-up MFA(5 分钟有效期) - 级别:API - 步骤: - `TC-FON-000078-S01` 已登录但距上次 MFA 验证 > 5 分钟 - `TC-FON-000078-S02` `POST /admin/tenants/{id}/hard-delete/` - `TC-FON-000078-S03` 校验 412 + `MFA_REQUIRED`,要求重新 TOTP - 预期:5 分钟以外的高危操作必须 step-up。 ### TC-FON-000079 平台后台 Cookie 严格隔离 - 级别:API - 步骤:`S01` 登录获得 Session Cookie;`S02` 校验 Domain=`admin.fonrey.com`、`SameSite=Strict`、`Secure`、`HttpOnly`;`S03` 校验不会发送至 `app.fonrey.com` - 预期:与租户应用 Cookie 完全隔离。 --- ## B. 仪表盘(§5.4.3) ### TC-FON-000080 仪表盘默认载入与 KPI 字段 - 级别:E2E - 步骤:`S01` 登录后访问 `/admin/`;`S02` 校验 6 模块齐全(全局概览/系统健康/近期告警/资源概览/客户端覆盖/最近操作);`S03` 校验数据非空 - 预期:6 大模块全部渲染。 ### TC-FON-000081 仪表盘『最近高危操作』链接到审计日志带筛选 - 级别:E2E - 步骤:`S01` 仪表盘点击某条高危记录;`S02` 跳转 `/admin/audit-logs/?action_type=...&operator_id=...`;`S03` 校验筛选自动应用 - 预期:URL 携带筛选参数,列表只剩匹配条目。 --- ## C. 租户列表与筛选(§5.4.4) ### TC-FON-000082 租户列表分页(默认 20 条) - 级别:API+E2E - 步骤:`S01` `GET /admin/tenants/?page=1`;`S02` 校验返回 20 条;`S03` 翻第 2 页 - 预期:分页参数与默认页大小符合 §5.4.4。 ### TC-FON-000083 租户列表多维度筛选 - 级别:API - 步骤:`S01` 筛选 `status=active&plan=Professional`;`S02` 筛选 `expiring_within_15_days=true`;`S03` 筛选 `users_at_limit=true` - 预期:三组筛选与 PRD `即将到期 / 用户数已满` 行为一致。 ### TC-FON-000084 租户列表关键词搜索(公司名/Tenant Code/邮箱) - 级别:API - 步骤:`S01` 搜索公司名片段;`S02` 搜索完整 12 位 `tenant_code`;`S03` 搜索邮箱片段 - 预期:三种关键词均能命中。 --- ## D. 新建租户(Story A1,§5.1.1–§5.1.2) ### TC-FON-000085 新建租户表单字段必填与格式校验 - 级别:E2E - 步骤:`S01` 提交缺少『公司名称』;`S02` 提交非法手机号;`S03` 提交 `license_user_limit=0` - 预期:三类校验失败均阻断提交且显示对应错误。 ### TC-FON-000086 新建租户成功路径 < 60 秒并写默认配置 - 级别:API - 步骤: - `TC-FON-000086-S01` `POST /admin/tenants/` 成功收到 202 + `task_id` - `TC-FON-000086-S02` 轮询任务状态在 60s 内变为 `success` - `TC-FON-000086-S03` 校验 `tenants.status='active'`、租户 schema 内已注入 PermissionDef + 7 个内置角色 + Tenant Admin(携带专属权限集合,独立于 7 个业务角色) - 预期:与 §5.1.2 默认配置内容完全一致。 ### TC-FON-000087 创建失败回滚所有已创建资源 - 级别:API - 步骤:`S01` 注入 migrate 失败;`S02` 校验 `tenants.status='failed'`;`S03` 校验 schema 已 DROP、R2 路径未占用 - 预期:失败原子回滚,无残留。 ### TC-FON-000088 联系人有邮箱时发送欢迎邮件 - 级别:API - 步骤:`S01` 创建携带邮箱;`S02` 校验邮件队列含主题『【房睿平台】您的账号已开通...』;`S03` 校验正文含 Tenant Code + 初始密码 + 脱敏手机号末三位 - 预期:邮件字段全量满足 §5.1.1 欢迎邮件规范。 ### TC-FON-000089 联系人无邮箱时下载入驻信息 PDF - 级别:E2E - 步骤:`S01` 创建不带邮箱的租户;`S02` 在详情页点击『下载入驻信息』;`S03` 校验 PDF 文件名 `{公司名称}_入驻信息_{日期}.pdf` 且包含与邮件等价信息 - 预期:PDF 路径与命名符合规范。 ### TC-FON-000090 Tenant Code 12 位纯数字唯一性 - 级别:API - 步骤:`S01` 连续创建 5 个租户;`S02` 校验 `tenant_code` 全部 12 位数字;`S03` 校验唯一约束 - 预期:格式与唯一性双重满足。 --- ## E. 挂起/恢复(Story A2,§5.1.3) ### TC-FON-000091 手动挂起后租户用户跳『账号已暂停』页 - 级别:API+E2E - 步骤:`S01` `POST /admin/tenants/{id}/suspend/` 选 `欠费`;`S02` 模拟租户内用户登录;`S03` 校验跳转暂停提示页 - 预期:挂起态对租户内用户生效。 ### TC-FON-000092 挂起后平台后台仍可访问该租户数据 - 级别:API - 步骤:`S01` 挂起租户;`S02` `GET /admin/tenants/{id}/users/`;`S03` 返回 200 - 预期:挂起仅影响租户侧,平台侧不受影响。 ### TC-FON-000093 设置到期时间自动恢复 - 级别:API - 步骤:`S01` 挂起设 `suspend_until=now+1h`;`S02` 时间到达后 Celery Beat 触发;`S03` 校验状态恢复 `active` + 通知邮件 - 预期:到期自动恢复 + 邮件发送。 ### TC-FON-000094 挂起原因枚举校验 - 级别:API - 步骤:`S01` 提交合法 `欠费`;`S02` 提交合法 `license_expired`;`S03` 提交非法 `xxx` - 预期:DDL CHECK 与视图校验一致拒绝非法值。 --- ## F. License 时效(Story A3,§5.1.3) ### TC-FON-000095 License 到期当日自动挂起 - 级别:API - 步骤:`S01` 设 `license_expires_at=today`;`S02` 触发每日定时任务;`S03` 校验状态 `suspended` + `suspended_reason='license_expired'` + 审计 `AUTO_SUSPEND_LICENSE_EXPIRED` - 预期:自动挂起 + 标准审计动作。 ### TC-FON-000096 License 到期前 15 天 Tenant Admin 倒计时横幅 - 级别:E2E - 前置:到期日 = today+14 - 步骤:`S01` Tenant Admin 登录租户;`S02` 校验顶部横幅文案『您的 License 将于 X 天后到期...』;`S03` 普通 Agent 登录不显示横幅 - 预期:横幅仅 Tenant Admin 可见。 ### TC-FON-000097 调整 License 到期日期写入审计 - 级别:API - 步骤:`S01` `POST /admin/tenants/{id}/license/`;`S02` 校验 `tenants.license_expires_at` 更新;`S03` 校验审计 `UPDATE_LICENSE` - 预期:字段更新且有审计。 --- ## G. License 用户数(Story A4,§5.1) ### TC-FON-000098 当前用户数 / 上限实时显示 - 级别:API - 步骤:`S01` 查询租户详情;`S02` 校验返回 `current_user_count` 与 `license_user_limit`;`S03` 创建一个用户后再查为 +1 - 预期:实时计数。 ### TC-FON-000099 达上限后租户内创建用户被拒 - 级别:API - 步骤:`S01` 设 `license_user_limit=current`;`S02` 租户内 Tenant Admin 创建新用户;`S03` 校验返回错误 + 提示『当前用户数已达 License 上限...』 - 预期:阻断且提示对齐 §A4。 ### TC-FON-000100 调整用户数上限写入审计 - 级别:API - 步骤:`S01` `POST /admin/tenants/{id}/license/user-limit/` 50→100;`S02` 校验字段更新;`S03` 校验审计 `UPDATE_LICENSE_USER_LIMIT` + before/after - 预期:审计含变更前后值。 ### TC-FON-000101 缩容到低于当前用户数允许执行但锁定新增 - 级别:API - 步骤:`S01` 当前 30 用户;`S02` 上限调至 20;`S03` 校验现存用户保留但新建被拒 - 预期:缩容不删用户但阻新增。 --- ## H. 删除与撤销(§5.1.4) ### TC-FON-000102 软删除进入 30 天冷静期 - 级别:API - 步骤:`S01` 勾选『确认数据导出已完成』后提交;`S02` 校验 `status='pending_delete'` + `pending_delete_until=now+30d`;`S03` 审计 `DELETE_TENANT` - 预期:状态、时长、审计三对齐。 ### TC-FON-000103 冷静期内撤销软删除 - 级别:API - 步骤:`S01` 软删除后立即 `POST /admin/tenants/{id}/restore/`;`S02` 校验状态恢复 `active`;`S03` 审计含 RESTORE 动作 - 预期:可逆。 ### TC-FON-000104 硬删除强制 MFA 二次验证 - 级别:API - 步骤:`S01` 未持 step-up token 调 `hard-delete`;`S02` 412 `MFA_REQUIRED`;`S03` 携带新鲜 TOTP 后成功 - 预期:必须 MFA。 ### TC-FON-000105 硬删除后释放 Tenant Code / R2 / License 席位 - 级别:API - 步骤:`S01` 硬删除完成;`S02` 校验同 Tenant Code 可被新租户复用;`S03` 校验 R2 前缀被清空、License 席位归还 - 预期:三项资源全释放。 ### TC-FON-000106 硬删除前必须勾选导出确认 - 级别:API - 步骤:`S01` 不勾选确认提交;`S02` 校验 422 + 提示 - 预期:未确认则阻断。 --- ## I. 数据导出 / 备份 / 恢复(§5.1.5–§5.1.7) ### TC-FON-000107 数据导出异步任务状态流转 - 级别:API - 步骤:`S01` `POST /admin/tenants/{id}/exports/`;`S02` 轮询 `Pending → In Progress → Done`;`S03` 校验下载链接 24h 有效 - 预期:状态机与签名链接 TTL 准确。 ### TC-FON-000108 CSV 导出文件资产为 CDN URL 分号分隔 - 级别:API - 步骤:`S01` 选模块『房源数据』+ CSV;`S02` 下载 CSV;`S03` 校验 `photos` 列以 `;` 分隔的 CDN URL - 预期:与 §5.1.5 表格一致。 ### TC-FON-000109 完整备份含 R2 文件实体 - 级别:API - 步骤:`S01` 触发完整备份;`S02` 校验产物含 `pg_dump.sql.gz` + `assets/`;`S03` 校验 `backup_records.size_bytes` - 预期:含库 + 文件实体,区别于导出。 ### TC-FON-000110 恢复前自动当前快照 + 维护模式 - 级别:API - 步骤:`S01` 选历史备份执行 restore;`S02` 校验先生成 pre-restore 快照;`S03` 校验租户进入 `maintenance` 状态、用户访问被拒 - 预期:流程严格按 §5.1.7。 ### TC-FON-000111 恢复需 MFA 二次验证 - 级别:API - 步骤:`S01` 无 step-up token 触发 restore;`S02` 412 `MFA_REQUIRED` - 预期:与硬删除一致门槛。 ### TC-FON-000112 备份保留策略 N=10 自动清理 - 级别:API - 步骤:`S01` 连续触发 11 次备份;`S02` 校验最旧 1 条被自动清理;`S03` 校验 R2 对应文件已删 - 预期:保留 N 与默认 10 一致。 ### TC-FON-000113 单租户备份计划覆盖全局 - 级别:API - 步骤:`S01` 全局 02:00 每日;`S02` 单租户改 06:00 每周;`S03` 校验 Beat 调度按租户配置执行 - 预期:单租户优先级高于全局。 --- ## J. 套餐升级(§5.1.8) ### TC-FON-000114 套餐升级前展示差异对比 - 级别:E2E - 步骤:`S01` 选 Basic→Professional;`S02` 校验弹窗含功能/用户数/存储/API 额度对比;`S03` 选立即生效 - 预期:差异表与生效模式齐全。 ### TC-FON-000115 套餐升级前自动备份 - 级别:API - 步骤:`S01` 触发升级;`S02` 校验任务先生成备份记录;`S03` 校验 `backup_records.trigger='pre_plan_upgrade'` - 预期:备份联动准确。 --- ## K. 租户用户管理(§5.1.9) ### TC-FON-000116 平台直接创建 Tenant Admin - 级别:API - 步骤:`S01` `POST /admin/tenants/{id}/admins/`;`S02` 校验目标 schema 写入用户 + 专属权限集合;`S03` 审计 `CREATE_ADMIN` - 预期:写入与审计一致。 ### TC-FON-000117 重置密码(链接方式) - 级别:API - 步骤:`S01` `POST /admin/tenants/{id}/users/{uid}/reset-password/?mode=link`;`S02` 校验邮件含一次性链接;`S03` 链接 24h 失效 - 预期:链接 TTL 与口径对齐。 ### TC-FON-000118 重置密码(临时密码方式 + 首登强制改) - 级别:API - 步骤:`S01` `mode=temp`;`S02` 返回临时密码并标记 `force_change_on_first_login=true`;`S03` 校验审计 `RESET_PASSWORD` - 预期:双模式齐全。 --- ## L. 监控与告警(§5.1.10 / §5.4.1 #13) ### TC-FON-000119 阈值告警触发邮件 + Webhook - 级别:API - 步骤:`S01` 配置 CPU>80% 邮件+Webhook;`S02` 模拟指标超阈;`S03` 校验两通道均收到 - 预期:双通道并行。 ### TC-FON-000120 SLA 月报可导出 - 级别:API - 步骤:`S01` 选近 30 天;`S02` `GET /admin/monitoring/sla.csv`;`S03` 校验 CSV 含可用率、故障事件、影响描述 - 预期:导出字段齐全。 --- ## M. 平台升级(Story B1,§5.2.1) ### TC-FON-000121 升级前健康检查阻断 - 级别:API - 步骤:`S01` 注入 Redis 异常;`S02` 触发 upgrade;`S03` 校验返回 `UPGRADE_HEALTH_CHECK_FAILED` - 预期:异常服务下不允许升级。 ### TC-FON-000122 灰度升级仅作用于内测租户名单 - 级别:API - 步骤:`S01` 配置内测组 = [t1,t2];`S02` 触发灰度;`S03` 校验仅 t1/t2 数据版本前进,其余租户保持原版本 - 预期:名单边界严格。 ### TC-FON-000123 升级期间实时进度按租户维度可见 - 级别:E2E - 步骤:`S01` 启动 B 类分批升级;`S02` 页面轮询 `upgrade_events.tenant_progress` JSONB;`S03` 校验各租户状态实时刷新 - 预期:进度透明可观察。 ### TC-FON-000124 升级失败触发告警与一键回滚入口 - 级别:API - 步骤:`S01` 模拟某租户 migrate 失败;`S02` 校验 `upgrade_events.status='halted'` 并发告警;`S03` 页面出现『一键回滚』按钮 - 预期:halted 后告警 + 回滚入口出现。 --- ## N. 升级回滚(Story B2,§5.2.2) ### TC-FON-000125 回滚前自动状态快照 - 级别:API - 步骤:`S01` 触发 rollback;`S02` 校验先生成 pre-rollback 快照;`S03` 审计 `ROLLBACK` - 预期:先存档再回退。 ### TC-FON-000126 单租户回滚不影响其他租户 - 级别:API - 步骤:`S01` 选 t1 回滚;`S02` 校验 t1 数据版本回退;`S03` 其他租户版本不变 - 预期:scope 严格。 ### TC-FON-000127 回滚需 MFA 二次验证 - 级别:API - 步骤:`S01` 无 step-up;`S02` 412 `MFA_REQUIRED` - 预期:高危操作统一门槛。 ### TC-FON-000128 回滚事件报告字段齐全 - 级别:API - 步骤:`S01` 完成回滚;`S02` `GET /admin/system/versions/events/{id}/`;`S03` 校验失败原因/耗时/受影响租户齐全 - 预期:报告契约满足。 --- ## O. 版本总览(Story B3,§5.4.1 #11) ### TC-FON-000129 平台基础数据版本展示 - 级别:E2E - 步骤:`S01` 进入 `/admin/system/versions/`;`S02` 校验 Part1 卡片含版本号/最后升级时间/描述/执行人 - 预期:4 字段完整。 ### TC-FON-000130 各租户数据版本筛选『待升级 / 升级失败』 - 级别:API+E2E - 步骤:`S01` 筛 `state=pending`;`S02` 筛 `state=failed`;`S03` 点击行跳转该租户备份记录 Tab - 预期:跳转到 `/admin/tenants/{id}/backups/`。 ### TC-FON-000131 版本数据 5 分钟缓存延迟可接受 - 级别:API - 步骤:`S01` 升级某租户;`S02` 立即查总览;`S03` 校验 ≤ 5 分钟内必更新 - 预期:缓存上限符合 §B3。 --- ## P. 客户端发布(Story C1,§5.3.1) ### TC-FON-000132 上传 EXE 自动计算 SHA-256 - 级别:API - 步骤: - `TC-FON-000132-S01` `POST /admin/api/client-releases/` multipart 上传 `.exe` - `TC-FON-000132-S02` 校验响应 `checksum_sha256` 为 64 hex 且与本地 sha256 一致 - `TC-FON-000132-S03` DB `client_releases.checksum_sha256 NOT NULL` - 预期:强制 SHA-256(`ADR-20260430-008`)。 ### TC-FON-000133 SemVer 格式严格校验 - 级别:API - 步骤:`S01` 提交 `1.2`;`S02` 提交 `v1.2.3`(带前缀 v);`S03` 提交 `1.2.3-alpha` - 预期:仅 `X.Y.Z` 通过;其他全部 422 `RELEASE_INVALID_VERSION`。 ### TC-FON-000134 同 (platform, arch) 仅一个 published 版本 - 级别:API - 步骤: - `TC-FON-000134-S01` v1.5.0 已 published - `TC-FON-000134-S02` 直接 publish v1.6.0 - `TC-FON-000134-S03` 校验 v1.5.0 自动转 `offline`,唯一索引 `idx_client_releases_published` 不冲突 - 预期:单 published 不变量保持。 ### TC-FON-000135 草稿态不对外可见 - 级别:API - 步骤:`S01` 客户端 `GET /api/release/v1/latest`;`S02` 校验仅返回 published;`S03` draft 不在响应内 - 预期:状态隔离。 ### TC-FON-000136 已发布版本回滚把当前版本置为已下线 - 级别:API - 步骤:`S01` 当前 published=v1.6.0;`S02` 对 v1.5.0 调 rollback;`S03` 校验 v1.5.0=published, v1.6.0=offline + 审计两条 - 预期:状态切换 + 审计成对。 ### TC-FON-000137 上传体积超 500MB 拒绝 - 级别:API - 步骤:`S01` 上传 501MB;`S02` 校验 413 + `RELEASE_FILE_TOO_LARGE` - 预期:边界严格。 ### TC-FON-000138 更新日志 Markdown 上限 2000 字 - 级别:API - 步骤:`S01` 提交 2001 字;`S02` 校验 422 - 预期:长度阈值。 ### TC-FON-000139 便携版 ZIP 可选上传 - 级别:API - 步骤:`S01` 仅 EXE;`S02` EXE+ZIP;`S03` 校验两种均可成功 - 预期:可选字段。 ### TC-FON-000140 客户端获取最新版本接口契约 - 级别:API - 步骤: - `TC-FON-000140-S01` `GET /api/release/v1/latest?platform=win32&arch=x64` - `TC-FON-000140-S02` 校验响应含 `version / download_url / checksum_sha256 / is_force_update / min_compatible_version / changelog` - `TC-FON-000140-S03` 校验 `download_url` 为 `download.fonrey.com` CDN - 预期:客户端契约稳定。 --- ## Q. 客户端分布与活跃榜(Story C2,§5.3.2) ### TC-FON-000141 Heartbeat Upsert 锚点 (tenant_id, device_id) - 级别:API - 步骤: - `TC-FON-000141-S01` 同一 device_id 在 1 小时内上报 5 次 - `TC-FON-000141-S02` 校验 `client_heartbeats` 该 (tenant_id, device_id) 唯一行被 update 而非 insert - `TC-FON-000141-S03` 校验 `last_seen_at` 单调递增 - 预期:与 `ADR-20260430-007` 一致。 ### TC-FON-000142 24h 活跃口径聚合饼图 - 级别:API - 步骤:`S01` 构造 last_seen 跨 24h 边界的 4 条;`S02` `GET /admin/api/client-releases/distribution/`;`S03` 校验仅最近 24h 心跳计入活跃 - 预期:24h 窗口准确。 ### TC-FON-000143 全平台租户活跃榜按活跃数降序 - 级别:API - 步骤:`S01` 构造 3 个 active 租户活跃数 [50,200,80];`S02` 拉取活跃榜;`S03` 校验排序为 [200,80,50] - 预期:仅 active 租户参与,排序正确。 ### TC-FON-000144 活跃榜支持历史装机总数列 - 级别:API - 步骤:`S01` 查询;`S02` 校验返回 `tenant_code / 名称 / active_24h / install_total_all_time` - 预期:四字段齐全。 ### TC-FON-000145 单租户版本分布钻取 - 级别:E2E - 步骤:`S01` 在分布页选某租户;`S02` 校验该租户内员工的客户端版本饼图;`S03` 数据来源 `client_heartbeats.tenant_id` 维度聚合 - 预期:钻取 tenant_id 准确。 --- ## R. 强制更新(§5.3.3) ### TC-FON-000146 推送强制更新需 MFA + 二次确认 - 级别:API+E2E - 步骤: - `TC-FON-000146-S01` 选 < v1.5.0 推送强制;`S02` 校验弹出二次确认弹窗;`S03` 校验 412 `MFA_REQUIRED`,通过 step-up 后审计 `FORCE_UPDATE_PUSH` - 预期:双重保护。 ### TC-FON-000147 客户端 latest 接口对低版本返回 is_force_update=true - 级别:API - 步骤:`S01` 推送强制后;`S02` 客户端 v1.4.0 调 latest;`S03` 校验 `is_force_update=true` - 预期:服务端契约驱动客户端强制升级。 --- ## S. 审计日志(Story D1,§5.7) ### TC-FON-000148 审计日志多维筛选 + CSV 导出 - 级别:API - 步骤: - `TC-FON-000148-S01` 筛 `operator_id + time_range + action_type=HARD_DELETE_TENANT` - `TC-FON-000148-S02` `GET /admin/audit-logs/export.csv` - `TC-FON-000148-S03` 校验 CSV 列含 operator/operator_name/action_type/target_type/target_id/target_name/payload_summary/result/error_message/ip_address/created_at - 预期:字段对齐 §5.7 + DDL。 ### TC-FON-000149 审计日志不可变(DB 触发器层) - 级别:API - 步骤: - `TC-FON-000149-S01` 直接尝试 `UPDATE platform_audit_logs SET ...` - `TC-FON-000149-S02` 校验抛 `IntegrityError`(BEFORE UPDATE OR DELETE 触发器) - `TC-FON-000149-S03` 应用层 Manager `update()/delete()` 也抛 `AUDIT_IMMUTABLE` - 预期:双层不可变保证。 ### TC-FON-000150 审计 action_type 全集落库 - 级别:API - 步骤:`S01` 触发 16 个动作(CREATE/SUSPEND/RESUME/DELETE/HARD_DELETE/RESTORE/UPGRADE/ROLLBACK/RESET_PASSWORD/RELEASE/OFFLINE/FORCE_UPDATE/UPDATE_LICENSE/UPDATE_LICENSE_USER_LIMIT/AUTO_SUSPEND_LICENSE_EXPIRED/CREATE_ADMIN);`S02` 校验 16 行写入;`S03` 校验所有 `target_type` 落入 {Tenant,User,System,Backup,ClientRelease,Admin} - 预期:枚举与 PRD §5.7 + DDL 一致。 --- ## T. 安全(§5.6) ### TC-FON-000151 Platform Admin 强制登出指定管理员 - 级别:API - 步骤: - `TC-FON-000151-S01` 操作员 X 已登录持有 Session - `TC-FON-000151-S02` Platform Admin 调 `POST /admin/settings/admins/{X}/force-logout/` - `TC-FON-000151-S03` X 下一请求被重定向 `/admin/login/`,Session 失效;审计 `FORCE_LOGOUT` - 预期:会话即刻失效。 --- ## U. 角色矩阵交叉(§6) ### TC-FON-000152 三角色权限矩阵全覆盖回归 - 级别:API - 前置:分别准备 Platform Admin / 运营人员 / 只读审计员 三账号 - 步骤: - `TC-FON-000152-S01` 以 Platform Admin 身份遍历 §6 全部 21 行操作,校验 ✅ 行返回 200/202、❌ 行返回 403 - `TC-FON-000152-S02` 以运营人员身份遍历同 21 行,校验:硬删除/数据恢复/系统升级/系统回滚/客户端发布/客户端回滚/强制更新/管理员账号/强制登出/IP 白名单 共 10 项 403;其余 ✅ 行 200/202 - `TC-FON-000152-S03` 以只读审计员身份遍历同 21 行,校验:仅『查看客户端版本分布与活跃榜』『查看审计日志』『导出审计日志』3 项 200,其他 18 项 403 - 预期:三角色行为与 §6 矩阵 100% 一致;任一格偏差视为 P0。 --- ## 5. 状态机断言(贯穿用例) > §7 租户状态机所有合法跃迁与非法跃迁已在用例 D/E/F/H/M/N 中以正向 + 反向覆盖: > - Creating→Active:D 系列 > - Active→Suspended:E 系列、F 系列 > - Suspended→Active:E93、F95(自动恢复) > - Active→Pending Delete:H102 > - Pending Delete→Active:H103(撤销) > - Pending Delete→Deleted:H105(硬删除立即态)/ 冷静期到期清除(已并入 §6.4 定时任务,不独立列用例) > - 非法跃迁(如 Deleted→Active):由 DDL CHECK + 视图 422 双重保障,已在 D87(创建失败)副断言覆盖 --- ## 6. 工程实现指引(给测试开发工程师) 1. **目录建议** - `tests/integration/platform_admin/test_tc_fon_000073_000152.py` - `tests/e2e/platform_admin/test_tc_fon_000073_000152.spec.ts` - `tests/integration/release_api/test_tc_fon_release_endpoints.py`(C1/C2/R 系列) 2. **命名规范** - 函数名带用例 ID:`def test_tc_fon_000086_create_tenant_success_within_60s():` 3. **公共夹具** - `platform_admin_client` / `ops_operator_client` / `read_only_auditor_client`:三角色已登录、已通过 MFA 的 `Client` 实例 - `with_step_up_token` 装饰器:注入 5 分钟内 TOTP 验证状态 - `tenant_factory(status='active')` / `client_release_factory(state='draft')` 4. **步骤日志** - 每步执行前后打印 step_id;断言失败时把 step_id 写入异常消息 5. **报告聚合** - 生成 `reports/platform_admin_run_.json` + `reports/platform_admin_run_.html` - 汇总分组:A–V(21 组) 6. **CI 门禁** - `TC-FON-000073` ~ `TC-FON-000152` 全量通过且零 `blocked` 才允许合并到主干 --- ## 7. 变更规则 - 新增本模块用例:从 `TC-FON-000153` 开始递增(同步更新 `TEST_CASE_REGISTRY.md` 水位) - 后续模块继续用同一全局序列,不得重号 - 禁止删除历史用例 ID;可标记 `deprecated` 但保留编号与历史报告可追溯性 - PRD §5 任意小节字段或验收标准变更 → 必须同步本文档对应用例并提升 `v1.x`