Files
social-app/docs/plans/2026-02-26-social-data-model-redesign.md
T

25 KiB
Raw Blame History

Plan: social-app 数据库数据模型重设计(支持社交/事项/自动化)

Date: 2026-02-26 Author: AI Assistant Status: Draft

Overview

本方案面向 social-app 的下一阶段功能升级,重设计 PostgreSQL 数据模型,统一支持用户专属 agent、好友/群组协作、待处理消息、设置、可订阅且可授权编辑的日程事项、待办联动与自动化定时任务。目标是在 FastAPI + Flutter 协作场景下提供长期稳定的数据基础,降低后续 API 演进和跨端同步复杂度。

Requirements

Functional

  • 每个用户有专属 agent,且模型可扩展到未来多 agent 能力
  • 用户支持好友关系、群组创建与成员管理
  • 用户支持 inbox/pending 待处理消息
  • 用户支持个性化设置(偏好/隐私/通知)
  • 用户支持“绑定日程的事项”,可多人订阅,且仅特定人可修改
  • 用户支持待办事项(可由日程事项提取,也可手动创建)
  • 用户支持自动化定时任务(循环触发)

Non-Functional

  • 性能:核心读路径(inbox 列表、待办列表、事项列表)P95 < 150ms(单用户典型数据量)
  • 安全:权限以后端业务授权为准;数据库层保留 RLS 防御边界
  • 一致性:关键写路径(好友状态、权限变更、任务触发)使用事务保障
  • 可演进:支持旧表迁移、双写与灰度切换

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 形态演进
好友关系用单表双向规范化表示 避免 A-B / B-A 重复,降低去重成本
事项权限采用 ACL 表而非仅 owner 满足“仅特定人可修改”的协作场景
待办采用主表 + 源映射表 支持从事项提取、手动创建、去重与追踪来源
自动化调度采用 rrule + cron + interval 三选一 同时覆盖日历型循环和工程型间隔任务
inbox 采用事件聚合模型 将好友请求/群组邀请/事项变更统一进入待处理中心

A. 设计原则与边界

1) 核心实体与聚合边界

  • 用户聚合:profiles(含 settings JSONB, user_agents
  • 社交聚合:friendships, groups, group_members
  • 协作事项聚合:schedule_items, schedule_item_subscriptions, schedule_item_permissions
  • 消息聚合:inbox_events, inbox_receipts
  • 待办聚合:todos, todo_sources
  • 自动化聚合:automation_jobs, automation_schedules, automation_runs

2) 一致性分级

  • 强一致(同事务):好友关系状态迁移、群组成员角色变更、事项权限写入、定时任务抢占执行
  • 最终一致:inbox 衍生、待办同步、提醒派发(允许异步补偿)

3) 多租户假设

  • 默认假设:单租户产品(同一业务库服务所有用户),以 user_id 做数据隔离
  • 扩展预留:各核心表可预留 tenant_id UUID NULL(需业务确认是否近期引入组织空间)

B. 领域模型与关系图(文字化)

实体与关系

  • auth.users (1) - (1) profilessettings 作为 JSONB 内嵌)
  • auth.users (1) - (1) user_agents
  • auth.users (N) - (N) auth.users 通过 friendships
  • auth.users (1) - (N) groups(创建者)
  • groups (1) - (N) group_membersauth.users (1) - (N) group_members
  • auth.users (1) - (N) schedule_items(创建者)
  • schedule_items (1) - (N) schedule_item_subscriptionsauth.users (1) - (N) schedule_item_subscriptions
  • schedule_items (1) - (N) schedule_item_permissionsauth.users (1) - (N) schedule_item_permissions
  • inbox_events (1) - (N) inbox_receiptsauth.users (1) - (N) inbox_receipts
  • auth.users (1) - (N) todos
  • todos (1) - (N) todo_sources(一条待办可有多个来源记录,默认 1 条)
  • auth.users (1) - (N) automation_jobs
  • automation_jobs (1) - (N) automation_schedules
  • automation_jobs (1) - (N) automation_runs

关键约束

  • 唯一性:
    • user_agents.user_id 唯一
    • friendships(user_low_id, user_high_id) 唯一
    • group_members(group_id, user_id) 唯一
    • schedule_item_subscriptions(item_id, subscriber_id) 唯一
    • schedule_item_permissions(item_id, subject_type, subject_id, permission) 唯一
    • todo_sources(source_type, source_id, owner_id) 唯一(防止重复抽取)
    • automation_runs(job_id, idempotency_key) 唯一
  • 外键:统一显式 ON DELETE 策略(见下)
  • 可空性:权限关键字段、状态字段、外部幂等键默认 NOT NULL
  • 删除策略:
    • 用户删除:大部分 CASCADE(用户私有数据);跨用户协作数据优先软删
    • 事项删除:对子表 CASCADE;待办来源保留历史可改 SET NULL + 软删

C. 数据库表设计(PostgreSQL

以下为推荐主表(方案 1,规范化优先)。字段示例采用 UUID + timestamptz + enum/text-check

1) 用户与 agent

profiles(已有,建议补齐)

  • PK: id UUID (auth.users.id)
  • 关键字段: username, avatar_url, bio
  • 新增 JSONB 字段:
    • settings JSONB(用户自定义设置,含 preferences, privacy, notification 三大块)
    • settings_version INTEGER DEFAULT 1(兼容旧数据的版本字段)
  • 时间字段: 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 JSONBagent 配置参数)
    • capability_version INTEGER DEFAULT 1
  • 时间字段: created_at, updated_at, deleted_at
  • 状态字段: statusactive|paused|migrating
  • 索引:
    • UNIQUE(user_id) WHERE deleted_at IS NULL
    • INDEX(status)
    • INDEX(agent_type)
    • GIN(config)(按需)
  • 审计: created_by, updated_by

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
  • 状态字段: statuspending|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, visibility, owner_id
  • 时间字段: created_at, updated_at, deleted_at
  • 状态字段: statusactive|archived
  • 索引: INDEX(owner_id, status), INDEX(visibility)
  • 审计: created_by, updated_by

group_members

  • PK: id UUID
  • 关键字段:
    • group_id, user_id
    • roleJSONB 数组,权柄组合,如 ["view"] / ["view", "invite"] / ["view", "invite", "edit"]
    • join_sourceinvited|joined
    • invited_by, joined_at
  • 时间字段: created_at, updated_at, removed_at
  • 状态字段: statusactive|muted|removed
  • 约束: UNIQUE(group_id, user_id)
  • 索引:
    • INDEX(group_id, status)
    • INDEX(user_id, status)
    • GIN 索引支持权柄查询:INDEX group_members_role USING GIN(role)
  • 审计: created_by, updated_by

权柄说明

权柄 含义
view 查看群组信息、成员列表、聊天记录
invite 邀请新成员入群
edit 修改群组信息、管理成员(禁言/移除)
  • 群主(创建者)默认拥有全部权柄:["view", "invite", "edit"]
  • 权柄可动态变更:服务层使用 jsonb ||jsonb - 原子操作增减权柄

3) 用户设置(已合并至 profiles 表)

用户设置采用 JSONB 内嵌方式,渐进式扩展无需改表结构:

{
  "version": 1,
  "preferences": {
    "theme": "dark",
    "language": "zh-CN",
    "timezone": "Asia/Shanghai"
  },
  "privacy": {
    "profile_visible_to": "friends",
    "activity_visible_to": "friends",
    "allow_friend_requests": true
  },
  "notification": {
    "enabled": true,
    "push_enabled": true,
    "email_enabled": false,
    "quiet_hours_start": "22:00",
    "quiet_hours_end": "08:00"
  }
}
  • 扩展方式:新增字段时递增 settings_version,应用层做 schema 兼容
  • 索引策略:对高频查询字段(如 notification.enabled)使用表达式索引
  • 更新方式:服务层使用 JSONB merge 或字段级 UPDATE,避免读-改-写并发问题(建议用 jsonb_set 原子操作)

4) 事项与订阅/权限

schedule_items

  • PK: id UUID
  • 关键字段:
    • owner_id, title, description
    • start_at, end_at, timezone
    • recurrence_rule(可空)
    • source_typemanual|imported|agent_generated
  • 时间字段: created_at, updated_at, deleted_at
  • 状态字段: statusrunning|completed|archived
  • 索引:
    • INDEX(owner_id, start_at)
    • INDEX(status, start_at)
    • INDEX(updated_at DESC)
  • 审计: created_by, updated_by

schedule_item_subscriptions

  • PK: id UUID
  • 关键字段: item_id, subscriber_id, notify_level, subscription_source
  • 时间字段: created_at, updated_at, unsubscribed_at
  • 状态字段: statusactive|paused|unsubscribed
  • 约束: UNIQUE(item_id, subscriber_id)
  • 索引: INDEX(subscriber_id, status), INDEX(item_id, status)
  • 审计: created_by, updated_by

schedule_item_permissions

  • PK: id UUID
  • 关键字段: item_id, subject_typeuser|group|friend_circle, subject_id, permission
  • 时间字段: created_at, updated_at, expires_at
  • 状态字段: statusactive|revoked|expired
  • 约束:
    • UNIQUE(item_id, subject_type, subject_id, permission)
    • permission 建议枚举:view|comment|edit|manage
  • 索引:
    • INDEX(item_id, permission, status)
    • INDEX(subject_type, subject_id, status)
  • 审计: granted_by, updated_by

5) 待处理消息(Inbox

inbox_events

  • PK: id UUID
  • 关键字段: event_type, actor_id, object_type, object_id, payload_jsonb, dedupe_key
  • 时间字段: created_at, updated_at
  • 状态字段: statusopen|resolved|canceled
  • 约束: UNIQUE(dedupe_key)
  • 索引: INDEX(event_type, created_at DESC), GIN(payload_jsonb)
  • 审计: created_by, updated_by

inbox_receipts

  • PK: id UUID
  • 关键字段: event_id, recipient_id, inbox_state, action_required, acted_at
  • 时间字段: created_at, updated_at, read_at
  • 状态字段: inbox_statepending|read|accepted|rejected|dismissed|expired
  • 约束: UNIQUE(event_id, recipient_id)
  • 索引:
    • INDEX(recipient_id, inbox_state, created_at DESC)
    • 部分索引 INDEX(recipient_id, created_at DESC) WHERE inbox_state='pending'
  • 审计: created_by, updated_by

6) 待办与来源映射

todos

  • PK: id UUID
  • 关键字段: owner_id, title, description, due_at, priority, origin_type, source_hash
  • 时间字段: created_at, updated_at, completed_at, deleted_at
  • 状态字段: statuspending|in_progress|done|canceled|archived
  • 索引:
    • INDEX(owner_id, status, due_at)
    • INDEX(owner_id, updated_at DESC)
    • 部分索引 INDEX(owner_id, due_at) WHERE status IN ('pending','in_progress')
  • 审计: created_by, updated_by

todo_sources

  • PK: id UUID
  • 关键字段: todo_id, owner_id, source_typeschedule_item|manual|inbox_event|automation, source_id, extracted_at, sync_mode
  • 时间字段: created_at, updated_at
  • 状态字段: statuslinked|unlinked|stale
  • 约束: UNIQUE(owner_id, source_type, source_id)(去重关键)
  • 索引:
    • INDEX(todo_id)
    • INDEX(owner_id, source_type, status)
  • 审计: created_by, updated_by

7) 自动化定时任务

automation_jobs

  • PK: id UUID
  • 关键字段: owner_id, name, job_type, target_type, target_id, params_jsonb
  • 时间字段: created_at, updated_at, deleted_at
  • 状态字段: statusactive|paused|disabled
  • 索引: INDEX(owner_id, status), INDEX(target_type, target_id)
  • 审计: created_by, updated_by

automation_schedules

  • PK: id UUID
  • 关键字段:
    • job_id UNIQUE
    • schedule_typecron|rrule|interval
    • cron_expr / rrule_text / interval_seconds(三选一)
    • timezone, start_at, end_at, next_run_at
  • 时间字段: created_at, updated_at
  • 状态字段: statusactive|paused|expired|invalid
  • 约束:
    • CHECK 保证三种表达互斥且至少一项有效
  • 索引:
    • 部分索引 INDEX(next_run_at) WHERE status='active'
    • INDEX(job_id, status)
  • 审计: created_by, updated_by

automation_runs

  • PK: id UUID
  • 关键字段: job_id, scheduled_for, started_at, finished_at, attempt, max_retries, idempotency_key, worker_id, result_jsonb, error_code
  • 时间字段: created_at, updated_at
  • 状态字段: statusqueued|running|succeeded|failed|canceled|dead_letter
  • 约束:
    • UNIQUE(job_id, idempotency_key)
    • CHECK(attempt <= max_retries + 1)
  • 索引:
    • INDEX(job_id, scheduled_for DESC)
    • INDEX(status, scheduled_for)
    • 部分索引 INDEX(status, updated_at) WHERE status IN ('queued','running')
  • 审计: created_by, updated_by

D. 权限与协作模型

1) 事项编辑权限落表

  • 权限决策顺序:
    1. schedule_items.owner_id(天然 manage
    2. schedule_item_permissions 针对 subject_type=user 的显式授权
    3. 用户所在群组在 subject_type=group 的授权
    4. 默认无编辑权限
  • 建议在服务层计算“有效权限”,可落缓存字段 effective_permission(可选)

2) 群组角色与事项关系

  • group_members.roleJSONB 数组,权柄组合 ["view"] / ["view", "invite"] / ["view", "invite", "edit"]
  • 群主(创建者)默认拥有全部权柄
  • 权柄与事项权限映射:
    • 群成员 view → 事项 view
    • 群成员 invite → 隐含 view
    • 群成员 edit → 事项 edit|manage
  • 若事项绑定群组上下文,可增 schedule_items.context_group_id NULL

E. 消息与待办联动

1) inbox 关联来源

  • inbox_events.event_type 建议枚举:
    • friend_request
    • group_invitation
    • group_role_changed
    • schedule_item_changed
    • schedule_item_permission_granted
    • automation_run_failed
  • 通过 object_type/object_id 直接关联业务对象

2) 待办提取与防循环

  • 从事项提取待办:
    • 先计算 source_hash = sha256(owner_id + source_type + source_id + title + due_at_bucket)
    • todo_sources(owner_id, source_type, source_id) 唯一约束防重复
  • 防循环同步:
    • todo_sources.sync_modeone_way|two_way
    • 当来源为 schedule_itemtwo_way 时,写回需携带 sync_trace_id
    • 同一 sync_trace_id 在同一对象链路只消费一次(应用层幂等)

F. 定时任务模型

1) 循环表达建议

  • 推荐优先级:
    • 用户型日历任务:rrule
    • 运维/工程任务:cron
    • 简单轮询:interval_seconds
  • 数据层统一在 automation_schedules,并通过 schedule_type 区分

2) 触发记录与重试

  • 任务调度器按 next_run_at 扫描活跃计划,插入 automation_runs(status='queued')
  • 执行器抢占:SELECT ... FOR UPDATE SKIP LOCKED
  • 重试策略:attempt 递增,失败后按退避策略更新下一次 scheduled_for

3) 幂等与并发冲突

  • 幂等键:idempotency_key = sha256(job_id + scheduled_for + logical_partition)
  • 冲突处理:唯一约束冲突时视为重复投递,直接忽略或合并结果
  • 并发安全:automation_jobs.version(乐观锁)可选

G. 演进与迁移计划(从旧表到新模型)

Phase 1: 基础并行建模(8-12 小时)

  1. 新建核心表(不删旧表):user_agents, friendships, groups, group_members
  2. profiles 表新增 settings JSONB, settings_version 字段
  3. 建立最小外键和索引,启用 RLS deny-all 策略
  4. 提供只写新表的影子接口(内部开关)

Phase 2: 协作与联动接入(12-16 小时)

  1. 新建 schedule_items*, inbox_*, todos*, automation_*
  2. 编写回填脚本(从旧事项/旧消息结构回填,若不存在则跳过)
  3. 开启双写:旧接口写旧表同时写新表,记录双写差异日志

Phase 3: 读切换与一致性校验(8-12 小时)

  1. API 读路径灰度切换到新表(按用户百分比)
  2. 每日对账:记录数、状态分布、关键字段哈希比对
  3. 指标稳定后停止旧表写入,保留只读回滚窗口

Phase 4: 收尾与清理(4-8 小时)

  1. 下线旧读路径和旧双写逻辑
  2. 保留旧表冷备份后归档/删除
  3. 固化运行手册与告警阈值

回滚策略

  • 任意阶段回滚:读切回旧表 + 关闭新表写开关
  • 双写阶段故障:保留操作日志,可按时间窗重放补偿
  • 最终切换前必须满足:新旧关键查询结果偏差 < 0.1%

H. 两套方案对比

方案 1(推荐):规范化、可维护性优先

  • 特点:按领域拆表,ACL 与来源映射独立,严格约束
  • 优点:一致性好、权限边界清晰、长期演进成本低
  • 缺点:联表较多,初期 API 复杂度较高

方案 2:开发效率优先、适度反规范化

  • 特点:将部分结构合并为 JSONB(如 permissions_snapshot, todo_origin
  • 优点:开发快、迁移初期改动小
  • 缺点:约束弱、查询和审计困难、后续重构成本高
  • 注:user_settings 已按此思路内嵌至 profiles,其他模块仍建议保持规范化

对比矩阵

维度 方案 1(规范化) 方案 2(反规范化)
复杂度 中高
查询性能 读热点需索引与缓存优化 单行读取快,复杂筛选慢
写入成本 中(多表事务) 低到中
扩展性 中低
风险 中(实施复杂) 中高(数据质量和权限风险)

推荐结论

  • 推荐方案 1:当前业务已包含社交关系、协作权限、跨域联动和自动化调度,若选择反规范化将把复杂性转移到应用层并放大后续维护风险。方案 1 在 FastAPI + PostgreSQL 下更符合长期可维护与可审计目标。

I. 交付物

I-1. 可直接进入实现计划的结论性摘要(12 条)

  1. auth.users 为身份主键,业务表统一 user_id 外键。
  2. 引入 user_agents,通过 UNIQUE(user_id) 满足每用户专属 agent。
  3. 用户设置内嵌至 profiles.settings JSONB,支持渐进式扩展。
  4. 好友关系采用标准化双向一行模型,避免重复边。
  5. 群组采用 groups + group_members,角色内建 owner/admin/member。
  6. 事项、订阅、权限三表解耦,支持多人订阅与精细编辑授权。
  7. inbox 采用 events + receipts,统一承载待处理动作。
  8. 待办采用 todos + todo_sources,实现来源追踪与去重。
  9. 自动化采用 jobs + schedules + runs,支持 cron/rrule/interval。
  10. 所有关键表补齐状态机字段与审计字段,支持可观测与追责。
  11. 索引以“用户维度 + 状态 + 时间”为主,兼顾移动端列表查询。
  12. 迁移走“四阶段”:并行建模 -> 双写回填 -> 读切换 -> 清理。
  13. 通过幂等键、部分索引和事务边界保障高并发稳定性。

I-2. 后续 API 设计所需数据契约清单

  • 用户/agent
    • UserAgentDTO: id,user_id,llm_id,agent_type,status,capability_version,config,updated_at
    • UserSettingsDTO(内嵌于 Profile: settings JSONB, settings_version
  • 好友
    • FriendshipDTO: id,user_a,user_b,status,initiator_id,requested_at,accepted_at
    • 状态流转:pending -> accepted|declined|canceled|blocked
  • 群组
    • GroupDTO: id,name,owner_id,visibility,status
    • GroupMemberDTO: group_id,user_id,role,status,joined_at
  • 事项
    • ScheduleItemDTO: id,owner_id,title,start_at,end_at,status,timezone,recurrence_rule
    • ScheduleSubscriptionDTO: item_id,subscriber_id,status,notify_level
    • SchedulePermissionDTO: item_id,subject_type,subject_id,permission,status
  • Inbox
    • InboxEventDTO: id,event_type,object_type,object_id,payload,status,created_at
    • InboxReceiptDTO: event_id,recipient_id,inbox_state,action_required,read_at,acted_at
  • Todo
    • TodoDTO: id,owner_id,title,due_at,status,priority,origin_type
    • TodoSourceDTO: todo_id,source_type,source_id,sync_mode,status
  • 自动化
    • AutomationJobDTO: id,owner_id,job_type,target_type,target_id,status
    • AutomationScheduleDTO: job_id,schedule_type,cron_expr,rrule_text,interval_seconds,next_run_at,status
    • AutomationRunDTO: id,job_id,scheduled_for,status,attempt,idempotency_key,error_code

I-3. 最小可行迁移 DDL 清单(按优先级)

P0(身份与社交基础)

  1. ALTER TABLE profiles ADD COLUMN settings JSONB DEFAULT '{}'
  2. ALTER TABLE profiles ADD COLUMN settings_version INTEGER DEFAULT 1
  3. CREATE INDEX idx_profiles_settings_notification ON profiles ((settings->>'notification_enabled'))
  4. CREATE TABLE user_agents (...)
  5. CREATE TABLE friendships (...)
  6. CREATE TABLE groups (...)
  7. CREATE TABLE group_members (...)
  8. CREATE INDEX/UNIQUE/CHECKfriendships 规范化约束)

P1(协作事项) 7. CREATE TABLE schedule_items (...) 8. CREATE TABLE schedule_item_subscriptions (...) 9. CREATE TABLE schedule_item_permissions (...) 10. CREATE INDEXowner/status/time + permission 查询)

P2(消息与待办) 11. CREATE TABLE inbox_events (...) 12. CREATE TABLE inbox_receipts (...) 13. CREATE TABLE todos (...) 14. CREATE TABLE todo_sources (...) 15. CREATE UNIQUE INDEX uq_todo_sources_owner_source (...)

P3(自动化) 16. CREATE TABLE automation_jobs (...) 17. CREATE TABLE automation_schedules (...) 18. CREATE TABLE automation_runs (...) 19. CREATE UNIQUE INDEX uq_automation_runs_job_idempotency (...) 20. CREATE INDEX idx_automation_schedules_next_run_active (...)

P4(安全与治理) 21. 对新增 public 表执行 ALTER TABLE ... ENABLE ROW LEVEL SECURITY 22. 为 anon, authenticated 创建默认 deny-all SELECT/INSERT/UPDATE/DELETE policy 23. 审计字段回填脚本与触发器(如需)

Dependencies

  • PostgreSQL 扩展:pgcryptoUUID/哈希,若已启用可跳过)
  • Alembic 迁移体系(现有)
  • 后端任务执行器(Celery)用于自动化触发与补偿

Testing Strategy

  • Unit Tests: 状态流转、权限决策、去重哈希、幂等键生成
  • Integration Tests: 迁移升级/回滚、双写一致性、RLS policy 基线、并发抢占执行
  • E2E Tests: 好友请求到 inbox、群组邀请处理、事项订阅变更到待办、自动化任务触发到结果回显

Risks & Mitigations

Risk Impact Likelihood Mitigation
旧表结构未知导致回填失败 High Medium 先做 schema 探测脚本,按表存在性分支回填
双写期间新旧数据不一致 High Medium 引入操作日志 + 对账任务 + 幂等补偿
权限模型过复杂影响上线进度 Medium Medium 先上线最小权限集(owner/user/group),后续扩展
自动化任务并发冲突 Medium Medium SKIP LOCKED + 幂等键 + 乐观锁版本号
索引不足导致移动端列表慢 Medium Medium 先覆盖 P0/P1 热路径索引,监控后增量优化

Estimated Effort

Phase Effort
Phase 1 8-12 hours
Phase 2 12-16 hours
Phase 3 8-12 hours
Phase 4 4-8 hours
Total 32-48 hours

需业务确认(关键不确定项)

  1. profiles.username 是否允许重名(已确认:允许重名,仅建普通索引)。
  2. group_members.role 权柄组合(已确认:JSONB 数组 ["view", "invite", "edit"])。
  3. 是否近期需要“组织/团队”多租户(决定 tenant_id 是否立即强制)。
  4. 事项是否必须绑定群组上下文(context_group_id 是否必需)。
  5. 待办与事项同步是否默认双向(推荐默认单向,降低循环风险)。
  6. 自动化任务失败重试上限与退避策略(固定/指数)。