Initial TrueGrowth source import
This commit is contained in:
177
specs/003-chat-drawer/data-model.md
Normal file
177
specs/003-chat-drawer/data-model.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# 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`
|
||||
Reference in New Issue
Block a user