Files
social-app/docs/plans/2026-02-27-schedule-items-api-design.md
T

192 lines
4.1 KiB
Markdown
Raw Normal View History

# 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
- 前端实现