# 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)",
  "redirect_to": "string? (optional)",
  "invite_code": "string? (8 chars, 排除易混淆字符 0/1/I/L/O)"
}
```

**Response:** 202 Accepted
```json
{
  "email": "user@example.com"
}
```

**邀请码说明：**
- 可选字段，不填则注册不受影响
- 格式：8 位字母数字组合，排除易混淆字符 (0, 1, I, L, O)
- 注册时传入有效邀请码会建立邀请关系并增加邀请码使用次数
- 无效邀请码（不存在/已禁用/已过期/已达上限）不会阻断注册成功

**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: 请求参数无效

---

### 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: 请求过于频繁

---

### 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: 请求参数无效

---

## 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: 事项不存在

---

### 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: 日历事项不存在或用户不存在

---

## 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: 用户不存在

---

## 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: 消息不是待处理状态

---

## Users

> **Note:** `/users/me` 与 `/profile/me` 功能重叠（历史兼容）。推荐使用 `/profile/me`。

### 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: 请求参数无效

---

### POST /users/search

搜索用户（需要认证）。

支持两种查询模式：
- **用户名查询**：模糊匹配，返回最多 20 个结果
- **邮箱查询**：精确匹配，返回 0 或 1 个结果

查询类型自动识别：包含 `@` 符号视为邮箱查询。

**Request:**
```json
{
  "query": "string (1-100 chars)"
}
```

**Response:** 200 OK
```json
[
  {
    "id": "string",
    "username": "string",
    "avatar_url": "string?",
    "bio": "string?"
  }
]
```

**Errors:**
- 401: 未认证
- 503: Auth 服务不可用（仅邮箱查询）
- 422: 请求参数无效

---

## 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: 好友关系不存在

---

## Agent

### POST /agent

运行 Agent 对话（需要认证）。

**Request:**
```json
{
  "message": "string (1-8000 chars)",
  "session_id": "string? (UUID)"
}
```

**Response:** 200 OK
```json
{
  "session_id": "string (UUID)",
  "output": "string",
  "events": [
    {
      "type": "string",
      "run_id": "string?",
      "message_id": "string?",
      "delta": "string?",
      "tool_name": "string?",
      "result": "string?",
      "output": "string?",
      "error": "string?"
    }
  ]
}
```

**Errors:**
- 401: 未认证
- 422: 请求参数无效

---

## 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` 字段显示给用户。
