2026-02-26 14:37:51 +08:00
|
|
|
|
# Runtime API Routes
|
|
|
|
|
|
|
|
|
|
|
|
本文档记录所有 HTTP API 端点。修改路由时必须同步更新此文档。
|
|
|
|
|
|
|
|
|
|
|
|
## 格式说明
|
|
|
|
|
|
|
|
|
|
|
|
- Request/Response 使用 JSON 格式
|
|
|
|
|
|
- 错误响应使用 RFC 7807 `application/problem+json`
|
|
|
|
|
|
- 所有端点前缀: `/api/v1`
|
|
|
|
|
|
|
|
|
|
|
|
## Auth
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/verifications
|
|
|
|
|
|
|
|
|
|
|
|
创建验证码(注册发起)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"username": "string (3-30 chars)",
|
|
|
|
|
|
"email": "string (email)",
|
|
|
|
|
|
"password": "string (min 6 chars)",
|
2026-02-28 10:56:09 +08:00
|
|
|
|
"redirect_to": "string? (optional)",
|
|
|
|
|
|
"invite_code": "string? (8 chars, 排除易混淆字符 0/1/I/L/O)"
|
2026-02-26 14:37:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 202 Accepted
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "user@example.com"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-28 10:56:09 +08:00
|
|
|
|
**邀请码说明:**
|
|
|
|
|
|
- 可选字段,不填则注册不受影响
|
|
|
|
|
|
- 格式:8 位字母数字组合,排除易混淆字符 (0, 1, I, L, O)
|
|
|
|
|
|
- 注册时传入有效邀请码会建立邀请关系并增加邀请码使用次数
|
|
|
|
|
|
- 无效邀请码(不存在/已禁用/已过期/已达上限)不会阻断注册成功
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/verifications/resend
|
|
|
|
|
|
|
|
|
|
|
|
重发验证码。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (email)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/verifications/verify
|
|
|
|
|
|
|
|
|
|
|
|
验证码校验。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (email)",
|
|
|
|
|
|
"token": "string (6 digits)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"access_token": "string",
|
|
|
|
|
|
"refresh_token": "string",
|
|
|
|
|
|
"expires_in": 3600,
|
|
|
|
|
|
"token_type": "bearer",
|
|
|
|
|
|
"user": {
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"email": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 验证码无效或已过期
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/sessions
|
|
|
|
|
|
|
|
|
|
|
|
登录(创建会话)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (email)",
|
|
|
|
|
|
"password": "string (min 6 chars)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"access_token": "string",
|
|
|
|
|
|
"refresh_token": "string",
|
|
|
|
|
|
"expires_in": 3600,
|
|
|
|
|
|
"token_type": "bearer",
|
|
|
|
|
|
"user": {
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"email": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 邮箱或密码错误
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/sessions/refresh
|
|
|
|
|
|
|
|
|
|
|
|
刷新 Token。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"refresh_token": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"access_token": "string",
|
|
|
|
|
|
"refresh_token": "string",
|
|
|
|
|
|
"expires_in": 3600,
|
|
|
|
|
|
"token_type": "bearer",
|
|
|
|
|
|
"user": {
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"email": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 无效的 refresh token
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### DELETE /auth/sessions
|
|
|
|
|
|
|
|
|
|
|
|
登出(删除会话)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"refresh_token": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
### POST /auth/password-reset
|
|
|
|
|
|
|
|
|
|
|
|
发送密码重置验证码。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (email)",
|
|
|
|
|
|
"redirect_to": "string? (optional)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /auth/password-reset/confirm
|
|
|
|
|
|
|
|
|
|
|
|
验证 recovery 验证码并完成改密。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (email)",
|
|
|
|
|
|
"token": "string (6 digits)",
|
|
|
|
|
|
"new_password": "string (min 6 chars)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 验证码无效或已过期
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
- 429: 请求过于频繁
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
### GET /auth/users
|
|
|
|
|
|
|
|
|
|
|
|
按邮箱查询用户(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
|
- `email`: string (required)
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"email": "string",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"email_confirmed_at": "string? (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 403: 无权限访问
|
|
|
|
|
|
- 404: 用户不存在
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-28 11:03:29 +08:00
|
|
|
|
## Schedule Items
|
|
|
|
|
|
|
|
|
|
|
|
### POST /schedule-items
|
|
|
|
|
|
|
|
|
|
|
|
创建日历事项(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"title": "string (1-255 chars, required)",
|
|
|
|
|
|
"description": "string? (max 2000 chars)",
|
|
|
|
|
|
"start_at": "string (ISO 8601 datetime, required)",
|
|
|
|
|
|
"end_at": "string? (ISO 8601 datetime)",
|
|
|
|
|
|
"timezone": "string? (default: UTC)",
|
|
|
|
|
|
"metadata": {
|
|
|
|
|
|
"color": "#FF6B6B",
|
|
|
|
|
|
"location": "会议室A",
|
|
|
|
|
|
"notes": "记得带身份证",
|
|
|
|
|
|
"attachments": [],
|
|
|
|
|
|
"version": 1
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 201 Created
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"title": "string",
|
|
|
|
|
|
"description": "string?",
|
|
|
|
|
|
"start_at": "string",
|
|
|
|
|
|
"end_at": "string?",
|
|
|
|
|
|
"timezone": "string",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"status": "active",
|
|
|
|
|
|
"source_type": "manual",
|
|
|
|
|
|
"created_at": "string",
|
|
|
|
|
|
"updated_at": "string"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 400: end_at 早于 start_at
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 503: 服务不可用
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /schedule-items
|
|
|
|
|
|
|
|
|
|
|
|
按时间范围查询日历事项列表(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
|
- `start_at`: ISO 8601 date/datetime(查询范围起始)
|
|
|
|
|
|
- `end_at`: ISO 8601 date/datetime(查询范围结束)
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"title": "string",
|
|
|
|
|
|
"start_at": "string",
|
|
|
|
|
|
"end_at": "string?",
|
|
|
|
|
|
"timezone": "string",
|
|
|
|
|
|
"status": "active"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 400: end_at 早于 start_at
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /schedule-items/{id}
|
|
|
|
|
|
|
|
|
|
|
|
获取单个日历事项详情(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 事项不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### PATCH /schedule-items/{id}
|
|
|
|
|
|
|
|
|
|
|
|
更新日历事项(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:** 支持 `title`/`description`/`start_at`/`end_at`/`timezone`/`metadata`/`status` 部分更新
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 事项不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### DELETE /schedule-items/{id}
|
|
|
|
|
|
|
|
|
|
|
|
删除日历事项(软删除,需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 事项不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-28 12:28:45 +08:00
|
|
|
|
### POST /schedule-items/{id}/share
|
|
|
|
|
|
|
|
|
|
|
|
分享日历事项给他人(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
通过邮箱邀请其他用户,被邀请人将收到待办消息邀请。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"email": "string (required, email of user to share with)",
|
|
|
|
|
|
"permission_view": "boolean (default: true)",
|
|
|
|
|
|
"permission_edit": "boolean (default: false)",
|
|
|
|
|
|
"permission_invite": "boolean (default: false)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Permission 位说明:**
|
|
|
|
|
|
| 权限 | 值 | 说明 |
|
|
|
|
|
|
|------|-----|------|
|
|
|
|
|
|
| view | 1 | 查看事项详情 |
|
|
|
|
|
|
| invite | 2 | 邀请其他人订阅此事项 |
|
|
|
|
|
|
| edit | 4 | 修改事项内容、管理订阅 |
|
|
|
|
|
|
|
|
|
|
|
|
可组合使用,如 view+edit = 5,view+invite+edit = 7。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"message": "Invitation sent to user@example.com"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 403: 非日历所有者无权分享
|
|
|
|
|
|
- 404: 日历事项不存在或用户不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-03-02 10:55:46 +08:00
|
|
|
|
## Profile
|
|
|
|
|
|
|
|
|
|
|
|
### GET /profile/me
|
|
|
|
|
|
|
|
|
|
|
|
获取当前用户信息(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"username": "string",
|
|
|
|
|
|
"avatar_url": "string?",
|
|
|
|
|
|
"bio": "string?"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### PATCH /profile/me
|
|
|
|
|
|
|
|
|
|
|
|
更新当前用户信息(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"username": "string? (3-30 chars)",
|
|
|
|
|
|
"avatar_url": "string? (URL)",
|
|
|
|
|
|
"bio": "string? (max 200 chars)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /profile/{username}
|
|
|
|
|
|
|
|
|
|
|
|
按用户名查询用户公开信息(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 用户不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-02-28 12:28:45 +08:00
|
|
|
|
|
|
|
|
|
|
## Inbox Messages
|
|
|
|
|
|
|
|
|
|
|
|
### GET /inbox/messages
|
|
|
|
|
|
|
|
|
|
|
|
获取当前用户的待办消息列表(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Query Parameters:**
|
|
|
|
|
|
- `status`: string (optional) - 过滤状态:`pending`/`accepted`/`rejected`/`dismissed`
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"recipient_id": "uuid",
|
|
|
|
|
|
"sender_id": "uuid?",
|
|
|
|
|
|
"message_type": "calendar",
|
|
|
|
|
|
"schedule_item_id": "uuid?",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"is_read": false,
|
|
|
|
|
|
"status": "pending",
|
|
|
|
|
|
"created_at": "2024-01-01T00:00:00Z"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /inbox/messages/{id}/accept
|
|
|
|
|
|
|
|
|
|
|
|
接受邀请(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
接受日历邀请时,会为当前用户创建订阅关系。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"permission_view": "boolean (default: true)",
|
|
|
|
|
|
"permission_edit": "boolean (default: false)",
|
|
|
|
|
|
"permission_invite": "boolean (default: false)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 消息不存在
|
|
|
|
|
|
- 400: 消息不是待处理状态或不是日历类型邀请
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /inbox/messages/{id}/dismiss
|
|
|
|
|
|
|
|
|
|
|
|
忽略邀请(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 消息不存在
|
|
|
|
|
|
- 400: 消息不是待处理状态
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
## Users
|
|
|
|
|
|
|
2026-03-02 10:55:46 +08:00
|
|
|
|
> **Note:** `/users/me` 与 `/profile/me` 功能重叠(历史兼容)。推荐使用 `/profile/me`。
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
### GET /users/me
|
|
|
|
|
|
|
|
|
|
|
|
获取当前用户信息(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"username": "string",
|
|
|
|
|
|
"avatar_url": "string?",
|
|
|
|
|
|
"bio": "string?"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### PATCH /users/me
|
|
|
|
|
|
|
|
|
|
|
|
更新当前用户信息(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"username": "string? (3-30 chars)",
|
|
|
|
|
|
"avatar_url": "string? (URL)",
|
|
|
|
|
|
"bio": "string? (max 200 chars)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"username": "string",
|
|
|
|
|
|
"avatar_url": "string?",
|
|
|
|
|
|
"bio": "string?"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
### POST /users/search
|
2026-02-26 14:37:51 +08:00
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
搜索用户(需要认证)。
|
2026-02-26 14:37:51 +08:00
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
支持两种查询模式:
|
|
|
|
|
|
- **用户名查询**:模糊匹配,返回最多 20 个结果
|
|
|
|
|
|
- **邮箱查询**:精确匹配,返回 0 或 1 个结果
|
2026-02-26 14:37:51 +08:00
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
查询类型自动识别:包含 `@` 符号视为邮箱查询。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
2026-02-26 14:37:51 +08:00
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-02-27 15:22:42 +08:00
|
|
|
|
"query": "string (1-100 chars)"
|
2026-02-26 14:37:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-27 15:22:42 +08:00
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "string",
|
|
|
|
|
|
"username": "string",
|
|
|
|
|
|
"avatar_url": "string?",
|
|
|
|
|
|
"bio": "string?"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
2026-02-27 15:22:42 +08:00
|
|
|
|
- 503: Auth 服务不可用(仅邮箱查询)
|
2026-02-26 14:37:51 +08:00
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-28 12:19:02 +08:00
|
|
|
|
## Friends
|
|
|
|
|
|
|
|
|
|
|
|
### POST /friends/requests
|
|
|
|
|
|
|
|
|
|
|
|
发送好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Request:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"target_user_id": "string (uuid)",
|
|
|
|
|
|
"content": "string? (max 500 chars)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 201 Created
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"from_user_id": "uuid",
|
|
|
|
|
|
"to_user_id": "uuid",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"status": "pending",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"updated_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 400: 不能添加自己为好友
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 目标用户不存在
|
|
|
|
|
|
- 409: 已是好友或请求已存在
|
|
|
|
|
|
- 422: 请求参数无效
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /friends/requests/inbox
|
|
|
|
|
|
|
|
|
|
|
|
获取收到的好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"from_user_id": "uuid",
|
|
|
|
|
|
"to_user_id": "uuid",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"status": "pending",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"updated_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /friends/requests/outgoing
|
|
|
|
|
|
|
|
|
|
|
|
获取发出的好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"from_user_id": "uuid",
|
|
|
|
|
|
"to_user_id": "uuid",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"status": "pending",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"updated_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /friends/requests/{id}/accept
|
|
|
|
|
|
|
|
|
|
|
|
接受好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"from_user_id": "uuid",
|
|
|
|
|
|
"to_user_id": "uuid",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"status": "accepted",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"updated_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 请求不存在
|
|
|
|
|
|
- 409: 请求已被处理
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### POST /friends/requests/{id}/decline
|
|
|
|
|
|
|
|
|
|
|
|
拒绝好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"from_user_id": "uuid",
|
|
|
|
|
|
"to_user_id": "uuid",
|
|
|
|
|
|
"content": "string?",
|
|
|
|
|
|
"status": "declined",
|
|
|
|
|
|
"created_at": "string (ISO 8601)",
|
|
|
|
|
|
"updated_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 请求不存在
|
|
|
|
|
|
- 409: 请求已被处理
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### DELETE /friends/requests/{id}
|
|
|
|
|
|
|
|
|
|
|
|
取消发出的好友请求(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 请求不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /friends
|
|
|
|
|
|
|
|
|
|
|
|
获取好友列表(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "uuid",
|
|
|
|
|
|
"friend_id": "uuid",
|
|
|
|
|
|
"username": "string",
|
|
|
|
|
|
"avatar_url": "string?",
|
|
|
|
|
|
"bio": "string?",
|
|
|
|
|
|
"created_at": "string (ISO 8601)"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### DELETE /friends/{id}
|
|
|
|
|
|
|
|
|
|
|
|
删除好友(需要认证)。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 204 No Content
|
|
|
|
|
|
|
|
|
|
|
|
**Errors:**
|
|
|
|
|
|
- 401: 未认证
|
|
|
|
|
|
- 404: 好友关系不存在
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-02-26 14:37:51 +08:00
|
|
|
|
## Infra
|
|
|
|
|
|
|
|
|
|
|
|
### GET /infra/health
|
|
|
|
|
|
|
|
|
|
|
|
检查基础设施健康状态。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"status": "healthy" | "unhealthy",
|
|
|
|
|
|
"services": {
|
|
|
|
|
|
"redis": {
|
|
|
|
|
|
"status": "healthy" | "unhealthy",
|
|
|
|
|
|
"latency_ms": 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### GET /health
|
|
|
|
|
|
|
|
|
|
|
|
检查服务健康状态。
|
|
|
|
|
|
|
|
|
|
|
|
**Response:** 200 OK
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"status": "ok"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Error Response Format (RFC 7807)
|
|
|
|
|
|
|
|
|
|
|
|
所有错误响应使用 `application/problem+json` 格式:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "about:blank",
|
|
|
|
|
|
"title": "Unauthorized",
|
|
|
|
|
|
"status": 401,
|
|
|
|
|
|
"detail": "验证码无效或已过期",
|
|
|
|
|
|
"instance": "/api/v1/auth/verifications/verify"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
前端应优先读取 `detail` 字段显示给用户。
|