Files
EasyGoAdmin_GoFrame_EleVue/document/architecture.md
T
2026-10-20 11:37:25 +08:00

23 KiB
Raw Blame History

EasyGoAdmin_GoFrame_EleVue 全栈架构设计(最终定稿)

本文件为后端服务实施的唯一权威设计文档(定稿)。实施过程中的任何偏差以本文档为准。

0. 定稿变更清单

# 变更 状态
1 is_delete → del_flag 全量统一(含索引名 idx_*_del_flag、唯一键 (…, del_flag)) ✅ 定稿
2 每张数据表对应一个模块,给出全套文件(api/controller/logic/生成物) ✅ §3
3 标准接口七件套:分页/列表/详情/新增/修改/删除/批量删除,+ 导入导出 ✅ §1.3
4 路由与方法命名对齐 ui/src/api 与 PHP 参考控制器 ✅ 全量提取
5 集成操作日志中间件 + 登录日志 + 两个查询模块 ✅ §4
6 前端位于根目录 ui/(同仓库,后端 API 前缀与之逐条对齐) ✅ §2
7 utility/ 保留顶层(官方案例一致) ✅
8 主键统一 int 数据库自增,停用雪花算法(2026-10-13 定稿:插入后 LastInsertId() 回读;utility/id 已移除) ✅ 定稿

1. 全局设计规范

1.1 分层与调用链

main.go(5驱动) → internal/cmd(启动) → internal/router(注册+元数据)
  → middleware: CORS → Response → JWT → Tenant → Permission → OperationLog
  → controller(薄) → service接口(生成) → logic实现(sXxx) → dao → gdb → DB

1.2 标准接口七件套(所有模块统一)

方法名 HTTP 路由模板 说明
Page GET /{prefix}/page 分页,入参 pageNo/pageSize + 筛选
List GET /{prefix}/list 全量/树形列表(下拉、树选择)
Detail GET /{prefix}/detail/:id 详情
Add POST /{prefix}/add 新增,返回 {id}
Update PUT /{prefix}/update 修改(body 含 id)
Delete DELETE /{prefix}/delete/:id 删除(软删 del_flag=1)
BatchDelete DELETE /{prefix}/batchDelete 批量删除,body {ids:[]}
Import POST /{prefix}/import 导入(multipart file,xls/xlsx)
Export GET /{prefix}/export 导出(返回文件路径/流)

结构体命名:{Mod}{Action}Req / {Mod}{Action}Res(如 UserPageReq、LevelExportRes)。 controller 方法名 = logic 方法名 = 上表方法名(与 PHP 控制器一致);logic 结构体命名 sUser/sRole/…,供 gf gen service 生成 IUser/IRole 接口。

1.3 注解规范(Go 版 #[Log]/#[Permission],gmeta 扩展标签)

type UserPageReq struct {
    gmeta.Meta `method:"get" path:"/user/page" summary:"用户分页" permission:"sys:user:page" log:"用户管理-查询分页记录" logType:"query"`
    common.PageReq                            // pageNo/pageSize
    Keyword string `json:"keyword" dc:"关键词"`
    Status  int    `json:"status"  dc:"状态"`
}

internal/router/bind.go 在注册时反射解析上述标签 → 生成路由元数据表 map["GET /user/page"]{Permission, Log, LogType},供 permission 与 operation_log 中间件查表使用(等价 PHP 属性切面)。

1.4 权限码与日志标题规则(从参考项目提取后统一)

  • 权限码:sys:{module}:{action},module 用小驼峰(fileTemplate/loginLog/operLog/configItem/dictItem/jobLog),action 同方法名。permission 标签留空 = 仅登录即可。
  • 日志标题:{模块中文名}-{动作},动作映射:
action 日志动作 action 日志动作
page 查询分页记录 update 修改记录
list 查询列表 delete 删除记录
detail 查询详情 batchDelete 批量删除记录
add 新增记录 import/export 导入数据 / 导出数据

(覆盖参考项目中“查询全量列表/查询树形列表”等混用写法,统一为上表;特殊日志标题在 §3 各模块单列。)

  • logType 枚举(consts/log_type.go):query/add/update/delete/import/export/reset。

1.5 统一响应与分页

{ "code": 0, "msg": "操作成功", "data": { } }
{ "list": [ ], "total": 0 }

错误码经 consts/biz_err.go 中 gcode.Register 注册;响应封装在 utility/response + middleware/response.go。

2. 模块总表(25 表 ↔ 27 模块)

域 模块 表 路由前缀 api / controller / logic 文件({m}=模块名全小写)
auth auth —(写 login_log) 顶层 /login /logout /captcha … api/v1/auth/auth.go | controller/auth/auth.go | logic/auth/auth.go
index index —(聚合 user/menu) /index/* api/v1/index/index.go | controller/index/index.go | logic/index/index.go
system user goframe_user /user api/v1/system/user.go | controller/system/user.go | logic/system/user.go
role goframe_role + role_menu /role …/system/role.go ×3
menu goframe_menu /menu …/system/menu.go ×3
dept goframe_dept /dept …/system/dept.go ×3
level goframe_level /level …/system/level.go ×3
position goframe_position /position …/system/position.go ×3
tenant goframe_tenant /tenant …/system/tenant.go ×3
data config goframe_config /config …/data/config.go ×3
configitem goframe_config_item /config/item …/data/configitem.go ×3
param goframe_param /param …/data/param.go ×3
dict goframe_dict /dict …/data/dict.go ×3
dictitem goframe_dict_item /dict/item …/data/dictitem.go ×3
notice goframe_notice /notice …/data/notice.go ×3
city goframe_city /city(别名 /area) …/data/city.go ×3
content article goframe_article /article …/content/article.go ×3
category goframe_category /category(树形) …/content/category.go ×3
link goframe_link /link …/content/link.go ×3
monitor operlog goframe_operation_log /oper/log …/monitor/operlog.go ×3
loginlog goframe_login_log /login/log …/monitor/loginlog.go ×3
job goframe_job /job …/monitor/job.go ×3
joblog goframe_job_log /job/log …/monitor/joblog.go ×3
tool example goframe_example /example …/tool/example.go ×3
filetemplate goframe_file_template /file/template …/tool/filetemplate.go ×3
generator —(读 information_schema) /generator …/tool/generator.go ×3
upload —(存 resource/upload) /upload …/tool/upload.go ×3

user_role 关联表不单列模块:归 user logic(保存用户-角色);role_menu 归 role logic(§3 扩展接口)。 生成物(每表一套,make gen 产出):internal/dao/{m}.go(可扩展)+ internal/dao/internal/{m}.go、internal/model/entity/{m}.go、internal/model/do/{m}.go、internal/service/{m}.go。以下各模块不再重复列出生成物。

标准七件套启用矩阵(✓=启用,—=豁免):

模块 page list detail add update delete batchDelete 导入 导出
user ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
level ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
example ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
role / position / tenant / config / configitem / param / dict / notice / article / category / link / city / filetemplate ✓ ✓ ✓ ✓ ✓ ✓ ✓ — —
menu / dept ✓(新增权限点) ✓(树形) ✓ ✓ ✓ ✓ ✓(新增权限点) — —
operlog / loginlog / joblog ✓ ✓ ✓ —(日志不可增改) — ✓ ✓ — —
job ✓ ✓ ✓ ✓ ✓ ✓ ✓ — —

导入导出定稿启用模块:user、level + example(前端已调用,PHP 参考亦有 sys:example:import/export)。 新增权限点(参考项目没有、本期补齐):sys:menu:page、sys:menu:batchDelete、sys:dept:page、sys:dept:batchDelete、sys:city:page 等——须同步写入 goframe_menu 初始化数据。

3. 模块文件明细(按域)

3.1 auth 认证域(无表)

文件:api/v1/auth/auth.go|internal/controller/auth/auth.go|internal/logic/auth/auth.go

方法 HTTP 路由 权限 日志 说明
Login POST /login 公开 写 login_log(logType=1) {username,password,tenantCode?,captcha?,uuid?} → 校验租户 status/expire → 签发 access+refresh
Logout GET /logout 登录 写 login_log(logType=2) jti 入缓存黑名单
Captcha GET /captcha 公开 — 图形码,缓存 captcha:{uuid} TTL 300s
Refresh POST /oauth2/token 公开(refresh_token) — 前端 common/user.ts 既有路由;轮换 token、旧 jti 拉黑
CheckToken GET /oauth2/check/token 登录 — 前端 common/index.ts 调用
RemoveToken DELETE /oauth2/remove/:token 登录 — 指定 token 拉黑
Register POST /register 公开 — 白名单已放行,路由未注册(启用时补实现)

api 结构体:LoginReq/LoginRes(含 accessToken/refreshToken/expiresIn/userInfo)、CaptchaRes、RefreshReq、CheckTokenRes。 logic 职责:bcrypt 校验(utility/crypto)、租户校验(缓存)、双 token 签发(utility/jwt)、黑名单、login_log 落库。

3.2 index 个人中心/菜单聚合域(无表)

文件:api/v1/index/index.go|controller/index/index.go|logic/index/index.go

方法 HTTP 路由 权限 日志标题(取自 PHP 参考)
GetUser GET /index/getUser 登录 个人中心-查询用户信息
GetMenus GET /index/getMenus 和 /index/getMenus/:id 登录 个人中心-查询菜单
UpdatePassword PUT /index/updatePassword 登录 个人中心-修改密码(旧密码校验+bcrypt)
UpdateProfile PUT /index/updateProfile 登录 个人设置-更新个人信息

getMenus 注册两条路由(common/menu.ts 无参、system/menu.ts 带 /1),同一 handler。

3.3 system 域

user 用户模块|表 goframe_user

文件:api/v1/system/user.go|controller/system/user.go|logic/system/user.go 七件套:全部启用(含 import/export)。扩展:

方法 HTTP 路由 权限 日志标题
ResetPwd PUT /user/resetPwd sys:user:resetPwd 用户管理-重置密码
Import POST /user/import sys:user:import 用户管理-导入数据
Export GET /user/export sys:user:export 用户管理-导出数据(chunkList 分批防 OOM)

logic 私有方法:sUser.AssignRoles(userId, roleIds)(写 goframe_user_role)、checkTenantUserMax(tenant.max_user_num)、手机号/用户名租户内唯一校验(走 uk)。

role 角色模块|表 goframe_role + goframe_role_menu

文件:api/v1/system/role.go|controller/system/role.go|logic/system/role.go 七件套:全部启用。扩展:

方法 HTTP 路由 权限 日志标题
MenuList GET /role/menu/list/:roleId sys:role:list 角色管理-查询角色菜单
SavePermission POST /role/menu/save sys:role:savePermission 角色管理-保存权限(重写 role_menu,清缓存)

menu 菜单模块|表 goframe_menu

文件:…/system/menu.go ×3。七件套全启用;List 返回树形(日志:菜单管理-查询树形列表)。logic 含 GetUserMenuTree(userId)(供 index.GetMenus:user→role→role_menu→menu)。

dept 部门模块|表 goframe_dept

文件:…/system/dept.go ×3。七件套全启用;List 返回树形;禁止删除有子部门/用户的部门。

level 职级模块|表 goframe_level

文件:…/system/level.go ×3。七件套 + Import/Export: POST /level/import、GET /level/export。

position 岗位模块|表 goframe_position

文件:…/system/position.go ×3。七件套全启用。

tenant 租户模块|表 goframe_tenant

文件:…/system/tenant.go ×3。七件套全启用。扩展:

方法 HTTP 路由 权限 日志标题
Account POST /tenant/account sys:tenant:add 租户管理-创建租户账号(建租户+初始管理员,code=T+4位ID)
Users GET /tenant/users/:tenantId sys:tenant:list 租户管理-查询租户用户

3.4 data 域

模块 文件(data/ 下三件套) 扩展接口
config config.go ×3 GET /config/web/index(设置页读取)、POST /config/web/save(Log:网站设置-保存,perm sys:config:update)
configitem configitem.go ×3 七件套(路由前缀 /config/item)
param param.go ×3 七件套
dict dict.go ×3 七件套 + POST /dict/refreshCache(Log:字典管理-刷新缓存,perm sys:dict:update)+ 别名 GET /dictionary/list、GET /dictionary/info(前端 system/dictionary.ts,登录即可)
dictitem dictitem.go ×3 七件套 + 快捷 GET /dict/item/getDictItemList/:code(登录即可,缓存 dict:item:{code})
notice notice.go ×3 七件套
city city.go ×3 七件套 + GET /city/getCityList/:parentCode(Log:城市管理-查询下级城市)+ 别名 GET /area/getParent(Log:查询省份列表)、GET /area/findByParentCode(Log:查询城市列表)——均登录即可

3.5 content 域

模块 文件(content/ 下三件套) 说明
article article.go ×3 七件套,List 支持 categoryId/status/keyword
category category.go ×3 七件套,List 返回树形(Log:分类管理-查询树形列表)
link link.go ×3 七件套

3.6 monitor 域

operlog 操作日志|表 goframe_operation_log

文件:…/monitor/operlog.go ×3。启用 page/list/detail/delete/batchDelete(增改豁免)。 路由前缀 /oper/log:GET /oper/log/page、GET /oper/log/list、GET /oper/log/detail/:id、DELETE /oper/log/delete/:id、DELETE /oper/log/batchDelete。权限 sys:operLog:{page|list|detail|delete|batchDelete}。

loginlog 登录日志|表 goframe_login_log

文件:…/monitor/loginlog.go ×3。同上五件,前缀 /login/log,权限 sys:loginLog:*。

job 定时任务|表 goframe_job

文件:…/monitor/job.go ×3。七件套 + 控制接口(与 monitor/job.ts 逐条对齐):

方法 HTTP 路由 权限 日志标题
RunOnce GET /job/runOnce/:id sys:job:execute 定时任务-执行任务
Pause GET /job/pause/:id sys:job:pause 定时任务-暂停任务
Resume GET /job/resume/:id sys:job:resume 定时任务-恢复任务
Status POST /job/status sys:job:update 定时任务-设置状态
DaemonStatus GET /job/daemonStatus 登录即可 定时任务-查询调度器状态

实现:internal/logic/job/daemon.go — 基于 gctrl 的常驻调度器,启动时加载 goframe_job 中 status=1 任务,按 cron_expression 触发 url+params(HTTP 调用自身接口),执行结果写 goframe_job_log。

joblog 任务日志|表 goframe_job_log

文件:…/monitor/joblog.go ×3。五件套,前缀 /job/log,权限 sys:jobLog:*。

3.7 tool 域

模块 文件 接口
example …/tool/example.go ×3 七件套 + POST /example/import、GET /example/export(perm sys:example:import/export)
filetemplate …/tool/filetemplate.go ×3 七件套(前缀 /file/template)+ GET /file/template/getTemplateByCode/:code(Log:文件模板-查询模板详情,登录即可)
generator …/tool/generator.go ×3 GET /generator/page(Log:代码生成-查询数据表,sys:generator:page)、GET /generator/preview(预览代码)、POST /generator/generate、POST /generator/batchGenerate(sys:generator:generate)
upload …/tool/upload.go ×3 POST /upload/uploadFile(Log:文件上传-上传文件,sys:upload:file;存 resource/upload/,返回相对 URL)

4. 日志体系集成

4.1 操作日志(自动,中间件)

internal/middleware/operation_log.go:

  1. 请求前记录 start;请求后查路由元数据表(§1.3 注册时生成),无 log 标签的路由(登录、公共查询别名)跳过;
  2. 组装记录:title(log 标签)、type(logType)、source=0、method、url、param(JSON,password/salt 脱敏)、result(截断 8KB)、ip(gip)、os/browser(gclient)、consume_time、status(0 正常/1 异常,按 code!=0)、error;
  3. 异步落库:chan + 单 goroutine 批量写(100 条或 1s flush),失败降级 glogerror,绝不阻塞业务;
  4. 配置开关:operationLog.enable=true、operationLog.logQuery=true。

4.2 登录日志(业务写入)

logic/auth 内直接写 goframe_login_log:登录成功/失败(log_type=1,失败 status=1 存 error)、退出(log_type=2);记录 username/ip/location/os/browser/consume_time。

4.3 查询模块

即 §3.6 的 operlog、loginlog 两个模块(page/list/detail/delete/batchDelete)。

5. 认证 · 多租户 · 数据库(定稿要点)

  • JWT claims:user_id / tenant_id / jti / username / exp;access 2h + refresh 7d 轮换;黑名单 blacklist:token:{jti} TTL=剩余时效。
  • ctx 键(consts/context_key.go):CtxUserID / CtxTenantID / CtxUsername / CtxRoles / CtxPerms。
  • 租户过滤:internal/model/hooks/hooks.go(gdb model hook)——Insert 自动填 create_user/create_time/del_flag=0/tenant_id(主键交数据库自增);Select 自动 del_flag=0 且租户表追加 tenant_id IN (0,当前);Update 填 update_user/update_time+租户条件;Delete 改写软删。业务层禁止手写这些条件。
  • 中间件链:CORS → Response → JWT → Tenant(status/expire 缓存) → Permission(对照路由元数据表,超管放行) → OperationLog。
  • 五库驱动(main.go blank import):github.com/gogf/gf/contrib/drivers/{mysql,pgsql,mssql,oracle,sqlite}/v2;切换只改 database.default.type/link。
  • DDL:resource/sql/{mysql,pgsql,mssql,oracle,sqlite}.sql,表前缀 goframe_;MySQL 为规范基准;MSSQL 时间列 datetime2;主键自增(int),不用 ORM 回填主键。
  • 红线:禁方言 SQL、禁 InsertIgnore/Replace;主键由数据库自增(int),新增后经 LastInsertId() 回读(Oracle 方言差异由后续人工处理);删除一律软删、查询必经 dao。

6. 代码生成与工程文件

# hack/config.yaml(键名已对 gf v2.10.3 源码核实)
gfcli:
  gen:
    dao:
      link:           "mysql:root:root@tcp(127.0.0.1:3306)/easygoadmin.goframe.elevue"
      removePrefix:   "goframe_"
      jsonCase:       "CamelLower"
      descriptionTag: true
    service:
      srcFolder: "internal/logic"
      dstFolder: "internal/service"
      clear:     true
gen: ## 表结构变更后:重新生成 dao/service
	gf gen dao -c hack/config.yaml && gf gen service -c hack/config.yaml
run: ; go run main.go
build: ; go build -o bin/admin-server main.go
test: ; go test ./...

前置:go install github.com/gogf/gf/cmd/gf/v2@latest。

7. 前端遗留与未启用项

项 前端路由 处理
站内信 message /message/* 前端废弃功能,后端无表无模块,不实现
数据源管理 /data/source/* 前端废弃功能,后端无表无模块,不实现
主控台统计 dashboard/console.ts 纯前端 mock,无需接口 ✅
短信/OSS/WebSocket /sms/* /aliyun/* /websocket/* 后端桩接口已删除;前端遗留调用为废弃代码
注册 /register 白名单已放行、路由未注册;启用时补建表逻辑+开放策略+租户归属规则

8. 落地实施顺序

  1. P0 骨架:目录 + main.go 驱动 + config + Makefile + hack/config.yaml + router/bind + 6 中间件 + utility/{jwt,response,crypto} + model/hooks + MySQL DDL(goframe_ 前缀、del_flag)
  2. P0:auth + index(登录闭环)
  3. P1:system 域 7 模块(含 RBAC、导入导出)
  4. P1:data + content 域
  5. P1:monitor(operation_log 中间件 + 双日志模块 + job 调度)
  6. P2:tool 域(example/fileTemplate/upload/generator)
  7. P2:其余 4 份方言 DDL + SQLite 内存库集成测试

9. 环境信息

  • MySQL:127.0.0.1:3306,账号 root/root,数据库 easygoadmin.goframe.elevue(注意库名含点,DSN 直接使用,DDL 中引用需反引号)
  • 参考表结构源:document/easygoadmin.goframe.elevue.sql(think_ 前缀、is_delete 字段)
  • 前端 API 定义:ui/src/api/**;方法命名参考:D:\xampp8.2\htdocs\v3\RXThinkCMF_ThinkPhp8_EleVue\app\controller

10. 文件与富文本处理契约

10.1 上传两段式

  • 上传接口(POST /api/upload/uploadFile)先落 resource/upload/temp/{日期}/{随机名},返回 /upload/temp/** URL(可直接预览);
  • 表单提交保存时由 SaveFileField/SaveFileFields(internal/logic/base.go)把 temp 文件移动到正式子目录(如 user/20261013/时分秒_随机.ext),库中与响应统一存 /upload/** URL;
  • 校验:扩展名白名单(file.imageExt / file.fileExt)、单文件上限(file.maxSize MB)、图片魔数嗅探;
  • 运营闭环:每日 03:30 自动清理超过 file.tempExpireDays 天的 temp 日期目录;/upload/** 静态访问由 SetServerRoot("resource") 提供;.svg 响应强制 Content-Disposition: attachment + nosniff(防存储型 XSS)。

10.2 富文本占位符(持久化契约)

  • 正文(如 article.content)存库前经 LocalizeContentFields 处理:
    • 本站 /upload/temp/** 引用 → 转正并替换为 [IMG_URL]/{相对路径};
    • 本站 /upload/** 正式引用 → 去域名替换为 [IMG_URL]/{相对路径};
    • 外站 URL 不处理(规避 SSRF);
  • 匹配范围:img|video|source|embed 的 src 与 a 的 href(带文件后缀);
  • 读取侧统一经 ExpandContentFields 还原为 /upload/**(唯一还原出口,禁止业务代码手写字符串替换);
  • [IMG_URL] 为持久化格式的一部分:库内 content 字段不供第三方系统直接消费。

10.3 logic 共享能力层(internal/logic/base.go)

  • 分区:文件字段 / 富文本 / 枚举文本(DictGetText/SerializeMapOnRead)/ 唯一校验 / 事务 / 分块查询 / 树 / 临时目录清理;
  • 纪律:只依赖 dao/utility/consts;导出函数上限15个,超出按能力拆子包;
  • CheckUnique 仅为 UX 快速报错(先查后插存在 TOCTOU),并发唯一性以数据库唯一索引为准——调用点必须有对应 uk_* 索引(config/dict/param/file_template 已补 uk_code);
  • WithTrans 用于多写原子性(如租户开户),事务内禁止 HTTP/文件IO,bcrypt 等 CPU 操作须在事务外预计算。