identity_tenant_and_organization_repositories 模块技术文档
1. 模块概述
1.1 核心问题与定位
在多租户、多组织的企业级应用中,身份管理、租户隔离和资源共享是三个紧密关联且复杂的核心问题。想象一下,一个支持多个企业(租户)、每个企业内部有多个团队(组织)、用户可以跨组织协作、知识和智能体可以在组织间共享的平台,我们需要一个清晰、安全、高效的数据访问层来支撑这一切。
identity_tenant_and_organization_repositories 模块正是为了解决这个问题而存在。它充当了系统的"基础设施锚点",负责:
- 用户身份的持久化与认证令牌管理
- 租户级别的资源隔离与计费计量
- 组织的成员管理与加入流程
- 知识库和智能体在组织间的共享与访问控制
- 租户级别的共享资源禁用机制
1.2 心智模型
可以将这个模块想象成一个**"数字办公楼宇管理系统"**:
- 租户 (Tenant):就像大楼的业主,拥有整层或整个建筑的使用权,负责整体的资源配额和计费
- 用户 (User):就像办公楼里的员工,有自己的身份标识和访问凭证
- 组织 (Organization):就像大楼里的一个个办公室或会议室,用户可以加入多个组织,组织有自己的邀请码、成员列表和访问规则
- 共享记录 (Share):就像办公室之间共享的文件柜或投影仪,需要明确的授权关系
- 禁用记录 (Disabled):就像某个房间临时禁止使用某些共享设备
这种分层设计既保证了租户级别的强隔离,又提供了组织级别的灵活性和协作能力。
2. 架构概览
2.1 组件关系图
用户持久化] AuthTokenRepo[authTokenRepository
认证令牌管理] end subgraph "租户管理层" TenantRepo[tenantRepository
租户持久化] end subgraph "组织治理层" OrgRepo[organizationRepository
组织与成员管理] end subgraph "资源共享层" KBShareRepo[kbShareRepository
知识库共享] AgentShareRepo[agentShareRepository
智能体共享] DisabledAgentRepo[tenantDisabledSharedAgentRepository
租户禁用共享] end UserRepo --> AuthTokenRepo TenantRepo --> OrgRepo OrgRepo --> KBShareRepo OrgRepo --> AgentShareRepo TenantRepo --> DisabledAgentRepo AgentShareRepo --> DisabledAgentRepo
2.2 数据流向
以"用户通过邀请码加入组织并获得共享知识库访问权限"为例,数据流向如下:
- 认证阶段:用户登录 →
userRepository验证用户身份 →authTokenRepository颁发令牌 - 加入组织:用户使用邀请码 →
organizationRepository验证邀请码 → 创建OrganizationMember记录 - 获取共享资源:查询用户可访问的知识库 →
kbShareRepository关联用户所属组织 → 过滤出可用的共享知识库 - 访问控制:当用户使用共享智能体时 →
tenantDisabledSharedAgentRepository检查是否被当前租户禁用
3. 核心设计决策
3.1 分层职责隔离
决策:将用户、租户、组织、共享资源的存储完全分离到不同的 Repository 中。
原因:
- 单一职责原则:每个 Repository 只负责一类实体的持久化
- 独立演进:租户管理可能涉及计费逻辑,而组织管理更关注协作流程,分离后可以独立优化
- 测试友好:可以单独 Mock 某个 Repository 进行测试
权衡:
- ✅ 优点:代码清晰,职责明确,便于维护
- ❌ 缺点:需要在 Service 层进行跨 Repository 的事务协调
3.2 软删除与软删除一致性
决策:对于组织、知识库共享、智能体共享等实体采用软删除,且在查询时主动过滤已删除的关联实体。
原因:
- 审计需求:保留历史共享记录,便于追溯
- 数据恢复:误操作时可以恢复
- 一致性:如
ListByOrganization方法通过JOIN确保只返回知识库未被删除的共享记录
示例(来自 kbShareRepository.ListByOrganization):
Joins("JOIN knowledge_bases ON knowledge_bases.id = kb_shares.knowledge_base_id AND knowledge_bases.deleted_at IS NULL")
3.3 悲观锁用于存储计量
决策:在 tenantRepository.AdjustStorageUsed 中使用悲观锁(clause.Locking{Strength: "UPDATE"})来确保并发安全。
原因:
- 存储计量是关键业务数据,涉及计费
- 乐观锁在高并发场景下可能导致大量重试
- 悲观锁虽然性能稍低,但保证了数据一致性
权衡:
- ✅ 优点:数据一致性有保障,实现简单
- ❌ 缺点:在极端并发下可能成为瓶颈
3.4 邀请码过期逻辑放在 Repository 层
决策:在 organizationRepository.GetByInviteCode 中直接检查邀请码是否过期,并返回 ErrInviteCodeExpired。
原因:
- 邀请码过期是数据层面的业务规则,放在 Repository 层可以确保所有调用者都遵守这一规则
- 避免在 Service 层重复实现过期检查逻辑
示例:
if org.InviteCodeExpiresAt != nil && org.InviteCodeExpiresAt.Before(time.Now()) {
return nil, ErrInviteCodeExpired
}
4. 子模块概述
本模块包含以下三个核心子模块,每个子模块都有独立的详细文档:
4.1 用户身份与认证仓库 (user_identity_and_auth_repositories)
负责用户账户的 CRUD、认证令牌的管理和生命周期维护。核心组件包括 userRepository 和 authTokenRepository。
4.2 租户管理仓库 (tenant_management_repository)
负责租户的生命周期、搜索和存储计量。核心组件是 tenantRepository,特别是其中的 AdjustStorageUsed 方法实现了并发安全的存储计量。
4.3 组织成员、共享与访问控制仓库 (organization_membership_sharing_and_access_control_repositories)
这是最复杂的子模块,进一步细分为:
- 组织成员与治理仓库
- 共享资源访问仓库(知识库共享、智能体共享)
- 租户级共享智能体访问控制仓库
5. 跨模块依赖
5.1 输入依赖
本模块依赖于:
- core_domain_types_and_interfaces 模块:提供
types.User、types.Tenant、types.Organization等领域模型和interfaces.UserRepository等接口定义 - platform_infrastructure_and_runtime 模块:提供
gorm.DB数据库连接和日志工具
5.2 输出依赖
本模块被以下模块依赖:
- application_services_and_orchestration/agent_identity_tenant_and_configuration_services:调用这些 Repository 实现业务逻辑
- http_handlers_and_routing/agent_tenant_organization_and_model_management_handlers:通过 Service 层间接使用
6. 新贡献者指南
6.1 常见陷阱
-
忘记过滤软删除记录:当你直接查询共享表时,一定要记得过滤
deleted_at IS NULL,并且最好 JOIN 关联表确保关联实体也未被删除。 -
存储计量的并发安全:如果你需要扩展存储计量逻辑,务必保持
AdjustStorageUsed的事务和悲观锁机制,否则会出现数据不一致。 -
邀请码过期检查:不要只依赖数据库查询,一定要在 Repository 层检查
invite_code_expires_at。 -
共享记录的唯一性:在创建共享记录时,一定要先检查是否已存在(如
kbShareRepository.Create中的Count检查),避免重复共享。
6.2 扩展建议
- 如果你需要添加新的共享资源类型(如文件共享),可以参考
kbShareRepository和agentShareRepository的模式,创建新的 Repository。 - 如果你需要添加新的访问控制机制,可以参考
tenantDisabledSharedAgentRepository的设计,作为"黑名单"机制的补充。 - 所有 Repository 都通过接口(
interfaces.UserRepository等)对外暴露,这使得在测试时可以轻松 Mock。
6.3 调试技巧
- 当查询共享资源返回空结果时,检查是否有软删除的过滤器在起作用。
- 当存储计量不正确时,检查是否有其他地方绕过了
AdjustStorageUsed直接更新了storage_used字段。 - 利用 GORM 的
Debug()方法在开发环境查看生成的 SQL,确认 JOIN 和 WHERE 条件是否符合预期。