跳转至

ADR-0011 · 多用户边界:私有表带 user_id,共享表不带

背景(Context)

现状 user_skill.user_id 是裸字符串,没有 user 表、没有认证、没有隔离。一旦真多人用: company.slugposition.fingerprintskill.slug 的唯一约束全部失效;每个查询都要加租户过滤,漏一个就是串号级事故。 事后补租户列是数据库改造里最贵的一类。

决策(Decision)

  • 私有表(「我」的活动与状态)每张带 user_id / owner_idconversationchat_messagechat_segmenteventfactapplicationinterviewexperienceexperience_sourceuser_skilldocument_versiondocument_version_experiencedocument_version_factresume_assetnotememoryremindernudge
  • 共享表(跨用户的真实世界实体 / 词表)不带 user_iduser(账户)、personorganizationoccupationskillskill_aliaslocationlocation_aliasjob_posting
  • 认证后置:现在先加 user_id 列 + 复合唯一约束(UNIQUE(user_id, slug)),用固定默认用户,暂不接登录。

理由与代价(Consequences)

  • ✅ 现在加列几乎零成本;共享词表天然跨用户复用。
  • ✅ 明确边界,避免"哪些表要过滤"的歧义。
  • ❌ 每个私有表查询都要带 user_id 过滤(用 repository 基类统一处理)。

备选方案(Alternatives)

  • 完全单用户,将来整库迁移:省当下事,但那次迁移要动每张表、每个查询、每个唯一约束。
  • 一人一库(DB-per-user):隔离最彻底,但迁移要对 N 个库执行,跨用户共享技能词表无处安放。