# 美家卡智影 - 数据架构设计

## 1. 架构目标

- **离线优先**：无网络时也能正常使用
- **云端同步**：多设备间数据同步
- **多媒体本地存储**：大文件存本地目录，小数据存云端
- **自动冲突解决**：简化用户操作

## 2. 数据分层

```
┌─────────────────────────────────────────────────────────────────┐
│                        云端 (PostgreSQL)                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │
│  │   users     │  │  projects   │  │   avatars   │  ...          │
│  │  (用户账号)  │  │ (项目元数据) │  │ (形象元数据) │              │
│  └─────────────┘  └─────────────┘  └─────────────┘              │
│       小数据、结构数据、需要同步的数据                              │
└─────────────────────────────────────────────────────────────────┘
                              ↑↓ 同步
┌─────────────────────────────────────────────────────────────────┐
│                    本地 (Tauri + 浏览器)                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  SQLite / 文件系统 (~/Documents/Meijiaka/)               │    │
│  │  ├─ projects/           # 项目数据                        │    │
│  │  │   └─ {project_id}/                                  │    │
│  │  │       ├─ project.json     # 项目配置                 │    │
│  │  │       ├─ segments/        # 分镜数据                  │    │
│  │  │       ├─ videos/          # 生成的视频               │    │
│  │  │       └─ covers/          # 封面图片                 │    │
│  │  ├─ avatars/            # 克隆形象                       │    │
│  │  │   └─ {avatar_id}/                                    │    │
│  │  │       ├─ avatar.json     # 形象配置                  │    │
│  │  │       └─ video.mp4       # 形象视频                  │    │
│  │  └─ temp/               # 临时文件                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  SWR Cache (内存)                                       │    │
│  │  - API 响应缓存                                          │    │
│  │  - 乐观更新队列                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘
```

## 3. 数据分类

### 3.1 云端优先数据（小数据，结构化）

| 数据类型 | 存储位置 | 同步策略 | 说明 |
|---------|---------|---------|------|
| 用户信息 | 云端 | 实时 | 账号、设置偏好 |
| 项目列表 | 云端 | 实时 | 项目ID、标题、状态、更新时间 |
| 形象元数据 | 云端 | 实时 | 形象ID、名称、云端视频URL |
| 成本统计 | 云端 | 实时 | API 调用记录、费用 |
| 脚本内容 | 云端+本地 | 双向同步 | 分镜文案、场景描述 |

### 3.2 本地优先数据（大文件，多媒体）

| 数据类型 | 存储位置 | 同步策略 | 说明 |
|---------|---------|---------|------|
| 形象视频 | 本地 | 按需上传 | 克隆形象的原视频文件 |
| 生成视频 | 本地 | 可选上传 | AI生成的分镜视频 |
| 封面图片 | 本地 | 可选上传 | 项目封面 |
| 合成视频 | 本地 | 可选上传 | 最终成片 |
| 临时文件 | 本地 | 不同步 | 处理过程中的缓存 |

## 4. 同步策略

### 4.1 自动同步（实时）
```typescript
// 云端优先数据 - 自动同步
- 用户修改脚本 → 立即保存到云端
- 切换形象 → 立即同步到云端
- 项目状态变更 → 实时更新
```

### 4.2 手动同步（用户触发）
```typescript
// 大文件 - 手动同步
- 上传形象视频到云端备份
- 下载云端形象到本地
- 分享项目（打包上传）
```

### 4.3 离线队列
```typescript
// 离线时操作进入队列
interface OfflineQueue {
  id: string;
  type: 'create' | 'update' | 'delete';
  entity: 'project' | 'segment' | 'avatar';
  data: any;
  timestamp: number;
  retryCount: number;
}
```

## 5. 冲突解决

### 5.1 简单策略：最后写入优先
```typescript
// 基于 updatedAt 时间戳
const resolveConflict = (local: Data, remote: Data) => {
  return local.updatedAt > remote.updatedAt ? local : remote;
};
```

### 5.2 字段级合并（可选）
```typescript
// 不同字段分别决定
const mergeConflict = (local: Project, remote: Project) => {
  return {
    ...remote,
    segments: local.updatedAt > remote.updatedAt 
      ? local.segments 
      : remote.segments,
    coverPath: local.coverUpdatedAt > remote.coverUpdatedAt
      ? local.coverPath
      : remote.coverPath,
  };
};
```

## 6. 存储实现

### 6.1 本地目录结构
```
~/Documents/Meijiaka/                    # 用户文档目录
├── config.json                          # 全局配置
├── cache/                               # 缓存目录
│   └── swr/                             # SWR 缓存
├── projects/                            # 项目数据
│   └── {project_id}/
│       ├── meta.json                    # 项目元数据
│       ├── segments.json                # 分镜数据
│       ├── assets/                      # 资源文件
│       │   ├── videos/                  # 生成视频
│       │   ├── covers/                  # 封面图片
│       │   └── temp/                    # 临时文件
│       └── exports/                     # 导出文件
├── avatars/                             # 克隆形象
│   └── {avatar_id}/
│       ├── meta.json                    # 形象配置
│       └── source.mp4                   # 原视频
└── voices/                              # 克隆音色
    └── {voice_id}/
        └── sample.mp3
```

### 6.2 数据存储接口
```typescript
// 统一存储接口
interface StorageAdapter {
  // 项目数据
  saveProject(project: Project): Promise<void>;
  loadProject(projectId: string): Promise<Project | null>;
  deleteProject(projectId: string): Promise<void>;
  listProjects(): Promise<ProjectSummary[]>;
  
  // 形象数据
  saveAvatar(avatar: Avatar): Promise<void>;
  loadAvatar(avatarId: string): Promise<Avatar | null>;
  deleteAvatar(avatarId: string): Promise<void>;
  listAvatars(): Promise<AvatarSummary[]>;
  
  // 多媒体文件
  saveMedia(projectId: string, file: File, type: MediaType): Promise<string>;
  loadMedia(path: string): Promise<Blob>;
  deleteMedia(path: string): Promise<void>;
}
```

## 7. 状态管理

### 7.1 分层状态
```typescript
// 1. 服务端状态 (SWR)
const { data: projects } = useSWR('/api/projects', fetcher);

// 2. 本地持久化状态 (Zustand + Storage)
const projectStore = useProjectStore(); // 自动持久化到本地文件

// 3. 临时 UI 状态 (React State)
const [selectedTab, setSelectedTab] = useState('script');
```

### 7.2 同步 hook
```typescript
// 自动同步 hook
function useSyncProject(projectId: string) {
  const { data: remoteProject } = useSWR(`/api/projects/${projectId}`);
  const localProject = useProjectStore(state => state.project);
  const sync = useProjectStore(state => state.sync);
  
  useEffect(() => {
    if (remoteProject && localProject) {
      sync(remoteProject, localProject);
    }
  }, [remoteProject, localProject]);
}
```

## 8. 迁移路径

### Phase 1: 本地文件存储（当前）
- [x] 项目数据存 Tauri 本地
- [x] 形象数据存 localStorage

### Phase 2: 云端同步（下一步）
- [ ] 后端新增 project/avatar 表
- [ ] 实现双向同步逻辑
- [ ] 离线队列

### Phase 3: 多媒体管理
- [ ] 本地目录结构
- [ ] 文件导入/导出
- [ ] 云端备份（可选）

## 9. 关键决策

### Q1: 是否需要本地 SQLite？
**建议**：Phase 1 不需要，JSON 文件足够简单。Phase 2 如需复杂查询再引入。

### Q2: 如何处理大文件同步？
**建议**：不上传大文件，只在本地存储。用户需要跨设备时，提供"导出/导入"功能。

### Q3: 离线支持到什么程度？
**建议**：
- 脚本编辑：完全离线
- 视频生成：需要联网（AI 服务）
- 压制成片：可离线（本地 FFmpeg）
