Files
Neo-ZQYY/docs/database/BD_manual_soft_delete_user_site_roles.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

4.2 KiB
Raw Blame History

BD 手册user_site_roles / user_assistant_binding 软删除

变更日期

2026-03-24

变更说明

auth.user_site_rolesauth.user_assistant_binding 两张表上新增软删除字段,替代原有的物理删除(DELETE)。

新增字段

字段 类型 默认值 说明
auth.user_site_roles is_removed boolean false 软删除标记
auth.user_site_roles removed_at timestamptz NULL 移除时间戳
auth.user_assistant_binding is_removed boolean false 软删除标记
auth.user_assistant_binding removed_at timestamptz NULL 移除时间戳

新增索引

索引名 类型 说明
ix_user_site_roles_active user_site_roles 部分索引 WHERE is_removed = false 加速活跃记录查询
ix_user_assistant_binding_active user_assistant_binding 部分索引 WHERE is_removed = false 加速活跃记录查询

兼容性影响

后端 API已同步修改

所有查询 user_site_rolesuser_assistant_binding 的位置均已添加 AND is_removed = false 过滤:

  • xcx_auth.py登录、me 接口、切换门店、刷新令牌、获取门店列表、dev 调试接口
  • tenant_users.py:用户列表、编辑用户、更新绑定、移除用户
  • role.py:权限查询、门店列表、角色检查
  • task_manager.py:获取助教 ID
  • task_generator.py:门店助教规模检查、入驻时间保护
  • performance_service.py:助教信息查询

ETL

无直接影响。ETL 不写入这两张表。

小程序

无代码改动。被移除的用户在小程序端会因角色查询返回空而进入已有的无权限路由。

租户管理后台

remove_user 操作从 DELETE 改为 UPDATE SET is_removed = true, removed_at = now()

查询规则(强制)

所有读取 user_site_rolesuser_assistant_binding 的 SELECT 查询,必须包含 AND is_removed = false(或等效的 JOIN 条件 AND xxx.is_removed = false)。

例外:

  • 管理后台需要查看已移除记录的场景(如审计日志)
  • dev 调试接口中的物理删除操作(仅开发模式)

回滚策略

-- 1. 恢复所有被软删除的记录
UPDATE auth.user_site_roles SET is_removed = false, removed_at = NULL WHERE is_removed = true;
UPDATE auth.user_assistant_binding SET is_removed = false, removed_at = NULL WHERE is_removed = true;

-- 2. 删除索引
DROP INDEX IF EXISTS auth.ix_user_site_roles_active;
DROP INDEX IF EXISTS auth.ix_user_assistant_binding_active;

-- 3. 删除字段
ALTER TABLE auth.user_site_roles DROP COLUMN IF EXISTS removed_at;
ALTER TABLE auth.user_site_roles DROP COLUMN IF EXISTS is_removed;
ALTER TABLE auth.user_assistant_binding DROP COLUMN IF EXISTS removed_at;
ALTER TABLE auth.user_assistant_binding DROP COLUMN IF EXISTS is_removed;

注意:回滚后需同步还原后端代码中所有 AND is_removed = false 过滤条件,并将 remove_user 恢复为 DELETE

验证 SQL

-- 1. 确认字段存在且默认值正确
SELECT column_name, data_type, column_default
  FROM information_schema.columns
 WHERE table_schema = 'auth'
   AND table_name IN ('user_site_roles', 'user_assistant_binding')
   AND column_name IN ('is_removed', 'removed_at')
 ORDER BY table_name, column_name;

-- 2. 确认部分索引存在
SELECT indexname, indexdef
  FROM pg_indexes
 WHERE schemaname = 'auth'
   AND indexname IN ('ix_user_site_roles_active', 'ix_user_assistant_binding_active');

-- 3. 确认现有数据未被误标记(所有记录 is_removed 应为 false
SELECT 'user_site_roles' AS tbl, COUNT(*) AS total,
       COUNT(*) FILTER (WHERE is_removed = true) AS removed
  FROM auth.user_site_roles
UNION ALL
SELECT 'user_assistant_binding', COUNT(*),
       COUNT(*) FILTER (WHERE is_removed = true)
  FROM auth.user_assistant_binding;

-- 4. 确认活跃记录查询走部分索引EXPLAIN 检查)
EXPLAIN SELECT * FROM auth.user_site_roles WHERE user_id = 1 AND site_id = 1 AND is_removed = false;

迁移脚本

db/zqyy_app/migrations/20260324_soft_delete_user_site_roles_and_binding.sql