资源生命周期
本文是当前实现的生命周期契约。它描述管理员和运维人员可以观察到的状态、资源级联范围、恢复边界和清理顺序。保留期和聊天绝对保留上限见数据、隐私与保留策略。
生命周期状态
Section titled “生命周期状态”| 状态 | 访问与可见性 | 数据行为 | 恢复方式 |
|---|---|---|---|
| 活跃 | 正常可见和可用 | 业务查询返回行 | 正常业务操作 |
banned |
通过请求守卫、登录、建房、入房或房间访问检查拒绝 | 账号、成员、媒体、播放列表和聊天保持原状 | unban 解除有效 ban |
| 软删除 | 普通查询、资源列表和安全管线隐藏;现有 token 也被拒绝 | 事务内写入 deleted_at,依赖资源按来源记录保留关系 |
用户聚合可在保留期内恢复 |
| 永久清理 | 行、关系和关联文件引用被移除 | 清理任务在锁和依赖顺序下执行硬删除 | 数据库恢复或备份恢复流程 |
ban 表示访问控制状态,删除表示数据生命周期状态。两者可以同时存在,操作人员应根据违规处理和数据终止的不同目的选择动作。
deletion_source 是业务层的 SMALLINT 码,数据库保存数值并保留历史 NULL:
| 业务码 | 含义 | 典型场景 |
|---|---|---|
1 Account |
账号聚合删除 | 用户注销或管理员删除用户后级联资源 |
2 Admin |
管理员直接删除 | 管理员直接删除用户或房间 |
3 System |
系统任务删除 | 系统策略或后台流程 |
4 Room |
房间聚合删除 | 房间删除带走播放列表、媒体和聊天 |
5 User |
用户或成员直接删除资源 | 单独删除媒体、播放列表或聊天消息 |
NULL |
unknown |
历史数据缺少来源信息 |
数据库层不解析业务枚举,也不依赖来源 CHECK。清理任务按已知来源筛选,NULL 行进入历史数据路径并由管理员结合审计信息判断。
deleted_owner_id 是账号聚合的关联键。它把用户在自己房间和其他房间创建的资源绑定到同一次账号恢复或永久清理,避免只按资源所在房间推断归属。
Ban 生命周期
Section titled “Ban 生命周期”用户 ban 和房间 ban 都写入独立的记录表。有效记录满足 revoked_at IS NULL,并且当前时间处于 starts_at 和 ends_at 窗口内。
| 对象 | 影响 | unban 行为 |
数据清理 |
|---|---|---|---|
| 用户 | 拒绝登录、建房和加入房间;实时连接会被失效 | 撤销有效记录,保留账号和成员图 | 账号永久清理时删除该用户的 ban 历史,审计事件继续保留 |
| 房间 | 拒绝进入和使用房间;实时连接会被失效 | 撤销有效记录,保留房间资源 | 房间永久清理时删除房间 ban 记录 |
ban 记录保留 actor、原因、开始、结束和撤销信息。被删除用户作为 actor 时,生命周期事务将 actor 外键置为 NULL,审计主体和原因继续保留。
用户删除事务
Section titled “用户删除事务”账号关闭和管理员删除用户都在一个数据库事务中处理资源清理和用户行软删除。用户行的来源分别由操作选项记录;账号级关联资源使用 Account 来源并写入 deleted_owner_id。
事务包含以下步骤:
- 锁定用户,收集其拥有的活跃房间、其他房间中的自有播放列表和媒体。
- 在其他存活房间软删除用户创建的播放列表、媒体和聊天消息;播放状态引用这些资源时重置当前播放。
- 软删除用户拥有的房间。房间的成员关系立即移除,播放状态立即清空,房间设置留在可恢复房间聚合中。
- 将所有账号关联的 email/OAuth2 identity 标记为
Account软删除,从活跃唯一索引释放邮箱和 Provider subject。 - 立即删除 email token、email bind request、Provider 凭据和通知等短期或秘密数据。
- 其他房间的账号聊天保留正文和作者用于恢复,普通消息查询隐藏这些行;房间被删除时产生的聊天也归入同一账号聚合。
- 移除用户全部成员关系,清空 ban 记录中的 actor 引用,提交缓存、权限和 realtime 失效。
事务提交前的失败会整体回滚。提交后的缓存和实时通知失败会记录日志,并由后续失效或重试机制收敛。
资源级联矩阵
Section titled “资源级联矩阵”| 资源 | 用户删除时 | 房间删除时 | 永久清理 |
|---|---|---|---|
| 用户行 | deleted_at、来源、原因、操作人 |
不适用 | 用户保留期结束后硬删除 |
| 用户拥有的房间 | Account + deleted_owner_id,成员移除 |
房间来源为 User 或 Admin |
房间窗口和账号窗口协调后删除;账号硬清理会在同一事务清理拥有房间 |
| 其他房间中的用户播放列表、媒体 | Account + deleted_owner_id,普通列表隐藏 |
保持房间自己的来源 | 随账号硬清理删除 |
| 单独删除的播放列表、媒体 | User 来源软删除 |
Room 来源软删除 |
资源保留期结束后按叶节点到父节点清理;文件引用先过期 |
| 聊天消息 | 账号级消息使用 Account 并保留正文;单条删除会清空正文并使用 User |
Room 来源软删除并隐藏 |
资源窗口或聊天绝对保留上限先到者触发硬删除 |
| email/OAuth2 identity | Account 软删除并释放活跃唯一占位;主动解绑使用 User |
不适用 | 来源为 User 的 identity 按资源窗口删除;账号硬清理删除剩余 identity |
| token、bind request、Provider 凭据、通知 | 即时删除 | 房间关联运行态按房间清理 | 各自短期清理任务处理 |
| 审计日志 | 保留主体、动作、原因;被删除 actor 变为 NULL |
保留删除和 ban 审计 | 按审计分区保留策略处理 |
| 文件对象 | 业务行删除时标记引用过期 | 同上 | 文件对象清理 worker 在无活跃引用且经过对象保留期后删除 |
资源自身已有软删除状态时,级联操作只更新仍处于活跃状态的行。账号级级联通过 deleted_owner_id 记录聚合归属;恢复只匹配本次账号删除写入的 Account 来源,保留资源自身先前的 User 或 Room 删除事实。
用户恢复必须发生在用户和关联聚合被永久清理之前。恢复事务锁定用户和待恢复 identity,重新建立用户行、账号拥有房间和 Creator 成员关系,并恢复 Account 来源的播放列表、媒体和聊天。
恢复规则:
- 原用户名、email 和 OAuth2 identity 默认要求当前仍可用。任一占用都会返回冲突并回滚整个恢复事务。
--ignore-identity-conflicts允许恢复账号主体和资源。被占用的用户名改为restored_<user_id>,冲突 email/OAuth2 identity 保持释放状态,响应中的released_identities供管理员审计。- 用户主动解绑产生的
User来源 identity 不会被账号恢复重新激活。 - 用户主动删除的媒体、播放列表和单条聊天消息继续保持删除状态。
- 旧成员关系不会自动恢复。被恢复用户重新成为自己房间的 Creator,其他成员通过正常加入流程返回。
- 恢复记录
restored_at和restored_by,并刷新受影响房间的权限、缓存和 realtime 状态。
当前管理面提供用户恢复入口。独立删除的房间、媒体、播放列表和聊天没有通用的 standalone restore 命令;恢复依赖所属账号聚合或数据库备份。
房间生命周期
Section titled “房间生命周期”房间删除先写入 rooms.deleted_at,来源为 User 或 Admin,并在同一事务中软删除房间播放列表、媒体和聊天。成员关系、播放状态和实时权限立即失效,房间设置和资源行留在恢复窗口内。
房间 ban 只改变访问控制,房间仍可被管理员查询、解封和审计。房间永久清理按依赖顺序处理文件引用、媒体、播放列表、成员、设置、资源事件、聊天和 ban 记录,最后删除房间行。账号级房间还需要账号保留期结束,确保账号恢复不会得到不完整的房间聚合。
默认软删除保留期为 90 天,0 表示停用对应永久清理:
| 配置 | 默认值 | 覆盖范围 |
|---|---|---|
soft_delete_retention_days |
90 |
用户永久清理与账号聚合收尾 |
room_soft_delete_retention_days |
90 |
独立房间永久清理 |
resource_soft_delete_retention_days |
90 |
User 来源的媒体、播放列表、聊天、email/OAuth2 identity |
chat.message_retention_days |
90 |
所有聊天消息的绝对保留上限,可能先于软删除窗口生效 |
多副本部署由 leader 执行清理。执行顺序先处理满足条件的房间,再处理用户,再处理独立资源;每个批次使用行锁和 SKIP LOCKED,恢复事务与清理事务通过用户行锁协调。
文件引用在数据库硬删除前标记过期,未被任何活跃业务行引用的对象再经过 file_storage.unreferenced_object_retention_seconds 后由存储 worker 清理。数据库删除成功表示业务行退出生命周期,对象存储删除可能在后续周期完成。
# 查询包含恢复窗口内账号的列表synctv user list --include-deleted
# 在保留期内恢复账号聚合synctv user restore alicesynctv user restore alice --ignore-identity-conflicts
# 违规处理使用 bansynctv user ban alice --reason "abuse"synctv user unban alicesynctv room ban <ROOM_ID> --reason "policy"synctv room unban <ROOM_ID>
# 数据生命周期操作synctv user delete alicesynctv room delete <ROOM_ID>synctv user bans listsynctv room bans list管理 gRPC、HTTP 管理 API 和 synctv CLI 共享同一套服务语义。执行删除或恢复前记录工单、操作者和原因;恢复后检查用户名、身份绑定、房间 Creator、成员加入、媒体列表、聊天可见性和实时连接。
历史数据与备份
Section titled “历史数据与备份”历史 NULL 来源代表 unknown,清理任务不会把它自动归入 User、Room 或 Account 来源。需要处理这类行时,先结合审计日志、创建者和房间状态进行人工判定。
永久删除主库行不会同步擦除旧备份、日志平台或对象存储副本。生产环境应把数据库备份保留期、日志保留期、对象存储生命周期和删除请求的合规要求作为同一个运维策略管理。