5.6 KiB
5.6 KiB
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
// 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
const CHAT_STORAGE_KEYS = {
DRAWER_STATE: 'aitu:chat:drawer-state',
ACTIVE_SESSION: 'aitu:chat:active-session',
};
Validation Rules
ChatSession
id: 必须是有效的 UUID v4title: 非空,最大30字符,自动从首条消息截取createdAt/updatedAt: 有效的 Unix 时间戳
ChatMessage
id: 必须是有效的 UUID v4sessionId: 必须引用存在的 ChatSessionrole: 必须是 'user' 或 'assistant'content: 用户消息最大10000字符,AI消息无限制attachments: 单条消息最多5个附件
Attachment
type: 必须在支持的 MIME 类型列表中size: 单个文件最大10MBdata: 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