# 4.12 扩展性设计 :::tip 概述 系统的扩展点都是显式声明的:钩子承接业务差异、生成器模板可自定义、任务自注册、驱动可注册、中间件能力可接线裁剪。本页汇总"想加东西时从哪下手"。 ::: ## 扩展点地图 | 想做什么 | 扩展点 | 位置 | |---|---|---| | 模块特有 CRUD 差异 | ModuleSpec 钩子 | service 各模块 | | 标准方法覆盖不了的逻辑 | 手写方法(合法逃生舱) | service 各模块 | | 新定时任务 | init 自注册 | internal/task | | 新数据库方言 | RegisterDriver | internal/model/db | | 生成产物样式 | 模板替换 | templates/*.tpl | | 中间件依赖的业务能力 | Set*Loader / SetLogSink 接线 | middleware + service init | | 新基础设施能力 | 新建 utility 包 | utility/ | | 新配置节 | config.yaml + .env.example 同步 | config/ | ## ModuleSpec 钩子(最常用扩展点) 十个钩子覆盖 CRUD 全生命周期: ```text BeforeAdd / AfterAdd 新增前后 BeforeUpdate / AfterUpdate 修改前后 BeforeDelete / AfterDelete 删除前后 BeforeBatchDelete / AfterBatchDelete AfterPageList / AfterDetail 读侧后处理 ``` 约束:错误原样上抛、禁 HTTP/文件 IO、禁 append。超出约束的逻辑放 service 手写方法,不要硬塞钩子。 ## 代码生成器模板 ```text templates/ ├── dto.tpl / repository.tpl / service.tpl / handler.tpl 后端四件套 ├── ui/ 标准页面模板(api.ts/columns.ts/index/edit/detail/querySchemas) └── ui2/ 树形表页面模板 ``` 替换对应 tpl 即改变全项目生成风格;生成器同时负责菜单幂等创建与 router.go 声明块追加。见 [10.5 模板体系](/zh/generator/templates.html)。 ## 任务自注册 ```go // internal/task/xxx.go func init() { Register("任务名", spec) } // 调度器启动时自动纳入 ``` 调度器、执行锁、任务日志由 task 包统一提供,任务实现只写业务。 ## 驱动注册(数据库扩展) ```go db.RegisterDriver("oracle", factory) // 扩展方言经构建标签隔离 ``` 内置四方言在包内注册;Oracle 等重依赖方言用构建标签(`-tags oracle`)避免拖累默认构建。 ## 中间接线与裁剪 ```go middleware.SetIdentityLoader(...) // auth 模块 middleware.SetTenantLoader(...) // auth 模块 middleware.SetLogSink(...) // operation_log 模块 ``` 未接线的能力被 WireCheck 探测到只告警降级——按模块裁剪部署形态(如去掉内容管理模块)不会引发启动失败。 ## 前端扩展 | 扩展点 | 方式 | |---|---| | 公共组件 | ui/src/components 新增,全局注册 | | 布局插槽 | layout components 按区域扩展 | | 主题 | styles 主题变量 + designSetting store | | 路由 | 动态(菜单 API)+ constant 静态补充 | ## 扩展的边界 扩展不应破坏的稳定面:dto 契约字段名、RouteSpec 声明语义、统一信封结构、`gin_` 表列约定。生成器与前端都依赖这些稳定面,改动前先评估连锁影响。 ## 下一步 → [第 5 章 核心功能](/zh/core/jwt.html)