# 变更审计记录：租户管理员用户名大小写不敏感

| 字段 | 值 |
|------|-----|
| 日期 | 2026-03-23 00:35:44 |
| Prompt-ID | P20260323-003544 |
| Session-ID | 6d352688 |
| Session 路径 | docs/audit/session_logs/2026-03/23/03_6d352688_003156/main_01_87650f7e.md |

## 操作摘要

租户管理后台登录用户名大小写不敏感。新建 `admin_tenant_admins.py`（管理员 CRUD 路由）和 `tenant_auth.py`（租户认证路由），所有用户名比较和存储统一使用 `LOWER()`。新增迁移脚本将现有用户名转小写并创建大小写不敏感唯一索引。

## 高风险文件

| 文件 | 变更类型 | 风险标签 |
|------|----------|----------|
| `apps/backend/app/routers/admin_tenant_admins.py` | 新增 | dir:backend |
| `apps/backend/app/routers/tenant_auth.py` | 新增 | dir:backend |
| `db/zqyy_app/migrations/2026-03-23__case_insensitive_username.sql` | 新增 | dir:db, db-schema-change |

## 本次对话文件变更

### 新增文件
- `db/zqyy_app/migrations/2026-03-23__case_insensitive_username.sql`
- `docs/audit/prompt_logs/prompt_log_20260323_003544.md`
- `docs/audit/session_logs/2026-03/23/03_6d352688_003156/main_01_87650f7e.md`

### 修改文件
- `apps/backend/app/routers/admin_tenant_admins.py`
- `apps/backend/app/routers/tenant_auth.py`

## 迁移检查

| 迁移文件 | 执行状态 |
|----------|----------|
| `db/zqyy_app/migrations/2026-03-23__case_insensitive_username.sql` | ⏳ 待验证 |

⚠️ DDL 基线待合并（`compliance.has_ddl_baseline = false`）

## 接口同步检查

⚠️ 接口代码已变更但 OpenAPI spec 未同步（新增 `admin_tenant_admins.py` + `tenant_auth.py` 路由）。自动导出失败（`dashscope` 模块缺失导致后端无法导入），需手动安装依赖后运行 `python scripts/ops/_export_openapi.py` 重新导出 spec。


## 改动注解

### `apps/backend/app/routers/admin_tenant_admins.py`
- 变更类型：新增
- 原始原因：租户管理后台需要管理员 CRUD 功能，且用户名需大小写不敏感
- 思路分析：新建完整的管理员路由模块，包含列表查询（分页+搜索）、创建、编辑、软删除、重置密码 5 个端点。所有涉及 username 的 SQL 操作统一使用 `LOWER()` 函数：INSERT 时 `LOWER(%s)` 存储小写，UPDATE 时 `username = LOWER(%s)`，唯一性校验时 `LOWER(username) = LOWER(%s)`。权限依赖 `_require_admin()` 直接从 JWT 校验角色，不查 auth.users 表（因管理员在 admin_users 表）。创建时校验 `tenant_id` 在 `biz.tenants` 中存在且 `is_active=true`。列表查询 JOIN `biz.tenants` 获取 `tenant_name`。
- 修改结果：提供完整的租户管理员 CRUD API，所有用户名操作大小写不敏感。影响 `auth.tenant_admins` 表和 `biz.tenants` 表（只读）。

### `apps/backend/app/routers/tenant_auth.py`
- 变更类型：新增
- 原始原因：租户管理员需要独立的认证端点（登录+令牌刷新），与小程序用户认证分离
- 思路分析：新建租户认证路由，包含 `POST /api/tenant/auth/login` 和 `POST /api/tenant/auth/refresh` 两个端点。登录查询使用 `LOWER(username) = LOWER(%s)` 实现大小写不敏感匹配，同时过滤 `deleted_at IS NULL`（软删除记录不可登录）。JWT payload 包含 `aud=tenant-admin` 区分令牌类型，`managed_site_ids` 用于多门店权限控制。登录成功后更新 `last_login_at`。刷新令牌显式校验 `type=refresh` 和 `aud=tenant-admin`。
- 修改结果：租户管理员可通过用户名密码登录获取 JWT，支持令牌刷新。登录用户名大小写不敏感。影响 `auth.tenant_admins` 表（读+更新 last_login_at）。

### `db/zqyy_app/migrations/2026-03-23__case_insensitive_username.sql`
- 变更类型：新增
- 原始原因：数据库层面保障用户名大小写不敏感的唯一性约束
- 思路分析：两步操作——(1) 将现有用户名统一转小写 `SET username = LOWER(username)`（幂等，已小写的不受影响）；(2) 创建条件唯一索引 `idx_tenant_admins_username_lower ON auth.tenant_admins (LOWER(username)) WHERE deleted_at IS NULL`，在未删除记录中保障大小写不敏感唯一性。保留原 UNIQUE 约束防止完全相同的用户名，新索引额外覆盖大小写变体。包含回滚 SQL 和验证 SQL。
- 修改结果：`auth.tenant_admins` 表新增 `idx_tenant_admins_username_lower` 唯一索引。现有大写用户名被转为小写。与应用层 `LOWER()` 配合，完整实现用户名大小写不敏感。
