23 KiB
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关联表不单列模块:归userlogic(保存用户-角色);role_menu归rolelogic(§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:
- 请求前记录
start;请求后查路由元数据表(§1.3 注册时生成),无log标签的路由(登录、公共查询别名)跳过; - 组装记录:
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; - 异步落库:
chan+ 单 goroutine 批量写(100 条或 1s flush),失败降级glogerror,绝不阻塞业务; - 配置开关:
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. 落地实施顺序
- P0 骨架:目录 +
main.go驱动 + config + Makefile +hack/config.yaml+ router/bind + 6 中间件 +utility/{jwt,response,crypto}+model/hooks+ MySQL DDL(goframe_前缀、del_flag) - P0:auth + index(登录闭环)
- P1:system 域 7 模块(含 RBAC、导入导出)
- P1:data + content 域
- P1:monitor(operation_log 中间件 + 双日志模块 + job 调度)
- P2:tool 域(example/fileTemplate/upload/generator)
- 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 操作须在事务外预计算。