Become a sponsor

概述
后端按职责分为五层:契约(dto)、接口(handler)、业务(service)、数据(repository)、横切(middleware + hooks)。每层只做一件事,依赖单向向下。
middleware 横切处理(认证/租户/权限/日志/限流)
│ 注入身份与上下文到 ctx
▼
handler 极薄委托(签名固定,反射注册)
│
▼
service 业务规则(ModuleSpec 声明 + 手写逻辑 + 事务)
│
▼
repository 数据访问(Ctx 入口注入软删/租户 Scope)
│
▼
gorm + db 连接(多方言驱动注册表 + 全局钩子盖章)dto 被所有层引用(契约);utility 被任意层引用(无业务语义)。
| 层 | 做什么 | 不做什么 |
|---|---|---|
| dto | 请求/响应结构、binding/msg/form/json 标签、UnmarshalBody | 业务判断 |
| handler | 委托调用、调用转换 | 参数解析、权限、规则 |
| service | 业务规则、事务、错误上抛、ModuleSpec 声明 | HTTP 响应构造、裸 SQL 拼接 |
| repository | 条件查询、软删除、存在性判断 | 业务条件决策 |
| middleware | 认证、租户、鉴权、日志、限流、信封 | 业务逻辑 |
service:var Xxx *sXxx(init 注册,全进程单例,方法必须并发安全)
跨模块:同包直调 —— User.Page(...)、repository.NewDeptRepo()(无需 import)
仓储:无状态(仅持表名),NewXxxRepo() 按需构造、可并发使用事务是 service 的职责:
db.WithTrans(ctx, func(ctx context.Context) error {
// 回调内使用入参 ctx——它携带事务连接
// 内部所有 repository.Ctx(ctx) 自动加入事务
// 返回非 nil 错误整体回滚
})repository 无感知事务——它永远从 ctx 取连接,这是 ctx 贯穿设计的直接收益。
repository 返回 gorm 错误
↓
service 映射为业务错误(consts 哨兵 / apperr.Newf)或原样上抛
↓
handler 不接触,透传
↓
response 中间件统一映射为信封(apperr 按码输出,其余通用失败)| 执行点 | 时机 | 承担什么 |
|---|---|---|
| 中间件链 | HTTP 请求级 | 身份、租户、权限、日志、限流、信封 |
| GORM 全局钩子 | SQL 语句级 | 审计盖章、物理删除拦截 |
| repository Scope | SQL 构建前 | del_flag=0、租户过滤 |
同一个红线(软删/租户)在读写两侧分别由 Scope 与钩子执行,业务代码零参与。
一个模块固定四文件,写法见 第 3 章 模块开发实战 与 12.4 模块开发规约。