# 4.11 扩展性设计 :::tip 概述 扩展性来自两方面:一是**标准变更的操作清单**(按变更类型给出 checklist,不漏步骤、不变异架构);二是**逃生舱挂点**(基座装不下的需求有明确的合法出口)。本节按变更类型组织。 ::: ## 变更类型 Checklist ### 1. 给现有模块新增一个接口 ```text □ api/v1/{模块}.go:新增 {Mod}{Action}Req(内嵌 gmeta.Meta,path 带 /api 前缀、 permission、log、logType)+ {Mod}{Action}Res □ controller:同名方法,签名 func (c *CXxx) Action(ctx, req) (res, err) □ service/{模块}.go:接口追加方法声明(手维护) □ logic:实现方法(基座可表达走 spec 钩子,复杂走手写) □ 权限节点同步:若 permission 为新码,需在菜单管理为角色勾选 (或插入 goframe_menu type=1 节点) □ go build ./... && gofmt;重启;/api.json 核对新条目 ``` ### 2. 给现有模块加字段 ```text □ MySQL ALTER(列注释按枚举规范写"字段:1-x 2-y";需要唯一性则补 uk_*) □ gf gen dao -c hack/config.yaml(刷新 entity/do/dao internal;service 不动) □ api/v1:Req/Res/Item 结构体补字段(json 驼峰 + dc 注释) □ logic:ToData 补键;枚举补 SerializeMaps(字典编码 {模块}_{字段}); 文件字段补 FileFields+FileSaveDir;富文本补 ContentFields □ 前端:columns.ts / querySchemas.ts / edit.vue 同步 □ document/ 五方言脚本同步;必要时附录表清单更新 □ go build → 重启 → page/detail 黄金样本更新 ``` ### 3. 新增模块 ```text □ 设计表(统一审计列 + del_flag + uk_* + 注释枚举)→ DDL 落库 □ 租户级?→ hooks.tenantTables 登记 □ go run ./cmd/generator -tables "goframe_x|中文名"(或手动四件套) □ logic 调整:spec 声明(筛选/树形/字典/文件/唯一 Group)、扩展接口 □ service 接口核对;router.go 注册行确认 □ go build ./... → 重启 → 角色勾选新权限节点 ``` ### 4. 新增中间件 ```text □ internal/middleware/{name}.go:func(r *ghttp.Request),职责单一; 读配置用 cfgBool/cfgInt;客户端 IP 用 realClientIP;响应用 utility/response □ 不得 import 业务包——需要业务数据时在 wire.go 增加 Loader 函数变量, 由 logic init 注册(参照 IdentityLoader 模式) □ router.Register 的 s.Use 链按序插入(顺序即语义,评审明确插入点) □ public 路径行为:确认对 IsPublicPath 的放行策略 ``` ### 5. 新增定时任务 ```text □ internal/task/{task_name}.go + init RegisterJobHandler("TaskName", h) □ handler 签名 (ctx, params) (string, error);长任务分批+上限;禁 HTTP 于事务内 □ 任务表配置:url="TaskName"、params JSON、cron(6 段或 # 5 段)、 execute_policy/is_sync;发布(status=1) □ 验证:daemonStatus 挂载 + runOnce + job/log 成功记录 □ go build 重启(init 注册发生在进程加载期) ``` ### 6. 自定义 / 扩展 dao ```text □ dao/{m}.go 尾部"Add your custom methods"区追加方法(统计/联查等) □ 修改模板本身:改 hack/tpl/dao_index.tpl 后 gf gen dao 重新生成 (overwriteDao:false 保留手工扩展;新旧模板产物差异需人工合并) □ 红线:自定义方法也必须以 Ctx(ctx) 为查询入口;禁止在 dao 内做业务判断 ``` ### 7. 配置变更 ```text □ manifest/config/config.yaml 修改 □ 多环境差异用 GF_ 环境变量覆盖,不改文件 □ 新增配置键:注释说明 + 代码 cfgBool/cfgInt 带默认值读取(缺失不 panic) □ 影响限流/日志/上传/调度的键变更后跑对应回归 ``` ## 逃生舱与扩展挂点 | 挂点 | 场景 | 说明 | |------|------|------| | BodyUnmarshaler | 请求体形态不规则(平铺 map 等) | Req 实现 `UnmarshalBody(r)` 跳过默认 Parse(自行做 gvalid) | | ModuleSpec.Filter | 复杂查询条件 | 不与 Like/Eq 重复声明 | | ModuleSpec.DataScope | 数据权限挂点 | 共享工厂 `ApplyDataScope(col)`,声明即生效 | | ModuleSpec 钩子装不下 | 基座禁止按模块分支 | 整个方法手写(合法逃生舱,如 job.Detail 因嵌入结构手写) | | logic 包级共享函数 | 跨模块复用 | 放具体模块文件顶部(同包可见);横切能力进 base.go(15 导出上限) | | RegisterJobHandler | 本地任务处理器 | 全局注册表(重名 panic) | | middleware wire | 业务与中间件解耦 | 三 Loader/Sink 函数变量 | ## 未启用项与前端遗留 | 项 | 现状 | 启用/处理要点 | |----|------|-------------| | 用户注册 | publicPaths 含 /api/register(路由未注册) | 启用时补建表逻辑 + 开放策略 + 租户归属规则 | | 数据范围自定义档 | 现四档纯列值(role.data_scope) | 第 5 档需部门关联表 + 角色表单部门树多选 | | 导出增强 | 当前导出返回临时文件 URL | 可加流式下载/异步导出 | | SendSms 任务 | task/send_sms.go 仅记日志 | 接短信通道时替换实现 | | 站内信/数据源/短信/OSS/WebSocket | 前端遗留死代码(后端桩已删除) | 不再调用即无影响 | ## 封板后的变更纪律 ```text 1) 一切接口行为以 API 接口清单 + /api.json 为准,改动即更新文档 2) 表结构改动三同步:document/mysql/ 定稿 → 其余四方言脚本 → 迁移(跨环境时) 3) 破坏性变更(改名/删字段/改枚举值)必须走版本化说明 + 前端同步 + 黄金样本更新,禁止静默变更 4) 架构红线复查:绕过 dao / 手写租户条件 / 反向依赖 task / 超 15 导出的 base / 未登记 tenantTables——任何一项都应打回 ```