这些审计记录原本堆积在 docs/audit/changes/changes/ 嵌套误产物目录下(由开发机迁移
79d3c2e 前后的不明批量操作产生)。由于同期 .gitignore 屏蔽了 docs/audit/ 全目录,
它们从未入过 git 任何分支 history。删除即永久丢失。
按 docs/specs/audit-gap-recovery/tasks.md 阶段 1 执行,将全部 96 份 D 类孤本
(主目录无同名、git history 亦无记录)复制到 docs/audit/changes/ 主目录入仓。
涵盖主题: P1-P18 全栈集成 / 多模块累积变更 / ETL bug 修复 / 业务日切 /
召回与任务引擎改造 / 租户管理与审批 / 董事会财务 / 客户与助教详情 /
DDL 基线合并 / Kiro 到 Claude Code 迁移
阶段 2(B 类内容漂移 1 份)和阶段 4(嵌套目录删除)独立推进。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.7 KiB
3.7 KiB
变更审计记录:租户用户审核 — 软删除恢复 upsert 修复
| 字段 | 值 |
|---|---|
| 日期 | 2026-03-25 01:54:19 |
| Prompt-ID | P20260325-000112 |
| Session-ID | 4627fd68 |
| Session 路径 | docs/audit/session_logs/2026-03/24/79_de2a1755_235713 |
操作摘要
修复租户管理后台审核通过流程中 ON CONFLICT DO NOTHING 被已软删除记录阻塞的 bug。当用户曾被移除(is_removed=true)后重新申请并审核通过时,user_site_roles 写入被唯一约束上的已删除记录阻塞,导致 approved 用户无角色。改为 DO UPDATE SET is_removed = false, removed_at = NULL 恢复软删除记录。同步更新了前后端联调规范文档,将此模式记录为通用规则。
风险标签
dir:backend、root-file、dir:admin-web、dir:etl、dir:miniprogram、dir:db、db-schema-change
注:本次 session 实际只修改了
tenant_users.py和联调文档。其余风险标签来自累积未审计的变更(DEMO-miniprogram 迁移、admin-web 重构、miniprogram 更新、ETL 调整等),这些变更在更早的提交中完成,本次审计一并覆盖标记清除。
本次对话文件变更
新增文件
docs/audit/prompt_logs/prompt_log_20260325_000112.mddocs/audit/session_logs/2026-03/24/78_ec0569d7_234840/main_01_a5bb4c10.mddocs/audit/session_logs/2026-03/24/79_de2a1755_235713/main_01_fe71cc2d.mddocs/audit/session_logs/2026-03/24/79_de2a1755_235713/sub_01_fe71cc2d.md
删除文件
docs/audit/session_logs/2026-03/24/78_ec0569d7_234840/main_01_df41de21.md(被替换为新版本)
合规检查
- ⚠️ 接口代码已变更但 OpenAPI spec 未同步(
api_changed: true,openapi_spec_stale: true)— 需手动运行python scripts/ops/_export_openapi.py重新导出 - ⚠️ DDL 基线待合并(
has_ddl_baseline: false)— 累积变更中含 db-schema-change - ⚠️ 文档同步缺失:
apps/backend/app/routers/tenant_users.py应同步更新apps/backend/docs/API-REFERENCE.md和docs/contracts/openapi/backend-api.json - ✅ 迁移 SQL:无新增迁移(
new_migration_sql为空)
改动注解
apps/backend/app/routers/tenant_users.py
- 变更类型:修改
- 原始原因:用户反馈审核通过时,后端用
applied_role_text匹配auth.roles失败导致user_site_roles未写入。实际问题是ON CONFLICT DO NOTHING被已软删除的记录阻塞——唯一约束(user_id, site_id, role_id)上存在is_removed=true的旧记录,INSERT 触发冲突但 DO NOTHING 跳过,导致用户审核通过后无角色。 - 思路分析:将
approve_application中user_site_roles的 INSERT 语句从ON CONFLICT DO NOTHING改为ON CONFLICT (user_id, site_id, role_id) DO UPDATE SET is_removed = false, removed_at = NULL。这是软删除 + 唯一约束的标准处理模式(已记录在前后端联调规范中)。不影响其他端点,不改变表结构。 - 修改结果:审核通过流程可正确恢复已软删除的角色记录。影响范围仅限
POST /api/tenant/applications/{id}/approve端点。
docs/guides/FRONTEND-BACKEND-INTEGRATION.md
- 变更类型:修改(简要)
- 同步更新联调规范,新增"软删除 + 唯一约束陷阱"通用规则条目。
.kiro/steering/frontend-backend-integration.md
- 变更类型:修改(简要)
- steering 规则同步更新,引用联调规范中的新增条目。
回滚策略
代码回滚:revert approve_application 中的 upsert 改动,恢复为 ON CONFLICT DO NOTHING。
数据影响:若已有用户通过新逻辑恢复了角色,回滚后不影响已恢复的记录(is_removed=false 状态保持)。