# 4.7 基座与公共体系 :::tip 概述 项目有三个"基座"承担复用:`repository.Base`(数据访问红线入口)、`ModuleSpec`(声明式 CRUD)、`dto` 公共结构(分页/时间/空响应)。跨模块协作靠同包直调与 init 注册的接线机制。 ::: ## repository.Base ```go // internal/repository/base.go type Base struct{ table string } func (b Base) Ctx(ctx) *gorm.DB // 唯一常规入口:注入 del_flag=0 + 租户 Scope func (b Base) Raw(ctx) *gorm.DB // 受限入口:无 Scope,导入/字典等明确场景 func (b Base) SoftDelete(ctx, conds...) // 软删除统一入口 func (b Base) SoftDeleteByID(ctx, id) func (b Base) ExistsByCond(ctx, conds...) (bool, error) ``` 所有仓储内嵌 Base 获得能力,表名在构造时传入。事务连接经 `db.FromContext(ctx)` 自动复用。 ## ModuleSpec 声明式基座 `internal/service/module_spec.go` 的泛型结构,把标准 CRUD 的全部差异点参数化: | 类别 | 声明字段 | |---|---| | 查询 | Model / LikeFields / EqFields / KeywordFields / Filter / OrderBy / ListOrderBy / OrderableFields | | 输出 | IsTree / ParentOf / ChildSetter / SerializeMaps / FileFields / MultiFileFields / ContentFields / FileSaveDir / FieldLabels | | 规则 | UniqueFields / DataScope | | 钩子 | Before/AfterAdd、Before/AfterUpdate、Before/AfterDelete、Before/AfterBatchDelete、AfterPageList、AfterDetail | 标准方法 Page/List/Detail/Add/Update/Delete/BatchDelete 在声明之上执行固定流水线。完整字段语义见 [附录 G ModuleSpec 声明速查](/zh/appendix/module-spec.html)。 **钩子使用约束**:错误原样上抛;禁 HTTP/文件 IO;禁 append(可就地改元素);data 已含 ToData 结果与自动补齐的审计字段。 ## dto 公共结构 | 结构 | 用途 | |---|---| | PageReq | 分页入参(pageNo/pageSize + GetPageNo/GetPageSize 兜底) | | PageData[T] | 分页壳(records/total/size/current/pages;records 空时输出 []) | | EmptyRes | 无数据响应的统一壳 | | LocalTime | 时间输出格式化包装(NULL 输出 null) | ## 跨模块协作 ```text 同包直调:service 包内模块互相引用零 import —— User.Page(ctx, req) 仓储构造:任何模块可 repository.NewDeptRepo() 字典查询:DictGetText(ctx, dictCode, value)(dict 模块对外能力) ``` ## init 接线机制 服务模块用 init 把能力注册到包级变量,中间件/钩子消费已注册能力: | 接线点 | 注册方 | 消费方 | |---|---|---| | IdentityLoader / TenantLoader | auth 模块 init | JWT / Tenant 中间件 | | LogSink | operation_log 模块 init | OperationLog 中间件 | | SetDictLookup | dict 模块 init | ModuleSpec 字典回填 | | 任务自注册 | task 包 init | 调度器 | 未注册不 panic——`WireCheck` 启动时探测三个接线点,缺失打告警并说明降级后果,支持按模块裁剪部署。 ## 定时任务体系 ```text internal/task/task.go 调度器(cron 表达式 + 执行锁 + 日志) internal/task/xxx.go 任务实现(init 自注册) service/daemon.go DaemonInit 启动接线 service/job*.go 任务管理与日志的业务接口 ``` 新增任务 = 写一个 task 文件 + init 注册,无需改调度器。 ## 下一步 → [4.8 横切机制](/zh/architecture/cross-cutting.html)