Files
Neo-ZQYY/docs/audit/changes/2026-03-25__tenant-users-soft-delete-upsert-fix.md
Neo 14a12342b5 chore(audit): 补追 96 份未入仓审计孤本 — 覆盖 2026-02-26 ~ 2026-04-08
这些审计记录原本堆积在 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>
2026-04-20 06:35:42 +08:00

3.7 KiB
Raw Blame History

变更审计记录:租户用户审核 — 软删除恢复 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:backendroot-filedir:admin-webdir:etldir:miniprogramdir:dbdb-schema-change

注:本次 session 实际只修改了 tenant_users.py 和联调文档。其余风险标签来自累积未审计的变更DEMO-miniprogram 迁移、admin-web 重构、miniprogram 更新、ETL 调整等),这些变更在更早的提交中完成,本次审计一并覆盖标记清除。

本次对话文件变更

新增文件

  • docs/audit/prompt_logs/prompt_log_20260325_000112.md
  • docs/audit/session_logs/2026-03/24/78_ec0569d7_234840/main_01_a5bb4c10.md
  • docs/audit/session_logs/2026-03/24/79_de2a1755_235713/main_01_fe71cc2d.md
  • docs/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.mddocs/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_applicationuser_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 状态保持)。