kratos项目目录结构需严格遵循规范:根目录含api、cmd、configs等,internal为业务主战场;api仅存.proto文件;internal分data、biz、service、server四层;configs与migrations分离配置与数据演进;cmd仅为单一启动入口。

理解Kratos项目目录结构是正确使用框架、避免模块错位和依赖混乱的前提,直接关系到后续接口定义、服务注册、中间件注入能否正常生效。
根目录核心骨架
执行 kratos new helloworld 后生成的顶层目录包含:api、cmd、configs、internal、migrations、pkg、go.mod 和 Makefile。其中 internal 是业务逻辑主战场,api 是协议契约入口,cmd 是应用启动唯一出口——【任何业务代码不得写入 cmd 或根目录】,否则 Wire 依赖注入将无法扫描到。
所有自定义中间件、日志封装、错误码映射必须放在 internal/middleware、internal/log、internal/errors 等子包中,与 internal/service 平级。
api 目录:协议契约与代码生成源
该目录只存放 .proto 文件及配套生成文件,严禁手写 HTTP handler 或 gRPC service 实现。
方法一:按业务域建子目录,例如 api/user/v1/user.proto,其中 v1 表示版本隔离,升级时新建 v2 目录而非修改原文件。
方法二:每个 .proto 必须定义 package 名为 xxx.v1(如 user.v1),否则 make api 生成的 Go 代码会因包名冲突导致编译失败。
生成的 *_http.pb.go 和 *_grpc.pb.go 由 Makefile 自动写入 api/xxx/v1/ 下,不可手动编辑——这些是契约快照,修改需回到 .proto 并重新运行 make api。
internal 目录:四层职责划分
第一步:进入 internal,你会看到 data、biz、service、server 四个标准子包。
第二步:确认 data 包职责——仅封装数据访问,含 Ent/GORM Client 初始化、Repository 接口定义与实现、数据库迁移脚本调用。它不处理业务规则,也不感知 HTTP 或 gRPC 协议细节。
第三步:检查 biz 包——这里放置领域模型(如 User 结构体)、业务逻辑(Usecase 方法)、以及仓储接口(UserRepo)的抽象定义。它依赖 data 的接口,但绝不依赖其实现;它被 service 调用,但不依赖 service。
第四步:定位 service 包——它接收 server 层传入的原始请求参数,调用 biz 层完成业务流转,并将结果转换为 api 层定义的 protobuf message 返回。它是协议无关的胶水层,也是唯一可对请求做预校验(如 JWT 解析)的地方。
第五步:验证 server 包——它只做三件事:注册路由(srv.GET("/users", handler))、绑定中间件(srv.Use(logging.Server(logger)))、调用 service 实例的方法。它不包含任何业务判断,也不操作数据库。
configs 与 migrations:配置与数据演进分离
configs 目录下只有 config.yaml 和 config_test.yaml,用于定义数据库地址、JWT 密钥、服务名等运行时参数。所有键名必须与 configs/config.go 中 struct 字段标签完全一致,否则 conf.Load() 将静默忽略该字段。
migrations 目录存放 Ent 自动生成的数据库变更脚本,每条脚本以时间戳开头(如 20240315102345_init_users.up.sql)。执行 ent migrate status 可查看当前环境已应用的迁移版本,【禁止手动修改已提交的 .up.sql 文件内容】,回滚应通过新增 .down.sql 脚本完成。
cmd 目录:单一启动入口与依赖注入
打开 cmd/helloworld/main.go,确认其中只做了四件事:初始化日志、加载配置、构建 Wire Injector、调用 app.Run()。
Wire 注入器(internal/di)必须在 main() 中显式调用 di.InitApp(),否则 service、data 等实例不会被创建,应用启动后会 panic 报 “nil pointer dereference”。
该文件内不得出现任何业务逻辑、HTTP handler 注册或数据库操作——它只是把所有齿轮组装起来并拧紧的最后一颗螺丝。











