178 lines
5.6 KiB
Markdown
178 lines
5.6 KiB
Markdown
# Data Model: 对话抽屉 (Chat Drawer)
|
||
|
||
**Date**: 2025-12-03
|
||
**Feature**: 001-chat-drawer
|
||
|
||
## Entities
|
||
|
||
### ChatSession (对话会话)
|
||
|
||
| Field | Type | Description | Constraints |
|
||
|-------|------|-------------|-------------|
|
||
| id | string | 会话唯一标识 | UUID v4, 主键 |
|
||
| title | string | 会话标题 | 从首条消息截取,max 30字符 |
|
||
| createdAt | number | 创建时间戳 | Unix milliseconds |
|
||
| updatedAt | number | 最后更新时间戳 | Unix milliseconds |
|
||
| messageCount | number | 消息数量 | ≥ 0 |
|
||
|
||
**Lifecycle States**: Active → Archived (future)
|
||
|
||
**Indexes**:
|
||
- Primary: `id`
|
||
- Secondary: `updatedAt` (用于排序)
|
||
|
||
### ChatMessage (对话消息)
|
||
|
||
| Field | Type | Description | Constraints |
|
||
|-------|------|-------------|-------------|
|
||
| id | string | 消息唯一标识 | UUID v4, 主键 |
|
||
| sessionId | string | 所属会话ID | 外键 → ChatSession.id |
|
||
| role | 'user' \| 'assistant' | 消息角色 | 枚举值 |
|
||
| content | string | 消息内容 | Markdown格式 |
|
||
| timestamp | number | 发送时间戳 | Unix milliseconds |
|
||
| status | MessageStatus | 消息状态 | 枚举值 |
|
||
| attachments | Attachment[] | 附件列表 | 可选,数组 |
|
||
| error | string \| null | 错误信息 | 可选 |
|
||
|
||
**MessageStatus 枚举**:
|
||
- `sending`: 发送中
|
||
- `streaming`: AI正在生成
|
||
- `success`: 发送成功
|
||
- `failed`: 发送失败
|
||
|
||
**Indexes**:
|
||
- Primary: `id`
|
||
- Compound: `[sessionId, timestamp]` (用于按会话查询消息)
|
||
|
||
### Attachment (附件)
|
||
|
||
| Field | Type | Description | Constraints |
|
||
|-------|------|-------------|-------------|
|
||
| id | string | 附件唯一标识 | UUID v4 |
|
||
| name | string | 文件名 | max 255字符 |
|
||
| type | string | MIME类型 | e.g., 'image/png' |
|
||
| size | number | 文件大小 | bytes |
|
||
| data | string | 文件数据 | Base64 或 Blob URL |
|
||
| isBlob | boolean | 是否为Blob URL | 用于清理 |
|
||
|
||
**支持的文件类型**:
|
||
- 图片: image/png, image/jpeg, image/gif, image/webp
|
||
- 文档: application/pdf, text/plain, text/markdown
|
||
- 其他: application/json, text/csv
|
||
|
||
**大小限制**:
|
||
- 单个文件: 10MB
|
||
- 单条消息总附件: 20MB
|
||
|
||
### DrawerState (抽屉状态)
|
||
|
||
| Field | Type | Description | Constraints |
|
||
|-------|------|-------------|-------------|
|
||
| isOpen | boolean | 是否展开 | 默认 false |
|
||
| width | number | 当前宽度 | 320-500px,默认视口30% |
|
||
| activeSessionId | string \| null | 当前活跃会话ID | 可选 |
|
||
|
||
**Note**: DrawerState 存储在 localStorage,不使用 IndexedDB(需要同步访问)
|
||
|
||
## Relationships
|
||
|
||
```
|
||
┌─────────────────┐ ┌─────────────────┐
|
||
│ ChatSession │ 1:N │ ChatMessage │
|
||
│─────────────────│───────│─────────────────│
|
||
│ id (PK) │ │ id (PK) │
|
||
│ title │ │ sessionId (FK) │
|
||
│ createdAt │ │ role │
|
||
│ updatedAt │ │ content │
|
||
│ messageCount │ │ timestamp │
|
||
└─────────────────┘ │ status │
|
||
│ attachments[] │
|
||
└─────────────────┘
|
||
│
|
||
│ 1:N (embedded)
|
||
▼
|
||
┌─────────────────┐
|
||
│ Attachment │
|
||
│─────────────────│
|
||
│ id │
|
||
│ name │
|
||
│ type │
|
||
│ size │
|
||
│ data │
|
||
└─────────────────┘
|
||
```
|
||
|
||
## Storage Schema
|
||
|
||
### IndexedDB Configuration
|
||
|
||
```javascript
|
||
// Database: 'aitu-chat'
|
||
// Version: 1
|
||
|
||
const stores = {
|
||
sessions: {
|
||
keyPath: 'id',
|
||
indexes: [
|
||
{ name: 'updatedAt', keyPath: 'updatedAt', unique: false }
|
||
]
|
||
},
|
||
messages: {
|
||
keyPath: 'id',
|
||
indexes: [
|
||
{ name: 'sessionId', keyPath: 'sessionId', unique: false },
|
||
{ name: 'sessionTimestamp', keyPath: ['sessionId', 'timestamp'], unique: false }
|
||
]
|
||
}
|
||
};
|
||
```
|
||
|
||
### localStorage Keys
|
||
|
||
```typescript
|
||
const CHAT_STORAGE_KEYS = {
|
||
DRAWER_STATE: 'aitu:chat:drawer-state',
|
||
ACTIVE_SESSION: 'aitu:chat:active-session',
|
||
};
|
||
```
|
||
|
||
## Validation Rules
|
||
|
||
### ChatSession
|
||
- `id`: 必须是有效的 UUID v4
|
||
- `title`: 非空,最大30字符,自动从首条消息截取
|
||
- `createdAt/updatedAt`: 有效的 Unix 时间戳
|
||
|
||
### ChatMessage
|
||
- `id`: 必须是有效的 UUID v4
|
||
- `sessionId`: 必须引用存在的 ChatSession
|
||
- `role`: 必须是 'user' 或 'assistant'
|
||
- `content`: 用户消息最大10000字符,AI消息无限制
|
||
- `attachments`: 单条消息最多5个附件
|
||
|
||
### Attachment
|
||
- `type`: 必须在支持的 MIME 类型列表中
|
||
- `size`: 单个文件最大10MB
|
||
- `data`: Base64 字符串或有效的 Blob URL
|
||
|
||
## Data Cleanup Policies
|
||
|
||
### 自动清理
|
||
- 会话数量超过50时,删除最早的会话(保留最近50个)
|
||
- 单会话消息超过100条时,删除最早的消息
|
||
- Blob URL 在页面卸载时自动释放
|
||
|
||
### 手动清理
|
||
- 用户可删除单个会话及其所有消息
|
||
- 用户可清空所有对话历史
|
||
|
||
## Migration Strategy
|
||
|
||
### Version 1 (Initial)
|
||
- 创建 sessions 和 messages stores
|
||
- 无需迁移
|
||
|
||
### Future Versions
|
||
- 使用 localforage 的版本管理
|
||
- 迁移脚本模式参考 `history-migration.ts`
|