Skip to content

分层与依赖

标准 Go 布局,internal 按模块组织,严格三层:

internal/<module>/
  router.go                 路由注册 RegisterRoutes(r, prefix)
  handler/                  HTTP 层:绑定参数、调 service、返回 response.R
  service/                  业务逻辑;system 的 service 导出供 auth 复用
  repository/               数据访问,只有这一层碰 GORM/DB
  model/                    entity(表) / dto(入参) / vo(出参)

单向依赖

handler → service → repository → model
  • 禁止反向依赖。
  • 禁止 handler 直连 repository。
  • pkg 不能 import internal

例外:pkg 需要落库怎么办

注解层(如 pkg/oplog)需要落库,但 pkg 不能依赖 internal 的 service/repository,否则成环。解法是 Recorder 回调反向注册

go
// pkg/oplog 只定义 Recorder 接口与 Event 组装
type Recorder func(ctx context.Context, evt *Event)

// cmd/standalone/main.go 启动时由 internal 反向注册实现
oplog.Init(systemservice.OperLogSvcApp.RecordOper)

pkg 只组装 Event,由 internal/system 在进程启动时经 Init 反向注册 Recorder 消费。这正是原项目 LogAspectOperLogEventSysOperLogServiceImpl @Async @EventListener 落库那套解耦的等价物。详见 pkg 参考 / oplog

同理,审计字段填充(create_by / create_time / update_*)由 pkg/repository 的 GORM 回调做,但它只拿得到 *gorm.DB ,取不到 *gin.Context,故登录态经 context.Context 接力(WithAuditUser / AuditUserFrom)——由 loginhelper.AuditContext 中间件从 gin.Context 取登录用户写进 request.Context。详见 一次请求的流转

命名约定

  • 包名小写无下划线。
  • 文件名 xxx_handler.go / xxx_service.go / xxx_repository.go
  • 实体对应表名(SysUser → 表 sys_user)。GORM SingularTable:true,表名单数,实体无需 TableName()

跨模块复用矩阵

模块有 repository 层model 子目录复用方式
authmodel/ + model/vo/auth 复用 system service(in-process)
system是(14 个 repo)entity/bo/vo/dto 全套导出 service 供 auth 复用
monitormodel/vo/直读 system repo + pkg/redis
resource是(3 个 repo)entity/bo/vo/dto 全套业务逻辑部分仍在 system service(如 message/box)

基于 MIT 协议开源