这是一个系列 Blog作者将以一个 PHP 全栈工程师的身份利用 AI 工具claude code、codex、deepseek、豆包等从零开始学习 golang 语言并最终完成 ai-go-mallgithub | gitee开源项目的制作全程记录分享。在上一期我们已经完成 “泛型基服务、控制器、仓储实现自动发现和注册业务路由”本期将完成建立 CLAUDE.md 文件、整理目录结构建立 CLAUDE.md 文件这个文件根据 CLAUDE 官方的定义应当在 Claude 第二次犯同样的错误或者当某个约定给它讲过两次以上时可以将这些内容写入 CLAUDE.md当然也可以提前讲清项目定位、目录结构以便 CLAUDE 更好的工作。ai-go-mall 项目至今已经使用 cc 实现了配置系统带自动发现、环境配置文件、环境变量覆盖、数据库连接带读写分离支持链式函数式选项自定义 db、模型自动发现和迁移、四层业务架构的基类实现、自动发现和注册路由、统一响应结构和函数也支持链式调用和函数式选项等一大堆的功能却连个 CLAUDE.md 都没有足以见得 cc 的强大也可能说明了当开发者本身技术够硬时这些都是花架子无需过于纠结因为总有小伙伴纠结这东西咋写实际上就是随便写没有固定格式不要被网上卖课的哄骗免费的可以看大不了你多调几次调好了能少几轮对话或者多节约一些 token。我们直接使用/init命令让 cc 先自己做一份CLAUDE.md出来然后第一件事就是删除多余内容因为此文件将作为系统级上下文融入每一次对话中而 AI 很多时候并不需要特别细致的解释即可很好的完成工作最终整理出来的CLAUDE.md如下PS:其实里边还有很多都是特意改了给人看的让初次上手的开发者也能快速了解项目总体情况我个人认为目前最值得写入的内容尽量使用 GORM 的 Generics API 而不是 Traditional API只使用 GET 和 POST 请求方式大多数 CDN/全站加速 服务对 PUT、DELETE 兼容性差当我询问某方案是否合理时请先根据社区惯例判断是否合理合理直接实现不合理取消实现并解释原因# CLAUDE.md 本文件为 Claude Code 在当前代码库中工作时提供指导。 ## 项目概述 爱购商城ai-go-mall技术栈Go 1.25 Gin GORM PostgreSQL。 ## 回答偏好 - 回复使用中文 - 遇到有多种实现方案时列出选项让我选择而不是直接选一种 - 当我询问某方案是否合理时请先根据社区惯例判断是否合理合理直接实现不合理取消实现并解释原因社区惯例指对应技术栈的社区如 golang 开源社区Gin 开源社区开源高星仓库官方文档权威 blog 等 ## 泛型基类体系 核心应用架构为泛型驱动的四层架构模式请求 → Handler控制器→ Service业务逻辑→ Repository数据访问→ Model数据模型 前三层都有**泛型基础实现**具体模块通过**组合嵌入**复用 | 层级 | 泛型基类 | 接口 | 文件 | | ---------- | --------------- | ---------------- | ----------------------------- | | Repository | Repository[T] | IRepository[T] | internal/repository/base.go | | Service | Service[T] | IService[T] | internal/service/base.go | | Handler | Handler[T] | 无 | internal/handler/base.go | **扩展模式**以 User 为例 - UserRepository 嵌入 *Repository[model.User]可访问 GetDB() 编写自定义查询 - UserService 嵌入 IService[model.User] 并持有 *UserRepository可覆盖业务逻辑 - UserHandler 嵌入 *Handler[model.User] 并持有 *UserService注册路由可调用 RegisterBaseRoutes 后再追加自定义路由 ## 路由自动发现 internal/router/registry/ 提供 Routes 切片 Register(fn) 函数。 子模块在 init() 中调用 registry.Register(func(r *gin.Engine) { ... }) 自注册路由分组internal/router/router.go 通过空白导入触发 init() router.go ──_ import──→ admin/ ──init()──→ registry.Register(...) ├─_ import──→ user/ ──init()──→ registry.Register(...) └─Setup() ──→ 遍历 registry.Routes 新增路由模块 1. 新建子目录并于 init() 调 registry.Register 2. 在 router.go 加一行空白导入以触发 init() ## 启动流程 1. config.Init() — 合并 config/*.yaml .env.yaml环境变量覆盖热加载 2. database.Init() — 连接 PostgreSQL配置读写分离AutoMigrate 所有 model.Register() 的模型 3. engine.Use(database.Middleware()) — 注入 *gorm.DB 到 gin.Context 4. router.Setup(engine) — 遍历 registry.Routes 注册所有路由 5. engine.Run() ## 关键约定 - **只使用 GET 和 POST 请求方式**大多数 CDN/全站加速 服务对 PUT、DELETE 兼容性差 - **包名**全小写、单数、无下划线handler、service - **文件名**全小写、下划线分隔user_service.go - **导出符号**大驼峰私有符号小驼峰 - **数据库字段**蛇形命名user_name、created_at - **统一响应**response.Success(c, opts...) / response.Fail(c, opts...)支持 functional options 和链式调用两种风格优先使用 functional options - **GORM**尽量使用 GORM 的 Generics APIgorm.G[Model](db)....而不是 Traditional API在使用 Generics API 时一般应直接使用全局 db 实例internal\database\database.go 中的 GetDB 可获取调用操作方法时再传递合适的 ctx 即可。整理目录结构新增目录比起最初的目录结构我在internal下增加了database、response、router三个目录它们三都是值得于 internal 单独一个目录存放的内容。database数据库的重要性不必多少单独一个包首先就是调用方法简洁方便虽目前只有数据库连接实现、未来可能会有数据库中间件、一些数据库相关的全局类等等router路由系统作为 WEB 项目核心且未来路由定义文件可能很多单目录又支持子级目录的路由自动发现和注册非常合理response存放统一响应的实现响应比数据库的调用会更频繁单独包只为调用方便也是值得的四层架构功能明确即 Handler → Service → Repository → Model 四层应用架构说实话我还是第一次接触这种架构只是基本理解这里结合各大 AI 的解释对架构各部分功能进行明确如下Handler处理器层解析请求JSON → struct 调用 Service 序列化响应struct → JSON可以做请求合法性校验如手机号格式、参数非空一般是参数不对就可以直接返回错误信息的检查Service服务层处理业务逻辑业务规则校验如余额是否足够逻辑编排事务控制接收 Handler 层调用调用 Repository 层返回结果给 Handler 层Repository仓储层只处理数据库操作把数据从 DB 搬到内存或反过来接收 Service 层调用返回结果给 Service 层Model模型层只定义表结构可有表名函数常见问题如何区分某参数应该在 Handler 还是 Service 层检查Handler 中的检查和业务无关只看 “请求对不对”非法请求在入口直接拦截不进业务、不查库包括参数非空必传字段参数格式错误手机号、邮箱、身份证、UUID参数长度超限用户名太短 / 太长参数类型错误数字传成字符串枚举值不在范围内性别只允许男 / 女 / 未知路径参数 / 查询参数格式错误请求体结构非法总结前端传错了、格式错了、少传了 → Handler 直接拦掉Service 中的检查和业务强相关必须依赖业务逻辑 / 数据库 / 状态判断的包括数据是否已存在用户名重复、手机号已注册数据状态是否允许操作已取消的订单不能支付权限校验不是自己的地址不能删除业务规则限制余额不足、库存不足、年龄不够多参数关联校验开始时间不能晚于结束时间跨表 / 跨服务校验用户是否存在、商品是否上架总结需要查库、需要业务状态、需要走流程、前端不可能知道的Handler 和 Service 能否融合不能Service 层可以脱离 HTTP 单独测试Service 层还可以供定时任务、消息队列直接使用。