# Database Schema

**Status:** Active
**Reference:** [Plan: social-app 数据模型重设计](../plans/2026-02-26-social-data-model-redesign.md)

---

## 枚举约定

所有枚举使用字符串存储，不使用整数值：
- Database: `VARCHAR(20)` + `CHECK` 约束
- Code: Python `Enum` 继承 `str`

---

## 表清单

| 表名 | 说明 |
|------|------|
| `profiles` | 用户资料（含 settings JSONB） |
| `user_agents` | 用户专属 Agent |
| `memories` | 用户/工作记忆 |
| `friendships` | 好友关系 |
| `groups` | 群组 |
| `group_members` | 群组成员 |
| `schedule_items` | 日程事项 |
| `schedule_subscriptions` | 日程订阅与权限 |
| `inbox_messages` | 待处理消息 |
| `todos` | 待办 |
| `todo_sources` | 待办与日程来源关联 |
| `automation_jobs` | 定时任务 |
| `sessions` | Agent 对话会话 |
| `llm_factories` | LLM 工厂配置 |
| `llms` | LLM 模型实例 |

---

## 表结构

### profiles

用户资料表，含内置设置。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK，`auth.users.id` |
| `username` | VARCHAR(50) | 用户名 |
| `avatar_url` | TEXT | 头像 URL |
| `bio` | TEXT | 个人简介 |
| `settings` | JSONB | 用户设置 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |

**settings JSONB 默认结构：**
```json
{
  "version": 1,
  "preferences": {
    "interface_language": "zh-CN",
    "ai_language": "zh-CN",
    "timezone": "Asia/Shanghai"
  },
  "privacy": {},
  "notification": {}
}
```

---

### user_agents

用户专属 Agent 配置。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `user_id` | UUID | 用户 ID（唯一） |
| `llm_id` | UUID | 关联的 LLM 模型 |
| `agent_type` | VARCHAR(20) | 枚举：`INTENT_RECOGNITION`, `TASK_EXECUTION`, `RESULT_REPORTING` |
| `config` | JSONB | Agent 配置参数 |
| `status` | VARCHAR(20) | 状态：`active`, `paused`, `migrating` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |

---

### memories

用户与工作记忆。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 用户 ID |
| `agent_id` | UUID | Agent ID（work 类型必填） |
| `memory_type` | VARCHAR(20) | 枚举：`user`, `work` |
| `title` | VARCHAR(255) | 标题 |
| `content` | JSONB | 记忆内容 |
| `source` | VARCHAR(20) | 来源：`manual`, `agent`, `imported` |
| `status` | VARCHAR(20) | 状态：`active`, `disabled` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

**约束：** work 类型必须有 agent_id，user 类型必须无 agent_id

**content JSONB 示例：**
```json
// 用户记忆
{"type": "preference", "data": {"style": "concise", "language": "zh-CN"}}

// 工作记忆
{"type": "workflow_summary", "data": {"task": "代码审查", "learnings": ["优先检查安全漏洞"], "improvements": []}}
```

---

### friendships

好友关系（双向规范化）。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `user_low_id` | UUID | 较小 UUID |
| `user_high_id` | UUID | 较大 UUID |
| `initiator_id` | UUID | 发起方用户 ID |
| `status` | VARCHAR(20) | 状态：`pending`, `accepted`, `blocked`, `declined`, `canceled` |
| `requested_at` | TIMESTAMPTZ | 请求时间 |
| `accepted_at` | TIMESTAMPTZ | 接受时间 |
| `blocked_by` | UUID | 阻止者用户 ID |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

**约束：** `user_low_id < user_high_id`，`(user_low_id, user_high_id)` 唯一

---

### groups

群组。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `name` | VARCHAR(100) | 群组名称 |
| `description` | TEXT | 群组描述 |
| `owner_id` | UUID | 创建者 ID |
| `status` | VARCHAR(20) | 状态：`active`, `archived` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |

---

### group_members

群组成员。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `group_id` | UUID | 群组 ID |
| `user_id` | UUID | 用户 ID |
| `role` | VARCHAR(20) | 角色：`owner`, `admin`, `member` |
| `join_source` | VARCHAR(20) | 加入方式：`invited`, `joined` |
| `invited_by` | UUID | 邀请人 ID |
| `joined_at` | TIMESTAMPTZ | 加入时间 |
| `status` | VARCHAR(20) | 状态：`active`, `muted`, `removed` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `removed_at` | TIMESTAMPTZ | 移除时间 |

**约束：** `(group_id, user_id)` 唯一

---

### schedule_items

日程事项。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 所有者 ID |
| `title` | VARCHAR(255) | 标题 |
| `description` | TEXT | 描述 |
| `start_at` | TIMESTAMPTZ | 开始时间 |
| `end_at` | TIMESTAMPTZ | 结束时间 |
| `timezone` | VARCHAR(50) | 时区 |
| `metadata` | JSONB | 扩展字段 |
| `recurrence_rule` | VARCHAR(100) | 循环规则 |
| `source_type` | VARCHAR(20) | 来源：`manual`, `imported`, `agent_generated` |
| `status` | VARCHAR(20) | 状态：`active`, `completed`, `canceled`, `archived` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

**metadata JSONB 默认结构：**
```json
{
  "color": "#FF6B6B",
  "location": "会议室A",
  "notes": "记得提前准备投影仪",
  "attachments": [
    {
      "name": "会议纪要.pdf",
      "url": "https://...",
      "visible_to": [],
      "type": "document"
    },
    {
      "name": "投影仪提醒",
      "visible_to": ["uuid1"],
      "type": "reminder",
      "content": "记得带投影仪"
    }
  ],
  "version": 1
}
```

---

### schedule_subscriptions

日程订阅与权限。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `item_id` | UUID | 日程事项 ID |
| `subscriber_id` | UUID | 订阅者 ID |
| `permission` | INTEGER | 权限位图（view=1, invite=2, edit=4） |
| `notify_level` | VARCHAR(20) | 通知级别：`all`, `mentions`, `none` |
| `status` | VARCHAR(20) | 状态：`active`, `paused`, `unsubscribed` |
| `created_at` | TIMESTAMPTZ | 创建时间 |

**约束：** `(item_id, subscriber_id)` 唯一，`permission BETWEEN 0 AND 7`

---

### inbox_messages

待处理消息（接收者视角）。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `recipient_id` | UUID | 接收者 ID |
| `sender_id` | UUID | 发送者 ID（系统消息可为 NULL） |
| `message_type` | VARCHAR(20) | 类型：`friend_request`, `calendar`, `system`, `group` |
| `friendship_id` | UUID | 好友请求关联（friend_request 时必填） |
| `schedule_item_id` | UUID | 日程关联（calendar 时必填） |
| `group_id` | UUID | 群组关联（group 时必填） |
| `content` | TEXT | 消息内容（system 用） |
| `is_read` | BOOLEAN | 是否已读 |
| `status` | VARCHAR(20) | 状态：`pending`, `accepted`, `rejected`, `dismissed` |
| `created_at` | TIMESTAMPTZ | 创建时间 |

**message_type 与业务字段对应：**
| message_type | 必填字段 |
|--------------|----------|
| friend_request | friendship_id |
| calendar | schedule_item_id |
| system | 全部可空 |
| group | group_id |

---

### todos

待办事项。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 所有者 ID |
| `title` | VARCHAR(255) | 标题 |
| `description` | TEXT | 描述 |
| `due_at` | TIMESTAMPTZ | 截止时间 |
| `priority` | INTEGER | 优先级（1=重要且紧急, 2=重要不紧急, 3=紧急不重要, 4=不重要不紧急） |
| `status` | VARCHAR(20) | 状态：`pending`, `done`, `canceled` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `completed_at` | TIMESTAMPTZ | 完成时间 |

---

### todo_sources

待办与日程来源关联。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `todo_id` | UUID | 待办 ID |
| `schedule_item_id` | UUID | 日程事项 ID |
| `created_at` | TIMESTAMPTZ | 创建时间 |

**约束：** `(todo_id, schedule_item_id)` 唯一

---

### automation_jobs

自动化定时任务。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 所有者 ID |
| `title` | VARCHAR(255) | 任务标题 |
| `prompt` | TEXT | AI 执行 prompt |
| `schedule_type` | VARCHAR(20) | 调度类型：`daily`, `weekly` |
| `run_at` | TIMESTAMPTZ | 首次运行时间 |
| `next_run_at` | TIMESTAMPTZ | 下次运行时间 |
| `timezone` | VARCHAR(50) | 时区 |
| `last_run_at` | TIMESTAMPTZ | 最近运行时间 |
| `status` | VARCHAR(20) | 状态：`active`, `disabled` |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

---

### sessions

Agent 对话会话。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `user_id` | UUID | 用户 ID |
| `session_type` | VARCHAR(20) | 会话类型：`chat`, `automation` |
| `job_id` | UUID | 自动化任务 ID（automation 时必填） |
| `last_activity_at` | TIMESTAMPTZ | 最后活跃时间 |
| `created_at` | TIMESTAMPTZ | 创建时间 |

**约束：** `session_type='chat' → job_id IS NULL`, `session_type='automation' → job_id IS NOT NULL`

---

### llm_factories

LLM 工厂配置。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `name` | VARCHAR(50) | 工厂名称 |
| `base_url` | TEXT | API 基础 URL |
| `api_key` | TEXT | API 密钥 |
| `enabled` | BOOLEAN | 是否启用 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

---

### llms

LLM 模型实例。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `factory_id` | UUID | 工厂 ID |
| `model_id` | VARCHAR(50) | 模型标识 |
| `name` | VARCHAR(100) | 显示名称 |
| `context_window` | INTEGER | 上下文窗口大小 |
| `enabled` | BOOLEAN | 是否启用 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |

---

## 外键删除策略

| 外键 | 删除策略 |
|------|----------|
| `sessions.job_id` | RESTRICT |
| `todo_sources.todo_id` | CASCADE |
| `todo_sources.schedule_item_id` | CASCADE |
| `inbox_messages.friendship_id` | CASCADE |
| `inbox_messages.schedule_item_id` | CASCADE |
| `inbox_messages.group_id` | CASCADE |

---

## RLS 策略

所有 `public` 业务表默认启用 RLS：
- `anon`: 全部 DENY
- `authenticated`: 全部 DENY
- `service_role`: 由后端服务连接，不依赖 RLS
