8a111ad2ae
将 v2.5.0 的扁平多租户模型重写为私有化部署两层 Tenant 树(Root + 0~N Child),
为 v2.5.1 后续 Feature(F012 resolver / F013 FGA / F018 交接)铺路。
核心变更:
- tenant 表加 parent_tenant_id + share_default_to_children;status 枚举含 orphaned
- user_tenant 加 is_active + uk_user_active(user_id, is_active) 唯一叶子约束
- department 加 is_tenant_root + mounted_tenant_id(挂载点标记)
- audit_log 追加结构化列:tenant_id/operator_tenant_id/action/target_type/target_id/reason/metadata
- 新增 TenantMountService(mount/unmount 三策略/resource migrate-from-root)
- 新增 DepartmentDeletionHandler(SSO/Celery/manual 三源孤儿处理)
- POST /tenants + /user/switch-tenant 改 HTTP 410 Gone(AC-15)
- PUT /tenants/1/status + DELETE /tenants/1 → 403 + 22008(INV-T11)
- 新增 4 个 API 端点:POST/DELETE /departments/{id}/mount-tenant、POST /tenants/{child}/resources/migrate-from-root
- 错误码模块 220 tenant_tree (22001-22011),原 spec 190 与 permission F004 冲突重分配
Alembic:
- v2_5_1_f011_tenant_tree.py:ALTER 四张既有表 + Root 回填 + uk_user_tenant→uk_user_active
- 业务逻辑抽到 alembic_helpers/f011.py 便于单测
测试(117 passed / 0 regressions):
- test_f011_migration.py:Root 回填 + is_active 回填 + 多 active dedup
- test_tenant_tree_dao.py / test_user_tenant_leaf.py / test_audit_log_v2.py:ORM + DAO SELECT 语义
- test_tenant_service_root_protect.py / test_deprecated_tenant_endpoints.py:Root 保护 + 410
- test_tenant_mount_service.py / test_department_deletion_handler.py:Service 单元
- test_tenant_mount_api.py:TestClient 端到端
- test_abulk_update_tenant_id.py:AC-04a 原子性(rollback on mid-loop failure)
SDD 产出:
- features/v2.5.1/release-contract.md 表 3 模块编码 190→220
- features/v2.5.1/011-tenant-tree-model/{spec,tasks,ac-verification}.md
- CLAUDE.md 模块编码清单 + v2.5 Tenant 树形上下文
- F012-F021 spec 骨架同步入仓
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>