Skip to content

1.3 项目目录结构 ​

概述

在软件开发过程中,优秀的目录结构对项目的组织、开发、维护和扩展至关重要。本项目后端采用"单包平铺"结构(api/controller/logic/service 各一个包,每模块一个文件),与常见的"按域分目录"不同——这是刻意的设计决策,详见下方说明。

设计原则 ​

text
1. 目录平铺:api/v1、controller、logic、service 均为单包,每模块一个 snake_case 文件;
   跨模块直接同包调用(如 user 直接调用 ResolveCityNames,无需 import)。
2. 分层架构:controller(HTTP)→ service 接口(依赖倒置)→ logic(业务)→ dao(数据),职责清晰。
3. 模块化管理:25 张表对应 27 个模块文件,文件名 = 表名去 goframe_ 前缀。
4. 依赖红线:中间件不依赖业务层(函数变量接线)、task 单向依赖 logic、migrate 不走 dao。

项目根目录 ​

text
├── main.go                     # 服务入口:注册五库驱动 + Redis 适配器 → cmd.Run
├── Makefile                    # run/build/test/vet/fmt/gen(gen-dao)/clean
├── api/                        # 全部请求/响应结构体(单包 v1)
│   └── v1/                     #   每模块一文件:user.go、config_item.go…
├── cmd/                        # CLI 入口
│   ├── generator/              #   代码生成器 CLI(go run ./cmd/generator)
│   └── migrator/               #   整库迁移 CLI(go run ./cmd/migrator)
├── internal/                   # 后端核心代码(详见下方)
├── templates/                  # 代码生成器模板(后端 {{ }} 定界;ui* 前端 [[ ]] 定界)
│   └── ui/ ui2/                #   前端模板(ui2 为树形模块变体)
├── utility/                    # 基础能力包(无业务依赖)
├── manifest/
│   ├── config/config.yaml      # 运行时配置(唯一配置文件)
│   └── data/ip2region.xdb      # IP 归属地库
├── resource/
│   ├── static/                 # 静态资源(验证码字体等)
│   ├── swagger/                # 本地托管 API 文档页面
│   └── upload/                 # 上传文件静态服务根(SetServerRoot "resource")
├── hack/                       # gf gen dao 配置与自定义模板、黄金样本回归基线
├── .dockerignore               # Docker 构建上下文排除清单(硬规则:必须在上下文根目录)
├── docker/                     # Docker 化文件(构建上下文为项目根,-f docker/Dockerfile)
│   ├── Dockerfile              #   多阶段构建:静态编译 → alpine 运行(非 root + HEALTHCHECK)
│   ├── docker-compose.yml      #   三服务编排:后端 + MySQL8 + Redis7(GF_ 注入配置)
│   └── .env.example            #   compose 变量模板(复制为 .env,明文密钥不入库)
├── ui/                         # 前端工程(Vue3 + Element Plus)
├── document/                   # 项目文档(五方言 SQL 脚本、架构定稿、wiki 等)
│   ├── mysql/                  #   MySQL 定稿 DDL(规范基准)
│   ├── postgresql/             #   PostgreSQL 定稿 DDL
│   ├── sqlserver/              #   SQL Server 定稿 DDL
│   ├── oracle/                 #   Oracle 定稿 DDL
│   ├── sqlite/                 #   SQLite 定稿 DDL
│   ├── architecture.md         #   架构定稿
│   └── wiki/                   #   后端开发者文档
├── upload/                     # 上传物理目录(file.uploadDir)
├── log/                        # 运行日志
└── bin/                        # 编译产物

后端目录(internal/) ​

text
internal/
├── cmd/                        # 启动编排:cache.Init → 依赖接线 → 路由 → 调度器 → 运行
├── consts/                     # 业务错误码 / 缓存键 / 上下文键 / 日志类型枚举
│   ├── biz_err.go              #   17 个业务错误码(gcode.Register 语义值)
│   ├── cache_key.go            #   Redis 键统一前缀 easygoadmin:
│   ├── context_key.go          #   上下文读写(consts.GetXxx(ctx))
│   └── log_type.go             #   41 个操作日志类型常量与静态映射
├── controller/                 # 控制器(单包,薄层,仅转发 service)
│   ├── user.go                 #   CUser:Page/List/Detail/Add/Update/Status/…
│   └── …                       #   文件命名 snake_case 对齐 dao
├── dao/                        # 数据访问层(自定义模板产出,挂钩子 + Ctx 覆写)
│   └── internal/               #   dao 内部实现(自动生成,勿手改)
├── logic/                      # 业务逻辑(单包,每模块一文件,同包 init 注册)
│   ├── base.go                 #   共享能力层(文件/富文本/字典/事务/分块/树,15 个导出上限)
│   ├── module_spec.go          #   ModuleSpec 泛型声明式 CRUD 基座
│   ├── data_scope.go           #   行级数据权限共享工厂 ApplyDataScope
│   ├── user.go role.go …       #   各模块业务实现(sUser/sRole…)
│   └── generator_side.go       #   生成器副作用(菜单/字典/路由注册)
├── middleware/                  # 7 个中间件 + 白名单 + 依赖接线(wire.go)
│   ├── cors.go response.go     #   CORS / 响应兜底(SVG 加固、panic 恢复)
│   ├── ratelimit.go demo.go    #   限流 / 演示模式
│   ├── jwt.go tenant.go        #   认证 / 租户状态校验
│   ├── operation_log.go        #   操作日志异步采集
│   ├── public.go               #   免登录白名单(精确匹配)
│   └── wire.go                 #   IdentityLoader/TenantLoader/LogSink 函数变量
├── migrate/                    # 整库迁移引擎(内省/翻译/DDL 渲染/搬运/序列修复)
├── model/
│   ├── entity/                 # 实体(gf gen dao 产物)
│   ├── do/                     # 数据对象 DO(gf gen dao 产物)
│   └── hooks/                  # 全局模型钩子(审计盖章/软删改写/租户隔离)
├── router/                     # 路由注册(router.go)+ gmeta 反射绑定(bind.go)
│   └── meta/                   #   路由元数据表(权限/日志注解即事实)
├── service/                    # 服务接口层(每模块一文件,手维护,勿运行 gf gen service)
└── task/                       # 定时任务处理器(init 自注册到 logic.RegisterJobHandler)
    ├── task.go                 #   注册与参数辅助
    ├── hello_world.go          #   示例任务(验证调度链路)
    ├── send_sms.go             #   短信示例任务
    └── log_clean.go            #   日志清理内置任务(每日 02:30)

前端目录(ui/src/) ​

text
ui/src/
├── api/                        # 接口模块(按域分目录:system/data/content/monitor/tool…)
├── components/                 # 公共组件(25 类:Table/Form/Upload/Editor/Excel/ChinaArea…)
├── directives/                 # 自定义指令(permission 权限指令等)
├── enums/                      # 枚举常量(http/cache/page/permissions/role…)
├── hooks/                      # 组合式函数(core/event/setting/web…)
├── layout/                     # 布局系统
├── router/                     # 路由(constant 常量路由 + generator-routers 动态菜单路由)
├── settings/                   # 全局设置(项目设置/设计设置/组件设置/动画设置)
├── store/                      # Pinia(modules:user/asyncRoute/tabsView/designSetting…)
├── styles/                     # 全局样式与主题变量
├── utils/                      # 工具库(http 请求封装/auth/storage/downloadFile…)
└── views/                      # 页面(按域分目录)
    ├── system/                 #   user/role/menu/dept/level/position/tenant/logger
    ├── data/                   #   city/config/dict/notice/param
    ├── content/                #   article/category/link
    ├── monitor/                #   online/server/cache/job
    ├── tool/                   #   generator/example
    ├── file/ setting/ dashboard/ login/ exception/ iframe/ redirect/ about/

为什么选择"单包平铺"而非"按域分目录" ​

对比项单包平铺(本项目)按域分目录
跨模块复用同包直接调用包级函数,零 import需要 import,易产生循环依赖
新增模块4 个文件各放一处,位置固定无歧义需要在多级目录间跳转
生成器产出目标路径唯一确定需推断目录层级
包体积单包文件多,但 Go 编译无压力包粒度细
init 注册同包全量加载,无需 blank import需要 blank import 触发

文件命名统一为表名去 goframe_ 前缀的 snake_case(如 config_item.go、file_template.go),与 dao 产物命名对齐;前端文件仍使用驼峰(如 fileTemplate.ts)。

小蚂蚁云团队 · 提供技术支持