# Plan: social-app 数据库数据模型重设计(支持社交/事项/自动化) **Date:** 2026-02-26 **Author:** AI Assistant **Status:** Draft ## 枚举存储约定 **统一使用枚举名称(字符串)存储,不使用整数值。** - 数据库层:`VARCHAR(20)` + `CHECK` 约束 - 代码层:Python `Enum` 类继承 `str` - 优势:调试可读、易扩展(新增枚举值无需迁移旧数据)、ORM 友好 ```python class AgentType(str, Enum): INTENT_RECOGNITION = "INTENT_RECOGNITION" TASK_EXECUTION = "TASK_EXECUTION" RESULT_REPORTING = "RESULT_REPORTING" ``` ```sql -- Migration ALTER TABLE user_agents ADD CONSTRAINT chk_agent_type CHECK (agent_type IN ('INTENT_RECOGNITION', 'TASK_EXECUTION', 'RESULT_REPORTING')); ``` ## Overview 本方案面向 `social-app` 的下一阶段功能升级,重设计 PostgreSQL 数据模型,统一支持用户专属 agent、好友/群组协作、待处理消息、设置、可订阅且可授权编辑的日程事项、待办联动与自动化定时任务。目标是在 FastAPI + Flutter 协作场景下提供长期稳定的数据基础,降低后续 API 演进和跨端同步复杂度。 ## Requirements ### Functional - [x] 每个用户有专属 agent,且模型可扩展到未来多 agent 能力 - [x] 用户支持好友关系、群组创建与成员管理 - [x] 用户支持 inbox/pending 待处理消息 - [x] 用户支持个性化设置(偏好/隐私/通知) - [x] 用户支持“绑定日程的事项”,可多人订阅,且仅特定人可修改 - [x] 用户支持待办事项(可由日程事项提取,也可手动创建) - [x] 用户支持自动化定时任务(循环触发) ### Non-Functional - [x] 性能:核心读路径(inbox 列表、待办列表、事项列表)P95 < 150ms(单用户典型数据量) - [x] 安全:权限以后端业务授权为准;数据库层保留 RLS 防御边界 - [x] 一致性:关键写路径(好友状态、权限变更、任务触发)使用事务保障 - [x] 可演进:当前阶段采用重建库快速迭代;后续稳定后切换为增量迁移与灰度 ## Technical Approach 采用“认证域(`auth.users`)+ 业务域(`public.*`)”分层建模。保持 `auth.users` 作为身份主键来源,业务表统一引用 `user_id UUID -> auth.users.id`。领域边界拆分为:Identity/Profile、Social Graph、Collaboration(事项/订阅/权限)、Inbox、Todo、Automation。通过“规范化主模型 + 局部物化/冗余快照”平衡一致性与查询性能。 ### Key Decisions | Decision | Rationale | |----------|-----------| | 用户与 agent 采用 1:1 主约束 + 可扩展结构 | 当前满足"每用户专属 agent",未来允许多 agent 形态演进 | | 记忆系统采用单表 + memory_type 区分 | user 类型可选 agent_id,work 类型必须绑定 agent_id | | 好友关系用单表双向规范化表示 | 避免 A-B / B-A 重复,降低去重成本 | | 事项权限采用 ACL 表而非仅 owner | 满足“仅特定人可修改”的协作场景 | | 待办采用主表 + 关联表 | `todos` + `todo_sources` 保证来源关系可校验 | | 自动化采用 Jobs 单表 + Sessions 关联 | `sessions` 通过 `session_type + job_id` 区分普通对话与自动化运行 | | inbox 采用单表接收者视角 | 发送者 + 消息类型 + 关联业务,一表搞定待处理消息 | ## A. 设计原则与边界 ### 1) 核心实体与聚合边界 - 用户聚合:`profiles`(含 settings JSONB), `user_agents`, `memories` - 社交聚合:`friendships`, `groups`, `group_members` - 协作事项聚合:`schedule_items`, `schedule_subscriptions`(当前仅用户主体) - 消息聚合:`inbox_messages` - 待办聚合:`todos` - 自动化聚合:`automation_jobs` ### 2) 一致性分级 - 强一致(同事务):好友关系状态迁移、群组成员角色变更、事项权限写入、定时任务抢占执行 - 最终一致:inbox 衍生、待办同步、提醒派发(允许异步补偿) ### 3) 多租户假设 - 默认假设:单租户产品(同一业务库服务所有用户),以 `user_id` 做数据隔离 - 扩展预留:各核心表可预留 `tenant_id UUID NULL`(需业务确认是否近期引入组织空间) ## B. 领域模型与关系图(文字化) ### 实体与关系 - `auth.users (1) - (1) profiles`(settings 作为 JSONB 内嵌) - `auth.users (1) - (1) user_agents` - `auth.users (1) - (N) memories` - `user_agents (1) - (N) memories`(work 类型) - `auth.users (N) - (N) auth.users` 通过 `friendships` - `auth.users (1) - (N) groups`(创建者) - `groups (1) - (N) group_members`,`auth.users (1) - (N) group_members` - `auth.users (1) - (N) schedule_items`(创建者) - `schedule_items (1) - (N) schedule_subscriptions`,`auth.users (1) - (N) schedule_subscriptions` - `auth.users (1) - (N) inbox_messages` - `auth.users (1) - (N) todos` - `auth.users (1) - (N) automation_jobs` - `automation_jobs (1) - (N) sessions`(通过 `sessions.job_id` 关联) ### 关键约束 - 唯一性: - `user_agents.user_id` 唯一 - `friendships(user_low_id, user_high_id)` 唯一 - `group_members(group_id, user_id)` 唯一 - `schedule_subscriptions(item_id, subscriber_id)` 唯一 - CHECK: - `friendships`: `user_low_id < user_high_id` 且 `user_low_id <> user_high_id` - `schedule_subscriptions`: `permission BETWEEN 0 AND 7` - `memories`: `work` 类型必须有 `agent_id`,`user` 类型必须无 `agent_id` - `sessions`: `session_type/job_id` 组合一致 - 外键:统一显式 `ON DELETE` 策略(见下) - 可空性:权限关键字段、状态字段默认 `NOT NULL` - 删除策略: - 用户删除:大部分 `CASCADE`(用户私有数据);跨用户协作数据优先软删 - 事项删除:对子表 `CASCADE`;待办保留历史,改 `status = 'archived'` ### 外键删除策略明细(必做) - `sessions.job_id -> automation_jobs.id`: `ON DELETE RESTRICT` - `todo_sources.todo_id -> todos.id`: `ON DELETE CASCADE` - `todo_sources.schedule_item_id -> schedule_items.id`: `ON DELETE CASCADE` - `inbox_messages.friendship_id -> friendships.id`: `ON DELETE CASCADE` - `inbox_messages.schedule_item_id -> schedule_items.id`: `ON DELETE CASCADE` - `inbox_messages.group_id -> groups.id`: `ON DELETE CASCADE` ## C. 数据库表设计(PostgreSQL) 以下为推荐主表(方案 1,规范化优先)。字段示例采用 `UUID + timestamptz + enum/text-check`。 ### 1) 用户与 agent #### `profiles`(已有,建议补齐) - PK: `id UUID` (`auth.users.id`) - 关键字段: `username`, `avatar_url`, `bio` - **新增 JSONB 字段**: - `settings JSONB`(用户自定义设置,含 `version`, `preferences`, `privacy`, `notification` 四大块) - 时间字段: `created_at`, `updated_at`, `deleted_at` - 索引: - `INDEX(username)`(允许重名,仅用于列表查询) - `GIN(settings)`(支持 JSONB 表达式查询) - 表达式索引:`(settings->'notification'->>'enabled')`(按需,对高频查询字段单独建) - 审计: `created_by`, `updated_by`(可等于 id) - 删除策略: 用户删除时 `CASCADE` #### `user_agents` - PK: `id UUID` - 关键字段: - `user_id UNIQUE`(每用户专属 agent) - `llm_id UUID NOT NULL`(关联绑定的 LLM 模型) - `agent_type VARCHAR(20) NOT NULL`(枚举限制:`INTENT_RECOGNITION` | `TASK_EXECUTION` | `RESULT_REPORTING`) - `config JSONB`(agent 配置参数) - 时间字段: `created_at`, `updated_at`, `deleted_at` - 状态字段: `status`(`active|paused|migrating`) - 索引: - `UNIQUE(user_id) WHERE deleted_at IS NULL` - `INDEX(status)` - `INDEX(agent_type)` - `GIN(config)`(按需) - 审计: `created_by`, `updated_by` #### `memories` - PK: `id UUID` - 关键字段: - `owner_id`(用户,NOT NULL) - `agent_id`(work 类型时必需) - `memory_type`(枚举:`user | work`) - `title` - `content`(JSONB,存储具体记忆结构) - `source`(`manual | agent | imported`) - 时间字段: `created_at`, `updated_at` - 状态字段: `status`(`active | disabled`) - 索引: - `INDEX(owner_id, memory_type, status)` - `INDEX(agent_id, memory_type, status)` - `GIN(content)`(支持 JSONB 内容查询) - 约束: `CHECK ((memory_type = 'work' AND agent_id IS NOT NULL) OR (memory_type = 'user' AND agent_id IS NULL))` **memory_type 说明**: | 类型 | agent_id | 说明 | |------|----------|------| | `user` | 可空 | 用户记忆:偏好、背景信息、实体等 | | `work` | 必需 | 工作记忆:长期运行后对工作流程的经验整理,避免重复错误 | **content JSONB 示例**: ```json // 用户记忆 {"type": "preference", "data": {"style": "concise", "language": "zh-CN"}} // 工作记忆 {"type": "workflow_summary", "data": {"task": "代码审查", "learnings": ["优先检查安全漏洞", "关注性能热点"], "improvements": []}} ``` ### 2) 社交关系 #### `friendships` - PK: `id UUID` - 关键字段: - `user_low_id`(两者中较小的 UUID) - `user_high_id`(两者中较大的 UUID) - `initiator_id`(发起请求方的 user_id,用于追溯谁主动) - `status`, `requested_at`, `accepted_at`, `blocked_by` - 时间字段: `created_at`, `updated_at` - 状态字段: `status`(`pending|accepted|blocked|declined|canceled`) - 约束: - `CHECK(user_low_id < user_high_id)`(强制小值放 low,大值放 high,确保 A→B 和 B→A 是同一行) - `CHECK(initiator_id IN (user_low_id, user_high_id))` - `UNIQUE(user_low_id, user_high_id)` - 索引: - `INDEX(user_low_id, status)` - `INDEX(user_high_id, status)` - 部分索引 `INDEX(status) WHERE status='pending'` - 审计: `created_by`, `updated_by` **查询示例**: - 查询用户 A 的所有好友:`SELECT * FROM friendships WHERE user_low_id = A OR user_high_id = A` #### `groups` - PK: `id UUID` - 关键字段: `name`, `description`, `owner_id` - 时间字段: `created_at`, `updated_at`, `deleted_at` - 状态字段: `status`(`active|archived`) - 索引: `INDEX(owner_id, status)` - 审计: `created_by`, `updated_by` #### `group_members` - PK: `id UUID` - 关键字段: - `group_id`, `user_id` - `role`(枚举:`owner` | `admin` | `member`) - `join_source`(`invited|joined`) - `invited_by`, `joined_at` - 时间字段: `created_at`, `updated_at`, `removed_at` - 状态字段: `status`(`active|muted|removed`) - 约束: `UNIQUE(group_id, user_id)` - 索引: - `INDEX(group_id, role, status)` - `INDEX(user_id, status)` - 审计: `created_by`, `updated_by` **role 说明**: | role | 含义 | |------|------| | `owner` | 群主/创建者 | | `admin` | 管理员 | | `member` | 普通成员 | - 角色可升降:服务层变更 role 字段即可 ### 3) 用户设置(已合并至 profiles 表) 用户设置采用 JSONB 内嵌方式,渐进式扩展无需改表结构: ```json { "version": 1, "preferences": { "interface_language": "zh-CN", "ai_language": "zh-CN", "timezone": "Asia/Shanghai" }, "privacy": {}, "notification": {} } ``` - 索引策略:对高频查询字段使用表达式索引 - 更新方式:服务层使用 JSONB merge 或字段级 UPDATE,避免读-改-写并发问题(建议用 `jsonb_set` 原子操作) ### 4) 事项与订阅/权限 #### `schedule_items` - PK: `id UUID` - 关键字段: - `owner_id` - `title` - `description` - `start_at` - `end_at` - `timezone`(用于将日程时间转换为用户本地时间显示) - `metadata`(JSONB,扩展字段) - `recurrence_rule`(可选,支持循环日程) - `source_type`(`manual | imported | agent_generated`) - 时间字段: `created_at`, `updated_at` - 状态字段: `status`(`active | completed | canceled | archived`) - 索引: - `INDEX(owner_id, start_at)` - `INDEX(status, start_at)` - 审计: `created_by` **metadata JSONB 示例**: ```json { "color": "#FF6B6B", "location": "会议室A", "notes": "记得提前准备投影仪", "attachments": [ { "name": "会议纪要.pdf", "url": "https://...", "visible_to": [], "type": "document" }, { "name": "投影仪提醒", "visible_to": ["uuid1"], "type": "reminder", "content": "记得带投影仪" }, { "name": "技术方案.docx", "url": "https://...", "visible_to": ["uuid2"], "type": "document", "note": "需要他确认预算" } ], "version": 1 } ``` | type | 说明 | 特殊字段 | |------|------|----------| | document | 文档/文件 | url, note | | reminder | 提醒 | content | #### `schedule_subscriptions` - PK: `id UUID` - 关键字段: - `item_id` - `subscriber_id` - `permission`(INTEGER,用位运算存储权限组合,`NOT NULL DEFAULT 1`) - `notify_level`(`all | mentions | none`,`NOT NULL DEFAULT 'all'`) - 时间字段: `created_at` - 状态字段: `status`(`active | paused | unsubscribed`,`NOT NULL DEFAULT 'active'`) - 约束: `UNIQUE(item_id, subscriber_id)` - 约束补充: `CHECK(permission BETWEEN 0 AND 7)`(`view=1, invite=2, edit=4`,`0` 表示无权限) - 索引: `INDEX(subscriber_id, status)`, `INDEX(item_id, status)` - 审计: `created_by` **权柄说明(位运算)**: | 权柄 | 值 | 二进制 | 说明 | |------|-----|--------|------| | view | 1 | 001 | 查看事项详情 | | invite | 2 | 010 | 邀请其他人订阅此事项 | | edit | 4 | 100 | 修改事项内容、管理订阅 | - 权限检查:`permission & 2 = 2` 检查是否有 invite 权限 - 权限添加:`permission | 2` 添加 invite 权限 - 事项 owner 默认拥有全部权柄:`7`(111) - owner 权柄由服务层恒等判定为 `7`,不依赖 owner 是否在 `schedule_subscriptions` 中存在记录 **当前版本边界**: - `schedule_subscriptions` 仅支持用户订阅(`subscriber_id -> auth.users.id`) - 事项协作暂不引入群主体授权 ### 5) 待处理消息(Inbox) #### `inbox_messages` - PK: `id UUID` - 关键字段: - `recipient_id`(接收者) - `sender_id`(发送者,系统消息可为 NULL) - `message_type`(枚举:`friend_request | calendar | system | group`) - `friendship_id`(可空,`friend_request` 时必填) - `schedule_item_id`(可空,`calendar` 时必填) - `group_id`(可空,`group` 时必填) - `content`(TEXT,消息内容,系统消息用) - 时间字段: `created_at` - 状态字段: - `is_read`(BOOLEAN,是否已读) - `status`(`pending | accepted | rejected | dismissed`) - 索引: - `INDEX(recipient_id, status, created_at DESC)` - 部分索引 `INDEX(recipient_id, created_at DESC) WHERE status='pending'` - 审计: `created_by` **message_type 与业务字段对应关系**: | message_type | 对应业务字段 | |--------------|-----------------| | friend_request | friendship_id -> friendships.id | | calendar | schedule_item_id -> schedule_items.id | | system | 三个业务字段均为 NULL(内容直接在 content) | | group | group_id -> groups.id | **说明**:一张表搞定,接收者视角,通过 `message_type + 对应业务字段` 直接定位要处理的业务,避免单列多态外键带来的引用不一致问题。 **一致性约束(必做)**: - 使用 `CHECK` 保证不同 `message_type` 下仅允许对应业务字段非空(`system` 时业务字段全空) - 使用 `CHECK` 保证 `message_type='system'` 时 `sender_id IS NULL`,否则 `sender_id IS NOT NULL` - `friendship_id`、`schedule_item_id`、`group_id` 分别建立 FK,并显式声明 `ON DELETE` 策略 ### 6) 待办 #### `todos` - PK: `id UUID` - 关键字段: - `owner_id` - `title` - `description` - `due_at` - `priority`(INTEGER,用于四象限:1=重要且紧急, 2=重要不紧急, 3=紧急不重要, 4=不重要不紧急) - 时间字段: `created_at`, `completed_at` - 状态字段: `status`(`pending | done | canceled`) - 索引: - `INDEX(owner_id, status, due_at)` - `INDEX(owner_id, created_at DESC)` - 部分索引 `INDEX(owner_id, due_at) WHERE status='pending'` - 审计: `created_by` #### `todo_sources` - PK: `id UUID` - 关键字段: - `todo_id`(FK -> todos.id) - `schedule_item_id`(FK -> schedule_items.id) - 时间字段: `created_at` - 约束: `UNIQUE(todo_id, schedule_item_id)` - 索引: `INDEX(todo_id)`, `INDEX(schedule_item_id)` **说明**: - 手动创建待办:不写 `todo_sources` - 从事项提取待办:写入 `todo_sources`,替代 JSONB 数组,保证来源关系可校验 ### 7) 自动化定时任务 #### `automation_jobs` - PK: `id UUID` - 关键字段: - `owner_id` - `title`(任务标题) - `prompt`(AI 执行的 prompt) - `schedule_type`(枚举:`daily | weekly`) - `run_at`(首次运行时间) - `next_run_at`(下次运行时间,调度器扫描主字段) - `timezone`(时区,如 `Asia/Shanghai`) - `last_run_at`(最近运行时间,可空) - 时间字段: `created_at`, `updated_at` - 状态字段: `status`(`active | disabled`) - 索引: `INDEX(owner_id, status)`, `INDEX(status, next_run_at)` - 约束补充: `UNIQUE(id, owner_id)`(用于 `sessions(job_id, user_id)` 归属一致性外键) - 审计: `created_by` **说明**:定时任务执行时,在 sessions 表创建记录存储 AI 对话内容。 ### 8) 会话表扩展(已有 sessions) #### `sessions`(更新) - 新增字段: - `session_type`(`chat | automation`) - `job_id`(可空,FK -> automation_jobs.id) - 一致性约束: - `CHECK((session_type = 'chat' AND job_id IS NULL) OR (session_type = 'automation' AND job_id IS NOT NULL))` - 通过复合 FK 约束归属一致性:`FOREIGN KEY(job_id, user_id) -> automation_jobs(id, owner_id)` - 索引: - `INDEX(user_id, session_type, last_activity_at DESC)` - `INDEX(job_id)` ## D. 权限与协作模型 ### 1) 事项权限落表 - 权限直接存储在 `schedule_subscriptions.permission` 整数中(位运算) - owner 不写入 `schedule_subscriptions`,owner 权限仅由 `schedule_items.owner_id` 推导 - 权限决策顺序: 1. `schedule_items.owner_id` → 服务层恒等全部权柄 `["view", "invite", "edit"]`(7) 2. `schedule_subscriptions` 中该用户的 `permission` 位图 3. 非 owner 且非 subscriber 默认无权限(0) ### 2) 当前版本边界 - 事项权限仅处理用户主体(owner + subscriber) - 群组与事项权限继承关系不在本期范围 ## E. 消息与待办联动 ### 1) inbox 关联业务对象 - `inbox_messages.message_type` 枚举: - `friend_request`(好友请求)→ `friendship_id` 指向 friendships - `calendar`(日程邀请)→ `schedule_item_id` 指向 schedule_items - `system`(系统消息)→ 业务字段均为 NULL - `group`(群组邀请)→ `group_id` 指向 groups - 通过 `message_type + 对应业务字段` 直接定位业务对象,并用 `CHECK` 约束保证字段一致性 ### 2) 待办来源提取 - 从事项提取待办时,写入 `todo_sources(todo_id, schedule_item_id)` - 手动创建的待办不写 `todo_sources` - 支持多来源:同一待办可关联多个日程事项(多行 `todo_sources`) - 待办完成时无需反向更新来源事项状态(简化设计) ## F. 定时任务模型 ### 1) 调度规则 - `schedule_type` 枚举:`daily`(每日) | `weekly`(每周) - `run_at` 用于首次执行时间,`next_run_at` 用于后续调度 - 调度器扫描 `status='active' AND next_run_at <= now()` 的任务,执行后回写下一次 `next_run_at` - `timezone` 参与下一次执行时间计算,避免时区偏差 ### 2) 执行记录 - 每次执行在 sessions 表创建记录,通过 `sessions.job_id` 关联 job - `sessions` 通过 `session_type` 区分 `chat` 与 `automation` - 执行失败时记录在 `automation_jobs`(如 `last_error`,可后续细化) ## G. 数据库迁移思路 ### 策略:重建数据库 + Alembic ORM 迁移 由于是全新设计的数据模型,且当前处于开发初期(可清除旧数据),采用**重建数据库**策略: **执行门禁(强制)**: - 仅允许在本地开发环境执行 - 禁止在生产/共享环境执行 `rm backend/alembic/versions/*.py` - 执行前必须备份数据库或创建 git tag 1. **删除所有旧 migration 脚本**(保留 `env.py`) 2. **创建 ORM 模型文件** 3. **生成 Alembic migration** 4. **重建数据库并执行迁移** ### 执行步骤 1. 删除旧 migration 文件 ```bash rm backend/alembic/versions/*.py ``` 2. 重建空数据库(确保以空库基线生成 initial migration) ```bash docker compose --env-file .env -f infra/docker/docker-compose.yml down -v docker compose --env-file .env -f infra/docker/docker-compose.yml up -d db ``` 3. 创建 ORM 模型文件(参考 `models/` 目录结构) - 新增:`user_agents.py`, `memories.py`, `friendships.py`, `groups.py`, `group_members.py`, `schedule_items.py`, `schedule_subscriptions.py`, `inbox_messages.py`, `todos.py`, `todo_sources.py`, `automation_jobs.py` - 更新:`profile.py` - 添加 `settings` 字段 - 更新:`agent_chat_session.py` - 添加 `session_type`、`job_id` 字段 - 重写:`create_profile_for_new_user` 触发器,确保 `profiles.settings` 有默认值 4. 更新 `models/__init__.py` 导出所有模型 5. 更新 `alembic/env.py` 添加模型导入 6. 生成 initial migration(以空库为对比基线) ```bash cd backend && uv run alembic revision --autogenerate -m "initial schema" ``` 7. 为所有新建 `public` 业务表补齐 RLS(`SELECT/INSERT/UPDATE/DELETE` policy) - 每张表都执行 `ENABLE ROW LEVEL SECURITY` - 每张表都显式创建 `SELECT/INSERT/UPDATE/DELETE` policy - downgrade 必须可逆,不得弱化既定安全边界 - `anon/authenticated` 默认全部 deny RLS 最小策略矩阵(本期统一模板): - `anon`:`SELECT/INSERT/UPDATE/DELETE` 全部 deny - `authenticated`:`SELECT/INSERT/UPDATE/DELETE` 全部 deny - `service_role`:由后端服务连接使用,不依赖 RLS 放行 8. 执行迁移 ```bash cd backend && uv run alembic upgrade head ``` 9. 验证表结构 ## H. 交付物 ### ORM 模型文件清单 | 文件 | 说明 | |------|------| | `models/user_agents.py` | 用户专属 agent | | `models/memories.py` | 用户/工作记忆 | | `models/friendships.py` | 好友关系 | | `models/groups.py` | 群组 | | `models/group_members.py` | 群组成员 | | `models/schedule_items.py` | 日程事项 | | `models/schedule_subscriptions.py` | 日程订阅与权限 | | `models/inbox_messages.py` | 待处理消息 | | `models/todos.py` | 待办 | | `models/todo_sources.py` | 待办与事项来源关联 | | `models/automation_jobs.py` | 定时任务 | | `models/profile.py` | 更新:添加 `settings` 字段 | | `models/agent_chat_session.py` | 更新:添加 `session_type`、`job_id` 字段 | ### 执行步骤 1. 删除旧 migration 文件 ```bash rm backend/alembic/versions/*.py ``` 2. 重建空数据库(确保以空库基线生成 initial migration) ```bash docker compose --env-file .env -f infra/docker/docker-compose.yml down -v docker compose --env-file .env -f infra/docker/docker-compose.yml up -d db ``` 3. 创建/更新 ORM 模型文件 4. 更新 `models/__init__.py` 导出所有模型 5. 更新 `alembic/env.py` 添加模型导入 6. 生成 initial migration(以空库为对比基线) ```bash cd backend && uv run alembic revision --autogenerate -m "initial schema" ``` 7. 为所有新建 `public` 业务表补齐 RLS(`SELECT/INSERT/UPDATE/DELETE` policy) - 每张表都执行 `ENABLE ROW LEVEL SECURITY` - 每张表都显式创建 `SELECT/INSERT/UPDATE/DELETE` policy - downgrade 必须可逆,不得弱化既定安全边界 8. 执行迁移 ```bash cd backend && uv run alembic upgrade head ``` 9. 更新测试文件适配新表结构 ## I. 数据库表名规范与审计 ### 1) 命名规范(统一执行) - 使用 `snake_case` - 业务表统一使用复数名词(如 `profiles`, `friendships`, `automation_jobs`) - 关联表使用 `<主实体复数>_<从实体复数>` 或约定俗成复数短语(如 `group_members`, `todo_sources`) - 禁止过于泛化的表名(如 `messages`, `sessions`),必须带业务前缀 - 存量历史表允许短期例外,但必须在审计表中登记并给出迁移计划 - 缩写保持一致:LLM 统一使用 `llm` 前缀,不混用 `model`/`llm` 两套命名 ### 2) 表名审计结果 | 当前表名 | 审计结论 | 建议表名 | 说明 | |----------|----------|----------|------| | `profiles` | 通过 | - | 符合复数名词规范 | | `user_agents` | 通过 | - | 语义清晰 | | `memories` | 通过 | - | 语义清晰 | | `friendships` | 通过 | - | 关系表命名清晰 | | `groups` | 通过 | - | 符合规范 | | `group_members` | 通过 | - | 关联表命名清晰 | | `schedule_items` | 通过 | - | 语义清晰 | | `schedule_subscriptions` | 通过 | - | 语义清晰 | | `inbox_messages` | 通过 | - | 带业务前缀,避免歧义 | | `todos` | 通过 | - | 简洁且清晰 | | `todo_sources` | 通过 | - | 关联关系明确 | | `automation_jobs` | 通过 | - | 语义清晰 | | `llms` | 通过 | - | 与 LLM 语义一致 | | `llm_factory` | 建议调整 | `llm_factories` | 当前为单数,建议改复数以统一规范 | | `sessions` | 建议调整 | `agent_chat_sessions` | 过于泛化,建议加业务前缀 | | `messages` | 建议调整 | `agent_chat_messages` | 过于泛化,建议加业务前缀 | ### 3) 落地建议 - 本期命名边界:不重命名 `llm_factory/sessions/messages`,仅在新表严格执行命名规范 - 本期最小可行:先保持现有表名可运行,新增表全部遵循规范 - 下期统一治理:通过一次性迁移将 `llm_factory/sessions/messages` 重命名到规范名 - 若本期直接重命名,需同步 ORM 模型、外键、索引、RLS policy 名称与运行文档