这是一份 Go Admin core foundation 的落地复盘:一个已有企业级 Admin 系统在迁移到 Go/Gin 时,认证、会话、RBAC、用户管理、操作日志、队列、上传、WebSocket、测试和 smoke 如何形成一条可验证的工程链路。
写在前面:Go 不是魔法,是主后端工程能力
很多人谈 Go,喜欢先谈高并发、微服务、Kubernetes、gRPC。听起来热闹,但我这个项目遇到的真问题不是这些。我的真问题很具体:已经有一套 PHP / Webman 写出来并上线过的企业级 Admin 系统,里面有登录、Access / Refresh Token、Redis Session、动态菜单、按钮权限、AI Agent、SSE、WebSocket、支付、队列、通知、上传、审计日志、桌面端更新和线上部署。现在我要把它迁到 Go 主后端,但不能把已有前端、登录路径、菜单权限和业务使用方式砸烂。
这件事的重点不是 Go 语法。语法不难,难的是边界:哪些东西进 Go 主后端,哪些东西留给 Python AI 自动化,哪些只是 PHP 旧系统里的业务事实,哪些历史包袱不能带进新架构。更难的是节奏:如果一上来重做数据库、重做 RBAC、重做前端权限、重做 UI、重做接口命名,那不是重构,是把一个能跑的系统拆成半成品。
所以我给这个项目定了三条硬问题:
1. 这是个真问题吗?2. 有更简单的做法吗?3. 会破坏已有前端、登录、菜单和权限吗?答案很清楚:真问题是后台系统边界变重,旧 PHP 继续堆功能会越来越难维护;更简单的做法不是微服务,而是 Gin modular monolith;不能破坏用户空间,所以旧接口和旧前端路径必须被显式 adapter 保护,而不是被新架构“教育”。
为什么主后端选 Go,Python 和 PHP 放在正确位置
PHP / Webman / Workerman 在旧系统里已经承接过接口、队列、SSE、WebSocket、支付回调、存储和后台任务,也提供了完整的业务语义来源。问题是长期维护不能继续被旧项目的历史风格牵着走:路由风格、命名习惯、历史兼容和分层包袱都会越来越重。
Python 也很重要,但它的位置不是拿来替代整个 Admin 主后端。Python 的强项在 AI 应用、RAG、OCR、TTS、embedding、批量数据处理、自动化脚本、模型评估和内容流水线。把 Python 当 AI sidecar / automation layer 是合理的;让 Python 去承接整个 Admin 的认证、会话、RBAC、菜单、审计、支付和长期 HTTP 服务,不是当前最优解。
Go 的位置最清楚:它适合长期运行的后台服务。单二进制部署干净;标准库对 HTTP、context、并发和测试支持强;类型系统能让接口契约更早暴露问题;goroutine 适合队列、WebSocket、后台任务和并发 I/O;简单语法逼你少搞抽象。真正写 Go 项目,不是把 Java 设计模式搬过来,而是把调用链收短,把错误显式返回,把资源生命周期讲清楚。
因此我的技术分工是:
Go -> Admin 主后端:REST API / auth / session / RBAC / queue / upload / realtimePython -> AI 应用与自动化:采集 / 清洗 / OCR / TTS / 模型调用 / 评估 / 脚本流水线PHP -> 已上线业务事实:存量系统、迁移参考、业务语义来源前端 -> 强交付层:Vue / React / uni-app / Electron / Tauri / 权限菜单 / UI 工程关键不是把所有技术混在一起,而是让每个技术栈只承担它最适合的职责。
当前项目状态:已经不是 skeleton
当前 Go 项目已经进入 Admin core foundation 阶段,不是刚起一个 Gin skeleton。
当前 Go 后端已经落地的模块包括:
authsessionauthplatformcaptchauserpermissionroleoperationlogqueuemonitorsystemsettingsystemloguploadconfiguploadtokenrealtime当前已经形成闭环的能力包括:
health / ready登录配置滑块验证码密码 / 验证码登录Access / Refresh TokenToken Hash + PepperRedis token cacheMySQL session fallback平台认证策略设备 / IP / 单端登录策略Users/init RBAC bootstrappermission definitions RESTrole grant / restore用户管理 REST个人资料 / 账号安全系统日志操作日志Asynq queue monitor系统设置上传配置COS 上传 tokenWebSocket baselinebasic-admin-smokefull-admin-smoke当前代码规模已经能反映工程密度:本地仓库约 229 个 Go 文件、70 个测试文件、365 个测试函数;go test ./...、go vet -p=1 ./...、git diff --check 已经通过。这些数字只说明一件事:这套 Go 后端已经进入“能被验证、能继续迁移”的状态。
架构选择:Gin Modular Monolith,而不是微服务
我采用的顶层结构是:
cmd -> bootstrap -> server -> module -> platform模块内部默认是:
route -> handler -> service -> repository -> model这个结构不新奇,但它解决实际问题。cmd/admin-api 只启动 HTTP API;cmd/admin-worker 只跑队列消费和 scheduler;bootstrap 装配 config、logger、resources、service、middleware 和 router;server 负责 Gin engine、全局 middleware 和路由挂载;internal/module 放业务模块;internal/platform 放数据库、Redis、队列、调度、存储、WebSocket 等外部资源边界。
为什么不一开始微服务?因为当前真问题是迁移 Admin 核心链路,不是给每个模块单独起进程。微服务不是架构成熟的象征,它是组织、部署、监控、网络、数据一致性和故障隔离都准备好之后的结果。现在先用 modular monolith 把 auth、RBAC、operationlog、queue、storage、realtime、AI workflow 的边界写清楚,未来要拆也有路可走。
好架构不是层数多,而是特殊情况少。没有数据库的模块不硬造 repository;没有表的模块不硬造 model;没有两个真实实现的地方不硬造 interface;没有业务任务时不写 fake cron。少一层是一层,少一个特殊情况就是进步。
认证会话:不是套一个 JWT middleware 就完事
这个系统不是纯 JWT stateless auth。旧系统已经有 token hash、Redis session、MySQL session、平台策略、设备绑定、IP 绑定、单端登录和 refresh token 语义。Go 迁移不能把这些事实抹掉。
当前 session/auth 链路做了这些事:
access token / refresh token 生成sha256(token + pepper) hashRedis token cacheMySQL user_sessions fallbacksession.platform 作为可信 platformaccess_ttl / refresh_ttl 从 auth_platforms 读取refresh rotationlogout revokesingle_session / max_sessionsbind_platform / bind_device / bind_ip登录日志 taskAuthToken middleware 只做认证边界:解析 Authorization: Bearer <token>,读取 platform / device-id / client-ip,调用 authenticator,拿到 AuthIdentity 后挂到 Gin context。它不生成 token,不查业务权限,不判断 RBAC,不处理验证码。这些东西都在 service 层,不能塞进 middleware。
这里有个细节:浏览器 WebSocket 和队列监控 iframe 这类入口不能稳定附加 Authorization header,所以我做了 path-scoped cookie token。只允许 GET/HEAD /api/admin/v1/queue-monitor-ui/* 和 GET /api/admin/v1/realtime/ws 从 access_token cookie 取 token;普通 JSON API 不允许 cookie fallback,POST/PUT/PATCH/DELETE 也不允许。这是显式边界,不是全局兜底。
RBAC:Admin 系统的硬骨头
RBAC 是 Admin 的核心,不是三张表那么简单。它同时影响菜单、路由、按钮、接口权限、缓存、前端动态路由和审计。
当前 Go 版本保留旧系统已经验证过的语义:
users.role_id 单角色模型permissions: DIR / PAGE / BUTTONrole_permissions: PAGE / BUTTON 授权BUTTON 授权隐含父 PAGEUsers/init 返回 permissions + router + buttonCodes + quick_entryshow_menu 只控制菜单显示,不代表无页面权限button cache 只做性能加速,不做权限真相源PermissionCheck fail-closed权限/角色变更后清理受影响用户 button grant cache为什么第一阶段不做多角色?因为多角色不是免费的。它会改变授权合并、冲突处理、审计解释、前端展示和缓存失效逻辑。当前业务事实是单角色,那就先把单角色迁稳。以后要做多角色,应该在边界清楚后演进,而不是迁移第一阶段顺手改语义。
PermissionCheck 不靠反射、注解或 handler 名字猜权限码。只有显式 route metadata 配了规则,才检查。用户不存在、角色不存在、权限数据异常,全部 fail-closed。缓存 miss 或 Redis error 必须回源计算,不能把缓存当成权限真相源。
这才是 RBAC 的重点:菜单是菜单,页面权限是页面权限,按钮权限是按钮权限,接口权限是接口权限,缓存是缓存,数据库事实是数据库事实。混在一起就会烂。
用户管理、个人资料和账号安全:别把业务塞错模块
用户管理不是简单列表。当前 Go REST 已经覆盖:
GET /api/admin/v1/users/page-initGET /api/admin/v1/usersPUT /api/admin/v1/users/:idPATCH /api/admin/v1/users/:id/statusPATCH /api/admin/v1/usersDELETE /api/admin/v1/users/:idDELETE /api/admin/v1/users个人资料和账号安全没有另起一个空模块,而是归在 user 模块,因为表事实就是 users 和 user_profiles:
GET /api/admin/v1/profileGET /api/admin/v1/users/:id/profilePUT /api/admin/v1/profilePUT /api/admin/v1/profile/security/passwordPUT /api/admin/v1/profile/security/emailPUT /api/admin/v1/profile/security/phone这里的边界很重要:用户编辑自己的资料,不应该挂用户管理按钮权限;它只需要登录态,并记录 profile.update_profile 操作日志。账号安全写操作复用验证码 store,但不让 handler 或 repository 直接碰 Redis。GET profile 不偷偷创建缺失 profile 行,读接口不能暗中写库。
这些细节看起来小,但能看出代码品味。坏代码喜欢为了“方便”新开模块、偷偷写库、顺手兜底字段。好代码先问:这个业务事实到底归谁?读路径能不能保持只读?权限是不是刚好够用?
操作日志:显式 metadata,不靠猜
操作日志不是 access log。access log 记录 HTTP 横切信息;operation log 记录后台用户做了什么业务操作。
当前 Go 版本用显式 route metadata 维护操作日志规则:
method + route pattern -> module / action / title比如新增权限、编辑角色、删除操作日志、编辑个人资料、修改登录密码、签发上传凭证等,都通过显式规则记录。middleware 在 handler 执行后拿到 status、success、latency、request_id、user_id、session_id、platform、client_ip,再写入 repository。
敏感字段必须被 sanitizer 遮蔽,验证码坐标、密码、token、secret 不允许进审计日志。日志记录失败不应该打断普通业务主流程,但高风险操作如果未来要求强审计,那应该作为单独业务规则设计,而不是在通用 middleware 里偷偷改变语义。
队列和 worker:API 不消费任务,scheduler 不直接跑业务
Go 后端当前采用单体多进程,而不是微服务:
cmd/admin-api # HTTP APIcmd/admin-worker # queue consumer + scheduler队列使用 Asynq,scheduler 使用 gocron/v2,但业务模块不直接到处 import asynq/gocron。底层封装在:
internal/platform/taskqueueinternal/platform/schedulerinternal/jobs队列 lane 分为:
criticaldefaultlow这不是按目录建 fast/slow。快慢是运行时策略,不是业务所有权。登录日志、权限缓存刷新这类短任务走 critical;普通业务走 default;慢任务、批量任务、AI 后处理以后走 low。scheduler 只能投递 queue task,不直接执行业务。worker handler 必须幂等,因为队列语义是 at-least-once。
当前已经有 auth:login-log:v1 和 system:no-op:v1 这样的版本化 task,queue monitor 采用 Asynq 官方 asynqmon 只读挂载,而不是重新手写一个半吊子 dashboard。这个取舍很现实:能用成熟生态就用,但要包在项目自己的边界里。
上传:配置是配置,运行时 token 是运行时 token
上传是很容易写烂的地方。很多系统会先做一个“上传中心”,然后倒推各种 scene,最后一堆无主文件记录没人知道归谁。我这里反过来:上传 token 只签发临时凭证,不定义业务;真正业务模块自己保存 object key/url、状态、权限和操作日志。
当前 Go 版本拆成两块:
uploadconfig -> 管理 upload drivers / rules / settingsuploadtoken -> 读取 enabled setting,签发 COS 临时凭证配置管理支持 cos/oss 记录,是因为存量数据可能有两种配置;但运行时默认只实现 COS-first token。OSS runtime 没实现就显式报错,不静默 fallback。
关键规则包括:
driver secret 使用 VAULT_KEY + AES-GCM secretbox 加密secret 永不返回明文或密文,只返回 hintsetting 启用互斥在 repository transaction 内完成folder/file_name/file_size/file_kind 双层校验object key 服务端生成rule.max_size_mb / image_exts / file_exts 是上传限制真相COS_STS_ENABLED=false 时显式报未启用这比“调个 SDK 上传文件”更重要。上传不是 SDK 问题,是权限、配置、密钥、规则、业务归属和安全边界问题。
WebSocket baseline:先把连接生命周期打稳
Realtime 当前只做基建,不假装业务通知和 AI streaming 已经完成。当前已经实现:
GET /api/admin/v1/realtime/wsAuthorization bearer 优先浏览器 path-scoped cookie authlocal connection managerbounded send queueread pump / write pumpserver ping control frameclient ping -> server pong envelopeconnected eventtopic subscribe 白名单骨架local / noop PublisherREALTIME_ENABLED=false 明确 503unknown publisher 明确 down,不假装 Redis fan-out这里最重要的是生命周期。WebSocket 不能让业务代码直接拿 conn 到处写。当前 Session 拥有一个 bounded send queue,所有输出都经过队列串行化;队列满了说明 slow client,直接关闭连接,不能让内存无限涨。read pump / write pump 通过 context 和 done channel 退出,App shutdown 会关闭本机 manager 下的连接。
AI streaming 未来可以走 WebSocket,但现在不写假实现。Redis Pub/Sub / Redis Streams fan-out 也还没实现,所以配置成 redis publisher 时 readiness 必须 down。没做就是没做,别把 planned 写成 implemented。
前端边界:迁移不能只看后端
这个 Go 项目不是后端单边改造。迁移能成功,前端工程也必须跟上。现有前端要处理登录恢复、权限菜单、动态路由、按钮权限、请求封装、401 刷新队列、WebSocket URL 切换、iframe queue monitor、上传 client、个人资料和账号安全页面适配。
前端侧涉及的技术和交付边界包括:
Vue 3 / React / TypeScript / ViteElement Plus / Ant Design / Vant / TailwindPinia / Zustand / React Query动态路由 / 权限菜单 / 按钮权限uni-app 移动端 / H5 / 小程序 / Android / iOS / 鸿蒙配置腾讯 IM / TRTC / 移动推送Electron / Tauri 桌面端Capacitor 跨端壳层思路Figma Make / AI UI 生成代码收口后端迁移如果不了解前端真实消费顺序,很容易把接口改得“理论正确、实际不可用”。权限状态怎么恢复、接口契约在哪里会炸、哪些 fallback 会掩盖后端错误,这些都必须在迁移时一起处理。前端不是附属品,它是验证 Go 后端契约是否稳定的第一现场。
Python 边界:AI 自动化和内容流水线
Python 不抢 Go 主后端的位置,但在 AI 应用和自动化链路里非常关键。
例如电商 AI 内容流水线:
商品采集图片 / OCR商品数据清洗卖点提取AI 口播生成TTS 合成SRT 字幕批量文件处理接口调试与回放AI 工具链验证这些任务天然适合 Python。Web 后台负责权限、状态、任务流和人工审核;Go/PHP 后端负责主业务和持久化;Python 负责自动化、数据处理和模型生态。硬把 Python 写成一个普通 CRUD 服务没有意义;把 Python 放进 AI 工作流和自动化链路里,价值更明确。
测试和 smoke:没有验证,不叫完成
迁移项目最怕“看起来能跑”。所以我给 Go 项目建立了测试和 smoke 门禁。
单元测试覆盖 handler、service、middleware、platform wrapper 和核心业务规则。service 层用 fake repository 做 table-driven tests;handler 层用 httptest 验证 HTTP 契约;middleware 验证 AuthToken / PermissionCheck / OperationLog 的 fail-closed 和执行顺序;platform 层验证 taskqueue / scheduler / realtime / secretbox / COS signer 边界。
smoke 分两层:
basic-admin-smoke.ps1full-admin-smoke.ps1basic smoke 证明基础 admin 链路没断:/ready、login config、captcha、login、users/me、users/init、users page-init/list、permission + role RBAC loop、logout、WebSocket connect/ping/pong。
full smoke 在 basic 基础上探测 operation log、queue monitor、system logs、system settings、upload config、upload token shape、profile/account security 等更慢模块。写库 smoke 必须用临时数据,成功后清理,失败保留 .tmp 日志。
当前我已经验证过:
go test ./...go vet -p=1 ./...git diff --check这才是迁移项目该有的态度:没有验证证据,不准说完成。
当前边界:已经落地的和还没落地的
到目前为止,这个 Go 后端已经完成的是 Admin core foundation,而不是完整业务迁移。这个边界必须说清楚。
已经落地的部分,是认证、会话、RBAC、用户管理、系统设置、系统日志、操作日志、队列监控、上传配置、COS 上传 token 和 WebSocket baseline。这些能力共同构成后台系统继续迁移的地基。
还没有落地的部分,也不能假装完成。真实业务模块还没有批量迁移,短信/邮件发送器还只是 dev-mode 边界,AI streaming 还没有接入 WebSocket,Redis fan-out 也还没有实现。上传现在是 COS-first runtime token,不是完整文件管理系统,也不是 OSS runtime。
这个阶段的目标不是“把所有功能一次写完”,而是先把系统最容易出事故的基础链路固定住:登录不能乱,权限不能乱,缓存不能变成真相源,队列不能和 API 进程搅在一起,上传密钥不能明文暴露,WebSocket 不能无边界写连接,测试和 smoke 不能缺席。
结尾:真正的升级,是边界变清楚
Go 项目最容易写成两种垃圾:一种是披着 Go 外衣的 Java 项目,目录复杂、interface 泛滥、ServiceImpl 到处飞;另一种是脚本式 Go,所有逻辑塞 handler,数据库、权限、缓存、响应混在一起。前者假装专业,后者假装快速,最后都会难维护。
我想要的是第三种:少层级、少抽象、先跑通、再提炼。先保护已有用户路径,再替换内部实现;先把认证和 RBAC 打稳,再迁业务模块;先用 tests 和 smoke 证明契约,再谈优化;先保持 modular monolith,再决定未来是否拆服务。
这就是我对 Go 主后端的理解:Go 的强项不是让你写更多框架,而是逼你把事情说清楚。一个好的 Admin 后端,不应该靠魔法、兜底和猜测运行。它应该让每个请求从进入系统到返回结果都能被解释,让每个权限判断都有来源,让每个错误都能暴露,让每个迁移步骤都能验证。做到这些,Go 才不是口号,而是真正能承接业务系统的工程能力。
2026-05-31 强化:admin_back_go 的 Go 项目框架不是 Gin 模板,是模块化单体
这篇文章现在明确以 E:\admin_go\admin_back_go 为事实来源。别把它写成“Gin + GORM 后台模板”。模板只解决启动问题,项目框架要解决的是:进程边界、依赖装配、模块边界、中间件顺序、配置、数据库、Redis、队列、调度、迁移、测试、部署和失败治理。
当前判断:这是一个 Gin + GORM + Redis + Asynq + gocron 的模块化单体 Admin 后端。不是微服务,也不是玩具 CRUD。
1. 进程模型:admin-api 和 admin-worker 分开
真实入口只有两个:
cmd/admin-api/main.gocmd/admin-worker/main.goadmin-api 做 HTTP 服务:
LoadDotEnv -> config.Load -> logging.NewLogger(admin-api) -> bootstrap.New -> app.Runadmin-worker 做队列和调度:
LoadDotEnv -> config.Load -> logging.NewLogger(admin-worker) -> bootstrap.NewWorker -> signal.NotifyContext -> worker.Start -> graceful Shutdown这比在 HTTP handler 里临时 go func() 扔后台任务强太多。后者没有重试、没有队列、没有观测、没有优雅关闭。能跑,不代表能维护。
2. 组合根:bootstrap 负责 new,handler 不到处 new
internal/bootstrap/app.go 是组合根,负责:
1. 规范化 AI / Scheduler / Token 等配置2. 校验运行时 APP_SECRET3. 构建 KeyRing / SecretBox4. 初始化 MySQL、Redis、TokenRedis、QueueRedis5. 构建 repository / service / cache / gateway6. 构建 Authenticator / PermissionChecker7. 把依赖一次性塞进 server.NewRouter组合根的价值是:依赖集中、启动失败集中、handler 干净。烂写法是在 handler 里到处 database.Open、redis.Open、NewService。那种代码该删。
3. Router:中间件顺序就是系统边界
internal/server/router.go 的 Gin 顺序:
RecoveryRequestIDAccessLogCORSi18nAuthTokenPermissionCheckOperationLogregister routes顺序不是随便摆的:
Recovery兜 panic。RequestID尽早生成,日志和错误都要带。AccessLog覆盖后续处理。CORS处理 OPTIONS。i18n在业务错误前确定语言。AuthToken先识别用户。PermissionCheck再判断权限。OperationLog最后记录带用户身份的操作。
这就是框架。不是目录画得漂亮,而是请求进来后每一步谁负责、谁失败、谁放行都明确。
4. 模块化单体:internal/module/* 是业务边界
当前模块包括:
auth / auth_platform / user / permission / role / profileoperationlog / systemlog / systemsetting / clientversionuploadconfig / uploadtoken / notification / realtime / queuemonitorcrontask / export / mail / sms / payment / ai/* / canvas典型结构:
internal/module/<name>/├── dto.go├── model.go├── repository.go├── service.go└── transport/ └── admin/ ├── handler.go ├── request.go └── route.go职责要硬:
| 文件 | 应做 | 不该做 |
|---|---|---|
model.go | 表模型和领域结构 | HTTP 逻辑 |
repository.go | 数据库读写 | 业务策略 |
service.go | 业务规则和状态流转 | 依赖 Gin context |
request.go | 请求结构和校验标签 | 查库 |
handler.go | bind、调用 service、response | 拼 SQL / 堆业务 |
route.go | 注册路由 | new 基础设施 |
这不是为了“分层而分层”,是为了让每个文件能被读懂、能测试、能替换。
5. infra 层:基础设施统一封装
internal/infra 放基础能力:
accesstoken -> JWT access token codecdatabase -> MySQL/GORM/sql DBredisclient -> Redis clientredislock -> scheduler distributed lockscheduler -> gocron wrappersecretkey -> APP_SECRET 派生 keysecretbox -> 敏感配置加解密taskqueue -> Asynq client/server/muxlogging/logstore -> 日志输出和读取mail/sms -> Tencent Cloud adaptersstorage/cos -> COS object storagepayment/alipay -> Alipay gatewayrealtime -> websocket publisher/subscriberai/* -> OpenAI-compatible providers业务模块不应该直接关心第三方 SDK 细节。支付模块依赖 gateway 抽象,上传模块依赖 signer/writer/reader,AI 模块依赖 provider/runtime。基础设施封装不是多写一层,是让业务不被供应商绑死。
6. 配置:集中读取,默认值和危险值都要治理
internal/config/config.go 把配置收敛到:
App / HTTP / Logging / MySQL / Redis / Token / Queue / Realtime / Scheduler / Payment / AI / CORS规则:
- 业务代码不直接读环境变量。
- 默认值必须显式。
- 危险默认值必须禁止上生产。
- Docker / 本地 / 宝塔部署的配置入口要统一。
- 配置变更要能被测试覆盖。
APP_SECRET 这种东西必须校验,不能空、不能默认、长度不能太短。否则认证系统就是纸糊的。
7. 资源层:MySQL、Redis、TokenRedis、QueueRedis 分用途
bootstrap.NewResources 做资源初始化:
MySQL DSN 非空 -> database.OpenRedis Addr 非空 -> resources.RedisTokenRedis -> Redis 同地址不同 DBQueueRedis -> Queue 启用时同地址不同 DBReadiness -> database / redis / token_redis / queue_redis / realtimeRedis 分用途很重要:普通缓存、token session、queue backend 不混一个 DB。即使物理 Redis 是一个实例,也要逻辑隔离。
/health 只说明进程活着,/ready 才说明数据库、Redis、Token Redis、Queue Redis、Realtime 是否可用。
8. Worker:队列和 DB-backed cron 在后台进程里跑
bootstrap.NewWorker 初始化:
Queue enabled?-> NewResources-> taskqueue.NewClient-> taskqueue.NewServer-> taskqueue.NewMux-> 注册 notification / export / ai / payment job handlers-> Scheduler enabled? -> scheduler.New -> Redis lock -> crontask.NewSchedulerService.RegisterEnabled -> jobs.RegisterSchedules这说明后台任务不是随便 go func()。它有 Asynq queue server、job registry、DB-backed cron、Redis 分布式锁、graceful shutdown 和单独日志。
9. 权限 route metadata:显式比魔法强,但要测试兜住
internal/bootstrap/route_meta.go 维护:
HTTP method + route path -> permission code优点是可审查、权限码稳定;风险是新增写接口漏配 metadata 时,PermissionCheck 会因为找不到权限码直接放行。硬规则应该是:
所有 POST / PUT / PATCH / DELETE:- 要么出现在 route_meta- 要么出现在明确免权限白名单- 否则测试失败这就是后台系统里的“不要破坏用户空间”:别让新接口悄悄改变权限边界。
10. Docker-first 与验证
当前部署方向是 Docker-first,同一镜像可以启动:
admin-apiadmin-worker部署结构应该是:
admin-go-state -> MySQL + Redisadmin-go-backend -> admin-api + admin-worker前端不强行塞进这个后端 Docker。用户已经明确前端保持现有部署方式没问题,后端走宝塔 Docker / docker-first。
验证不能只靠“能编译”:
go test ./...go vet ./...再配合:
basic-admin-smoke.ps1full-admin-smoke.ps1check-contract.ps1check-payment-certs.ps1没有验证,不叫框架,只叫目录模板。
11. 当前框架的优点和风险
优点:双进程模型清楚、组合根集中、中间件顺序明确、模块化单体实用、Redis 分用途、认证/RBAC 真实现、Docker-first 路径明确、测试和 smoke 成为契约。
风险:bootstrap/app.go 会膨胀;route metadata 手工维护容易漏;模块多后跨模块依赖容易乱;Worker/API 共用配置时要避免队列或调度误启;migrations 多后需要更强 DB 状态核验。
12. 我认可的 Go 后端框架骨架
cmd/ # admin-api / admin-workerinternal/bootstrap/ # composition rootinternal/config/ # env -> typed configinternal/server/ # gin router + route groupsinternal/middleware/ # auth / permission / logs / corsinternal/infra/ # db / redis / queue / storage / providersinternal/module/ # business modulesinternal/shared/ # response / errors / validate / enum / i18ninternal/readiness/ # dependency readinessinternal/jobs/ # queue job registrationdatabase/migrations/ # SQL migrationsdeploy/docker-first/ # backend docker-first deploymentscripts/ # smoke and contract checks目录不能解释职责,就是垃圾分层;职责清楚,目录才有意义。