feat(admin): Add user management and upgrade to module permission system

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
This commit is contained in:
2026-01-16 13:42:10 +08:00
parent 98d862dbd4
commit 66255368b7
560 changed files with 70424 additions and 52353 deletions

View File

@@ -1,4 +1,4 @@
# <EFBFBD>唳旿摨枏<EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD>?
# 数据库开发规范
> 版本: v1.0
> 更新日期: 2026-01-11
@@ -14,27 +14,27 @@
⚠️ 黄金法则:任何数据库操作前,必须先备份!
```
### 1.2 <EFBFBD>迫雿輻鍂<EFBFBD><EFBFBD><EFBFBD>拙𦶢隞?
### 1.2 禁止使用的危险命令
| 命令 | 危险等级 | 说明 |
|------|----------|------|
| `prisma db push --force-reset` | <EFBFBD>𣞁 **<EFBFBD><EFBFBD><EFBFBD>** | 隡𡁜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇㺭<EFBFBD><EFBFBD><EFBFBD>鱲risma蝞∠<EFBFBD><EFBFBD><EFBFBD>笆鞊?|
| `prisma migrate reset` | <EFBFBD>𣞁 **<EFBFBD><EFBFBD><EFBFBD>** | <EFBFBD>滨蔭<EFBFBD>港葵<EFBFBD>唳旿摨?|
| `DROP DATABASE` | <EFBFBD>𣞁 **<EFBFBD><EFBFBD><EFBFBD>** | <EFBFBD>𣳇膄<EFBFBD>港葵<EFBFBD>唳旿摨?|
| `TRUNCATE TABLE` | <EFBFBD><EFBFBD> 擃?| 皜<>征銵冽㺭<E586BD>?|
| `prisma db push --force-reset` | 🔴 **极高** | 会删除所有数据和非Prisma管理的对象 |
| `prisma migrate reset` | 🔴 **极高** | 重置整个数据库 |
| `DROP DATABASE` | 🔴 **极高** | 删除整个数据库 |
| `TRUNCATE TABLE` | 🟠 高 | 清空表数据 |
### 1.3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>典𦶢隞?
### 1.3 推荐的安全命令
| <EFBFBD>賭誘 | <20><EFBFBD>?| 摰匧<E691B0><E58CA7>?|
| 命令 | 用途 | 安全性 |
|------|------|--------|
| `prisma migrate dev` | <EFBFBD><EFBFBD>𤑳㴓憓<EFBFBD><EFBFBD>蝘?| <20>?摰匧<E691B0> |
| `prisma migrate deploy` | <EFBFBD>煺漣<EFBFBD><EFBFBD><EFBFBD>宏 | <20>?摰匧<E691B0> |
| `prisma db push` (<EFBFBD>?--force-reset) | <EFBFBD>峕郊schema<EFBFBD>唳㺭<EFBFBD><EFBFBD> | <20>𩤃<EFBFBD> 靚冽<E99D9A>雿輻鍂 |
| `prisma generate` | <EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝡?| <20>?摰匧<E691B0> |
| `prisma migrate dev` | 开发环境迁移 | ✅ 安全 |
| `prisma migrate deploy` | 生产环境迁移 | ✅ 安全 |
| `prisma db push` (--force-reset) | 同步schema到数据库 | ⚠️ 谨慎使用 |
| `prisma generate` | 生成客户端 | ✅ 安全 |
---
## 2. <EFBFBD>唳旿摨枏<EFBFBD>隞質<EFBFBD><EFBFBD>?
## 2. 数据库备份规范
### 2.1 备份命令
@@ -51,11 +51,11 @@ docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > "
| 时机 | 是否必须 |
|------|----------|
| <EFBFBD><EFBFBD>隞颱<EFBFBD> `prisma migrate` <EFBFBD>?| <20>?敹<> |
| <EFBFBD><EFBFBD> `prisma db push` <EFBFBD>?| <20>?敹<> |
| <EFBFBD>函蔡<EFBFBD><EFBFBD>鈭抒㴓憓<EFBFBD><EFBFBD> | <20>?敹<> |
| 瘥𤩺𠯫<EFBFBD>芸𢆡憭<EFBFBD>遢 | <20>?<3F><EFBFBD> |
| <EFBFBD>滚之<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?| <20>?敹<> |
| 执行任何 `prisma migrate` 前 | ✅ 必须 |
| 执行 `prisma db push` 前 | ✅ 必须 |
| 部署到生产环境前 | ✅ 必须 |
| 每日自动备份 | ✅ 推荐 |
| 重大功能发布前 | ✅ 必须 |
### 2.3 备份文件管理
@@ -87,7 +87,7 @@ graph TD
### 3.2 具体步骤
```bash
# 1. <EFBFBD><EFBFBD>唳旿摨?
# 1. 备份数据库
docker exec ai-clinical-postgres pg_dump -U postgres -d ai_clinical_research > backup_before_migration.sql
# 2. 修改 schema.prisma
@@ -100,36 +100,36 @@ cat prisma/migrations/xxx_describe_your_change/migration.sql
# 5. 测试
# 6. <EFBFBD><EFBFBD>憭梯揖嚗峕<EFBFBD>憭滚<EFBFBD>隞?
# 6. 如果失败,恢复备份
cat backup_before_migration.sql | docker exec -i ai-clinical-postgres psql -U postgres -d ai_clinical_research
```
---
## 4. Prisma 銝擧㺭<EFBFBD><EFBFBD>銝滢<EFBFBD><EFBFBD>湧䔮憸?
## 4. Prisma 与数据库不一致问题
### 4.1 Prisma 不管理的对象
隞乩<EFBFBD><EFBFBD>唳旿摨枏笆鞊∩<EFBFBD><EFBFBD>?`schema.prisma` 銝剖<EFBFBD>銋㚁<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祉恣<EFBFBD><EFBFBD><EFBFBD>
以下数据库对象不在 `schema.prisma` 中定义,需要单独管理:
| 对象 | 类型 | 来源 | 恢复脚本 |
|------|------|------|----------|
| `platform_schema.job_common` | 銵?| pg-boss 餈鞱<EFBFBD><EFBFBD><EFBFBD>撱?| `restore_job_common.sql` |
| `platform_schema.create_queue()` | <EFBFBD>賣㺭 | pg-boss <EFBFBD><EFBFBD><EFBFBD>?| `restore_pgboss_functions.sql` |
| `platform_schema.delete_queue()` | <EFBFBD>賣㺭 | pg-boss <EFBFBD><EFBFBD><EFBFBD>?| `restore_pgboss_functions.sql` |
| `platform_schema.job_common` | | pg-boss 运行时创建 | `restore_job_common.sql` |
| `platform_schema.create_queue()` | 函数 | pg-boss 初始化 | `restore_pgboss_functions.sql` |
| `platform_schema.delete_queue()` | 函数 | pg-boss 初始化 | `restore_pgboss_functions.sql` |
### 4.2 <EFBFBD><EFBFBD><EFBFBD>?Prisma 蝞∠<EFBFBD><EFBFBD><EFBFBD>笆鞊?
### 4.2 恢复非 Prisma 管理的对象
```bash
# <EFBFBD><EFBFBD>霂臬<EFBFBD>鈭?pg-boss <20><EFBFBD>撖寡情嚗峕<E59A97>銵䕘<E98AB5>
# 如果误删了 pg-boss 相关对象,执行:
npx prisma db execute --file restore_job_common.sql --schema prisma/schema.prisma
npx prisma db execute --file restore_pgboss_functions.sql --schema prisma/schema.prisma
```
### 4.3 <EFBFBD><EFBFBD>交㺭<EFBFBD><EFBFBD>銝?Prisma <EFBFBD><EFBFBD><EFBFBD>?
### 4.3 检查数据库与 Prisma 一致性
```bash
# <EFBFBD><EFBFBD><EFBFBD>唳旿摨㮖葉<EFBFBD><EFBFBD><EFBFBD>?
# 查看数据库中的函数
SELECT routine_name FROM information_schema.routines WHERE routine_schema = 'platform_schema';
# 查看数据库中的表
@@ -140,29 +140,29 @@ SELECT table_name FROM information_schema.tables WHERE table_schema = 'platform_
---
## 5. 憭?Schema <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
## 5. Schema 架构规范
### 5.1 Schema 命名规范
| Schema | <EFBFBD><EFBFBD>?| 蝷箔<E89DB7>銵?|
| Schema | 用途 | 示例表 |
|--------|------|--------|
| `platform_schema` | 平台基础设施 | users, tenants, app_cache |
| `admin_schema` | 运营管理 | admin_operation_logs |
| `aia_schema` | AI智能问答 | conversations, messages |
| `asl_schema` | <EFBFBD><EFBFBD>讃蝑偦<EFBFBD>?| screening_projects, literatures |
| `asl_schema` | 文献筛选 | screening_projects, literatures |
| `dc_schema` | 数据清洗 | dc_templates, dc_extraction_tasks |
| `pkb_schema` | 銝芯犖<EFBFBD><EFBFBD>摨?| knowledge_bases, documents |
| `pkb_schema` | 个人知识库 | knowledge_bases, documents |
| `iit_schema` | IIT项目 | projects, audit_logs |
| `rvw_schema` | 论文预审 | review_tasks |
| `capability_schema` | 通用能力 | prompt_templates |
| `public` | <EFBFBD>扳㺭<EFBFBD>?<3F>澆捆 | users (<EFBFBD>?, admin_logs |
| `public` | 旧数据/兼容 | users (旧), admin_logs |
### 5.2 銵典𦶢<EFBFBD><EFBFBD><EFBFBD>?
### 5.2 表命名规范
```
{schema_name}.{module_prefix}_{entity_name}
蝷箔<EFBFBD>嚗?
示例:
- dc_schema.dc_templates
- dc_schema.dc_extraction_tasks
- asl_schema.screening_projects
@@ -170,12 +170,12 @@ SELECT table_name FROM information_schema.tables WHERE table_schema = 'platform_
---
## 6. 憭㚚睸銝擧㺭<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
## 6. 外键与数据完整性
### 6.1 頝?Schema 憭㚚睸
### 6.1 Schema 外键
```prisma
// <EFBFBD>?甇<>嚗𡁏<E59A97>蝖格<E89D96>摰𡁜<E691B0>蝟?
// ✅ 正确:明确指定关系
model ReviewTask {
userId String @map("user_id")
user PublicUser @relation(fields: [userId], references: [id])
@@ -191,9 +191,9 @@ model PublicUser {
}
```
### 6.2 憭㚚睸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 6.2 外键指向检查
<EFBFBD>其蝙<EFBFBD>?`prisma db push` <EFBFBD>𠬍<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>格糓<EFBFBD>行迤蝖殷<EFBFBD>
在使用 `prisma db push` 后,检查外键是否正确:
```sql
SELECT
@@ -213,7 +213,7 @@ WHERE tc.constraint_type = 'FOREIGN KEY';
```bash
# 1. 停止应用
# 2. 隞𤾸<EFBFBD>隞賣<EFBFBD>憭?
# 2. 从备份恢复
cat backup_xxx.sql | docker exec -i ai-clinical-postgres psql -U postgres -d ai_clinical_research
# 3. 验证数据
@@ -222,13 +222,13 @@ npx tsx verify_system.ts
# 4. 重启应用
```
### 7.2 Schema 銝滢<EFBFBD><EFBFBD><EFBFBD>憭?
### 7.2 Schema 不一致恢复
```bash
# 1. <EFBFBD><EFBFBD>亙榆撘?
# 1. 检查差异
npx tsx compare_schema_db.ts
# 2. <EFBFBD><EFBFBD>蝻箏仃<EFBFBD><EFBFBD>笆鞊?
# 2. 恢复缺失的对象
npx prisma db execute --file restore_xxx.sql --schema prisma/schema.prisma
# 3. 验证
@@ -236,37 +236,37 @@ npx prisma db execute --file restore_xxx.sql --schema prisma/schema.prisma
---
## 8. <EFBFBD><EFBFBD>𤑳㴓憓?vs <20>煺漣<E785BA><EFBFBD>
## 8. 开发环境 vs 生产环境
### 8.1 <EFBFBD><EFBFBD>𤑳㴓憓?
### 8.1 开发环境
- 可以使用 `prisma migrate dev`
- 可以使用 `prisma db push`(谨慎)
- 摰𡁏<EFBFBD><EFBFBD>峕郊<EFBFBD>煺漣<EFBFBD>唳旿摨梶<EFBFBD><EFBFBD>?
- 定期同步生产数据库结构
### 8.2 生产环境
- **只能**使用 `prisma migrate deploy`
- **<EFBFBD>迫**雿輻鍂隞颱<E99A9E> `--force` <EFBFBD>?`--reset` <EFBFBD><EFBFBD>
- **禁止**使用任何 `--force` `--reset` 参数
- 变更前必须有回滚计划
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞?
- 必须有最新备份
---
## 9. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
## 9. 检查清单
### 9.1 <EFBFBD>唳旿摨枏<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 9.1 数据库变更前检查
- [ ] 已备份数据库
- [ ] 撌脣恣<EFBFBD>?schema.prisma <EFBFBD>䀹凒
- [ ] 撌脫<EFBFBD><EFBFBD>交糓<EFBFBD>血蔣<EFBFBD><EFBFBD> Prisma 蝞∠<E89D9E><E288A0><EFBFBD>笆鞊?
- [ ] 撌脣<EFBFBD><EFBFBD><EFBFBD>皛𡁏䲮獢?
- [ ] 撌脣銁撘<EFBFBD><EFBFBD>𤑳㴓憓<EFBFBD><EFBFBD>霂?
- [ ] 已审查 schema.prisma 变更
- [ ] 已检查是否影响非 Prisma 管理的对象
- [ ] 已准备回滚方案
- [ ] 已在开发环境测试
### 9.2 <EFBFBD>函蔡<EFBFBD><EFBFBD><EFBFBD>?
### 9.2 部署后检查
- [ ] 应用正常启动
- [ ] <EFBFBD>唳旿摨栞<EFBFBD><EFBFBD>交迤撣?
- [ ] 数据库连接正常
- [ ] pg-boss 队列正常工作
- [ ] 核心功能测试通过
@@ -278,14 +278,14 @@ npx prisma db execute --file restore_xxx.sql --schema prisma/schema.prisma
```
backend/
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> verify_system.ts # 蝟餌<EFBFBD>摰峕㟲<EFBFBD><EFBFBD>霂?
├── verify_system.ts # 系统完整性验证
├── compare_schema_db.ts # Schema与数据库对比
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> check_iit_asl_data.ts # <EFBFBD><EFBFBD>交芋<EFBFBD>埈㺭<EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> restore_job_common.sql # <EFBFBD><EFBFBD> job_common 銵?
├── check_iit_asl_data.ts # 检查模块数据
├── restore_job_common.sql # 恢复 job_common
└── restore_pgboss_functions.sql # 恢复 pg-boss 函数
```
### 10.2 敹恍<EFBFBD><EFBFBD><EFBFBD>𦶢隞?
### 10.2 快速验证命令
```bash
# 设置环境变量
@@ -294,27 +294,27 @@ $env:DATABASE_URL="postgresql://postgres:postgres123@localhost:5432/ai_clinical_
# 验证系统
npx tsx verify_system.ts
# <EFBFBD><EFBFBD>交㺭<EFBFBD>?
# 检查数据
npx tsx check_iit_asl_data.ts
```
---
## <EFBFBD><EFBFBD><EFBFBD>嚗帋<EFBFBD><EFBFBD><EFBFBD><EFBFBD>靘?
## 附录:事故案例
### <EFBFBD><EFBFBD>1嚗?026-01-11 <EFBFBD>唳旿摨㯄<EFBFBD>蝵桐<EFBFBD><EFBFBD>?
### 案例12026-01-11 数据库重置事故
**<EFBFBD><EFBFBD>**嚗帋蝙<E5B88B>?`prisma db push --force-reset` 撖潸稲<EFBFBD>?Prisma 蝞∠<EFBFBD><EFBFBD><EFBFBD>笆鞊∩腺憭?
**原因**:使用 `prisma db push --force-reset` 导致非 Prisma 管理的对象丢失
**敶勗<EFBFBD>**嚗?
- pg-boss <EFBFBD>賣㺭銝仃嚗屸<EFBFBD><EFBFBD><EFBFBD>瘜閙釣<EFBFBD>?
- job_common 銵其腺憭?
- <EFBFBD><EFBFBD><EFBFBD>唳旿銝仃嚗<EFBFBD><EFBFBD><EFBFBD> seed <EFBFBD><EFBFBD>嚗?
**影响**
- pg-boss 函数丢失,队列无法注册
- job_common 表丢失
- 用户数据丢失(已通过 seed 恢复)
**<EFBFBD>躰悌**嚗?
**教训**
1. 永远不要使用 `--force-reset`
2. <EFBFBD><EFBFBD><EFBFBD><EFBFBD>憿餃<EFBFBD>隞?
3. <EFBFBD> Prisma <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
2. 操作前必须备份
3. 了解 Prisma 的管理边界
详见:`docs/08-项目管理/2026-01-11-数据库事故总结.md`
@@ -323,4 +323,3 @@ npx tsx check_iit_asl_data.ts