interfaces.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. // 仓储接口(Service 层依赖抽象,供纯 mock 单测——不连 DB 也能覆盖 AuthService 逻辑)。
  2. //
  3. // 设计决策(依赖倒置 + 零返工):
  4. // - Service 只依赖这 3 个**接口**(不 import 具体结构体);
  5. // 生产装配时注入具体实现(NewUserRepo(db) 等),单测时注入 mock。
  6. // - 接口签名与具体仓储方法**逐一对齐**(入参/出参/error 语义完全一致),
  7. // 生产装配时具体结构体隐式满足接口——若后续改方法签名,main 装配处编译期即暴露。
  8. //
  9. // 命名约定:接口名带 "…Repository"(UserRepository/IdentityRepository/MembershipRepository),
  10. // 与本包内具体结构体(UserRepo/IdentityRepo/MembershipRepo)区分,避免同名冲突。
  11. //
  12. // 为什么在 repository 包内定义(而非 service 包):
  13. // - 接口的"自然归属"是数据访问层(描述"能取哪些数据");
  14. // - service 包 import repository 包取接口(service → repository,方向正确);
  15. // - 若接口放 service 包,repository 包要 import service 包实现它 → 反向依赖,违反铁律。
  16. //
  17. // 平台级访问(同 user_repo.go 包注释):这 3 个接口的实现不继承 scope.BaseRepo——
  18. // 登录/用户/成员关系是平台级全局查询,多租户防线在后续业务域 Repository 才启动。
  19. package repository
  20. import (
  21. "context"
  22. "yuansiwei/unified-backend/internal/identity/model"
  23. orgmodel "yuansiwei/unified-backend/internal/org/model"
  24. )
  25. // UserRepository 用户主表数据访问接口(*UserRepo 隐式满足)。
  26. type UserRepository interface {
  27. // GetByCanonicalUserID 按 canonical_user_id(ULID)取单个用户(含密码三列——仅登录链路在内存消费)。
  28. GetByCanonicalUserID(ctx context.Context, uid string) (*model.User, error)
  29. // UpdatePasswordLazyUpgrade 惰性升级写回(argon2 重哈希 + salt 置 NULL + hash_version='argon2')。
  30. UpdatePasswordLazyUpgrade(ctx context.Context, uid, newHash string) error
  31. }
  32. // IdentityRepository 登录身份数据访问接口(*IdentityRepo 隐式满足)。
  33. type IdentityRepository interface {
  34. // GetByTypeIdentifier 按 (type, identifier) 唯一键取登录身份记录。
  35. GetByTypeIdentifier(ctx context.Context, typ, identifier string) (*model.Identity, error)
  36. }
  37. // MembershipRepository 成员关系数据访问接口(*MembershipRepo 隐式满足)。
  38. type MembershipRepository interface {
  39. // ListByCanonicalUserID 取某用户全部成员关系(登录第一步返回机构/校区选择列表用;空时返非 nil 空切片)。
  40. ListByCanonicalUserID(ctx context.Context, uid string) ([]orgmodel.Membership, error)
  41. // GetByUserInstitutionCampus 按 (canonical_user_id, institution_id, campus_id) 取唯一 membership
  42. // (登录第二步 /auth/issue 选定作用域后取 role;同作用域多角色取 created_at 最新)。
  43. GetByUserInstitutionCampus(ctx context.Context, uid string, institutionID, campusID int64) (*orgmodel.Membership, error)
  44. }
  45. // 编译期接口断言:具体仓储结构体须满足对应接口(防止"接口与实现签名漂移"——
  46. // 改任一侧方法签名时,main 装配处把具体实现当接口传参会编译失败,此处再显式兜一层)。
  47. var (
  48. _ UserRepository = (*UserRepo)(nil)
  49. _ IdentityRepository = (*IdentityRepo)(nil)
  50. _ MembershipRepository = (*MembershipRepo)(nil)
  51. )