25 KiB
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) profiles(settings 作为 JSONB 内嵌)auth.users (1) - (1) user_agentsauth.users (N) - (N) auth.users通过friendshipsauth.users (1) - (N) groups(创建者)groups (1) - (N) group_members,auth.users (1) - (N) group_membersauth.users (1) - (N) schedule_items(创建者)schedule_items (1) - (N) schedule_item_subscriptions,auth.users (1) - (N) schedule_item_subscriptionsschedule_items (1) - (N) schedule_item_permissions,auth.users (1) - (N) schedule_item_permissionsinbox_events (1) - (N) inbox_receipts,auth.users (1) - (N) inbox_receiptsauth.users (1) - (N) todostodos (1) - (N) todo_sources(一条待办可有多个来源记录,默认 1 条)auth.users (1) - (N) automation_jobsautomation_jobs (1) - (N) automation_schedulesautomation_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 JSONB(agent 配置参数)capability_version INTEGER DEFAULT 1
- 时间字段:
created_at,updated_at,deleted_at - 状态字段:
status(active|paused|migrating) - 索引:
UNIQUE(user_id) WHERE deleted_at IS NULLINDEX(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 - 状态字段:
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,visibility,owner_id - 时间字段:
created_at,updated_at,deleted_at - 状态字段:
status(active|archived) - 索引:
INDEX(owner_id, status),INDEX(visibility) - 审计:
created_by,updated_by
group_members
- PK:
id UUID - 关键字段:
group_id,user_idrole(JSONB 数组,权柄组合,如["view"]/["view", "invite"]/["view", "invite", "edit"])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, 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,descriptionstart_at,end_at,timezonerecurrence_rule(可空)source_type(manual|imported|agent_generated)
- 时间字段:
created_at,updated_at,deleted_at - 状态字段:
status(running|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 - 状态字段:
status(active|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_type(user|group|friend_circle),subject_id,permission - 时间字段:
created_at,updated_at,expires_at - 状态字段:
status(active|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 - 状态字段:
status(open|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_state(pending|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 - 状态字段:
status(pending|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_type(schedule_item|manual|inbox_event|automation),source_id,extracted_at,sync_mode - 时间字段:
created_at,updated_at - 状态字段:
status(linked|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 - 状态字段:
status(active|paused|disabled) - 索引:
INDEX(owner_id, status),INDEX(target_type, target_id) - 审计:
created_by,updated_by
automation_schedules
- PK:
id UUID - 关键字段:
job_id UNIQUEschedule_type(cron|rrule|interval)cron_expr/rrule_text/interval_seconds(三选一)timezone,start_at,end_at,next_run_at
- 时间字段:
created_at,updated_at - 状态字段:
status(active|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 - 状态字段:
status(queued|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) 事项编辑权限落表
- 权限决策顺序:
schedule_items.owner_id(天然manage)schedule_item_permissions针对subject_type=user的显式授权- 用户所在群组在
subject_type=group的授权 - 默认无编辑权限
- 建议在服务层计算“有效权限”,可落缓存字段
effective_permission(可选)
2) 群组角色与事项关系
group_members.role:JSONB 数组,权柄组合["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_requestgroup_invitationgroup_role_changedschedule_item_changedschedule_item_permission_grantedautomation_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_mode:one_way|two_way- 当来源为
schedule_item且two_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 小时)
- 新建核心表(不删旧表):
user_agents,friendships,groups,group_members - 对
profiles表新增settings JSONB,settings_version字段 - 建立最小外键和索引,启用 RLS deny-all 策略
- 提供只写新表的影子接口(内部开关)
Phase 2: 协作与联动接入(12-16 小时)
- 新建
schedule_items*,inbox_*,todos*,automation_* - 编写回填脚本(从旧事项/旧消息结构回填,若不存在则跳过)
- 开启双写:旧接口写旧表同时写新表,记录双写差异日志
Phase 3: 读切换与一致性校验(8-12 小时)
- API 读路径灰度切换到新表(按用户百分比)
- 每日对账:记录数、状态分布、关键字段哈希比对
- 指标稳定后停止旧表写入,保留只读回滚窗口
Phase 4: 收尾与清理(4-8 小时)
- 下线旧读路径和旧双写逻辑
- 保留旧表冷备份后归档/删除
- 固化运行手册与告警阈值
回滚策略
- 任意阶段回滚:读切回旧表 + 关闭新表写开关
- 双写阶段故障:保留操作日志,可按时间窗重放补偿
- 最终切换前必须满足:新旧关键查询结果偏差 < 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 条)
- 以
auth.users为身份主键,业务表统一user_id外键。 - 引入
user_agents,通过UNIQUE(user_id)满足每用户专属 agent。 - 用户设置内嵌至
profiles.settings JSONB,支持渐进式扩展。 - 好友关系采用标准化双向一行模型,避免重复边。
- 群组采用
groups + group_members,角色内建 owner/admin/member。 - 事项、订阅、权限三表解耦,支持多人订阅与精细编辑授权。
- inbox 采用
events + receipts,统一承载待处理动作。 - 待办采用
todos + todo_sources,实现来源追踪与去重。 - 自动化采用
jobs + schedules + runs,支持 cron/rrule/interval。 - 所有关键表补齐状态机字段与审计字段,支持可观测与追责。
- 索引以“用户维度 + 状态 + 时间”为主,兼顾移动端列表查询。
- 迁移走“四阶段”:并行建模 -> 双写回填 -> 读切换 -> 清理。
- 通过幂等键、部分索引和事务边界保障高并发稳定性。
I-2. 后续 API 设计所需数据契约清单
- 用户/agent
UserAgentDTO:id,user_id,llm_id,agent_type,status,capability_version,config,updated_atUserSettingsDTO(内嵌于 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,statusGroupMemberDTO:group_id,user_id,role,status,joined_at
- 事项
ScheduleItemDTO:id,owner_id,title,start_at,end_at,status,timezone,recurrence_ruleScheduleSubscriptionDTO:item_id,subscriber_id,status,notify_levelSchedulePermissionDTO:item_id,subject_type,subject_id,permission,status
- Inbox
InboxEventDTO:id,event_type,object_type,object_id,payload,status,created_atInboxReceiptDTO:event_id,recipient_id,inbox_state,action_required,read_at,acted_at
- Todo
TodoDTO:id,owner_id,title,due_at,status,priority,origin_typeTodoSourceDTO:todo_id,source_type,source_id,sync_mode,status
- 自动化
AutomationJobDTO:id,owner_id,job_type,target_type,target_id,statusAutomationScheduleDTO:job_id,schedule_type,cron_expr,rrule_text,interval_seconds,next_run_at,statusAutomationRunDTO:id,job_id,scheduled_for,status,attempt,idempotency_key,error_code
I-3. 最小可行迁移 DDL 清单(按优先级)
P0(身份与社交基础)
ALTER TABLE profiles ADD COLUMN settings JSONB DEFAULT '{}'ALTER TABLE profiles ADD COLUMN settings_version INTEGER DEFAULT 1CREATE INDEX idx_profiles_settings_notification ON profiles ((settings->>'notification_enabled'))CREATE TABLE user_agents (...)CREATE TABLE friendships (...)CREATE TABLE groups (...)CREATE TABLE group_members (...)CREATE INDEX/UNIQUE/CHECK(friendships 规范化约束)
P1(协作事项)
7. CREATE TABLE schedule_items (...)
8. CREATE TABLE schedule_item_subscriptions (...)
9. CREATE TABLE schedule_item_permissions (...)
10. CREATE INDEX(owner/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 扩展:
pgcrypto(UUID/哈希,若已启用可跳过) - 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 |
需业务确认(关键不确定项)
(已确认:允许重名,仅建普通索引)。profiles.username是否允许重名group_members.role 权柄组合(已确认:JSONB 数组["view", "invite", "edit"])。- 是否近期需要“组织/团队”多租户(决定
tenant_id是否立即强制)。 - 事项是否必须绑定群组上下文(
context_group_id是否必需)。 - 待办与事项同步是否默认双向(推荐默认单向,降低循环风险)。
- 自动化任务失败重试上限与退避策略(固定/指数)。