Files
backend/ARCHITECTURE.md
lafay 6d335e393d
All checks were successful
Build Backend / build (push) Successful in 18m57s
Build Backend / build-docker (push) Successful in 1m4s
feat(websocket): integrate WebSocket support and refactor SSE handling
- Added WebSocket support by introducing a new WSHandler and related infrastructure.
- Replaced SSE implementations with WebSocket equivalents across message and QR code handlers.
- Updated service and repository layers to utilize WebSocket for real-time messaging.
- Removed obsolete SSE hub and related code, streamlining the application for WebSocket usage.
- Enhanced router to include WebSocket endpoints for real-time communication.
2026-03-26 21:17:49 +08:00

8.3 KiB
Raw Blame History

后端架构设计规范

1. 分层架构原则

层级定义

Handler (控制器层) → Service (业务逻辑层) → Repository (数据访问层) → Infrastructure (基础设施层)

层级职责

层级 职责 依赖关系
Handler 接收HTTP请求、参数校验、调用Service、返回响应 仅依赖Service
Service 实现业务逻辑、事务管理、组合多个Repository 仅依赖Repository接口
Repository 数据CRUD操作、数据库事务管理 仅依赖Model和GORM
Infrastructure 缓存、消息队列、RPC等外部服务 被Service调用

关键约束

  • Handler禁止直接依赖Repository或直接操作数据库
  • Service禁止直接依赖gorm.DB必须通过Repository间接操作
  • 所有外部依赖通过接口抽象

2. Repository 层规范

2.1 接口 + 私有实现模式

所有Repository必须采用接口定义 + 私有实现结构体的模式:

// ✅ 正确:接口 + 私有实现
type UserRepository interface {
    Create(user *model.User) error
    GetByID(id string) (*model.User, error)
}

type userRepository struct {
    db *gorm.DB
}

func NewUserRepository(db *gorm.DB) UserRepository {
    return &userRepository{db: db}
}

func (r *userRepository) Create(user *model.User) error {
    return r.db.Create(user).Error
}
// ❌ 错误:直接暴露结构体指针
type UserRepository struct {
    db *gorm.DB
}

func NewUserRepository(db *gorm.DB) *UserRepository {
    return &UserRepository{db: db}
}

2.2 Repository方法设计原则

  • 方法签名中使用接口类型而非指针func (r *userRepository) GetByID(...) (*model.User, error)
  • 避免在Repository层直接返回指针切片,使用值切片更安全
  • 事务操作在Repository内部封装Service不应直接调用db.Transaction()

2.3 新增Repository流程

  1. repository/目录下创建xxx_repo.go文件
  2. 定义XxxRepository接口,包含所有数据访问方法
  3. 创建私有实现结构体xxxRepository
  4. 创建构造函数NewXxxRepository(db *gorm.DB) XxxRepository
  5. wire/repository.goRepositorySet中注册

3. Service 层规范

3.1 接口 + 私有实现模式

// ✅ 正确
type UserService interface {
    CreateUser(ctx context.Context, req *dto.CreateUserRequest) (*model.User, error)
    GetUserByID(ctx context.Context, id string) (*model.User, error)
}

type userService struct {
    userRepo repository.UserRepository
    // 其他Repo都使用接口类型
}

func NewUserService(userRepo repository.UserRepository) UserService {
    return &userService{userRepo: userRepo}
}

3.2 Service依赖管理

  • 所有Repository依赖必须使用接口类型,禁止使用*repository.XxxRepository指针
  • 禁止在Service中直接持有gorm.DB如有数据库操作必须下沉到Repository
  • 如需事务支持在Repository中封装事务方法Service调用封装好的方法

3.3 Service间依赖

  • Service之间通过接口依赖避免循环依赖
  • 如Service A需要调用Service B的方法确保该方法在接口中定义

4. Handler 层规范

4.1 Handler只依赖Service

// ✅ 正确
type UserHandler struct {
    userService service.UserService  // 仅依赖Service接口
}

func NewUserHandler(userService service.UserService) *UserHandler {
    return &UserHandler{userService: userService}
}
// ❌ 错误直接依赖Repository或Cache
type UserHandler struct {
    userRepo    *repository.UserRepository  // 禁止
    cache       cache.Cache               // 禁止
}

4.2 参数和类型分离

  • Query参数和Filter类型应定义在dto/包中,而非repository/
  • Handler负责将HTTP参数转换为DTO后传递给Service

5. DTO/Filter 类型规范

5.1 放置位置

  • 所有查询参数、过滤条件、分页参数定义在internal/dto/目录下
  • 禁止在repository/包中定义供Handler使用的Filter类型

5.2 文件组织

internal/dto/
├── filter.go          # 通用过滤条件LogFilter, LoginFilter等
├── user_converter.go  # 用户相关转换
└── ...

5.3 Filter类型定义示例

// internal/dto/filter.go

type LogFilter struct {
    UserID     string
    Operation  string
    TargetType string
    StartTime  string
    EndTime    string
}

type PaginationParams struct {
    Page     int
    PageSize int
}

6. Wire 依赖注入规范

6.1 Provider函数设计

// ✅ 正确Provider返回接口类型
func ProvideUserService(
    userRepo repository.UserRepository,  // 接口类型
    cacheBackend cache.Cache,
) service.UserService {
    return service.NewUserService(userRepo, cacheBackend)
}

// ❌ 错误:返回指针类型
func ProvideUserService(userRepo *repository.UserRepository) *service.UserService

6.2 NewXxxService构造函数签名

  • 构造函数参数使用接口类型
  • 返回值使用接口类型
// ✅ 正确
func NewUserService(
    userRepo repository.UserRepository,      // 接口
    cache cache.Cache,
) UserService {                             // 返回接口
    return &userService{userRepo: userRepo}
}

6.3 禁止的直接注入

  • 禁止在Handler的Provider中直接注入Repository和Cache应仅注入Service
  • 禁止在Service的Provider中直接注入gorm.DB

7. 事务管理规范

7.1 事务边界在Repository层

// ✅ 正确事务封装在Repository内部
func (r *userRepository) CreateUserWithProfile(user *model.User, profile *model.Profile) error {
    return r.db.Transaction(func(tx *gorm.DB) error {
        if err := tx.Create(user).Error; err != nil {
            return err
        }
        profile.UserID = user.ID
        return tx.Create(profile).Error
    })
}

7.2 Service调用事务方法

// ✅ Service通过调用Repository的封装方法使用事务
func (s *userService) CreateUser(ctx context.Context, req *dto.CreateUserRequest) error {
    user := &model.User{Name: req.Name}
    profile := &model.Profile{Bio: req.Bio}
    return s.userRepo.CreateUserWithProfile(user, profile)
}

8. 常见错误示例

错误1Handler直接依赖Repository

// ❌ 错误
type PostHandler struct {
    postRepo *repository.PostRepository
}

// ✅ 正确
type PostHandler struct {
    postService service.PostService
}

错误2Service直接使用gorm.DB

// ❌ 错误
type postService struct {
    db *gorm.DB
}

func (s *postService) CreatePost(post *model.Post) error {
    return s.db.Create(post).Error
}

// ✅ 正确使用Repository
func (s *postService) CreatePost(post *model.Post) error {
    return s.postRepo.Create(post)
}

错误3Repository返回指针类型

// ❌ 错误
func NewUserRepository(db *gorm.DB) *UserRepository {
    return &UserRepository{db: db}
}

// ✅ 正确
func NewUserRepository(db *gorm.DB) UserRepository {
    return &userRepository{db: db}
}

错误4Filter类型放在repository包

// ❌ 错误repository包不应该被handler直接引用
package repository
type LogFilter struct {
    UserID string
}

// ✅ 正确放在dto包
package dto
type LogFilter struct {
    UserID string
}

9. 新功能开发 Checklist

开发新功能时,确保满足以下规范:

  • Repository定义

    • 接口 + 私有实现结构体
    • 构造函数返回接口类型
    • 方法参数使用值类型而非指针
    • wire/repository.go中注册
  • Service定义

    • 接口 + 私有实现结构体
    • 所有Repository依赖使用接口类型
    • 不直接持有gorm.DB
    • 事务操作下沉到Repository
  • Handler定义

    • 仅依赖Service接口
    • 不直接依赖Repository或Cache
    • Query/Filter参数使用dto包类型
  • Wire Provider

    • 参数使用接口类型
    • 返回值使用接口类型
    • 不直接注入gorm.DB到Service

10. 相关文件位置参考

类别 目录
Handler internal/handler/
Service internal/service/
Repository internal/repository/
DTO/Filter internal/dto/
Model internal/model/
Wire internal/wire/
Cache internal/cache/