Files
social-app/docs/runtime/runtime-database.md
T

502 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 对话会话 |
| `messages` | 会话消息记录 |
| `llm_factory` | LLM 工厂配置 |
| `llms` | LLM 模型实例 |
| `user_agent_catalog` | Agent 类型目录 |
| `invite_codes` | 邀请码 |
---
## 表结构
### profiles
用户资料表,含内置设置。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK`auth.users.id` |
| `username` | VARCHAR(30) | 用户名 |
| `avatar_url` | TEXT | 头像 URL |
| `bio` | VARCHAR(200) | 个人简介 |
| `settings` | JSONB | 用户设置 |
| `referred_by` | UUID | 邀请人 ID |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `username` 唯一
**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_by` | UUID | 创建者 |
| `updated_by` | UUID | 更新者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `(user_id, agent_type)` 唯一
---
### memories
用户与工作记忆。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 用户 ID |
| `agent_id` | UUID | Agent IDwork 类型必填) |
| `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_iduser 类型必须无 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_by` | UUID | 创建者 |
| `updated_by` | UUID | 更新者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_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_by` | UUID | 创建者 |
| `updated_by` | UUID | 更新者 |
| `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 | 加入时间 |
| `removed_at` | TIMESTAMPTZ | 移除时间 |
| `status` | VARCHAR(20) | 状态:`active`, `muted`, `removed` |
| `created_by` | UUID | 创建者 |
| `updated_by` | UUID | 更新者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_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(255) | 循环规则 |
| `source_type` | VARCHAR(20) | 来源:`manual`, `imported`, `agent_generated` |
| `status` | VARCHAR(20) | 状态:`active`, `completed`, `canceled`, `archived` |
| `created_by` | UUID | 创建者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_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),默认 1 |
| `notify_level` | VARCHAR(20) | 通知级别:`all`, `mentions`, `none`,默认 `all` |
| `status` | VARCHAR(20) | 状态:`active`, `paused`, `unsubscribed`,默认 `active` |
| `created_by` | UUID | 创建者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_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 | 是否已读,默认 false |
| `status` | VARCHAR(20) | 状态:`pending`, `accepted`, `rejected`, `dismissed` |
| `created_by` | UUID | 创建者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
**message_type 与业务字段对应:**
| message_type | 必填字段 |
|--------------|----------|
| friend_request | friendship_id |
| calendar | schedule_item_id |
| system | 全部可空 |
| group | group_id |
**sender 约束:** system 类型 sender_id 为空,其他类型 sender_id 必填
---
### todos
待办事项。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `owner_id` | UUID | 所有者 ID |
| `title` | VARCHAR(255) | 标题 |
| `description` | VARCHAR(1000) | 描述 |
| `due_at` | TIMESTAMPTZ | 截止时间 |
| `priority` | INTEGER | 优先级(1-41=重要且紧急) |
| `status` | VARCHAR(20) | 状态:`pending`, `done`, `canceled` |
| `completed_at` | TIMESTAMPTZ | 完成时间 |
| `created_by` | UUID | 创建者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `priority BETWEEN 1 AND 4`
---
### todo_sources
待办与日程来源关联。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `todo_id` | UUID | 待办 ID |
| `schedule_item_id` | UUID | 日程事项 ID |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_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_by` | UUID | 创建者 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `(id, owner_id)` 唯一
---
### sessions
Agent 对话会话。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `user_id` | UUID | 用户 ID |
| `session_type` | VARCHAR(20) | 会话类型:`chat`, `automation` |
| `job_id` | UUID | 自动化任务 IDautomation 时必填) |
| `title` | VARCHAR(255) | 会话标题 |
| `status` | VARCHAR(20) | 状态:`pending`, `running`, `completed`, `failed` |
| `last_activity_at` | TIMESTAMPTZ | 最后活跃时间 |
| `message_count` | INTEGER | 消息计数,默认 0 |
| `total_tokens` | INTEGER | 总 token 数,默认 0 |
| `total_cost` | NUMERIC(12,6) | 总费用,默认 0 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `session_type='chat' → job_id IS NULL`, `session_type='automation' → job_id IS NOT NULL`
---
### messages
会话消息记录。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `session_id` | UUID | 会话 ID |
| `seq` | INTEGER | 消息序号 |
| `role` | VARCHAR(20) | 角色:`user`, `assistant`, `system`, `tool` |
| `content` | TEXT | 消息内容 |
| `model_code` | VARCHAR(50) | 模型标识 |
| `tool_name` | VARCHAR(100) | 工具名称 |
| `input_tokens` | INTEGER | 输入 token 数,默认 0 |
| `output_tokens` | INTEGER | 输出 token 数,默认 0 |
| `cost` | NUMERIC(12,6) | 费用,默认 0 |
| `currency` | VARCHAR(3) | 货币,默认 USD |
| `latency_ms` | INTEGER | 延迟(毫秒) |
| `metadata` | JSONB | 扩展字段 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `(session_id, seq)` 唯一
---
### llm_factory
LLM 工厂配置。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `name` | VARCHAR(50) | 工厂名称 |
| `request_url` | VARCHAR(255) | API 请求 URL |
| `avatar` | TEXT | 头像 URL |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `name` 唯一
---
### llms
LLM 模型实例。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `factory_id` | UUID | 工厂 ID |
| `model_code` | VARCHAR(50) | 模型标识 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删时间 |
**约束:** `model_code` 唯一
---
### user_agent_catalog
Agent 类型目录。
| 字段 | 类型 | 说明 |
|------|------|------|
| `agent_type` | VARCHAR(20) | PKAgent 类型 |
| `llm_id` | UUID | 关联的 LLM 模型 |
| `status` | VARCHAR(20) | 状态:`active`, `paused`, `migrating` |
| `config` | JSONB | Agent 配置参数 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
---
### invite_codes
邀请码。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | UUID | PK |
| `code` | VARCHAR(8) | 邀请码(8 位大写字母数字) |
| `owner_id` | UUID | 拥有者 ID |
| `status` | VARCHAR(20) | 状态:`active`, `disabled`, `expired` |
| `used_count` | INTEGER | 已使用次数,默认 0 |
| `max_uses` | INTEGER | 最大使用次数 |
| `expires_at` | TIMESTAMPTZ | 过期时间 |
| `reward_config` | JSONB | 奖励配置 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
**约束:** `code` 唯一,`code` 符合 `[ABCDEFGHJKMNPQRSTUVWXYZ23456789]{8}``used_count >= 0`
---
## 外键删除策略
| 外键 | 删除策略 |
|------|----------|
| `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