Files
Inbox/Go项目实战/用户模块/01_实体关系图.md
2025-12-11 07:24:36 +08:00

5.1 KiB
Raw Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
ER 图
星期二, 十二月 9日 2025, 10:45:43 晚上 星期二, 十二月 9日 2025, 10:58:01 晚上

ER 图

设计思路分析:

  1. RBAC 模型选择: 为了满足“银行级权限控制”及“企业级样板间”的扩展性要求,我采用了标准的 RBAC Level 1 (Flat RBAC) 变体。虽然当前只有 3 个固定角色,但使用 多对多 (Many-to-Many) 的关联表 (user_roles) 能够支持未来某用户既是 "Editor" 又是 "TechLeader" 的混合权限场景,避免后续重构。
  2. 双令牌机制落地: 专门设计了 refresh_tokens 表。JWT 的 Access Token 是无状态的(不入库),但 Refresh Token 必须入库以实现“吊销”、“防重放”和“设备管理”功能。
  3. 软删除与审计: 所有核心表(users, roles)均继承了 Base Model包含 deleted_at 字段。

📊 阶段二:概念验证 (Conceptual Modeling - ER Diagram)

erDiagram
    %% ---------------------------------------------------------
    %% 1. 用户核心表 (Users)
    %% 核心聚合根,包含认证凭证与个人资料
    %% ---------------------------------------------------------
    users {
        bigint id PK "主键"
        string username "用户名, unique, not null"
        string password_hash "Argon2/Bcrypt 哈希值, not null"
        string nickname "用户昵称 (Profile)"
        string avatar_url "头像链接 (Profile)"
        string bio "个人简介 (Profile)"
        smallint status "状态: 1=Active, 0=Banned"
        timestamptz created_at "创建时间"
        timestamptz updated_at "更新时间"
        timestamptz deleted_at "软删除时间 (Soft Delete)"
    }

    %% ---------------------------------------------------------
    %% 2. 角色表 (Roles)
    %% 存储 Admin, Editor, Subscriber 等定义
    %% ---------------------------------------------------------
    roles {
        bigint id PK "主键"
        string code "角色编码 (e.g. 'admin'), unique"
        string name "角色显示名称 (e.g. '超级管理员')"
        string description "备注"
        timestamptz created_at
        timestamptz updated_at
        timestamptz deleted_at
    }

    %% ---------------------------------------------------------
    %% 3. 用户-角色关联表 (User Roles)
    %% 中间表,实现 RBAC 多对多关系
    %% ---------------------------------------------------------
    user_roles {
        bigint user_id FK "关联 users.id"
        bigint role_id FK "关联 roles.id"
        timestamptz created_at
    }

    %% ---------------------------------------------------------
    %% 4. 刷新令牌表 (Refresh Tokens)
    %% 用于双令牌机制的续期与风控
    %% ---------------------------------------------------------
    refresh_tokens {
        bigint id PK "主键"
        bigint user_id FK "关联 users.id"
        string token_hash "Refresh Token 的哈希值 (安全考虑不存明文)"
        string family_id "令牌家族ID (用于检测重用/Rotation)"
        string parent_token_id "父令牌ID (用于溯源)"
        boolean is_revoked "是否已撤销 (黑名单机制)"
        timestamptz expires_at "过期时间 (7天)"
        timestamptz created_at
    }

    %% ---------------------------------------------------------
    %% 关系定义 (Relationships)
    %% ---------------------------------------------------------
    
    %% 一个用户可以拥有多个 Refresh Token (多设备登录)
    users ||--o{ refresh_tokens : "has_many (sessions)"

    %% 一个用户可以拥有多个角色 (扩展性设计)
    users ||--o{ user_roles : "assigned_to"
    
    %% 一个角色可以包含多个用户
    roles ||--o{ user_roles : "includes"

🔑 关键关系业务含义说明

  1. Users ||--o{ Refresh Tokens (1 对 多):

    • 业务含义: 一个用户可以在多个设备手机、PC同时登录。
    • 风控逻辑: 当用户执行“修改密码”或“严重违规封号”时,后端会根据 user_id 批量将该用户下的所有 is_revoked 设为 true,从而实现强制下线
    • 令牌轮转: family_idparent_token_id 用于检测令牌复用攻击。如果一个旧的 RT 被使用,系统可以根据 family_id 级联作废整个令牌链。
  2. Users }|--|{ Roles (多 对 多,通过 user_roles):

    • 业务含义: 虽然 PRD 定义了三个层级,但物理模型采用“多对多”设计是架构上的防御性编程
    • 场景: 如果未来需要赋予某个 Editor 临时的 Admin 权限,或者创建一个 "SuperSubscriber"(付费会员),我们只需在 user_roles 插入一条记录,而无需修改表结构。
  3. Users 表的混合设计:

    • 决策: 我没有将 Profile (昵称/头像) 拆分为独立表。
    • 理由: 遵循“勿增实体”原则。在当前 V1 阶段Profile 字段较少(仅 3 个),且在列表页展示时(如“评论列表”)属于高频连表查询。合并不仅减少了 JOIN 开销,也简化了 GORM 的模型编写。