All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m45s
主要变更: 1. OpenAPI 文档契约对齐 - 统一错误响应字段名为 msg(非 message) - 规范 envelope 响应结构(code, msg, data, timestamp) - 个人客户路由纳入文档体系(使用 Register 机制) - 新增 BuildDocHandlers() 统一管理 handler 构造 - 确保文档生成的幂等性 2. Service 层错误处理统一 - 全面替换 fmt.Errorf 为 errors.New/Wrap - 统一错误码使用规范 - Handler 层参数校验不泄露底层细节 - 新增错误码验证集成测试 3. 代码质量提升 - 删除未使用的 Task handler 和路由 - 新增代码规范检查脚本(check-service-errors.sh) - 新增注释路径一致性检查(check-comment-paths.sh) - 更新 API 文档生成指南 4. OpenSpec 归档 - 归档 openapi-contract-alignment 变更(63 tasks) - 归档 service-error-unify-core 变更 - 归档 service-error-unify-support 变更 - 归档 code-cleanup-docs-update 变更 - 归档 handler-validation-security 变更 - 同步 delta specs 到主规范文件 影响范围: - pkg/openapi: 新增 handlers.go,优化 generator.go - internal/service/*: 48 个 service 文件错误处理统一 - internal/handler/admin: 优化参数校验错误提示 - internal/routes: 个人客户路由改造,删除 task 路由 - scripts: 新增 3 个代码检查脚本 - docs: 更新 OpenAPI 文档(15750+ 行) - openspec/specs: 同步 3 个主规范文件 破坏性变更:无 向后兼容:是
6.5 KiB
6.5 KiB
Change: OpenAPI 文档契约对齐
Why
确保 OpenAPI 文档描述的响应结构与真实运行时一致,避免 SDK 生成和接口对接问题。
当前问题:
-
响应字段名不一致:
- OpenAPI 错误响应定义为
message字段 - 真实运行时返回为
msg字段
- OpenAPI 错误响应定义为
-
成功响应缺少 envelope:
- OpenAPI 文档直接返回 DTO schema
- 真实运行时包裹在
{code, data, msg, timestamp}中
-
handlers 清单不完整:
cmd/api/docs.go和cmd/gendocs/main.go清单不一致- 缺少部分 handler(PersonalCustomer、ShopPackageBatchAllocation、ShopPackageBatchPricing)
-
个人客户路由未纳入文档:
/api/c/v1路由未使用Register(...)机制- 不在 OpenAPI 文档体系中
What Changes
4.1 响应字段名对齐
修改 OpenAPI 错误响应 schema:
# ❌ 当前
components:
schemas:
ErrorResponse:
properties:
code: { type: integer }
message: { type: string } # 错误:应为 msg
data: { type: object }
timestamp: { type: string }
# ✅ 修复后
components:
schemas:
ErrorResponse:
properties:
code: { type: integer, example: 0 }
msg: { type: string, example: "success" } # 对齐真实字段名
data: { type: object }
timestamp: { type: string, format: date-time }
4.2 成功响应体现 envelope
修改成功响应格式,包裹 DTO:
# ❌ 当前(直接返回 DTO)
/api/admin/users:
get:
responses:
200:
content:
application/json:
schema:
$ref: '#/components/schemas/UserDTO'
# ✅ 修复后(包裹 envelope)
/api/admin/users:
get:
responses:
200:
content:
application/json:
schema:
type: object
properties:
code: { type: integer, example: 0 }
msg: { type: string, example: "success" }
data:
$ref: '#/components/schemas/UserDTO'
timestamp: { type: string, format: date-time }
4.3 补齐 handlers 清单
在文档生成器中补充缺失的 handler:
// cmd/api/docs.go 和 cmd/gendocs/main.go
handlers := &bootstrap.Handlers{
// ... 现有 handlers
// 补充缺失的 handlers
PersonalCustomer: personal.NewPersonalCustomerHandler(nil),
ShopPackageBatchAllocation: admin.NewShopPackageBatchAllocationHandler(nil),
ShopPackageBatchPricing: admin.NewShopPackageBatchPricingHandler(nil),
}
4.4 个人客户路由纳入文档
改造 internal/routes/personal.go 使用 Register(...) 机制:
// ❌ 当前
func RegisterPersonalRoutes(app *fiber.App, handlers *bootstrap.Handlers) {
api := app.Group("/api/c/v1")
api.Get("/cards/:iccid", handlers.PersonalCustomer.GetCard)
// ...
}
// ✅ 修复后
func RegisterPersonalRoutes(doc *openapi.Generator, basePath string, handlers *bootstrap.Handlers) {
doc.Register(openapi.RouteSpec{
Method: "GET",
Path: "/api/c/v1/cards/:iccid",
Handler: handlers.PersonalCustomer.GetCard,
Summary: "获取个人客户卡详情",
Tags: []string{"个人客户"},
Auth: true,
Input: nil, // 路径参数
Output: &dto.CardDetailResponse{},
})
// ...
}
Decisions
OpenAPI 生成策略
- 统一 envelope 包裹:所有成功响应使用
{code, data, msg, timestamp} - 字段名一致:错误响应使用
msg而非message - DTO 保持具体类型:
data字段保留具体的 DTO schema - 自动化 handlers 构造:文档生成时 handlers 可以传入
nil依赖
文档生成复用
抽取公共函数避免重复:
// pkg/openapi/handlers.go (新建)
func BuildDocHandlers() *bootstrap.Handlers {
// 文档生成用,所有依赖传 nil
return &bootstrap.Handlers{
Account: admin.NewAccountHandler(nil, nil),
Shop: admin.NewShopHandler(nil, nil),
// ... 所有 handlers
}
}
在 cmd/api/docs.go 和 cmd/gendocs/main.go 中复用:
handlers := openapi.BuildDocHandlers()
Impact
Breaking Changes
- OpenAPI 文档结构变化(响应格式)
- 需要通知 SDK 使用方重新生成 SDK
- 前端可能需要调整响应解析逻辑(如果直接使用 OpenAPI 生成的类型)
Documentation Updates
- 更新
docs/api-documentation-guide.md补充 envelope 说明 - 补充个人客户 API 路由注册示例
- 在 API 文档中说明 envelope 格式
Testing Requirements
生成文档后对比验证:
# 1. 重新生成文档
go run cmd/gendocs/main.go
# 2. 对比差异
diff logs/openapi.yaml logs/openapi.yaml.old
# 3. 验证关键点
# - 检查响应字段名是否为 msg(非 message)
# - 检查成功响应是否包含 envelope
# - 检查 /api/c/v1 路由是否出现
# - 检查接口数量是否完整
Affected Specs
-
UPDATE:
openspec/specs/openapi-generation/spec.md- 补充 envelope 包裹要求
- 更新字段名规范
-
UPDATE:
openspec/specs/personal-customer/spec.md- 个人客户 API 进入文档体系
Verification Checklist
编译检查
go build -o /tmp/test_gendocs ./cmd/gendocs
文档生成
go run cmd/gendocs/main.go
文档验证
检查生成的 logs/openapi.yaml:
- 错误响应字段名为
msg(非message) - 成功响应包含 envelope:
200: content: application/json: schema: type: object properties: code: { type: integer } msg: { type: string } data: { ... } timestamp: { type: string } /api/c/v1路由出现在文档中- 接口数量完整(与已注册路由一致)
示例响应验证
对比文档示例与真实响应:
文档示例:
{
"code": 0,
"msg": "success",
"data": {
"id": 1,
"username": "admin"
},
"timestamp": "2026-01-29T10:00:00Z"
}
真实响应(curl 测试):
curl -X GET http://localhost:8080/api/admin/users/1 \
-H "Authorization: Bearer $TOKEN"
确认字段名和结构一致。
Estimated Effort
| 任务 | 预估时间 |
|---|---|
| 4.1 响应字段名对齐 | 0.5h |
| 4.2 成功响应 envelope | 1h |
| 4.3 补齐 handlers 清单 | 0.5h |
| 4.4 个人客户路由纳入 | 1h |
| 文档验证 | 0.5h |
| 文档更新 | 0.5h |
总计:约 4 小时