192 lines
4.1 KiB
Markdown
192 lines
4.1 KiB
Markdown
# Design: Schedule Items API
|
||
|
||
**Date:** 2026-02-27
|
||
**Status:** Approved
|
||
|
||
## Overview
|
||
|
||
实现日历事项(Schedule Items)的后端 CRUD API,支持用户创建、查询、更新、删除日历事项。
|
||
|
||
## Scope
|
||
|
||
- 仅后端 API,不涉及前端
|
||
- 全量 CRUD
|
||
- 查询按时间范围筛选
|
||
- 暂不支持重复日程(recurrence_rule 留空)
|
||
|
||
## API Endpoints
|
||
|
||
### 1. 创建日历事项
|
||
|
||
```
|
||
POST /api/v1/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, must be after start_at)",
|
||
"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"
|
||
}
|
||
```
|
||
|
||
### 2. 查询日历事项列表
|
||
|
||
```
|
||
GET /api/v1/schedule-items?start_at=2026-02-01&end_at=2026-02-28
|
||
```
|
||
|
||
**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"
|
||
}
|
||
]
|
||
```
|
||
|
||
### 3. 获取单个事项
|
||
|
||
```
|
||
GET /api/v1/schedule-items/{id}
|
||
```
|
||
|
||
**Response:** 200 OK(完整字段,同创建响应)
|
||
|
||
### 4. 更新事项
|
||
|
||
```
|
||
PATCH /api/v1/schedule-items/{id}
|
||
```
|
||
|
||
**Request:** 支持 `title`/`description`/`start_at`/`end_at`/`timezone`/`metadata`/`status` 部分更新
|
||
|
||
**Response:** 200 OK
|
||
|
||
### 5. 删除事项
|
||
|
||
```
|
||
DELETE /api/v1/schedule-items/{id}
|
||
```
|
||
|
||
**Response:** 204 No Content(软删除)
|
||
|
||
## Data Models
|
||
|
||
### Metadata 结构(Pydantic)
|
||
|
||
```python
|
||
from enum import Enum
|
||
from pydantic import BaseModel
|
||
from uuid import UUID
|
||
|
||
class AttachmentType(str, Enum):
|
||
DOCUMENT = "document"
|
||
REMINDER = "reminder"
|
||
|
||
class ScheduleItemMetadataAttachment(BaseModel):
|
||
name: str
|
||
type: AttachmentType
|
||
visible_to: list[UUID] = []
|
||
# document 类型
|
||
url: str | None = None
|
||
note: str | None = None
|
||
# reminder 类型
|
||
content: str | None = None
|
||
|
||
class ScheduleItemMetadata(BaseModel):
|
||
color: str | None = None
|
||
location: str | None = None
|
||
notes: str | None = None
|
||
attachments: list[ScheduleItemMetadataAttachment] = []
|
||
version: int = 1
|
||
```
|
||
|
||
### 数据库模型(已有)
|
||
|
||
参见 `backend/src/models/schedule_items.py`:
|
||
- `id`: UUID
|
||
- `owner_id`: UUID
|
||
- `title`: String(255)
|
||
- `description`: Text
|
||
- `start_at`: DateTime(timezone=True)
|
||
- `end_at`: DateTime(timezone=True)
|
||
- `timezone`: String(50)
|
||
- `extra_metadata`: JSONB (mapped as "metadata")
|
||
- `recurrence_rule`: String(255)
|
||
- `source_type`: Enum (MANUAL/IMPORTED/AGENT_GENERATED)
|
||
- `status`: Enum (ACTIVE/COMPLETED/CANCELED/ARCHIVED)
|
||
- `created_by`: UUID
|
||
|
||
## Architecture
|
||
|
||
遵循项目 `schemas / repository / service / router` 分层模式:
|
||
|
||
```
|
||
backend/src/v1/schedule_items/
|
||
├── __init__.py
|
||
├── schemas.py # Pydantic 请求/响应模型
|
||
├── repository.py # CRUD 操作(无 auth,无 commit)
|
||
├── service.py # 业务逻辑 + 授权 + 事务边界
|
||
├── router.py # FastAPI 路由定义
|
||
└── dependencies.py # DI(如有)
|
||
```
|
||
|
||
## Security
|
||
|
||
- 所有端点需要认证(JWT)
|
||
- `owner_id` 从 JWT `sub` 提取,不从请求体读取
|
||
- 用户只能操作自己的日历事项(`owner_id` 过滤)
|
||
- RLS 已在数据库层启用(防御边界)
|
||
|
||
## Error Handling
|
||
|
||
使用 RFC 7807 `application/problem+json` 格式:
|
||
- 400: 请求参数无效
|
||
- 401: 未认证
|
||
- 404: 事项不存在或无权限访问
|
||
- 422: 验证失败
|
||
|
||
## Out of Scope
|
||
|
||
- 重复日程(recurrence_rule)
|
||
- 日程订阅与协作(schedule_subscriptions)
|
||
- 待办事项联动(todos/todo_sources)
|
||
- 前端实现
|