登录模块审核

This commit is contained in:
Shen Wei
2026-04-30 18:40:55 +08:00
parent 4030a91100
commit 57600598ac
34 changed files with 2544 additions and 2431 deletions

View File

@@ -2,11 +2,11 @@
# Fonrey 测试规范TEST_SPEC
**版本**: 1.1
**版本**: 1.2
**项目**: Fonrey 房产经纪管理系统
**技术栈**: Django 4.x + django-tenants + PostgreSQL 16 + Redis + Celery + HTMX + Playwright
**关联文档**: `TECH_STACK/TECH_STACK.md``PRD/TASK.md`、各模块技术方案(登录/权限/房源/客源/楼盘/组织人事/系统管理)
**最后更新**: 2026-04-27
**关联文档**: `TECH_STACK/TECH_STACK.md``PRD/TASK.md``TEST_CASES/TEST_CASE_ID_SPEC.md``TEST_CASES/TEST_CASE_REGISTRY.md`各模块技术方案(登录/权限/房源/客源/楼盘/组织人事/系统管理)
**最后更新**: 2026-04-30
---
@@ -36,13 +36,13 @@ Fonrey 采用 AI 驱动迭代,测试是质量兜底。所有 P0 User Story 必
| `apps/*/services/` 业务逻辑层 | ≥ 80% |
| `apps/*/views*` 接口与视图层 | ≥ 70% |
| `apps/*/tasks.py` 异步任务 | ≥ 70% |
| E2E 核心旅程 | 5 条全部通过 |
| E2E 核心测试用例 | 覆盖指定核心用例并全部通过 |
### 2.2 质量门禁
- 每个 P0 US 对应至少一个集成测试场景集。
- PR 合并前:单元 + 集成必须全绿。
- `main/develop`:每日自动跑全量(含 E2E 核心旅程)。
- `main/develop`:每日自动跑全量(含 E2E 核心测试用例)。
---
@@ -50,7 +50,7 @@ Fonrey 采用 AI 驱动迭代,测试是质量兜底。所有 P0 User Story 必
```
┌─────────────────────────────────────────┐
│ E2E 测试(用户旅程 │ ← Playwright
│ E2E 测试(测试用例 │ ← Playwright
├─────────────────────────────────────────┤
│ 集成测试HTTP / View / Service / DB │ ← pytest-django + TenantClient
├─────────────────────────────────────────┤
@@ -71,7 +71,7 @@ Fonrey 采用 AI 驱动迭代,测试是质量兜底。所有 P0 User Story 必
### 3.3 E2E 测试
- 目标:验证真实用户关键路径。
- 约束:只覆盖核心旅程,避免把所有细节都堆到 E2E。
- 约束:只覆盖核心测试用例,避免把所有细节都堆到 E2E。
---
@@ -236,15 +236,12 @@ result = some_task.apply(args=[...])
## 九、E2E 测试规范
### 9.1 核心旅程(必须)
### 9.1 核心测试用例(必须)
| 编号 | 旅程 | 对应模块 |
|---|---|---|
| J-01 | 登录 → 进入首页 | 登录 |
| J-02 | 录入房源 → 上传图片 → 查看列表 | 房源 |
| J-03 | 录入客源 → 添加跟进 | 客源 |
| J-04 | 无权限访问受限页面 | 权限 |
| J-05 | 创建员工 → 分配角色 → 新员工登录 | 组织人事 + 权限 |
- E2E 覆盖对象采用“测试用例”定义不使用“旅程编号J-xx”。
- 每条 E2E 用例必须绑定全局唯一测试用例ID`TC-FON-XXXXXX`
- 当前登录模块核心用例以 `TEST_CASES/TEST_CASES_LOGIN_MODULE.md` 为准(`TC-FON-000001` ~ `TC-FON-000048`)。
- 其他模块(房源/客源/组织/权限等)按 `TEST_CASES/TEST_CASE_REGISTRY.md` 分配编号后补充。
### 9.2 Playwright 约束
@@ -264,9 +261,31 @@ page.wait_for_load_state('networkidle')
---
## 十、测试配置基线
## 十、测试用例编号与注册规范(强制)
### 10.1 `pytest.ini`
### 10.1 编号规范
- 测试用例ID`TC-FON-XXXXXX`(全局唯一)
- 步骤ID`TC-FON-XXXXXX-SYY`
- 详见:`TEST_CASES/TEST_CASE_ID_SPEC.md`
### 10.2 注册流程
1. 新增用例前,先在 `TEST_CASES/TEST_CASE_REGISTRY.md` 查看下一个可用编号。
2. 先登记编号段(可先 `reserved`),再编写文档和代码。
3. 合并前状态改为 `active`,并更新“当前编号水位”。
### 10.3 强约束
- 不允许按模块重置编号。
- 不允许复用已废弃编号。
- 不允许未登记编号直接入库测试代码。
---
## 十一、测试配置基线
### 11.1 `pytest.ini`
```ini
[pytest]
@@ -280,7 +299,7 @@ markers =
slow
```
### 10.2 `tests/settings_test.py` 关键项
### 11.2 `tests/settings_test.py` 关键项
- Celery eager 模式开启
- Cache 使用测试后端locmem/fakeredis
@@ -290,26 +309,27 @@ markers =
---
## 十、CI 自动化运行
## 十、CI 自动化运行
### 11.1 触发策略
### 12.1 触发策略
- 每日定时全量测试
- `main/develop` 每次 push 触发
### 11.2 流水线拆分
### 12.2 流水线拆分
1. `unit-and-integration`
2. `e2e`(依赖前者成功后执行)
### 11.3 最低产物
### 12.3 最低产物
- 覆盖率报告(终端 + 平台上传)
- E2E 失败截图 artifact
- 测试结果明细(至少含 `run_id``test_case_id``step_id``status``error_message``expected_result``actual_result`
---
## 十、AI 协作测试要求
## 十、AI 协作测试要求
每个 User Story 实现后,必须同时补齐:
@@ -326,7 +346,7 @@ markers =
---
## 十、禁止项Do NOT
## 十、禁止项Do NOT
- 禁止 Django 原生 `Client()` 进行租户集成测试
- 禁止固定等待(`sleep` / `wait_for_timeout`
@@ -334,12 +354,14 @@ markers =
- 禁止测试之间共享可变数据
- 禁止无权限/未登录场景缺失
- 禁止空测试占位后不补全
- 禁止未分配 `TC-FON-XXXXXX` 的匿名测试入库
---
## 十、文档同步规则
## 十、文档同步规则
- 新增/调整 User Story同步 `PRD/TASK.md` 与集成测试映射
- 模块 API 变更:同步对应模块技术方案
- 测试目录变更:同步本文件目录结构与 CI 脚本
- 新增测试基建fixture/工具):同步 `AGENTS.md` 与本文件
- 新增测试用例:同步 `TEST_CASES/TEST_CASE_REGISTRY.md`(编号段、水位、状态)

View File

@@ -2,281 +2,269 @@
# Fonrey 登录管理技术方案
**版本**: 3.1
**版本**: 4.0
**项目**: Fonrey 房产经纪管理系统
**技术栈**: Django 4.x + HTMX + Alpine.js + PostgreSQL 16 + Redis + Celery
**关联 PRD**: `PRD/登录管理/用户登录管理模块PRD.md`
**关联 PRD**: `PRD/登录管理/用户登录管理模块PRD.md`v2.0
**关联数据模型**: `DATA_MODEL/DATA_MODEL_LOGIN.md`(本方案不重复 DDL
**关联契约规范**: `TECH_STACK/API_CONTRACT.md`(全局 API 契约权威)
**最后更新**: 2026-04-27
**关联测试规范**: `TECH_STACK/测试规范.md``TEST_CASES/TEST_CASES_LOGIN_MODULE.md`
**最后更新**: 2026-04-30
---
## 一、文档定位与边界
本文件定义登录模块的:
本文件定义登录模块的实现口径
1. 模块边界与服务职责
2. API 端点设计(页面 / HTMX / JSON
3. 登录安全策略(验证码、锁定、会话、找回
4. 缓存与异步任务策略
1. 模块范围与职责边界
2. API 端点(页面 / HTMX / JSON
3. 安全策略(滑块验证、登录锁定、短信 OTP、会话
4. Redis/Celery 运行策略
5. 错误码与测试映射
> 不在本文件展开表字段索引、DDL。数据结构以 `DATA_MODEL_LOGIN.md` 为唯一权威。
> 本文件展开数据表字段索引。数据结构以 `DATA_MODEL_LOGIN.md` 为唯一权威。
---
## 二、范围定义(以 P0 为准)
## 二、范围定义(以 PRD v2.0 为准)
### 2.1 P0 必须覆盖
- Tenant ID 校验Public Schema
- 用户名 + 密码登录Tenant Schema
- 验证码挑战与一次性 pass token
- 连续失败锁定与解锁机制
- 找回用户名 / 重置密码
- 首次登录强制改密
- 安全登出与会话销毁
- Tenant Code 识别(首次启动 + 切换公司
- 密码登录(手机号/密码 + 滑块
- 首次登录强制修改密码
- 找回密码(纯短信三步流程)
- 手机验证码登录MVP 正式功能)
- 登录失败锁定 / 自动解锁 / 管理员解锁
- 安全登出与会话失效
### 2.2 预留(非本期强制)
### 2.2 非目标 / 预留
- MFAOTP / 短信
- 微信扫码登录(仅保留禁用入口与接口占位,不开放功能
- 企业 SSOOAuth2 / SAML
- 设备指纹与风险评分
- 风险评分/设备指纹
### 2.3 已废弃(不得实现)
- 找回用户名流程Story 4 已废弃)
---
## 三、模块架构边界
## 3.1 模块职责(`apps/account`
### 3.1 模块职责(`apps/account`
- 登录认证入口与 Session 建立
- 密码策略、锁定策略、登录防刷策略执行
- 找回流程与一次性重置令牌管理
- 登录/登出/失败审计事件写入
- 租户识别与租户上下文建立前置校验
- 登录鉴权、会话签发、登出销毁
- 首登改密门禁(`is_initial_password`
- 短信 OTP 发送/校验(找回密码 + 验证码登录)
- 登录与安全审计事件写入
## 3.2 多租户分层职责
### 3.2 多租户分层职责
| 层级 | Schema | 职责 |
|---|---|---|
| Tenant ID 校验 | Public | 校验租户标识、域名映射、租户状态 |
| 登录认证 | Tenant | 账号鉴权、失败计数、会话建立 |
| 密码找回 | Tenant | 身份确认、令牌签发与核销 |
| Tenant Code 校验 | Public | 校验 `tenant_code`、租户状态、品牌信息返回 |
| 登录认证 | Tenant | 账号鉴权、失败计数、锁定状态、会话签发 |
| 短信 OTP | Tenant | OTP 记录、场景区分、过期与尝试次数控制 |
## 3.3 外部依赖
### 3.3 外部依赖
| 依赖模块 | 用途 |
|---|---|
| `apps/org` | 员工状态联动(离职/冻结禁止登录) |
| `core/encryption.py` | 手机号等敏感信息加密与脱敏 |
| `core/cache.py` | 验证码票据、失败计数、频控缓存 |
| `Celery` | 找回消息异步发送、安全日报任务 |
| `apps/org` | 员工状态联动(离职/停用不可登录) |
| `core/encryption.py` | 手机号加密/哈希能力 |
| `core/cache.py` | 滑块票据、频控、锁定计数、重置 token |
| `Celery` | 短信发送异步化(可选,建议) |
---
## 四、API 设计原则
1. 登录链路固定三段:Tenant 校验 → 验证账号认证
2. 最小暴露原则:账号不存在与密码错误统一返回
3. 认证状态以数据库为准Redis 仅做加速与频控
4. 安全相关写操作后立即失效缓存,不依赖 TTL
5. HTMX 返回片段JSON 返回结构化错误体
1. 登录安全链路:**Tenant 校验 → 滑块验证 → 登录提交**
2. 防枚举:账号不存在/停用等敏感状态采用统一外显文案
3. 账号锁定是账号维度策略,不区分密码登录或验证码登录
4. Redis 仅作运行态与频控,最终状态以数据库持久化字段为准
5. 所有登录相关接口遵循 `TECH_STACK/API_CONTRACT.md` 的统一错误响应格式
---
## 五、端点清单(核心
## 五、端点清单(对齐 PRD
## 5.1 页面路由SSR
### 5.1 页面路由SSR
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
| `/account/tenant/verify/` | GET | 否 | 首次租户识别页 |
| `/account/login/` | GET | 否 | 登录页 |
| `/account/change-password/` | GET | | 首登强制改密页 |
| `/account/recover-username/` | GET | | 找回用户名页 |
| `/account/recover-password/` | GET | 否 | 找回密码页 |
| `/auth/tenant/identify/` | GET | 否 | Tenant 识别页 |
| `/auth/login/` | GET | 否 | 登录页(密码登录/验证码登录 Tab |
| `/auth/password/forgot/` | GET | | 找回密码三步页 |
| `/auth/password/change-initial/` | GET | | 首次登录强制改密页 |
## 5.2 HTMX 片段端点
> 说明:`/auth/wechat/*` 仅预留,不在 MVP 开放。
### 5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
| `/account/fragments/login-form/` | GET | 登录表单局刷 | HTML 片段 |
| `/account/fragments/captcha/` | GET | 验证码区块刷新 | HTML 片段 |
| `/account/fragments/recover-step/` | GET | 找回步骤局刷 | HTML 片段 |
| `/auth/fragments/captcha/` | GET | 刷新滑块区块 | HTML 片段 |
| `/auth/fragments/login-form/` | GET | 登录 Tab 内容局刷 | HTML 片段 |
| `/auth/fragments/forgot-step/` | GET | 找回密码步骤局刷 | HTML 片段 |
## 5.3 JSON APIP0
### 5.3 JSON APIMVP
| 端点 | 方法 | 说明 |
|---|---|---|
| `/api/account/tenant/verify/` | POST | 校验 tenant_id 与可用性 |
| `/api/account/captcha/generate/` | POST | 生成验证码 challenge |
| `/api/account/captcha/verify/` | POST | 校验 challenge 并签发 pass token |
| `/api/account/login/` | POST | 登录并建立 session |
| `/api/account/logout/` | POST | 登出并销毁 session |
| `/api/account/password/change/` | POST | 登录态改密 |
| `/api/account/username/recover/` | POST | 找回用户名 |
| `/api/account/password/recover/request/` | POST | 申请重置密码令牌 |
| `/api/account/password/recover/reset/` | POST | 使用令牌重置密码 |
| `/api/auth/tenant/verify/` | POST | Tenant Code 校验(公开接口) |
| `/api/auth/captcha/` | GET | 获取滑块拼图验证码(返回背景图 Base64 + 碎片图 Base64 + 验证 Token |
| `/api/auth/captcha/verify/` | POST | 校验滑块并签发 `captcha_pass_token` |
| `/api/auth/login/` | POST | 密码登录 |
| `/api/auth/login/phone/` | POST | 手机验证码登录 |
| `/api/auth/recover/password/request/` | POST | 找回密码步骤一:发 OTP |
| `/api/auth/recover/password/verify/` | POST | 找回密码步骤二:校验 OTP颁发 `sms_reset_token` |
| `/api/auth/recover/password/reset/` | POST | 找回密码步骤三:提交新密码 |
| `/api/auth/password/change-initial/` | POST | 首次登录强制改密提交 |
| `/api/auth/logout/` | POST | 登出销毁会话 |
---
## 六、关键 API 规范(请求/响应)
## 六、关键流程约束
## 6.1 登录
### 6.1 Tenant 识别
`POST /api/account/login/`
- `tenant_code` 固定 12 位数字,前后空格自动 trim
- 成功返回租户名称、Logo URL、登录地址
- 失败返回:`valid=false` + 统一错误信息
- 接口公开但必须限流:单 IP 每分钟 ≤ 10 次
### 6.2 密码登录
请求体(示例):
```json
{
"tenant_id": "fonrey-sh",
"username": "agent_001",
"password": "******",
"phone": "13800138000",
"password": "***",
"captcha_pass_token": "token"
}
```
成功 `200`
关键规则
- 滑块通过后方可提交登录
- 密码连续错误 ≥ 5 次,锁定 30 分钟
- `is_initial_password = true` 时强制跳转改密页
- 错误文案统一,不泄露账号存在性细节
### 6.3 找回密码(纯短信三步)
#### 步骤一:发送 OTP
- `scene = password_reset`
- OTP 有效期10 分钟
- 同手机号频控5 次/小时
- 手机号不存在/停用:统一提示“如该手机号已注册,验证码将在 1 分钟内发送”
#### 步骤二:校验 OTP
- 正确且未过期:签发 `sms_reset_token`15 分钟,一次性)
- 错误累计尝试≥5 次作废该 OTP
- 过期:提示重新获取
#### 步骤三:重置密码
- 必须携带有效 `sms_reset_token`
- 成功后:`is_initial_password = false`
- 该用户所有会话立即失效,跳回登录页
### 6.4 手机验证码登录MVP 正式)
请求体(示例):
```json
{
"message": "登录成功",
"redirect_url": "/home/"
"phone": "13800138000",
"sms_code": "123456"
}
```
失败码:`ACCOUNT_LOGIN_INVALID_CREDENTIAL` / `ACCOUNT_LOCKED` / `ACCOUNT_CAPTCHA_INVALID`
## 6.2 申请重置密码
`POST /api/account/password/recover/request/`
```json
{
"tenant_id": "fonrey-sh",
"username": "agent_001",
"contact": "138****0000"
}
```
规则:
- 频率限制(建议 5 次/小时)
- 统一返回文案,避免枚举账号存在性
关键规则:
- 获取登录验证码前必须先通过滑块
- `scene = login`
- OTP 有效期5 分钟
- 同手机号频控10 次/小时(与 `password_reset` 独立计数)
- OTP 错误 ≥5 次作废
- 账号 `locked``disabled` 时,验证码登录同样拒绝
---
## 七、HTMX 交互约定
## 7.1 Header 约定
- 请求头:`HX-Request: true`
- 成功触发:`HX-Trigger: {"toast":{"level":"success","message":"操作成功"}}`
- 失败触发:`HX-Trigger: {"toast":{"level":"error","message":"操作失败"}}`
- 登录成功:`HX-Redirect: /home/`
## 7.2 模板分片命名
- `templates/account/fragments/login_form.html`
- `templates/account/fragments/captcha_panel.html`
- `templates/account/fragments/recover_step.html`
---
## 八、权限与数据范围
## 8.1 访问控制
- 匿名可访问:租户校验、登录、找回相关端点
- 登录后访问:改密、登出
- 首登未改密用户仅允许访问改密页面
## 8.2 审计字段要求
登录与找回相关操作至少记录:
- tenant_schema
- username或脱敏标识
- ip / user_agent
- result_code
- created_at
---
## 九、异步任务与缓存策略
## 9.1 Celery 任务
| 任务 | 触发时机 | 说明 |
|---|---|---|
| `account_send_recover_message_task` | 找回请求成功后 | 异步发送邮件/短信 |
| `account_security_digest_task` | 定时任务 | 汇总锁定、失败、异常登录统计 |
## 9.2 Redis Key 规范
## 七、Redis Key 规范(对齐 PRD
| Key | TTL | 说明 |
|---|---|---|
| `{schema}:account:captcha:{challenge_id}` | 180s | 验证码挑战态 |
| `{schema}:account:captcha:pass:{token}` | 180s | 验证通过一次性票据 |
| `{schema}:account:login_fail:{username}` | 1800s | 登录失败计数 |
| `{schema}:account:recover:rate:{username}` | 3600s | 找回频控 |
| `captcha_token:{uuid}` | 3 分钟 | 滑块验证会话 |
| `captcha_pass:{uuid}` | 3 分钟 | 一次性通过凭证 |
| `login_fail:{tenant_id}:{username}` | 30 分钟 | 登录失败计数 |
| `sms_limit:password_reset:{phone}` | 1 小时 | 找回密码 OTP 发送频控≤5次 |
| `sms_limit:login:{phone}` | 1 小时 | 登录 OTP 发送频控≤10次 |
| `sms_reset_token:{token}` | 15 分钟 | 找回密码步骤三凭证 |
| `tenant_verify_ip:{ip}` | 1 分钟 | Tenant 校验接口 IP 限流≤10次 |
---
## 十、性能与可靠性约束
## 八、安全与合规
- 登录链路接口目标:`p95 < 300ms`(不含外部消息发送)
- 找回请求接口目标:`p95 < 400ms`(消息发送异步化)
- 缓存故障时系统应降级到 DB 校验,但保留频控硬兜底
- 验证码组件不可用时,应返回明确错误并禁止跳过登录防护
1. 密码仅允许 Django 安全哈希PBKDF2/Argon2
2. OTP 明文不得入库,仅存哈希。
3. 敏感字段日志脱敏手机号、token、验证码
4. 会话过期或登出后,受保护页面必须重定向登录。
5. HTTPS 强制,不允许明文传输降级。
---
## 十一、安全与合规
## 九、错误码建议(登录模块)
1. 密码仅允许 Django 安全哈希PBKDF2 / Argon2
2. 连续失败 N 次锁定(建议 5 次30 分钟)。
3. 重置令牌一次性使用,过期失效,不可复用。
4. 登出必须销毁会话,旧页面刷新需重定向登录。
5. 敏感字段仅脱敏返回,禁止明文日志输出。
---
## 十二、错误码建议
| code | HTTP | 场景 |
| code | HTTP | 中文含义 |
|---|---|---|
| `ACCOUNT_TENANT_INVALID` | 400 | tenant 无效或停用 |
| `ACCOUNT_CAPTCHA_INVALID` | 400 | 验证码失败/过期 |
| `ACCOUNT_LOGIN_INVALID_CREDENTIAL` | 401 | 账号或密码错误 |
| `ACCOUNT_LOCKED` | 423 | 账号锁定中 |
| `ACCOUNT_PASSWORD_WEAK` | 400 | 新密码不满足复杂度 |
| `ACCOUNT_RESET_TOKEN_INVALID` | 400 | 重置令牌无效/已使用 |
| `AUTH_TENANT_NOT_FOUND` | 400 | 租户识别码无效 |
| `AUTH_TENANT_RATE_LIMITED` | 429 | Tenant 校验请求过于频繁 |
| `AUTH_CAPTCHA_INVALID` | 400 | 滑块验证失败 |
| `AUTH_INVALID_CREDENTIAL` | 401 | 手机号或密码错误 |
| `AUTH_ACCOUNT_LOCKED` | 423 | 账号已锁定 |
| `AUTH_ACCOUNT_DISABLED` | 403 | 账号已停用 |
| `AUTH_SMS_OTP_INVALID` | 400 | 短信验证码错误 |
| `AUTH_SMS_OTP_EXPIRED` | 400 | 短信验证码过期 |
| `AUTH_SMS_OTP_RATE_LIMITED` | 429 | OTP 发送超限 |
| `AUTH_SMS_RESET_TOKEN_INVALID` | 400 | 重置凭证无效或过期 |
| `AUTH_PASSWORD_WEAK` | 400 | 新密码不满足强度规则 |
---
## 十、测试映射(P0
## 十、测试映射(与全局编号对齐
| 场景 | 最低覆盖 |
|---|---|
| Tenant 校验 | 有效/无效/停用租户 |
| 登录链路 | 验证码通过、失败锁定、解锁后登录 |
| 找回流程 | 频控、令牌一次性、过期处理 |
| 首登改密 | 未改密不可进入业务页 |
| 登出 | 会话销毁、回退重定向 |
- 测试编号规范:`TEST_CASES/TEST_CASE_ID_SPEC.md`
- 注册表:`TEST_CASES/TEST_CASE_REGISTRY.md`
- 登录模块用例:`TEST_CASES/TEST_CASES_LOGIN_MODULE.md`
测试文件:`tests/integration/account/test_us_account.py`
建议最小执行集:
- Tenant 识别:`TC-FON-000001` ~ `000010`
- 密码登录与锁定:`TC-FON-000011` ~ `000028`
- 首登改密:`TC-FON-000029` ~ `000033`
- 找回密码:`TC-FON-000034` ~ `000044`
- 验证码登录:`TC-FON-000045` ~ `000048`
---
## 十、落地顺序建议
## 十、落地顺序建议
1. 先实现 tenant 校验 + 登录主链路
2. 再接验证码 + 失败锁定
3. 再实现找回用户名/密码
4. 最后补安全摘要任务与审计报表
1. Tenant 识别 + 密码登录主链路
2. 滑块与失败锁定
3. 首登改密门禁
4. 找回密码三步(短信)
5. 手机验证码登录scene=login
6. 报表与监控补齐
---
## 十、文档同步规则
## 十、文档同步规则
- 登录数据结构调整:同步 `DATA_MODEL_LOGIN.md`
- 安全策略或门禁调整:同步 `权限管理系统技术方案.md`
- API 变更:同步本文件与登录 PRD 验收条目
- PRD 登录模块变更:同步本文件
- 数据结构调整:同步 `DATA_MODEL_LOGIN.md`
- 测试用例新增/变更:同步 `TEST_CASES/TEST_CASE_REGISTRY.md` 与登录用例文档
- API 契约调整:同步 `TECH_STACK/API_CONTRACT.md`