Files
aiot-platform-cloud/viewsh-module-system/viewsh-module-system-server
lzh 87beb1228e feat(tenant): 租户-项目两级架构 Phase 0+1 — 基础框架层
Phase 0 技术验证:
- ProjectBaseDO extends TenantBaseDO,新增 projectId 字段
- ProjectContextHolder (TransmittableThreadLocal) 项目上下文管理
- ProjectDatabaseInterceptor 实现 TenantLineHandler,返回 project_id 列
- 注册第二个 TenantLineInnerInterceptor,通过 @Qualifier 保证初始化顺序
- DualInterceptorTest 11 个用例验证双拦截器 SQL 注入(SELECT/INSERT/UPDATE/DELETE + JOIN + 子查询)

Phase 1 基础框架层:
- @ProjectIgnore 注解 + ProjectIgnoreAspect (SpEL 条件支持)
- ProjectUtils 工具类 (execute/executeIgnore)
- ProjectContextWebFilter 从请求 Header 解析 project-id
- WebFrameworkUtils 扩展 HEADER_PROJECT_ID + getProjectId()
- WebFilterOrderEnum 新增 PROJECT_CONTEXT_FILTER、PROJECT_SECURITY_FILTER
- RPC: TenantRequestInterceptor 自动透传 project-id
- MQ: Kafka/RocketMQ/RabbitMQ/Redis 全部支持 project-id 发送与消费
- @ProjectJob + ProjectJobAspect (@Order(2) 内层,配合 @TenantJob 使用)
- TenantJobAspect 补充 @Order(1) 外层标记
- ProjectDO + UserProjectDO + Mapper + ProjectService + ProjectController
- ProjectCommonApi (Feign) + ProjectApiImpl + ProjectFrameworkServiceImpl (Guava 缓存)
- TenantServiceImpl.createTenant() 联动创建默认项目
- ErrorCodeConstants 新增 1-002-030-xxx 项目错误码

Review 修复:
- Bean 初始化顺序: projectLineInnerInterceptor 依赖 @Qualifier 确保顺序
- computeIgnoreTable: @ProjectIgnore 检查优先于 isAssignableFrom
- ProjectFrameworkServiceImpl 注册为 Spring Bean
- RocketMQ SendHook: project-id 独立于 tenantId 传播
- createDefaultProject 移入 TenantUtils.execute 事务块内
- 全部 MQ/RPC 统一使用 HEADER_PROJECT_ID 常量
- ProjectJobAspect 增加租户上下文防御校验
- 移除 ProjectDO/UserProjectDO 无效的 @KeySequence
- ProjectServiceImpl/ProjectApiImpl 移除冗余 TenantUtils.execute 嵌套

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:22:57 +08:00
..
2025-12-31 11:48:19 +08:00
2025-12-31 11:48:19 +08:00