Features - User Management (Phase 4.1): - Database: Add user_modules table for fine-grained module permissions - Database: Add 4 user permissions (view/create/edit/delete) to role_permissions - Backend: UserService (780 lines) - CRUD with tenant isolation - Backend: UserController + UserRoutes (648 lines) - 13 API endpoints - Backend: Batch import users from Excel - Frontend: UserListPage (412 lines) - list/filter/search/pagination - Frontend: UserFormPage (341 lines) - create/edit with module config - Frontend: UserDetailPage (393 lines) - details/tenant/module management - Frontend: 3 modal components (592 lines) - import/assign/configure - API: GET/POST/PUT/DELETE /api/admin/users/* endpoints Architecture Upgrade - Module Permission System: - Backend: Add getUserModules() method in auth.service - Backend: Login API returns modules array in user object - Frontend: AuthContext adds hasModule() method - Frontend: Navigation filters modules based on user.modules - Frontend: RouteGuard checks requiredModule instead of requiredVersion - Frontend: Remove deprecated version-based permission system - UX: Only show accessible modules in navigation (clean UI) - UX: Smart redirect after login (avoid 403 for regular users) Fixes: - Fix UTF-8 encoding corruption in ~100 docs files - Fix pageSize type conversion in userService (String to Number) - Fix authUser undefined error in TopNavigation - Fix login redirect logic with role-based access check - Update Git commit guidelines v1.2 with UTF-8 safety rules Database Changes: - CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled) - ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code) - INSERT 4 permissions + role assignments - UPDATE PUBLIC tenant with 8 module subscriptions Technical: - Backend: 5 new files (~2400 lines) - Frontend: 10 new files (~2500 lines) - Docs: 1 development record + 2 status updates + 1 guideline update - Total: ~4900 lines of code Status: User management 100% complete, module permission system operational
510 lines
11 KiB
Markdown
510 lines
11 KiB
Markdown
# 数据库设计规范
|
||
|
||
> **版本:** v2.0
|
||
> **最后更新:** 2025-11-06
|
||
> **数据库:** PostgreSQL 15+
|
||
> **ORM:** Prisma
|
||
> **适用范围:** 平台层 + 能力层 + 业务模块层
|
||
|
||
---
|
||
|
||
## 📋 核心原则
|
||
|
||
本规范是所有模块数据库设计的基础规范,必须严格遵守。
|
||
|
||
**设计原则:**
|
||
- ✅ 遵循第三范式(3NF)
|
||
- ✅ 使用SERIAL作为主键(整数自增,性能更好)
|
||
- ✅ 所有表包含created_at和updated_at时间戳
|
||
- ✅ 重要表使用软删除(保留deleted_at字段)
|
||
- ✅ 外键约束使用ON DELETE CASCADE
|
||
- ✅ 敏感字段加密存储(密码使用bcrypt)
|
||
|
||
---
|
||
|
||
## 🏗️ Schema隔离策略 ⭐ 最重要
|
||
|
||
### 为什么需要Schema隔离
|
||
|
||
**核心原因:**
|
||
1. ✅ **模块独立性**:每个业务模块有独立的Schema
|
||
2. ✅ **支持独立部署**:可以单独导出某个模块的数据
|
||
3. ✅ **支持独立销售**:可以单独交付某个模块
|
||
4. ✅ **权限隔离**:可以为不同Schema设置不同权限
|
||
5. ✅ **避免命名冲突**:不同模块可以有相同的表名
|
||
|
||
### Schema命名规范
|
||
|
||
```
|
||
platform_schema # 平台基础层(全局共享)
|
||
aia_schema # AI智能问答
|
||
asl_schema # AI智能文献
|
||
pkb_schema # 个人知识库
|
||
dc_schema # 数据清洗整理
|
||
ssa_schema # 智能统计分析
|
||
st_schema # 统计分析工具
|
||
rvw_schema # 稿件审查系统
|
||
```
|
||
|
||
### Schema创建
|
||
|
||
```sql
|
||
-- 创建Schema
|
||
CREATE SCHEMA IF NOT EXISTS platform_schema;
|
||
CREATE SCHEMA IF NOT EXISTS asl_schema;
|
||
CREATE SCHEMA IF NOT EXISTS aia_schema;
|
||
-- ...其他Schema
|
||
```
|
||
|
||
### 跨Schema依赖规则 ⭐ 必须遵守
|
||
|
||
**允许的依赖:**
|
||
```sql
|
||
-- ✅ 允许:业务模块引用platform_schema
|
||
CREATE TABLE asl_schema.literature_projects (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INTEGER REFERENCES platform_schema.users(id) ON DELETE CASCADE,
|
||
...
|
||
);
|
||
|
||
-- ✅ 允许:通用能力引用platform_schema
|
||
CREATE TABLE platform_schema.llm_usage (
|
||
id SERIAL PRIMARY KEY,
|
||
user_id INTEGER REFERENCES platform_schema.users(id) ON DELETE CASCADE,
|
||
...
|
||
);
|
||
```
|
||
|
||
**禁止的依赖:**
|
||
```sql
|
||
-- ❌ 禁止:业务模块之间互相引用
|
||
CREATE TABLE ssa_schema.analysis_projects (
|
||
id SERIAL PRIMARY KEY,
|
||
-- 错误!不能引用其他业务模块
|
||
literature_project_id INTEGER REFERENCES asl_schema.literature_projects(id)
|
||
);
|
||
|
||
-- ❌ 禁止:platform_schema反向依赖业务模块
|
||
CREATE TABLE platform_schema.users (
|
||
id SERIAL PRIMARY KEY,
|
||
-- 错误!platform_schema不能依赖业务模块
|
||
current_project_id INTEGER REFERENCES asl_schema.literature_projects(id)
|
||
);
|
||
```
|
||
|
||
**正确做法:**
|
||
```
|
||
跨模块数据关联在应用层处理,不在数据库层!
|
||
|
||
方式1:通过user_id关联
|
||
- 两个模块都引用platform_schema.users
|
||
- 在应用层通过user_id查询两个模块的数据
|
||
- 在应用层组装数据
|
||
|
||
方式2:存储业务ID字符串
|
||
- 在表中存储其他模块的业务ID(VARCHAR)
|
||
- 不建立外键关系
|
||
- 在应用层验证ID的有效性
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 命名规范
|
||
|
||
### 表命名
|
||
|
||
**规则:**
|
||
- 小写字母
|
||
- 下划线分隔
|
||
- 复数形式
|
||
- Schema前缀(查询时使用)
|
||
|
||
**示例:**
|
||
```sql
|
||
-- ✅ 正确
|
||
CREATE TABLE asl_schema.literature_projects (...);
|
||
CREATE TABLE platform_schema.users (...);
|
||
CREATE TABLE pkb_schema.knowledge_bases (...);
|
||
|
||
-- ❌ 错误
|
||
CREATE TABLE ASLSchema.LiteratureProject (...); -- 驼峰
|
||
CREATE TABLE asl_schema.project (...); -- 单数
|
||
CREATE TABLE literature-projects (...); -- 使用连字符
|
||
```
|
||
|
||
### 字段命名
|
||
|
||
**规则:**
|
||
- 小写字母
|
||
- 下划线分隔
|
||
- 语义清晰
|
||
|
||
**示例:**
|
||
```sql
|
||
-- ✅ 正确
|
||
user_id
|
||
created_at
|
||
project_name
|
||
is_active
|
||
|
||
-- ❌ 错误
|
||
userId -- 驼峰
|
||
createdat -- 没有下划线
|
||
prjName -- 缩写不清晰
|
||
```
|
||
|
||
### 索引命名
|
||
|
||
**规则:** `idx_表名_字段名`
|
||
|
||
**示例:**
|
||
```sql
|
||
-- ✅ 正确
|
||
CREATE INDEX idx_users_email ON platform_schema.users(email);
|
||
CREATE INDEX idx_projects_user_id ON asl_schema.literature_projects(user_id);
|
||
CREATE INDEX idx_projects_user_status ON asl_schema.literature_projects(user_id, status);
|
||
|
||
-- ❌ 错误
|
||
CREATE INDEX user_email_idx ... -- 顺序错误
|
||
CREATE INDEX index_on_email ... -- 名称不清晰
|
||
```
|
||
|
||
### 外键命名
|
||
|
||
**规则:** `fk_表名_关联表名`
|
||
|
||
**示例:**
|
||
```sql
|
||
-- ✅ 正确
|
||
CONSTRAINT fk_projects_users
|
||
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id);
|
||
|
||
CONSTRAINT fk_items_projects
|
||
FOREIGN KEY (project_id) REFERENCES asl_schema.literature_projects(id);
|
||
|
||
-- ❌ 错误
|
||
CONSTRAINT user_fk ... -- 名称不清晰
|
||
CONSTRAINT foreign_key_users ... -- 太长
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 通用字段 ⭐ 必须包含
|
||
|
||
### 所有表必须包含
|
||
|
||
```sql
|
||
CREATE TABLE xxx_schema.table_name (
|
||
-- 主键(必须)
|
||
id SERIAL PRIMARY KEY,
|
||
|
||
-- 业务字段
|
||
...
|
||
|
||
-- 时间戳(必须)
|
||
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
|
||
updated_at TIMESTAMP DEFAULT NOW() NOT NULL
|
||
);
|
||
```
|
||
|
||
### 重要表应包含(软删除)
|
||
|
||
```sql
|
||
CREATE TABLE xxx_schema.important_table (
|
||
id SERIAL PRIMARY KEY,
|
||
|
||
-- 业务字段
|
||
...
|
||
|
||
-- 软删除字段(可选,重要表建议添加)
|
||
deleted_at TIMESTAMP,
|
||
|
||
-- 时间戳(必须)
|
||
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
|
||
updated_at TIMESTAMP DEFAULT NOW() NOT NULL
|
||
);
|
||
|
||
-- 查询时过滤已删除数据
|
||
SELECT * FROM xxx_schema.important_table WHERE deleted_at IS NULL;
|
||
```
|
||
|
||
### 用户关联表必须包含
|
||
|
||
```sql
|
||
CREATE TABLE xxx_schema.user_related_table (
|
||
id SERIAL PRIMARY KEY,
|
||
|
||
-- 用户外键(必须)
|
||
user_id INTEGER REFERENCES platform_schema.users(id) ON DELETE CASCADE NOT NULL,
|
||
|
||
-- 业务字段
|
||
...
|
||
|
||
-- 时间戳(必须)
|
||
created_at TIMESTAMP DEFAULT NOW() NOT NULL,
|
||
updated_at TIMESTAMP DEFAULT NOW() NOT NULL
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 索引设计规范
|
||
|
||
### 必须添加索引的字段
|
||
|
||
**1. 主键**
|
||
```sql
|
||
-- 自动创建,无需手动添加
|
||
id SERIAL PRIMARY KEY
|
||
```
|
||
|
||
**2. 外键字段**
|
||
```sql
|
||
-- 必须添加,提高JOIN性能
|
||
CREATE INDEX idx_projects_user_id ON asl_schema.literature_projects(user_id);
|
||
```
|
||
|
||
**3. 常用查询字段**
|
||
```sql
|
||
-- status(状态字段,常用于WHERE)
|
||
CREATE INDEX idx_projects_status ON asl_schema.literature_projects(status);
|
||
|
||
-- created_at(时间字段,常用于排序)
|
||
CREATE INDEX idx_projects_created_at ON asl_schema.literature_projects(created_at DESC);
|
||
```
|
||
|
||
**4. 唯一约束字段**
|
||
```sql
|
||
-- email等唯一字段
|
||
CREATE UNIQUE INDEX idx_users_email ON platform_schema.users(email);
|
||
```
|
||
|
||
### 复合索引
|
||
|
||
**规则:**
|
||
- 高频组合查询使用复合索引
|
||
- 最常查询的字段放在前面
|
||
- 复合索引最多3个字段
|
||
|
||
**示例:**
|
||
```sql
|
||
-- ✅ 正确:user_id + status 组合查询
|
||
CREATE INDEX idx_projects_user_status
|
||
ON asl_schema.literature_projects(user_id, status);
|
||
|
||
-- 可以优化以下查询:
|
||
-- WHERE user_id = ? AND status = ?
|
||
-- WHERE user_id = ? (只用前缀)
|
||
|
||
-- ❌ 错误:字段过多
|
||
CREATE INDEX idx_projects_complex
|
||
ON asl_schema.literature_projects(user_id, status, created_at, updated_at);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 外键约束规范
|
||
|
||
### ON DELETE策略
|
||
|
||
**规则:**
|
||
```sql
|
||
-- 用户删除时,级联删除关联数据
|
||
FOREIGN KEY (user_id)
|
||
REFERENCES platform_schema.users(id)
|
||
ON DELETE CASCADE;
|
||
|
||
-- 父记录删除时,级联删除子记录
|
||
FOREIGN KEY (project_id)
|
||
REFERENCES asl_schema.literature_projects(id)
|
||
ON DELETE CASCADE;
|
||
|
||
-- 特殊情况:不能删除
|
||
FOREIGN KEY (parent_id)
|
||
REFERENCES xxx_schema.parent_table(id)
|
||
ON DELETE RESTRICT; -- 有子记录时禁止删除
|
||
```
|
||
|
||
### 外键索引
|
||
|
||
**规则:** 所有外键必须添加索引
|
||
|
||
```sql
|
||
-- 创建外键
|
||
ALTER TABLE asl_schema.literature_items
|
||
ADD CONSTRAINT fk_items_projects
|
||
FOREIGN KEY (project_id) REFERENCES asl_schema.literature_projects(id)
|
||
ON DELETE CASCADE;
|
||
|
||
-- 必须添加索引
|
||
CREATE INDEX idx_items_project_id ON asl_schema.literature_items(project_id);
|
||
```
|
||
|
||
---
|
||
|
||
## ⚡ 性能优化规范
|
||
|
||
### 大表分区(可选)
|
||
|
||
**适用场景:** 年增长 > 100万记录
|
||
|
||
```sql
|
||
-- 按月分区(如llm_usage表)
|
||
CREATE TABLE platform_schema.llm_usage (
|
||
id SERIAL,
|
||
user_id INTEGER NOT NULL,
|
||
created_at TIMESTAMP NOT NULL,
|
||
...
|
||
) PARTITION BY RANGE (created_at);
|
||
|
||
-- 创建分区
|
||
CREATE TABLE platform_schema.llm_usage_2025_11
|
||
PARTITION OF platform_schema.llm_usage
|
||
FOR VALUES FROM ('2025-11-01') TO ('2025-12-01');
|
||
```
|
||
|
||
### 数据归档策略
|
||
|
||
```sql
|
||
-- 历史数据归档(如1年前的日志)
|
||
CREATE TABLE platform_schema.admin_logs_archive (
|
||
LIKE platform_schema.admin_logs INCLUDING ALL
|
||
);
|
||
|
||
-- 定期归档
|
||
INSERT INTO platform_schema.admin_logs_archive
|
||
SELECT * FROM platform_schema.admin_logs
|
||
WHERE created_at < NOW() - INTERVAL '1 year';
|
||
|
||
DELETE FROM platform_schema.admin_logs
|
||
WHERE created_at < NOW() - INTERVAL '1 year';
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 安全规范
|
||
|
||
### 敏感字段加密
|
||
|
||
```sql
|
||
-- 密码字段
|
||
password VARCHAR(255) NOT NULL -- 使用bcrypt加密,存储哈希值
|
||
|
||
-- API Key字段
|
||
api_key_encrypted TEXT NOT NULL -- 使用AES-256加密
|
||
|
||
-- 个人敏感信息
|
||
phone_encrypted VARCHAR(255) -- 手机号加密
|
||
id_card_encrypted VARCHAR(255) -- 身份证号加密
|
||
```
|
||
|
||
### 数据脱敏
|
||
|
||
```sql
|
||
-- 日志中不记录敏感字段
|
||
-- 开发/测试环境使用脱敏数据
|
||
UPDATE platform_schema.users
|
||
SET
|
||
email = CONCAT('user', id, '@example.com'),
|
||
phone = '138****0000'
|
||
WHERE environment = 'development';
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 数据类型选择
|
||
|
||
### 常用字段类型
|
||
|
||
| 用途 | 推荐类型 | 说明 |
|
||
|------|---------|------|
|
||
| 主键 | SERIAL | 整数自增 |
|
||
| 外键 | INTEGER | 与主键类型一致 |
|
||
| 短文本 | VARCHAR(N) | N<500,如姓名、标题 |
|
||
| 长文本 | TEXT | 无长度限制,如描述、内容 |
|
||
| 布尔值 | BOOLEAN | true/false |
|
||
| 日期时间 | TIMESTAMP | 精确到毫秒 |
|
||
| 金额 | DECIMAL(10,2) | 避免精度问题 |
|
||
| JSON | JSONB | 支持索引,性能更好 |
|
||
|
||
### 字段长度建议
|
||
|
||
```sql
|
||
-- 短文本
|
||
name VARCHAR(100) -- 姓名
|
||
title VARCHAR(200) -- 标题
|
||
email VARCHAR(255) -- 邮箱
|
||
phone VARCHAR(20) -- 手机号
|
||
|
||
-- 状态枚举
|
||
status VARCHAR(20) -- active, inactive, deleted
|
||
role VARCHAR(20) -- user, admin
|
||
|
||
-- 长文本
|
||
description TEXT -- 描述
|
||
content TEXT -- 内容
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 检查清单
|
||
|
||
**设计新表时必须检查:**
|
||
- [ ] 表名符合命名规范(小写+下划线+复数)
|
||
- [ ] 使用正确的Schema(platform/aia/asl/pkb等)
|
||
- [ ] 包含id主键(SERIAL PRIMARY KEY)
|
||
- [ ] 包含created_at和updated_at时间戳
|
||
- [ ] 用户关联表包含user_id外键
|
||
- [ ] 所有外键都有ON DELETE策略
|
||
- [ ] 所有外键都添加了索引
|
||
- [ ] 常用查询字段添加了索引
|
||
- [ ] 外键约束符合跨Schema依赖规则
|
||
- [ ] 敏感字段已加密存储
|
||
|
||
---
|
||
|
||
## 🔗 相关文档
|
||
|
||
**总览:**
|
||
- [数据库全局视图](./03-数据库全局视图.md) ⭐ 查看所有Schema和表
|
||
|
||
**模板:**
|
||
- [数据库设计模板](../_templates/数据库设计-模板.md)
|
||
|
||
**各模块设计:**
|
||
- [平台基础层](../01-平台基础层/README.md)
|
||
- [通用能力层](../02-通用能力层/README.md)
|
||
- [业务模块层](../03-业务模块/README.md)
|
||
|
||
---
|
||
|
||
**最后更新:** 2025-11-06
|
||
**维护人:** 技术架构师
|
||
**版本:** v2.0
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|