Files
Inbox/Go项目实战/用户模块/01_实体关系图.md

112 lines
5.1 KiB
Markdown
Raw Normal View History

2025-12-11 07:24:36 +08:00
---
tags: []
aliases:
- ER 图
date created: 星期二, 十二月 9日 2025, 10:45:43 晚上
date modified: 星期二, 十二月 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)
```mermaid
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_id``parent_token_id` 用于检测令牌复用攻击。如果一个旧的 RT 被使用,系统可以根据 `family_id` 级联作废整个令牌链。
2. **Users `}|--|{` Roles (多 对 多,通过 `user_roles`):**
- **业务含义:** 虽然 PRD 定义了三个层级,但物理模型采用“多对多”设计是架构上的**防御性编程**。
- **场景:** 如果未来需要赋予某个 Editor 临时的 Admin 权限,或者创建一个 "SuperSubscriber"(付费会员),我们只需在 `user_roles` 插入一条记录,而无需修改表结构。
3. **Users 表的混合设计:**
- **决策:** 我没有将 `Profile` (昵称/头像) 拆分为独立表。
- **理由:** 遵循“勿增实体”原则。在当前 V1 阶段Profile 字段较少(仅 3 个),且在列表页展示时(如“评论列表”)属于高频连表查询。合并不仅减少了 JOIN 开销,也简化了 GORM 的模型编写。