112 lines
5.1 KiB
Markdown
112 lines
5.1 KiB
Markdown
---
|
||
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 的模型编写。
|