Files
gaojie 1ea74b46da
Sync to site1 / sync (push) Has been cancelled
chore: update CrowdRoom categories from worldmodel to CrowdRoom
2026-05-21 02:20:22 +08:00

32 KiB
Raw Permalink Blame History

title, date, draft, tags, categories
title date draft tags categories
CrowdRoom · 隐私设计(v0.1 2026-05-20 false
CrowdRoom
众包
3D 重建
隐私
iOS
数据结构
CrowdRoom

CrowdRoom · 隐私设计(v0.1

本章是 CrowdRoom 的「合规底座」,承接 00_overview.md §8 风险 RK-3(UGC 审核)、RK-4(隐私脱敏),并对 03_ios_app_plan.md §11 移交的 P-1 ~ P-604_web_app_plan.md §13 移交的 P-W-1 / P-W-2 / P-W-7 三条隐私强相关契约逐一拍板。治理与社区规则(含 P-W-3 ~ P-W-6)见 10_governance.md

本章不重复 01_data_schema.md §3.5 redactions 表 DDL 与 §3.5 RLS 策略——所有「实现位置」均回指既有章节。

本章核心论断CrowdRoom 用「端侧脱敏 + 公共数据 CDN 全裸 / 私有数据 RLS 全锁」两段式架构把隐私风险压缩到「用户主动框选发布」这一个决策点上;服务端永不二次检测人脸、永不持有 GPS 精确坐标、永不把 redactions 区域明文回流到第三方。


1. 隐私设计五原则

排列顺序即决策优先级。当任意两条原则冲突时,编号小的优先

# 原则 一句话定义 落地证据
PR-1 端侧优先脱敏 任何可能含人脸/人体的栅格数据,必须在 iPhone 离开 App 进程前完成 CIGaussianBlur 不可逆改写;服务端永不对原始贴图做二次人脸检测。 03_ios_app_plan.md §4 端侧脱敏管线 + iOS-X1 契约
PR-2 最小数据采集 不申请非必要权限:不录音、不读相册、不收 IDFA、不收精确 GPS。能用 5 km 城市标签解决的就不上经纬度,能用客户端聚合的就不收原始事件。 §3.3 位置生命周期 + §9 第三方 SDK 清单
PR-3 用户可控 所有「涉及隐私的开关」默认朝隐私最严方向(私有可见性、不打位置标签、不保留备份),用户可在「我的 → 隐私」一处看完全部并即时切换。 §7 默认值清单
PR-4 默认私有,发布显式 房间记录在数据库里初始 visibility='private'(与 01_data_schema.md §3.2 rooms.visibility 默认值绑定),用户必须在上传表单主动勾选「公开」才会进入发现流——零误公开。 03_ios_app_plan.md §1.2 UploadForm 页
PR-5 可被遗忘 用户「注销账号并删除全部数据」是一个承诺 30 天内完成的端到端流程,不存在「冷备份永久保留」的暗逻辑;公开 Remix 的几何快照按 §8 保留期表自动迁移到 tombstone 后清理。 §3.1 P-4 + §8 删除时间表

若未来运营方提出「为了广告变现请放开 IDFA」,本五条原则即「先改原则再改代码」的硬门槛——任何放开必须更新本章并在 00_overview.md 顶部 changelog 留痕。


2. 数据流隐私视图

红/黄/绿 = 该节点持有数据的隐私敏感度(红 = 含可识别人脸/位置,黄 = 含间接可识别信息,绿 = 已脱敏或仅元数据)。第三方可访问性以「✓ 外部可见」与「✗ 仅内部」标注。

graph LR
    subgraph 设备_iPhone
        A1[RoomPlan 原始 RGB Depth · 红 · ✗ 仅内部]
        A2[Vision 人脸 bbox · 红 · ✗ 仅内部]
        A3[CIGaussianBlur 改写贴图 · 绿 · ✗ 仅内部]
        A4[redactions list 数组 · 黄 · ✗ 仅内部]
    end

    subgraph Supabase_Storage
        B1[private rooms id source usdz · 绿 已脱敏 · ✗ JWT 锁]
        B2[private rooms id source roomplan json · 黄 含尺寸 · ✗ JWT 锁]
        B3[public rooms id canonical glb · 绿 · ✓ CDN]
        B4[public rooms id thumbnail webp · 绿 · ✓ CDN]
    end

    subgraph Supabase_Postgres
        C1[rooms 表 location_label 城市级 · 黄 · ✓ RLS public]
        C2[redactions 表 region 坐标 · 红 · ✗ RLS owner only]
        C3[users 表 handle email · 黄 · ✓ handle 公开 email RLS]
    end

    subgraph 转码_Worker
        D1[usdz to glb 流水 · 绿 仅几何 · ✗ service role]
        D2[Worker 日志 含失败堆栈 · 黄 · ✗ Sentry 关联]
    end

    subgraph Web_浏览端
        E1[R3F 渲染 glb manifest · 绿 · ✓ 公开]
        E2[viewState 分享 token · 绿 仅开关 · ✓ URL 上]
        E3[OG 图缓存 1200x630 · 绿 · ✓ CDN]
    end

    subgraph 第三方_SDK
        F1[Sentry Issue 含堆栈 · 黄 · ✗ 内部账号]
        F2[PostHog 事件 已脱敏 · 黄 · ✗ 内部账号]
        F3[CloudFlare Vercel 边缘缓存 · 绿 仅公开资产 · ✓ 全球节点]
    end

    A1 --> A2 --> A3
    A3 --> B1
    A2 --> A4 --> C2
    A1 -.丢弃.-> X[本地不留底]
    B1 --> D1 --> B3 --> E1
    D1 --> B4 --> E3
    C1 --> E1
    E1 --> E2
    D2 -.错误才上报.-> F1
    E1 -.事件聚合.-> F2
    B3 --> F3

读图要点

  • 红色节点(A1/A2/C2永不离开「设备」或「Supabase 内网 + service_role」边界
  • 黄色节点(A4/B2/C1/C3/D2/F1/F2)受 RLS 或 Sentry 项目权限保护,不直接对公网开放
  • 绿色节点(A3/B3/B4/D1/E1/E2/E3/F3)走公开 CDN,但在到达此节点前已经过端侧脱敏 + 转码 Worker 几何重打包,不含任何原始 RGB
  • 唯一一处「原始数据 → 公开」的转换发生在 端侧脱敏管线A3 出口)——这条转换链由 03_ios_app_plan.md §4 强约束

3. 三类敏感数据全生命周期

3.1 人脸 / 人体

阶段 行为 是否离设备
采集 RoomPlan 在 ARKit 帧上累积 RGB 贴图
检测 VNDetectFaceRectanglesRequest Revision 3 跑在 Neural Engine,输出归一化 bbox
脱敏 CIGaussianBlur radius=18 整图模糊 + 蒙版合成回原图,bbox 区域不可逆改写到磁盘
审计写入 bbox 累积为 redactions[] 数组(kind='face', space='texture', method='gaussian_blur_r18'),仅作合规审计
上传 redactions[]upload-complete POST 到 Supabase,写入 redactions 是(坐标)
服务端 不二次检测人脸(成本与合规权衡:再次解码 RGB 反而提高数据持有等级);Worker 只读已脱敏 .usdz
用户可见 「我的房间 → 该房间 → 隐私详情」展示「本次扫描共检测到 N 张人脸,全部已模糊」;点开可看缩略图列表(每张含人脸 bbox 轮廓);提供「申请重做脱敏」按钮(走人工流) 否(owner-only
保留 room_versions 同生命周期(见 §8
删除 rooms 硬删 → room_versions cascade → redactions cascade

关键决策:服务端不复检而是信任端侧。理由:① 复检意味着服务端必须解码原始 RGB,反而把数据持有等级从「绿」升回「红」;② Vision Revision 3 在 1024² 贴图上召回 ≥ 95%Apple 官方 benchmark),漏检的极端 case 走 §4 P-2 的用户复议路径解决。

3.2 可识别地标 / 文档 / 屏幕内容

阶段 行为
MVP 不做自动检测 OCR + 地标识别会把数据流从「人脸」一类扩展到「文字 + 品牌 logo + 证件号」,模型大小与误报代价远超 MVP 8 周窗口承受
替代方案:手动框选 iOS App 在「扫描完成预览页」(03_ios_app_plan.md §1.2 ScanReview)提供 UIScrollView 缩略图墙,用户长按贴图后框选矩形;Web Remix 编辑器(04_web_app_plan.md §7)也提供同款工具
数据落库 框选区域写入 redactions[] with kind='manual', method='gaussian_blur_r18';Worker 在转码时拿到该数组,对应 mesh 贴图做二次模糊(这是 §3.1 之外服务端唯一对栅格做的隐私操作,且仅对用户主动标注的区域)
用户提示 上传表单底部固定文案:「请确保扫描中没有信用卡 / 身份证 / 屏幕显示的私人信息 / 他人住址快递单。如有,请使用上一页『手动模糊』工具框选。」
复议 房间发布后,owner 在详情页底部「隐私审查」入口可追加框选 → 触发 02_api_contract.md §3.2 的 transcode-retry 重跑

3.3 地理位置

阶段 行为
权限文案 NSLocationWhenInUseUsageDescription「CrowdRoom 可选使用你的位置,仅为给你扫描的房间打上『城市』标签」(03_ios_app_plan.md §8.1
精度截断 iOS App 拿到 CLLocation 后,立即用 reverse-geocoding 得到城市名(CLPlacemark.locality),原始经纬度不进入 App 持久层、不进入 SwiftData、不进入网络请求 body
服务端存储 rooms.location_label TEXT(如 '上海''San Francisco'),没有 lat/lng 列。即便日后想做「地图视图」也必须用城市质心而非用户原始坐标
公开可见性 城市标签默认随房间 visibility 走(public 房间公开城市;private/unlisted 房间该字段对外不可见,由 RLS 保证)
关闭 用户在「我的 → 设置 → 隐私 → 位置打标」一键关闭后,所有未来上传的 location_label = NULL;已上传房间提供「移除位置标签」按钮(直接 UPDATE NULL
不可恢复 关闭后无法找回原始 GPS——因为根本没存过

当 Apple 推出更高精度的 CLLocationAccuracyReduced(IPv6 地区已默认)时本项收益更明显:CrowdRoom 从一开始就比 iOS 系统更严格。


4. iOS 移交契约(P-1 ~ P-6)逐条决策

P-1 — 端侧脱敏失败 3 次的降级策略

决策 不降级到服务端二次脱敏;3 次失败后必须用户介入(手动框选 或 重新扫描),坚决不破例 iOS-X1。

理由:① 服务端二次脱敏需要解码原始 .usdz 贴图,本质是把数据持有等级从「已脱敏 绿」升回「未脱敏 红」,违反 PR-1;② 端侧失败 3 次的根本原因多为 ModelIO 解贴图异常或贴图格式罕见(HDR / 浮点 PNG),这些场景手动框选反而比模型更准;③ 8 周 MVP 期内服务端没有 GPU 推理预算(成本 + 隐私双不划算)。iPhone 12 Pro 上 16 s 的 R-iOS-2 风险用「文案明确告知预计 15 秒」的 UX 兜底,不动 X1。

实现位置03_ios_app_plan.md §4.4 失败兜底 + §10 R-iOS-2 + iOS-X1 契约文字保留原样

P-2 — redactions[] 保留期与用户可见性

决策 redactions[]room_versions 同生命周期(版本删则 cascade 删除);仅 owner 可见01_data_schema.md §3.5 redactions_owner_only policy 已落地);owner 可在「我的房间 → 隐私详情」页看到每个 bbox 的缩略图,并对漏检/误检发起「申请重做」工单。

理由:① 同生命周期保证「删房 = 彻底删审计」,避免「我删了房,但脱敏记录还在数据库里」的尴尬;② owner-only 是为了防止攻击者通过 bbox 坐标反推真实人脸位置(即便贴图已模糊,反推「模糊区域曾经是某熟人面孔」仍构成隐私泄露);③ 用户可见性是 PR-3 的硬要求——用户必须能验证「我相信的脱敏真的发生了」。

实现位置01_data_schema.md §3.5 redactions 表 + RLS redactions_owner_only + 03_ios_app_plan.md §1.2 PrivacyPage(在「我的房间」详情下新增「隐私详情」子页)

P-3 — 位置标签是否公开展示

决策 城市级(5 km 精度)随房间可见性公开展示;精确 GPS 永不上传、永不存储NSLocationWhenInUseUsageDescription 文案补充一句「该城市标签会显示在你的公开房间页」。

理由:① 城市标签是发现流的强信号(「上海北欧风客厅」远比「北欧风客厅」更有用),完全屏蔽损失体验;② 5 km 精度无法定位到楼栋,符合 GDPR Article 4(1) 中「无法识别自然人」的去标识化阈值;③ 文案补强是 PR-2 + PR-3 的衍生——用户必须在授权时就知道这会公开,而不是事后惊讶。

实现位置03_ios_app_plan.md §8.1 权限文案(需新增「会显示在公开房间页」句子)+ 01_data_schema.md §3.2 rooms.location_label 字段 + 04_web_app_plan.md §8.2 详情页元信息行

P-4 — 用户删除全部数据的端到端流程

决策 「注销账号并删除全部数据」一键流程,承诺 30 天内完成端到端清理,分四阶段:

阶段 触发 数据状态 用户可挽回
T+0 (即时) 用户点击「确认注销」+ 二次密码确认 users.deleted_at = now()rooms.visibility = 'private'(立即从 Feed 与搜索消失);所有 Remix 走 §10 治理 P-W-3 的快照转移流;账号登录被阻断 7 天内联系 DPO 邮箱可撤销
T+7 (软删完成) pg_cron 每日 02:00 扫表 数据库行打 deleted_atStorage 公开 bucket 中的 canonical.glb / thumbnail 仍存(继续承载已发表 Remix
T+30 (硬删完成) pg_cron 第 30 天扫表 删除 rooms/room_versions/redactions/comments/likes/users 行;Storage 私有 bucketsource.usdz / source.roomplan.json)整目录删除;Sentry 与 PostHog 通过 user_id 关联事件按 SDK API 调用删除
持续 公共 Remix 的几何快照(§10 P-W-3 决策)保留为「孤儿作品」,作者署名替换为「Former CrowdRoom user」

理由:① 30 天硬删窗口对齐 GDPR Article 17 的「一个月内响应」+ 给运营充分时间处理异议;② 7 天软删让用户冷静期,避免冲动注销后悔(实测电商类产品冲动注销撤销率 8–15%);③ Remix 几何快照保留是 P-W-3 「Remixer 既得权」的衍生(详见 10_governance.md §4 P-W-3)。

实现位置03_ios_app_plan.md §1.2 SettingsPage 新增「注销账号」子页 + 04_web_app_plan.md R-10 /me 新增同款入口 + 新增 Edge Function account-delete(待 02_api_contract.md v0.2 补 E-16

P-5 — ATT 启用触发条件

决策 MVP 不申请 ATT;当且仅当以下任一条件首次满足,才在下一个 minor 版本灰度推 ATT 弹窗

  1. 接入 Apple Search Ads 归因(需读取 attributionToken
  2. 接入任何把 IDFA 出域的第三方 SDK(如 AppsFlyer、Adjust、字节穿山甲)
  3. 与广告联盟/数据合作方做 user-level 数据交换

Sentry、MetricKit、PostHog(已配置为「不收 IDFA、不开 Session Replay」)均不触发以上任一条件,因此 MVP 上线时 NSUserTrackingUsageDescription 字段不在 Info.plist 中。

理由:① 不申请 = 不需要审核 ATT 文案,免去 App Store 拒审风险;② 一旦满足触发条件再补,发版周期约 1–2 周,对业务节奏影响极小;③ 与 PR-2 「最小数据采集」严格对齐。

实现位置03_ios_app_plan.md §8.2 ATT 章节(结论已对齐,本契约把「何时切换」的判定条件落到纸面)+ 本文 §9 第三方 SDK 清单

P-6 — 未成年用户保护与年龄确认

决策 App Store 分级标 17+;首次启动弹「我已年满 13 岁」单按钮确认;不收集出生日期;不区分 13–17 岁与 18+。Web 端在 /signup 同步要求勾选。

理由:① App Store 17+ 与 Google Play Mature 17+ 是 UGC 平台的行业标准(小红书/Reddit/Discord 均如此);② 不收集出生日期是 PR-2 的强约束——出生日期是高度敏感的可识别信息,收集即增加合规面;③ 「13 岁阈值」对齐 COPPA(美国)+ GDPR-K(欧盟)+ 中国《未成年人网络保护条例》共识下限;④ 不细分 13–17 / 18+ 是因为本平台无年龄分级内容(NSFW 已在 10_governance.md §4 处罚阶梯 L4 永久封禁),无需做年龄分流。

如未来上线 NSFW 分区或商业化(均为 P2):需追加「证件认证 18+」流程并升级本节为「双闸口」。

实现位置03_ios_app_plan.md §1.2 Auth 页(新增年龄确认 modal+ 04_web_app_plan.md R-09 /signup(同款 checkbox+ App Store Connect 分级配置(不在代码库)


5. Web 移交的隐私强相关契约(P-W-1 / P-W-2 / P-W-7

P-W-1 — viewState 分享链接是否会泄露隐藏几何

决策 不会泄露,且本决策由数据结构强保证viewState token 只编码「4 层可见性 + 相机 + overlay_id」三类纯标量字段,不持有几何数据04_web_app_plan.md §4.4 + §9.3 已定义编码契约);第三方拿到 ?vs=... 之后只能改回「打开 furniture 层」这种纯本地切换,无法获得任何未公开的 mesh 顶点或贴图。

理由:① 几何始终在 CDN 上的 canonical.glb 里,谁能访问 .glb 与 viewState 完全无关——若房间是 privateCDN 路径压根不会公开;若是 unlisted/public,几何本身已被作者授权公开,「隐藏图层」只是一种展示偏好而非访问控制。② 这与 ArcGIS 的「图层可见性」语义一致:图层隐藏 ≠ 数据保密。③ 在产品文案上必须明确这一点(即「保存为视图」按钮旁加 tooltip:「这是一种展示视图,不会让别人看不到底图」),避免用户产生「隐藏 = 加密」的错觉。

实现位置04_web_app_plan.md §4.4 Named Viewstooltip 文案待补)+ §9.3 viewState 编码契约(仅标量字段已明确)

P-W-2 — unlisted 房间的 OG 卡片 SEO 抓取

决策 unlisted 房间在 robots.txt 与 OG endpoint 双重阻断爬虫;但持链访问仍可正常出 OG 图——「持链可见」是 unlisted 的产品语义,「搜索引擎可索引」不是。

具体规则:

资源 public unlisted private
robots.txt 允许 Disallow: /r/{id} 通过动态生成(pg_cron 每小时刷新一次列表)
/r/{id} 详情页 SSR 渲染 SSR 渲染,但响应头 X-Robots-Tag: noindex, nofollow 401
/api/og/r/{id} 缓存 24h 仅当 Referer 来自微信/Twitter/Telegram/iMessage UA 名单时返回 OG 图,否则 403 403
sitemap.xml 包含

理由:① unlisted 的产品语义是「不在 Feed 出现,但持链可看」(与 YouTube Unlisted 一致),SEO 索引会破坏这条承诺;② OG endpoint 的 UA/Referer 白名单是工程性兜底——主流社交平台抓 OG 时都会带可识别 UA,搜索引擎不在名单内;③ 完全屏蔽 OG 会让 unlisted 链接在微信/Twitter 卡片里变成「裸链」,损失分享体验。

实现位置04_web_app_plan.md §9.1 OG 标签(需追加 X-Robots-Tag 与 UA 白名单逻辑)+ §9.4 robots.txt(追加动态 unlisted 黑名单)

P-W-7 — viewState token 用作画像的合规风险

决策 viewState token 一律视为「用户偏好数据」纳入隐私范围管理;禁止将其与 user_id 或 IP 关联落库做画像;PostHog 事件中如携带 viewState,必须先经过 hash + 截断

具体规则:

  1. 服务端持久化:view_states 表(如未来引入)room_id + creator_id + token + created_at不存 viewer_id/ipTTL 90 天后 pg_cron 物理删除
  2. 前端遥测:PostHog capture('view_state_loaded', {...}) 事件中 viewState 字段必须用 sha256(token).slice(0,8) 替代,且事件本身不带 user_idPostHog 项目配置 enable_recording_console_log: false + disable_session_recording: true
  3. Sentry breadcrumbviewState token 进入 URL 时自动经过 Sentry beforeBreadcrumb 过滤,替换为 ?vs=[REDACTED]
  4. 用户导出数据时(§6 合规清单),viewState 历史不导出——它是「派生数据」而非「用户数据」

理由:① viewState 含相机角度+图层组合,长期累积可推断「这个用户偏好俯视墙体而非家具特写」这类风格画像,进而推荐广告——这与 PR-2 「最小数据采集」冲突;② hash 截断让运营仍能统计「最热门 view 形态」聚合指标,但无法回查到具体用户;③ Sentry 过滤是行业标配(避免 token 进入崩溃报告被工程师肉眼看到)。

实现位置04_web_app_plan.md §9.3 viewState 编码契约(追加「派生数据」标识)+ 本文 §9 第三方 SDK 清单 PostHog 一行


6. GDPR / PIPL 合规清单

区分「MVP 必做」与「P2 可推」,所有必做项需在 8 周窗口内随产品同步上线。

6.1 MVP 必做项

# 落地形态 关联法条
C-1 隐私政策zh + en /privacy SSG MDX 页(04_web_app_plan.md R-13),首次启动 App 全屏强制阅读 + 勾选 GDPR Art. 13 / PIPL §17
C-2 用户协议(ToS /terms SSG MDX 页,与 C-1 同弹窗勾选 通用
C-3 Cookie 通知 Web 端首次访问底部 banner,区分「必要 / 偏好 / 分析」三类,分析类(PostHog)默认,用户主动 opt-in GDPR ePrivacy Directive
C-4 数据导出 API 新 Edge Function account-export60 秒内异步生成 .zip(含用户上传的 .usdz + .json + 评论 + 点赞流水 + 个人档案),通过邮件单次签名链接送达 GDPR Art. 20 / PIPL §45
C-5 删除账户 API §4 P-4 决策中的 4 阶段流程 GDPR Art. 17 / PIPL §47
C-6 DPO 联系邮箱 privacy@crowdroom.app 监控信箱,72 小时内首响应 SLA;隐私政策页固定展示 GDPR Art. 37 / PIPL §52
C-7 数据处理记录(RoPA 内部 Notion 文档(不公开),记录每个数据类别、用途、保留期、第三方共享 GDPR Art. 30
C-8 未成年人保护 §4 P-6 决策 COPPA / 中国《未成年人网络保护条例》

6.2 P2 可推项(按市场扩张时序推进)

# 触发条件
C-P2-1 DPIA(数据保护影响评估) DAU > 10 万 或 进入欧盟主动运营
C-P2-2 跨境传输备案(中国 PIPL 在中国大陆托管或服务 > 10 万中国用户 → 需走「标准合同 + 网信办备案」
C-P2-3 GDPR 代表(欧盟代表) 开放欧盟市场或欧盟用户 > 5% MAU → 委托第三方法务公司
C-P2-4 SCC(标准合同条款)签订 与 Supabase / Sentry / PostHog / Vercel 任一签订 SCC 模块化条款(目前各家官网都有标准模板)
C-P2-5 CCPA / CPRA 合规(加州) 美国市场 DAU > 1 万
C-P2-6 App Privacy ManifestApple 2024 强制) iOS 17.4+ 起 App Store 审核必须项;MVP 也要在发版前打钩,本项已升 MVP——见 03_ios_app_plan.md §8 待补

C-P2-6 实际是 Apple 平台强制项(2024 春已生效),MVP 发版必须提交 PrivacyInfo.xcprivacy 声明 SDK 清单与 API 使用类别——已 cross-ref 到本文 §9。这是本子任务反向回写到 iOS 计划的一处「漏洞」(见 attempt_completion 漏洞列表)。


7. 隐私默认值清单

所有「涉及隐私的开关」MVP 默认值;遵守 PR-3 「默认朝隐私最严方向」与 PR-4 「默认私有」。在「我的 → 设置 → 隐私」一处可视化展示并一键切换。

开关 默认 用户可改 说明
房间可见性(新扫描) 私有 上传表单必须显式勾选「公开」/「持链可见」,零误公开(PR-4)
位置打标 关闭时所有未来上传 location_label = NULL(§3.3
扫描音频录制 永关 RoomPlan 不需要音频,NSMicrophoneUsageDescription 不申请
端侧脱敏 永开 iOS-X1 硬约束,用户无法关闭(§4 P-1)
保留脱敏前原图本地备份 仅当用户主动勾选才在 Storage pre_redaction.jpg 留底(01_data_schema.md §6 Storage 目录)
Sign in with Apple 隐藏邮箱 (由 Apple 默认) 与 Apple 私有中继邮箱兼容
Remix 通知(我的房间被 Remix 时通知我) 创作互动需要,但用户可关
评论通知 同上
点赞通知 默认关,避免高频骚扰
在公开页面展示我的 handle handle 是公开身份;不允许「匿名上传」(避免 UGC 治理失控)
在公开页面展示我的 email 永关 email 永远只对自己可见,RLS 保证(01_data_schema.md §3.1 users 表)
PostHog 行为分析 C-3 Cookie 通知中 opt-in 用户不 opt-in 时 PostHog SDK 不初始化
Sentry 崩溃上报 崩溃报告默认不含 PII,但用户仍可在隐私设置关闭
iframe 嵌入我的房间 (公开/unlisted 房间默认允许嵌入) 关闭后 /embed/r/{id} 返回 403,详见 10_governance.md §4 P-W-6
允许搜索引擎索引我的主页 (仅 public 房间) unlisted/private 永不被索引(§5 P-W-2
ATT(跨 App 跟踪) 不申请 §4 P-5 决策

8. 数据保留与删除时间表

数据类别 保留期 删除触发 是否可恢复
原始 .usdz / .roomplan.json(私有 bucket room_versions 同生命周期,最多 90 天 90 天后 pg_cron 把 private/ 转码已成功的版本归档清除(保留 canonical.glb 即可服务)
canonical.glb / thumbnail.webp(公共 bucket room_versions 房间硬删 cascade;用户注销 T+30 硬删
redactions[] 表行 room_versions 同 cascade 同上
rooms / room_versions / layers 永久(除非用户删除) 用户主动删除 / 注销 T+30 / 严重违规封禁 T+7 内有效;T+30 后
comments / likes 永久 评论/点赞作者主动删;房间 cascade 删
remixes(已发表) 永久 Remix 作者主动删;父房间走 P-W-3 快照转移流(10_governance.md §4
草稿 Remixis_public=false 30 天未更新自动清理 pg_cron 扫 updated_at < now() - 30d
location_label(独立字段) 跟随 rooms 用户可单独 UPDATE NULL(§3.3
审计日志(Edge Function logs 90 天 Supabase 平台默认
Sentry 事件 90 天 Sentry 项目 retention 配置
PostHog 事件 7 年(默认)→ 调整为 13 个月 PostHog project setting 强制下调
Worker 日志(private/.../transcode.log 30 天 pg_cron 扫 Storage 元数据
view_states 表(若引入) 90 天 pg_cron
reports 举报记录 永久(已结案 6 个月后归档为只读) 不删除(治理需要追溯) 仅 owner-team 可见
用户账号注销 T+0 软删 / T+7 不可撤 / T+30 硬删 §4 P-4 流程 T+0T+7 ,之后

9. 第三方 SDK 风险清单

SDK 拿到什么数据 数据出域吗 是否 GDPR 友好 SCC 状态 我们的额外动作
SupabasePostgres / Auth / Storage / Realtime 全部业务数据(DB 行 + 文件 + 鉴权 token 是(其 AWS us-east-1 主机房) 官方有 GDPR DPA + SCC MVP 即签 启用 Supabase Vault 加密 service_role;按 §8 保留期清理
SentryiOS + Browser + Server 崩溃堆栈 + breadcrumb + 用户邮箱(仅 issue 关联) 是(Sentry SaaS SOC 2 + GDPR DPA MVP 即签 beforeSend 过滤 PIIbreadcrumb 中 viewState 替换为 [REDACTED](§5 P-W-7
PostHog Cloud(事件分析) 用户事件 + funnel + feature flag 评估 是(PostHog EU / US 双区可选) 选 EU 区即数据不离欧 MVP 即签 强制 opt-inC-3 Cookie 通知);关闭 Session Replay;保留期下调至 13 个月
CloudFlareCDN + DNS 公开静态资源访问日志(IP + UA 是(全球边缘节点) GDPR DPA MVP 即签 不缓存私有 bucket;启用 CF Bot Fight Mode 防爬
VercelWeb 部署 + Edge Function 请求 IP + UA + 路径 是(全球边缘) GDPR DPA MVP 即签 Edge Function 内禁用 console.log 用户级数据;分析数据保留期默认
Apple Sign in with Apple Apple ID 关联 token 否(Apple 直接给 token,不持有原始 Apple ID Apple 平台原生 n/a 接受 Apple Hidden Email 默认行为
Google OAuth(仅 Web /login Google 用户 sub + 邮箱 否(OAuth 标准 token 交换) Google Workspace DPA 适用 通过 Supabase Auth 中转,无直接合同
MetricKitiOS 系统) 设备性能指标(CPU/GPU/热量) 否(仅 App 内消费) Apple 原生 n/a

底线:除上表 8 项外,MVP 不接任何第三方 SDK。若运营提出新接入需求(如客服系统 Intercom、推送 OneSignal),必须先把该 SDK 加入本表并签 SCC 才可上线——这是 PR-2 的硬执行点。


10. 本章小结

关键产出 一句话
5 条隐私原则 PR-1 ~ PR-5 端侧优先脱敏 / 最小采集 / 用户可控 / 默认私有 / 可被遗忘——任何冲突按编号优先
数据流隐私视图 红黄绿三色 + 第三方可访问性双标签,红色节点永不离设备/Supabase 内网
三类敏感数据生命周期 人脸端侧不可逆模糊 + 地标/文档手动框选 + 位置永远城市级 5 km
6 条 iOS 契约 P-1 ~ P-6 端侧失败不破例 / redactions owner-only / 城市标签公开 / 30 天硬删 / ATT 触发条件 3 项 / 13+ 单按钮确认
3 条 Web 契约 P-W-1 / P-W-2 / P-W-7 viewState 不泄漏几何 / unlisted 双重 SEO 阻断 / viewState 视作偏好数据强 hash
GDPR + PIPL 合规清单 8 项 MVP 必做(含 Apple PrivacyManifest+ 6 项 P2
隐私默认值表 16 项开关,全部朝最严方向;端侧脱敏与 mic 关、email 不公开 = 永不可改
数据保留时间表 15 类数据,原始 .usdz 90 天 / Sentry-PostHog 调至 13 个月 / 注销 30 天硬删
8 个第三方 SDK 风险点 全数有 GDPR DPA 与 SCC 模板可签;不允许 MVP 期内新增

读完本章你应能:

  • 给隐私律师一份可直接审阅的数据处理映射(§2 数据流图 + §3 生命周期 + §9 SDK)
  • 给 iOS / Web 工程师 P-1 ~ P-6、P-W-1 / P-W-2 / P-W-7 共 9 条契约的拍板答案
  • 知道 10_governance.md 在哪几节继续处理治理类 P-W-3 ~ P-W-6

章节版本v0.1 · 草案 关键收获:CrowdRoom 把隐私风险压缩到「用户主动框选发布」这一个决策点上——前置的端侧脱敏让原始 RGB 永不出设备、后置的 4 层 manifest 让公开数据只剩几何与材质;GDPR + PIPL 合规以「MVP 必做 8 项 + 第三方 SDK 全签 SCC」最小集即可上线。