Files
junhong_cmp_fiber/specs/002-gorm-postgres-asynq/contracts/api.yaml
huang 984ccccc63 docs(constitution): 新增数据库设计原则(v2.4.0)
在项目宪章中新增第九条原则"数据库设计原则",明确禁止使用数据库外键约束和ORM关联标签。

主要变更:
- 新增原则IX:数据库设计原则(Database Design Principles)
- 强制要求:数据库表不得使用外键约束
- 强制要求:GORM模型不得使用ORM关联标签(foreignKey、hasMany等)
- 强制要求:表关系必须通过ID字段手动维护
- 强制要求:关联数据查询必须显式编写,避免ORM魔法
- 强制要求:时间字段由GORM处理,不使用数据库触发器

设计理念:
- 提升业务逻辑灵活性(无数据库约束限制)
- 优化高并发性能(无外键检查开销)
- 增强代码可读性(显式查询,无隐式预加载)
- 简化数据库架构和迁移流程
- 支持分布式和微服务场景

版本升级:2.3.0 → 2.4.0(MINOR)
2025-11-13 13:40:19 +08:00

734 lines
19 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.0.3
info:
title: 数据持久化与异步任务处理集成 API
description: |
GORM + PostgreSQL + Asynq 集成的数据持久化和异步任务处理功能 API 规范
**Feature**: 002-gorm-postgres-asynq
**Date**: 2025-11-12
## 核心功能
- 数据库连接管理和健康检查
- 异步任务提交和管理
- 数据 CRUD 操作(示例:用户管理)
## 技术栈
- Fiber (HTTP 框架)
- GORM (ORM)
- PostgreSQL (数据库)
- Asynq (任务队列)
- Redis (任务队列存储)
version: 1.0.0
contact:
name: API Support
email: support@example.com
servers:
- url: http://localhost:8080/api/v1
description: 开发环境
- url: http://staging.example.com/api/v1
description: 预发布环境
- url: https://api.example.com/api/v1
description: 生产环境
tags:
- name: Health
description: 健康检查和系统状态
- name: Users
description: 用户管理(数据库操作示例)
- name: Tasks
description: 异步任务管理
paths:
/health:
get:
tags:
- Health
summary: 健康检查
description: |
检查系统健康状态,包括数据库连接和 Redis 连接
**测试用例**:
- FR-011: 系统必须提供健康检查接口
- SC-010: 健康检查应在 1 秒内返回
operationId: healthCheck
responses:
'200':
description: 系统健康
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: [ok]
description: 系统整体状态
postgres:
type: string
enum: [up, down]
description: PostgreSQL 连接状态
redis:
type: string
enum: [up, down]
description: Redis 连接状态
example:
status: ok
postgres: up
redis: up
'503':
description: 服务降级或不可用
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: [degraded, unavailable]
postgres:
type: string
enum: [up, down]
redis:
type: string
enum: [up, down]
error:
type: string
description: 错误详情
example:
status: degraded
postgres: down
redis: up
error: "数据库连接失败"
/users:
post:
tags:
- Users
summary: 创建用户
description: |
创建新用户(演示数据库 CRUD 操作)
**测试用例**:
- FR-002: 支持标准 CRUD 操作
- FR-003: 支持数据库事务
- User Story 1 - Acceptance 1: 数据持久化
operationId: createUser
security:
- TokenAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'200':
description: 用户创建成功
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UserResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'409':
$ref: '#/components/responses/Conflict'
'500':
$ref: '#/components/responses/InternalServerError'
get:
tags:
- Users
summary: 用户列表
description: |
分页查询用户列表
**测试用例**:
- FR-002: 支持分页列表查询
- FR-005: 支持条件查询、分页、排序
- User Story 1 - Acceptance 5: 分页和排序
operationId: listUsers
security:
- TokenAuth: []
parameters:
- name: page
in: query
schema:
type: integer
default: 1
minimum: 1
description: 页码
- name: page_size
in: query
schema:
type: integer
default: 20
minimum: 1
maximum: 100
description: 每页条数(最大 100
- name: status
in: query
schema:
type: string
enum: [active, inactive, suspended]
description: 用户状态过滤
responses:
'200':
description: 查询成功
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/ListUsersResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/users/{id}:
get:
tags:
- Users
summary: 获取用户详情
description: |
根据用户 ID 获取详细信息
**测试用例**:
- FR-002: 支持按 ID 查询
- User Story 1 - Acceptance 1: 数据检索
operationId: getUserById
security:
- TokenAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
minimum: 1
description: 用户 ID
responses:
'200':
description: 查询成功
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UserResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
put:
tags:
- Users
summary: 更新用户
description: |
更新用户信息
**测试用例**:
- FR-002: 支持更新操作
- User Story 1 - Acceptance 2: 数据更新
operationId: updateUser
security:
- TokenAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
minimum: 1
description: 用户 ID
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UserResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
'500':
$ref: '#/components/responses/InternalServerError'
delete:
tags:
- Users
summary: 删除用户
description: |
软删除用户(设置 deleted_at 字段)
**测试用例**:
- FR-002: 支持软删除操作
- User Story 1 - Acceptance 3: 数据删除
operationId: deleteUser
security:
- TokenAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: integer
minimum: 1
description: 用户 ID
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/SuccessResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalServerError'
/tasks/email:
post:
tags:
- Tasks
summary: 提交邮件发送任务
description: |
将邮件发送任务提交到异步队列
**测试用例**:
- FR-006: 提交任务到异步队列
- FR-008: 任务重试机制
- User Story 2 - Acceptance 1: 任务提交
operationId: submitEmailTask
security:
- TokenAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EmailTaskRequest'
responses:
'200':
description: 任务已提交
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/TaskResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
/tasks/sync:
post:
tags:
- Tasks
summary: 提交数据同步任务
description: |
将数据同步任务提交到异步队列(支持优先级)
**测试用例**:
- FR-006: 提交任务到异步队列
- FR-009: 任务优先级支持
- User Story 2 - Acceptance 1: 任务提交
operationId: submitSyncTask
security:
- TokenAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SyncTaskRequest'
responses:
'200':
description: 任务已提交
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/SuccessResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/TaskResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
components:
securitySchemes:
TokenAuth:
type: apiKey
in: header
name: token
description: 认证令牌
schemas:
# 通用响应
SuccessResponse:
type: object
required:
- code
- msg
- timestamp
properties:
code:
type: integer
enum: [0]
description: 响应码0 表示成功)
msg:
type: string
example: success
description: 响应消息
data:
type: object
description: 响应数据(具体结构由各端点定义)
timestamp:
type: string
format: date-time
example: "2025-11-12T16:00:00+08:00"
description: 响应时间戳ISO 8601 格式)
ErrorResponse:
type: object
required:
- code
- msg
- timestamp
properties:
code:
type: integer
description: 错误码(非 0
example: 1001
msg:
type: string
description: 错误消息(中文)
example: "参数验证失败"
data:
type: object
nullable: true
description: 错误详情(可选)
timestamp:
type: string
format: date-time
example: "2025-11-12T16:00:00+08:00"
# 用户相关
CreateUserRequest:
type: object
required:
- username
- email
- password
properties:
username:
type: string
minLength: 3
maxLength: 50
pattern: '^[a-zA-Z0-9_]+$'
description: 用户名3-50 个字母数字下划线)
example: testuser
email:
type: string
format: email
maxLength: 100
description: 邮箱地址
example: test@example.com
password:
type: string
format: password
minLength: 8
description: 密码(至少 8 个字符)
example: password123
UpdateUserRequest:
type: object
properties:
email:
type: string
format: email
maxLength: 100
description: 邮箱地址
example: newemail@example.com
status:
type: string
enum: [active, inactive, suspended]
description: 用户状态
UserResponse:
type: object
required:
- id
- username
- email
- status
- created_at
- updated_at
properties:
id:
type: integer
description: 用户 ID
example: 1
username:
type: string
description: 用户名
example: testuser
email:
type: string
description: 邮箱地址
example: test@example.com
status:
type: string
enum: [active, inactive, suspended]
description: 用户状态
example: active
created_at:
type: string
format: date-time
description: 创建时间
example: "2025-11-12T16:00:00+08:00"
updated_at:
type: string
format: date-time
description: 更新时间
example: "2025-11-12T16:00:00+08:00"
last_login_at:
type: string
format: date-time
nullable: true
description: 最后登录时间
example: "2025-11-12T16:30:00+08:00"
ListUsersResponse:
type: object
required:
- users
- page
- page_size
- total
- total_pages
properties:
users:
type: array
items:
$ref: '#/components/schemas/UserResponse'
description: 用户列表
page:
type: integer
description: 当前页码
example: 1
page_size:
type: integer
description: 每页条数
example: 20
total:
type: integer
format: int64
description: 总记录数
example: 100
total_pages:
type: integer
description: 总页数
example: 5
# 任务相关
EmailTaskRequest:
type: object
required:
- to
- subject
- body
properties:
to:
type: string
format: email
description: 收件人邮箱
example: user@example.com
subject:
type: string
maxLength: 200
description: 邮件主题
example: Welcome to our service
body:
type: string
description: 邮件正文
example: Thank you for signing up!
cc:
type: array
items:
type: string
format: email
description: 抄送列表
example: ["manager@example.com"]
priority:
type: string
enum: [critical, default, low]
default: default
description: 任务优先级
SyncTaskRequest:
type: object
required:
- sync_type
- start_date
- end_date
properties:
sync_type:
type: string
enum: [sim_status, flow_usage, real_name]
description: 同步类型
example: sim_status
start_date:
type: string
format: date
pattern: '^\d{4}-\d{2}-\d{2}$'
description: 开始日期YYYY-MM-DD
example: "2025-11-01"
end_date:
type: string
format: date
pattern: '^\d{4}-\d{2}-\d{2}$'
description: 结束日期YYYY-MM-DD
example: "2025-11-12"
batch_size:
type: integer
minimum: 1
maximum: 1000
default: 100
description: 批量大小
priority:
type: string
enum: [critical, default, low]
default: default
description: 任务优先级
TaskResponse:
type: object
required:
- task_id
- queue
properties:
task_id:
type: string
format: uuid
description: 任务唯一 ID
example: "550e8400-e29b-41d4-a716-446655440000"
queue:
type: string
enum: [critical, default, low]
description: 任务所在队列
example: default
estimated_time:
type: string
description: 预计执行时间
example: "within 5 minutes"
responses:
BadRequest:
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: 1001
msg: "参数验证失败"
data: null
timestamp: "2025-11-12T16:00:00+08:00"
Unauthorized:
description: 未授权或令牌无效
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: 1002
msg: "缺失认证令牌"
data: null
timestamp: "2025-11-12T16:00:00+08:00"
NotFound:
description: 资源不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: 1003
msg: "用户不存在"
data: null
timestamp: "2025-11-12T16:00:00+08:00"
Conflict:
description: 资源冲突(如用户名已存在)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: 1004
msg: "用户名已存在"
data: null
timestamp: "2025-11-12T16:00:00+08:00"
InternalServerError:
description: 服务器内部错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: 5000
msg: "服务器内部错误"
data: null
timestamp: "2025-11-12T16:00:00+08:00"