完善 API 文档生成规范:统一路由注册和 OpenAPI 文档自动生成
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m32s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m32s
主要改进: 1. 新增 docs/api-documentation-guide.md 详细文档指南 2. 在 AGENTS.md 中添加路由注册规范章节 3. 更新 README.md 文档目录结构 路由注册改进: - 统一使用 Register() 函数注册路由并自动生成文档 - 所有接口必须指定 RouteSpec(Summary, Tags, Input, Output, Auth) - 修复 docs.go 和 gendocs/main.go 使用 RegisterRoutesWithDoc 统一注册 DTO 规范更新: - shop_dto.go 和 shop_account_dto.go 补充完整的 description 标签 - 所有枚举字段必须列出可能值和中文说明 文档生成优化: - admin-openapi.yaml 自动生成更新 - 健康检查和任务管理接口加入文档 - H5 认证接口完整文档化 规范文档管理: - 添加规范文档管理流程说明 - 详细文档放在 docs/ 目录 - AGENTS.md 只保留核心规则和引导链接
This commit is contained in:
@@ -2,36 +2,35 @@ package model
|
||||
|
||||
// ShopAccountListRequest 代理商账号列表查询请求
|
||||
type ShopAccountListRequest struct {
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1"` // 页码
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100"` // 每页数量
|
||||
ShopID *uint `json:"shop_id" query:"shop_id" validate:"omitempty,min=1"` // 店铺ID过滤
|
||||
Username string `json:"username" query:"username" validate:"omitempty,max=50"` // 用户名(模糊查询)
|
||||
Phone string `json:"phone" query:"phone" validate:"omitempty,len=11"` // 手机号(精确查询)
|
||||
Status *int `json:"status" query:"status" validate:"omitempty,oneof=0 1"` // 状态
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||
ShopID *uint `json:"shop_id" query:"shop_id" validate:"omitempty,min=1" minimum:"1" description:"店铺ID过滤"`
|
||||
Username string `json:"username" query:"username" validate:"omitempty,max=50" maxLength:"50" description:"用户名(模糊查询)"`
|
||||
Phone string `json:"phone" query:"phone" validate:"omitempty,len=11" minLength:"11" maxLength:"11" description:"手机号(精确查询)"`
|
||||
Status *int `json:"status" query:"status" validate:"omitempty,oneof=0 1" description:"状态 (0:禁用, 1:启用)"`
|
||||
}
|
||||
|
||||
// CreateShopAccountRequest 创建代理商账号请求
|
||||
type CreateShopAccountRequest struct {
|
||||
ShopID uint `json:"shop_id" validate:"required,min=1"` // 店铺ID
|
||||
Username string `json:"username" validate:"required,min=3,max=50"` // 用户名
|
||||
Phone string `json:"phone" validate:"required,len=11"` // 手机号
|
||||
Password string `json:"password" validate:"required,min=8,max=32"` // 密码
|
||||
ShopID uint `json:"shop_id" validate:"required,min=1" required:"true" minimum:"1" description:"店铺ID"`
|
||||
Username string `json:"username" validate:"required,min=3,max=50" required:"true" minLength:"3" maxLength:"50" description:"用户名"`
|
||||
Phone string `json:"phone" validate:"required,len=11" required:"true" minLength:"11" maxLength:"11" description:"手机号"`
|
||||
Password string `json:"password" validate:"required,min=8,max=32" required:"true" minLength:"8" maxLength:"32" description:"密码"`
|
||||
}
|
||||
|
||||
// UpdateShopAccountRequest 更新代理商账号请求
|
||||
// UpdateShopAccountRequest 更新代理商账号请求(不包含 phone 和 password,按照业务规则不允许修改)
|
||||
type UpdateShopAccountRequest struct {
|
||||
Username string `json:"username" validate:"required,min=3,max=50"` // 用户名
|
||||
// 注意:不包含 phone 和 password,按照业务规则不允许修改
|
||||
Username string `json:"username" validate:"required,min=3,max=50" required:"true" minLength:"3" maxLength:"50" description:"用户名"`
|
||||
}
|
||||
|
||||
// UpdateShopAccountPasswordRequest 修改代理商账号密码请求(管理员重置)
|
||||
type UpdateShopAccountPasswordRequest struct {
|
||||
NewPassword string `json:"new_password" validate:"required,min=8,max=32"` // 新密码
|
||||
NewPassword string `json:"new_password" validate:"required,min=8,max=32" required:"true" minLength:"8" maxLength:"32" description:"新密码"`
|
||||
}
|
||||
|
||||
// UpdateShopAccountStatusRequest 修改代理商账号状态请求
|
||||
type UpdateShopAccountStatusRequest struct {
|
||||
Status int `json:"status" validate:"required,oneof=0 1"` // 状态(0=禁用 1=启用)
|
||||
Status int `json:"status" validate:"required,oneof=0 1" required:"true" description:"状态 (0:禁用, 1:启用)"`
|
||||
}
|
||||
|
||||
// ShopAccountResponse 代理商账号响应
|
||||
@@ -46,3 +45,29 @@ type ShopAccountResponse struct {
|
||||
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||
UpdatedAt string `json:"updated_at" description:"更新时间"`
|
||||
}
|
||||
|
||||
// ShopAccountPageResult 代理账号分页响应
|
||||
type ShopAccountPageResult struct {
|
||||
Items []ShopAccountResponse `json:"items" description:"代理账号列表"`
|
||||
Total int64 `json:"total" description:"总记录数"`
|
||||
Page int `json:"page" description:"当前页码"`
|
||||
Size int `json:"size" description:"每页数量"`
|
||||
}
|
||||
|
||||
// UpdateShopAccountParams 更新代理账号聚合参数 (用于文档生成)
|
||||
type UpdateShopAccountParams struct {
|
||||
IDReq
|
||||
UpdateShopAccountRequest
|
||||
}
|
||||
|
||||
// UpdateShopAccountPasswordParams 修改代理账号密码聚合参数 (用于文档生成)
|
||||
type UpdateShopAccountPasswordParams struct {
|
||||
IDReq
|
||||
UpdateShopAccountPasswordRequest
|
||||
}
|
||||
|
||||
// UpdateShopAccountStatusParams 修改代理账号状态聚合参数 (用于文档生成)
|
||||
type UpdateShopAccountStatusParams struct {
|
||||
IDReq
|
||||
UpdateShopAccountStatusRequest
|
||||
}
|
||||
|
||||
@@ -53,3 +53,18 @@ type ShopResponse struct {
|
||||
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||
UpdatedAt string `json:"updated_at" description:"更新时间"`
|
||||
}
|
||||
|
||||
// ShopPageResult 店铺分页响应
|
||||
// ShopPageResult 店铺分页响应
|
||||
type ShopPageResult struct {
|
||||
Items []ShopResponse `json:"items" description:"店铺列表"`
|
||||
Total int64 `json:"total" description:"总记录数"`
|
||||
Page int `json:"page" description:"当前页码"`
|
||||
Size int `json:"size" description:"每页数量"`
|
||||
}
|
||||
|
||||
// UpdateShopParams 更新店铺聚合参数 (用于文档生成)
|
||||
type UpdateShopParams struct {
|
||||
IDReq
|
||||
UpdateShopRequest
|
||||
}
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
)
|
||||
|
||||
// registerHealthRoutes 注册健康检查路由
|
||||
// 不需要认证,用于负载均衡器和监控系统
|
||||
func registerHealthRoutes(app *fiber.App) {
|
||||
// 健康检查
|
||||
app.Get("/health", func(c *fiber.Ctx) error {
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status" description:"健康状态"`
|
||||
Service string `json:"service,omitempty" description:"服务名称"`
|
||||
}
|
||||
|
||||
func registerHealthRoutes(app *fiber.App, doc *openapi.Generator) {
|
||||
Register(app, doc, "", "GET", "/health", func(c *fiber.Ctx) error {
|
||||
return response.Success(c, fiber.Map{
|
||||
"status": "healthy",
|
||||
"service": "junhong_cmp_fiber",
|
||||
})
|
||||
}, RouteSpec{
|
||||
Summary: "健康检查",
|
||||
Tags: []string{"系统"},
|
||||
Input: nil,
|
||||
Output: new(HealthResponse),
|
||||
Auth: false,
|
||||
})
|
||||
|
||||
// 就绪检查
|
||||
app.Get("/ready", func(c *fiber.Ctx) error {
|
||||
Register(app, doc, "", "GET", "/ready", func(c *fiber.Ctx) error {
|
||||
return response.Success(c, fiber.Map{
|
||||
"status": "ready",
|
||||
})
|
||||
}, RouteSpec{
|
||||
Summary: "就绪检查",
|
||||
Tags: []string{"系统"},
|
||||
Input: nil,
|
||||
Output: new(HealthResponse),
|
||||
Auth: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,24 +4,30 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/bootstrap"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||
)
|
||||
|
||||
// RegisterRoutes 路由注册总入口
|
||||
// 按业务模块调用各自的路由注册函数
|
||||
func RegisterRoutes(app *fiber.App, handlers *bootstrap.Handlers, middlewares *bootstrap.Middlewares) {
|
||||
RegisterRoutesWithDoc(app, handlers, middlewares, nil)
|
||||
}
|
||||
|
||||
// RegisterRoutesWithDoc 路由注册总入口(支持文档生成)
|
||||
func RegisterRoutesWithDoc(app *fiber.App, handlers *bootstrap.Handlers, middlewares *bootstrap.Middlewares, doc *openapi.Generator) {
|
||||
// 1. 全局路由
|
||||
registerHealthRoutes(app)
|
||||
registerHealthRoutes(app, doc)
|
||||
|
||||
// 2. Admin 域 (挂载在 /api/admin)
|
||||
adminGroup := app.Group("/api/admin")
|
||||
RegisterAdminRoutes(adminGroup, handlers, middlewares, nil, "/api/admin")
|
||||
RegisterAdminRoutes(adminGroup, handlers, middlewares, doc, "/api/admin")
|
||||
|
||||
// 任务相关路由 (归属于 Admin 域)
|
||||
registerTaskRoutes(adminGroup)
|
||||
registerTaskRoutes(adminGroup, doc, "/api/admin")
|
||||
|
||||
// 3. H5 域 (挂载在 /api/h5)
|
||||
h5Group := app.Group("/api/h5")
|
||||
RegisterH5Routes(h5Group, handlers, middlewares, nil, "/api/h5")
|
||||
RegisterH5Routes(h5Group, handlers, middlewares, doc, "/api/h5")
|
||||
|
||||
// 4. 个人客户路由 (挂载在 /api/c/v1)
|
||||
RegisterPersonalCustomerRoutes(app, handlers, middlewares.PersonalAuth)
|
||||
|
||||
@@ -4,20 +4,88 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||
)
|
||||
|
||||
func registerShopRoutes(router fiber.Router, handler *admin.ShopHandler, doc *openapi.Generator, basePath string) {
|
||||
router.Get("/shops", handler.List)
|
||||
router.Post("/shops", handler.Create)
|
||||
router.Put("/shops/:id", handler.Update)
|
||||
router.Delete("/shops/:id", handler.Delete)
|
||||
shops := router.Group("/shops")
|
||||
groupPath := basePath + "/shops"
|
||||
|
||||
Register(shops, doc, groupPath, "GET", "", handler.List, RouteSpec{
|
||||
Summary: "店铺列表",
|
||||
Tags: []string{"店铺管理"},
|
||||
Input: new(model.ShopListRequest),
|
||||
Output: new(model.ShopPageResult),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shops, doc, groupPath, "POST", "", handler.Create, RouteSpec{
|
||||
Summary: "创建店铺",
|
||||
Tags: []string{"店铺管理"},
|
||||
Input: new(model.CreateShopRequest),
|
||||
Output: new(model.ShopResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shops, doc, groupPath, "PUT", "/:id", handler.Update, RouteSpec{
|
||||
Summary: "更新店铺",
|
||||
Tags: []string{"店铺管理"},
|
||||
Input: new(model.UpdateShopParams),
|
||||
Output: new(model.ShopResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shops, doc, groupPath, "DELETE", "/:id", handler.Delete, RouteSpec{
|
||||
Summary: "删除店铺",
|
||||
Tags: []string{"店铺管理"},
|
||||
Input: new(model.IDReq),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
}
|
||||
|
||||
func registerShopAccountRoutes(router fiber.Router, handler *admin.ShopAccountHandler, doc *openapi.Generator, basePath string) {
|
||||
router.Get("/shop-accounts", handler.List)
|
||||
router.Post("/shop-accounts", handler.Create)
|
||||
router.Put("/shop-accounts/:id", handler.Update)
|
||||
router.Put("/shop-accounts/:id/password", handler.UpdatePassword)
|
||||
router.Put("/shop-accounts/:id/status", handler.UpdateStatus)
|
||||
shopAccounts := router.Group("/shop-accounts")
|
||||
groupPath := basePath + "/shop-accounts"
|
||||
|
||||
Register(shopAccounts, doc, groupPath, "GET", "", handler.List, RouteSpec{
|
||||
Summary: "代理账号列表",
|
||||
Tags: []string{"代理账号管理"},
|
||||
Input: new(model.ShopAccountListRequest),
|
||||
Output: new(model.ShopAccountPageResult),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shopAccounts, doc, groupPath, "POST", "", handler.Create, RouteSpec{
|
||||
Summary: "创建代理账号",
|
||||
Tags: []string{"代理账号管理"},
|
||||
Input: new(model.CreateShopAccountRequest),
|
||||
Output: new(model.ShopAccountResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shopAccounts, doc, groupPath, "PUT", "/:id", handler.Update, RouteSpec{
|
||||
Summary: "更新代理账号",
|
||||
Tags: []string{"代理账号管理"},
|
||||
Input: new(model.UpdateShopAccountParams),
|
||||
Output: new(model.ShopAccountResponse),
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shopAccounts, doc, groupPath, "PUT", "/:id/password", handler.UpdatePassword, RouteSpec{
|
||||
Summary: "重置代理账号密码",
|
||||
Tags: []string{"代理账号管理"},
|
||||
Input: new(model.UpdateShopAccountPasswordParams),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
|
||||
Register(shopAccounts, doc, groupPath, "PUT", "/:id/status", handler.UpdateStatus, RouteSpec{
|
||||
Summary: "启用/禁用代理账号",
|
||||
Tags: []string{"代理账号管理"},
|
||||
Input: new(model.UpdateShopAccountStatusParams),
|
||||
Output: nil,
|
||||
Auth: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
)
|
||||
|
||||
// registerTaskRoutes 注册任务相关路由
|
||||
// 用于异步任务状态查询等
|
||||
func registerTaskRoutes(api fiber.Router) {
|
||||
tasks := api.Group("/tasks")
|
||||
type TaskStatusResponse struct {
|
||||
ID string `json:"id" description:"任务ID"`
|
||||
Status string `json:"status" description:"任务状态 (pending:待处理, running:执行中, completed:已完成, failed:失败)"`
|
||||
}
|
||||
|
||||
// 获取任务状态(占位实现)
|
||||
tasks.Get("/:id", func(c *fiber.Ctx) error {
|
||||
func registerTaskRoutes(api fiber.Router, doc *openapi.Generator, basePath string) {
|
||||
tasks := api.Group("/tasks")
|
||||
groupPath := basePath + "/tasks"
|
||||
|
||||
Register(tasks, doc, groupPath, "GET", "/:id", func(c *fiber.Ctx) error {
|
||||
taskID := c.Params("id")
|
||||
return response.Success(c, fiber.Map{
|
||||
"id": taskID,
|
||||
"status": "pending",
|
||||
})
|
||||
}, RouteSpec{
|
||||
Summary: "查询任务状态",
|
||||
Tags: []string{"任务管理"},
|
||||
Input: new(model.IDReq),
|
||||
Output: new(TaskStatusResponse),
|
||||
Auth: true,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user