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,40 +1,40 @@
# <EFBFBD>唳旿摨栞<EFBFBD>蝘餌𠶖<EFBFBD><EFBFBD><EFBFBD>?
# 数据库迁移状态说明
> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𧋦嚗?* v1.0
> **<EFBFBD>𥕦遣<EFBFBD><EFBFBD>嚗?* 2025-11-23
> **蝏湔擪<EFBFBD><EFBFBD><EFBFBD>** ASL撘<4C><E69298>穃𣪧<E7A983>?
> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?* 霈啣<E99C88>ASL璅<E79285><E288AA>唳旿摨栞<E691A8>蝘餌𠶖<E9A48C><F0A0B696><EFBFBD>銝箸𧊋<E7AEB8><EFBFBD><E4BA99>睲犖<E79DB2><EFBFBD>靘𥟇<E99D98><F0A59F87><EFBFBD>銝𠹺<E98A9D><F0A0B9BA>?
> **文档版本:** v1.0
> **创建日期:** 2025-11-23
> **维护者:** ASL开发团队
> **文档目的:** 记录ASL模块数据库迁移状态为未来开发人员提供清晰的上下文
---
## 📋 当前数据库状态总览
### <EFBFBD>?ASL<EFBFBD>嚗Òsl_schema嚗? 摰<><E691B0><EFBFBD>
### ASL模块asl_schema- 完全正确
| 銵典<EFBFBD> | <20><EFBFBD>?| <20><EFBFBD>?| 霈啣<E99C88><E595A3>?|
| 表名 | 状态 | 用途 | 记录数 |
|-----|------|------|--------|
| `literatures` | <EFBFBD>?撌脫凒<E884AB>?| <20><><EFBFBD><EFBFBD>靽⊥<E99DBD><EFBFBD><EFBFBD><EFBFBD>摮埈挾嚗?| - |
| `screening_projects` | <EFBFBD>?甇<>虜 | 蝑偦<E89D91>厰★<E58EB0>?| - |
| `screening_tasks` | <EFBFBD>?甇<>虜 | <20><><EFBFBD><EFBFBD><EFBFBD><E48185><EFBFBD>隞餃𦛚 | - |
| `screening_results` | <EFBFBD>?甇<>虜 | <20><><EFBFBD><EFBFBD><EFBFBD><E48185><EFBFBD>蝏𤘪<E89D8F> | - |
| `fulltext_screening_tasks` | <EFBFBD>?<3F>啣遣 | <20><EFBFBD>憭滨<E686AD>隞餃𦛚 | 0 |
| `fulltext_screening_results` | <EFBFBD>?<3F>啣遣 | <20><EFBFBD>憭滨<E686AD>蝏𤘪<E89D8F> | 0 |
| `literatures` | ✅ 已更新 | 文献基础信息(含全文字段) | - |
| `screening_projects` | ✅ 正常 | 筛选项目 | - |
| `screening_tasks` | ✅ 正常 | 标题摘要初筛任务 | - |
| `screening_results` | ✅ 正常 | 标题摘要初筛结果 | - |
| `fulltext_screening_tasks` | ✅ 新建 | 全文复筛任务 | 0 |
| `fulltext_screening_results` | ✅ 新建 | 全文复筛结果 | 0 |
**<EFBFBD><EFBFBD>蝏栞捏**嚗?
- <EFBFBD>?ASL<EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇㺭<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鈭?`asl_schema`
- <EFBFBD>?瘝⊥<E7989D><E28AA5>唳旿瘜<E697BF><E7989C><EFBFBD>?`public` schema
- <EFBFBD>?Schema<EFBFBD>𠉛氖蝑𣇉裦<EFBFBD><EFBFBD><EFBFBD>
- <EFBFBD>?隞<><E99A9E>霈輸䔮頝臬<E9A09D><EFBFBD>嚗Ǒprisma.aslLiterature`, `prisma.aslScreeningProject` 蝑㚁<E89D91>
**核心结论**
- ASL模块所有数据完全位于 `asl_schema`
- ✅ 没有数据泄漏到 `public` schema
- Schema隔离策略执行正确
- ✅ 代码访问路径正确(`prisma.aslLiterature`, `prisma.aslScreeningProject` 等)
---
## <EFBFBD>𣞁 Public Schema<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ASL<EFBFBD><EFBFBD>嚗?
## 🔴 Public Schema历史遗留问题与ASL无关
### 问题描述
<EFBFBD>券★<EFBFBD>格𡟺<EFBFBD><EFBFBD><EFBFBD>睲葉嚗屸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銵刻◤<EFBFBD>躰秤<EFBFBD><EFBFBD>撱箏銁 `public` schema 銝哨<E98A9D>餈嘥<E9A488><EFBFBD>chema<6D>𠉛氖蝑𣇉裦嚗?
在项目早期开发中,部分模块的表被错误地创建在 `public` schema 中违反了Schema隔离策略
| <EFBFBD>躰秤銵典<EFBFBD> | 摨𥪜銁Schema | 敶枏<EFBFBD><EFBFBD><EFBFBD>?|
| 错误表名 | 应在Schema | 当前状态 |
|---------|-----------|---------|
| `public.users` | `platform_schema` | ⚠️ 重复存在 |
| `public.projects` | `aia_schema` | ⚠️ 重复存在 |
@@ -45,93 +45,93 @@
| `public.batch_tasks` | `pkb_schema` | ⚠️ 重复存在 |
| `public.batch_results` | `pkb_schema` | ⚠️ 重复存在 |
**<EFBFBD>唳旿撖寞<EFBFBD>嚗?025-11-23敹怎<E695B9>嚗?*嚗?
**数据对比2025-11-23快照**
```
platform_schema.users: 3<EFBFBD>∟扇敶?
public.users: 2<EFBFBD>∟扇敶?
platform_schema.users: 3条记录
public.users: 2条记录
aia_schema.projects: 2<EFBFBD>∟扇敶?
public.projects: 2<EFBFBD>∟扇敶?
aia_schema.projects: 2条记录
public.projects: 2条记录
pkb_schema.knowledge_bases: 2<EFBFBD>∟扇敶?
public.knowledge_bases: 2<EFBFBD>∟扇敶?
pkb_schema.knowledge_bases: 2条记录
public.knowledge_bases: 2条记录
```
**敶勗<EFBFBD><EFBFBD><EFBFBD>凒**嚗?
- <EFBFBD>叚 **銝滚蔣<E6BB9A><E894A3>SL璅<E79285>**嚗㇁SL摰<4C><E691B0><EFBFBD>𠉛氖<F0A0899B>sl_schema嚗?
- <EFBFBD>𩤃<EFBFBD> 敶勗<E695B6>AIA璅<E79285>嚗㇁I<E38781><EFBFBD>嚗?
- <EFBFBD>𩤃<EFBFBD> 敶勗<E695B6>PKB璅<E79285><EFBFBD>䰻霂<E4B0BB><E99C82>嚗?
**影响范围**
- 🟢 **不影响ASL模块**ASL完全隔离在asl_schema
- ⚠️ 影响AIA模块AI助手
- ⚠️ 影响PKB模块知识库
- ⚠️ 影响Platform模块用户系统
**<EFBFBD>遙敶鍦<EFBFBD>**嚗?
- <EFBFBD> ASL<EFBFBD><EFBFBD>嚗𡁏<EFBFBD><EFBFBD>遙嚗峕㺭<EFBFBD>桃恣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>冽迤蝖?
**责任归属**
- 🔵 ASL团队:无责任,数据管理完全正确
- 🟡 其他模块团队需自行清理public schema数据
---
## <EFBFBD><EFBFBD>儭?2025-11-23<EFBFBD><EFBFBD><EFBFBD>霈啣<EFBFBD>
## 🛠️ 2025-11-23迁移操作记录
### 迁移目标
为全文复筛功能Day 4开发添加数据库支持
1. 靽格㺿 `literatures` 銵剁<EFBFBD>瘛餃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>摮埈挾嚗?
2. <EFBFBD>𥕦遣 `fulltext_screening_tasks` 銵?
3. <EFBFBD>𥕦遣 `fulltext_screening_results` 銵?
1. 修改 `literatures` 表(添加全文相关字段)
2. 创建 `fulltext_screening_tasks`
3. 创建 `fulltext_screening_results`
### 迁移策略选择
**<EFBFBD>?<3F><EFBFBD>A嚗䥪risma Migrate<EFBFBD><EFBFBD><EFBFBD>嚗?*
**❌ 方案APrisma Migrate(被拒绝)**
```bash
npx prisma migrate dev --name add_fulltext_screening
```
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
- Prisma隡𡁜<EFBFBD>霂訫<EFBFBD><EFBFBD>?`public` schema銝剔<EFBFBD><EFBFBD><EFBFBD>銵?
- <EFBFBD><EFBFBD>敶勗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
- 餈嘥<EFBFBD>"蝞<E288AA>芸楛"<22><><EFBFBD><EFBFBD>?
**拒绝原因**
- Prisma会尝试删除 `public` schema中的重复表
- 可能影响其他模块的数据
- 违反"管好自己"的原则
**<EFBFBD>?<3F><EFBFBD>B嚗𡁏<E59A97><F0A1818F>沒QL<51>𡁏𧋦嚗<F0A78BA6><EFBFBD><E6AD87>鍂嚗?*
**✅ 方案B手动SQL脚本已采用**
```bash
# 创建手动迁移脚本
backend/prisma/migrations/manual_fulltext_screening.sql
# <EFBFBD><EFBFBD><EFBFBD>宏嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>asl_schema嚗?
# 执行迁移(仅操作asl_schema
Get-Content manual_fulltext_screening.sql | docker exec -i ai-clinical-postgres psql ...
```
**隡睃飵**嚗?
- <EFBFBD>?<3F><EFBFBD>雿?`asl_schema`嚗䔶<EFBFBD><EFBFBD><EFBFBD>隞騯chema
- <EFBFBD>?銝滚<E98A9D><E6BB9A>支遙雿?`public` <EFBFBD>唳旿
- <EFBFBD>?摰匧<E691B0><E58CA7><EFBFBD><EFBFBD><EFBFBD><E689BC>虾摰∟恣
- <EFBFBD>?蝚血<E89D9A>"蝞<E288AA>芸楛"<22><EFBFBD>
**优势**
- ✅ 只操作 `asl_schema`不动其他schema
- ✅ 不删除任何 `public` 数据
- ✅ 安全、可控、可审计
- ✅ 符合"管好自己"原则
### 迁移内容详情
#### 1. 靽格㺿 `literatures` 銵?
#### 1. 修改 `literatures`
<EFBFBD><EFBFBD>摮埈挾嚗?3銝迎<E98A9D>嚗?
新增字段13个
**文献生命周期**:
- `stage TEXT DEFAULT 'imported'` - <EFBFBD>嗆挾<EFBFBD><EFBFBD>扇嚗ǎmported <EFBFBD>?title_screened <EFBFBD>?fulltext_pending <EFBFBD>?fulltext_screened嚗?
- `stage TEXT DEFAULT 'imported'` - 阶段标记imported title_screened fulltext_pending fulltext_screened
**PDF管理**:
- `has_pdf BOOLEAN DEFAULT false` - 是否有PDF
- `pdf_storage_type TEXT` - 摮睃<EFBFBD>蝐餃<EFBFBD>嚗èss/dify/local嚗?
- `pdf_storage_ref TEXT` - 摮睃<EFBFBD>撘閧鍂嚗ɑey<EFBFBD>𦎾D嚗?
- `pdf_status TEXT DEFAULT 'pending'` - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>pending/extracting/completed/failed嚗?
- `pdf_storage_type TEXT` - 存储类型oss/dify/local
- `pdf_storage_ref TEXT` - 存储引用key或ID
- `pdf_status TEXT DEFAULT 'pending'` - 状态(pending/extracting/completed/failed
- `pdf_uploaded_at TIMESTAMP(3)` - 上传时间
**<EFBFBD><EFBFBD>蝞∠<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?*:
- `full_text_storage_type TEXT` - 摮睃<EFBFBD>蝐餃<EFBFBD>嚗èss/dify嚗?
**全文管理(云原生)**:
- `full_text_storage_type TEXT` - 存储类型oss/dify
- `full_text_storage_ref TEXT` - 存储引用
- `full_text_url TEXT` - 访问URL
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*:
- `full_text_format TEXT` - <EFBFBD><EFBFBD>嚗éarkdown/plaintext嚗?
- `full_text_source TEXT` - <EFBFBD>𣂼<EFBFBD><EFBFBD><EFBFBD>嚗ěougat/pymupdf嚗?
**全文元数据**:
- `full_text_format TEXT` - 格式markdown/plaintext
- `full_text_source TEXT` - 提取方式nougat/pymupdf
- `full_text_token_count INTEGER` - Token数量
- `full_text_extracted_at TIMESTAMP(3)` - 提取时间
@@ -140,9 +140,9 @@ Get-Content manual_fulltext_screening.sql | docker exec -i ai-clinical-postgres
- `idx_literatures_has_pdf`
- `idx_literatures_pdf_status`
#### 2. <EFBFBD>𥕦遣 `fulltext_screening_tasks` 銵?
#### 2. 创建 `fulltext_screening_tasks`
隞餃𦛚蝞∠<EFBFBD>銵剁<EFBFBD>摮埈挾<EFBFBD><EFBFBD>𡠺嚗?
任务管理表,字段包括:
- 基础信息:`id`, `project_id`
- 模型配置:`model_a`, `model_b`, `prompt_version`
- 进度跟踪:`total_count`, `processed_count`, `success_count`, `failed_count`, `degraded_count`
@@ -156,14 +156,14 @@ Get-Content manual_fulltext_screening.sql | docker exec -i ai-clinical-postgres
- `idx_fulltext_tasks_created_at`
**外键约束**:
- `project_id` <EFBFBD>?`screening_projects(id)` ON DELETE CASCADE
- `project_id` `screening_projects(id)` ON DELETE CASCADE
#### 3. <EFBFBD>𥕦遣 `fulltext_screening_results` 銵?
#### 3. 创建 `fulltext_screening_results`
蝏𤘪<EFBFBD>摮睃<EFBFBD>銵剁<EFBFBD>12摮埈挾璅⊥踎嚗㚁<EFBFBD>摮埈挾<EFBFBD><EFBFBD>𡠺嚗?
结果存储表12字段模板字段包括
- 关联信息:`task_id`, `project_id`, `literature_id`
- Model A蝏𤘪<EFBFBD>嚗䫤model_a_name`, `model_a_fields` (JSONB), `model_a_tokens`, `model_a_cost` 蝑?
- Model B蝏𤘪<EFBFBD>嚗䫤model_b_name`, `model_b_fields` (JSONB), `model_b_tokens`, `model_b_cost` 蝑?
- Model A结果:`model_a_name`, `model_a_fields` (JSONB), `model_a_tokens`, `model_a_cost`
- Model B结果:`model_b_name`, `model_b_fields` (JSONB), `model_b_tokens`, `model_b_cost`
- 验证结果:`medical_logic_issues` (JSONB), `evidence_chain_issues` (JSONB)
- 冲突检测:`is_conflict`, `conflict_severity`, `conflict_fields`, `review_priority`
- 人工复核:`final_decision`, `final_decision_by`, `exclusion_reason`, `review_notes`
@@ -182,35 +182,35 @@ Get-Content manual_fulltext_screening.sql | docker exec -i ai-clinical-postgres
- `unique_project_literature_fulltext (project_id, literature_id)`
**外键约束**:
- `task_id` <EFBFBD>?`fulltext_screening_tasks(id)` ON DELETE CASCADE
- `project_id` <EFBFBD>?`screening_projects(id)` ON DELETE CASCADE
- `literature_id` <EFBFBD>?`literatures(id)` ON DELETE CASCADE
- `task_id` `fulltext_screening_tasks(id)` ON DELETE CASCADE
- `project_id` `screening_projects(id)` ON DELETE CASCADE
- `literature_id` `literatures(id)` ON DELETE CASCADE
### 迁移结果验证
```sql
-- 撉諹<EFBFBD>銵典<EFBFBD>撱?
-- 验证表创建
\dt asl_schema.*
-- 蝏𤘪<EFBFBD>嚗?銝芾”
-- <EFBFBD>?literatures (撌脫凒<EFBFBD>?
-- <EFBFBD>?screening_projects
-- <EFBFBD>?screening_tasks
-- <EFBFBD>?screening_results
-- <EFBFBD>?fulltext_screening_tasks (<EFBFBD>啣遣)
-- <EFBFBD>?fulltext_screening_results (<EFBFBD>啣遣)
-- 结果6个表
-- literatures (已更新)
-- screening_projects
-- screening_tasks
-- screening_results
-- fulltext_screening_tasks (新建)
-- fulltext_screening_results (新建)
-- 撉諹<EFBFBD><EFBFBD><EFBFBD>畾?
-- 验证新字段
\d asl_schema.literatures
-- 蝏𤘪<EFBFBD>嚗?
-- <EFBFBD>?stage
-- <EFBFBD>?has_pdf
-- <EFBFBD>?full_text_storage_type
-- <EFBFBD>?full_text_storage_ref
-- <EFBFBD>?full_text_url
-- <EFBFBD>?full_text_format
-- ... 蝑?3銝芣鰵摮埈挾
-- 结果:
-- stage
-- has_pdf
-- full_text_storage_type
-- full_text_storage_ref
-- full_text_url
-- full_text_format
-- ... 等13个新字段
```
**Prisma Client生成**:
@@ -233,34 +233,34 @@ npx prisma generate
### 设计原则(来自系统架构文档)
```
<EFBFBD><EFBFBD><EFBFBD>埈㺭<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𠉛氖嚗?
各模块数据逻辑隔离:
├── admin_schema (系统管理)
├── platform_schema (用户系统)
├── aia_schema (AI助手)
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> asl_schema (AI<EFBFBD><EFBFBD><EFBFBD><EFBFBD>讃) <20>?<3F><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> pkb_schema (<EFBFBD><EFBFBD>摨?
├── asl_schema (AI智能文献) ✅ 执行正确
├── pkb_schema (知识库)
├── rvw_schema (审阅协作)
├── st_schema (统计分析)
├── dc_schema (数据采集)
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> ssa_schema (<EFBFBD>瑟𧋦<EFBFBD><EFBFBD><EFBFBD>?
├── ssa_schema (样本量分析)
└── common_schema (公共数据)
```
### ASL<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>?
### ASL模块执行情况 ✅
| <EFBFBD><EFBFBD>仿★ | <20><EFBFBD>?| 霂湔<E99C82> |
| 检查项 | 状态 | 说明 |
|-------|------|------|
| Schema<EFBFBD><EFBFBD> | <20>?甇<> | `asl_schema` |
| <EFBFBD><EFBFBD><EFBFBD>㕑”<EFBFBD>賢銁甇<EFBFBD>Schema | <20>?甇<> | 6銝芾”<E88ABE><EFBFBD><E588B8>?`asl_schema` |
| 瘝⊥<EFBFBD>銵典銁public | <EFBFBD>?甇<> | <20><EFBFBD>瞍?|
| Prisma Model<EFBFBD><EFBFBD><EFBFBD> | <20>?甇<> | `@@schema("asl_schema")` |
| <EFBFBD><EFBFBD>霈輸䔮頝臬<EFBFBD><EFBFBD> | <20>?甇<> | `prisma.aslXxx` |
| 憭㚚睸蝥行<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?| <20>?甇<> | <20><><EFBFBD>丽K<E4B8BD><4B><EFBFBD><EFBFBD>chema銵?|
| Schema命名 | ✅ 正确 | `asl_schema` |
| 所有表都在正确Schema | ✅ 正确 | 6个表全部在 `asl_schema` |
| 没有表在public | ✅ 正确 | 无泄漏 |
| Prisma Model映射正确 | ✅ 正确 | `@@schema("asl_schema")` |
| 代码访问路径正确 | ✅ 正确 | `prisma.aslXxx` |
| 外键约束内部化 | ✅ 正确 | 所有FK指向同schema|
**<EFBFBD><EFBFBD>蝷箔<EFBFBD>**嚗<>迤蝖株挪<E6A0AA>格䲮撘𧶏<E69298>嚗?
**代码示例**(正确访问方式):
```typescript
// <EFBFBD>?甇<>嚗𡁻<E59A97><EFBFBD>Prisma Client霈輸䔮asl_schema
// ✅ 正确:通过Prisma Client访问asl_schema
const project = await prisma.aslScreeningProject.findUnique({
where: { id: projectId },
});
@@ -273,7 +273,7 @@ const task = await prisma.aslFulltextScreeningTask.create({
data: { ... },
});
// <EFBFBD>?<3F>躰秤嚗𡁶凒<F0A181B6>兄QL霈輸䔮public嚗<63><E59A97>隡𡁜<E99AA1><F0A1819C><EFBFBD><EFBFBD><EFBFBD>牐蛹銵其<E98AB5><E585B6>ublic嚗?
// ❌ 错误直接SQL访问public不会发生因为表不在public
await prisma.$queryRaw`SELECT * FROM public.literatures`;
```
@@ -285,13 +285,13 @@ await prisma.$queryRaw`SELECT * FROM public.literatures`;
**推荐策略**继续使用手动SQL脚本
**<EFBFBD><EFBFBD>**嚗?
1. <EFBFBD>?Public schema<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>䠷䔮憸条<EFBFBD><EFBFBD><EFBFBD><EFBFBD>瘜閗圾<EFBFBD>?
2. <EFBFBD>?<3F>见𢆡<E8A781>𡁏𧋦<F0A1818F><EFBFBD><E6B8B8><EFBFBD><E585B7><EFBFBD>?
3. <EFBFBD>?<3F><EFBFBD><E8B8B9><EFBFBD>敶勗<E695B6><E58B97><EFBFBD><E79285>
4. <EFBFBD>?靘蹂<E99D98><EFBFBD><E99A9E>摰⊥䰻<E28AA5><E4B0BB>恣霈?
**原因**
1. Public schema的历史遗留问题短期无法解决
2. ✅ 手动脚本更安全、可控
3. ✅ 避免意外影响其他模块
4. ✅ 便于代码审查和审计
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
**操作流程**
```bash
# 1. 修改 Prisma Schema
@@ -300,7 +300,7 @@ await prisma.$queryRaw`SELECT * FROM public.literatures`;
# 2. 编写手动SQL脚本
# backend/prisma/migrations/manual_xxx.sql
# 3. <EFBFBD><EFBFBD><EFBFBD>𡁏𧋦嚗<EFBFBD><EFBFBD><EFBFBD>asl_schema嚗?
# 3. 执行脚本(只操作asl_schema
Get-Content manual_xxx.sql | docker exec -i ai-clinical-postgres psql ...
# 4. 验证结果
@@ -314,7 +314,7 @@ git add .
git commit -m "feat(asl): add xxx tables for xxx feature"
```
**SQL<EFBFBD>𡁏𧋦璅⊥踎**嚗?
**SQL脚本模板**
```sql
-- 只操作asl_schema不影响其他schema
@@ -325,33 +325,33 @@ CREATE INDEX IF NOT EXISTS idx_xxx ON asl_schema.xxx(...);
### 对于其他模块
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*嚗𡁜<E59A97><E79285><EFBFBD><E69298>穃𣪧<E7A983>?
**问题所有者**:各模块开发团队
**撱箄悅<EFBFBD><EFBFBD>**嚗<><EFBFBD><E79C8F><EFBFBD>堒𣪧<E5A092>蠘䌊銵<E48C8A><E98AB5>摰𡄯<E691B0>嚗?
1. <EFBFBD><EFBFBD>?`public` schema銝剜糓<EFBFBD><EFBFBD><EFBFBD>祆芋<EFBFBD><EFBFBD>銵?
2. 撖寞<EFBFBD><EFBFBD>唳旿撌桀<EFBFBD>嚗Ǒpublic` vs <EFBFBD>schema嚗?
**建议操作**(由各模块团队自行决定):
1. 检查 `public` schema中是否有本模块的表
2. 对比数据差异(`public` vs 正确schema
3. 决策是否需要数据迁移或清理
4. 执行清理操作(风险自负)
**ASL<EFBFBD><EFBFBD>蝡见㦤**嚗?
- <EFBFBD>㩞 銝滢蜓<E6BBA2><EFBFBD><E586BD><EFBFBD><EFBFBD>隞𡝗芋<F0A19D97><EFBFBD>public銵?
**ASL团队立场**
- 🔵 不主动清理其他模块的public
- 🔵 不对其他模块数据安全负责
- <EFBFBD>㩞 銝𤘪釣鈭箢sl_schema<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝔喳<EFBFBD><EFBFBD>?
- 🔵 专注于asl_schema的质量和稳定性
---
## <EFBFBD><EFBFBD> <20>唳旿摰峕㟲<E5B395><EFBFBD>霂?
## 📊 数据完整性验证
### ASL<EFBFBD><EFBFBD>唳旿<EFBFBD>喟頂<EFBFBD>?
### ASL模块数据关系图
```
asl_schema.screening_projects (项目)
<EFBFBD>?1:N
1:N
asl_schema.literatures (文献)
<EFBFBD>?1:1 <EFBFBD>?1:1
1:1 1:1
asl_schema.screening_results asl_schema.fulltext_screening_results
(标题摘要初筛结果) (全文复筛结果)
<EFBFBD>?N:1 <EFBFBD>?N:1
N:1 N:1
asl_schema.screening_tasks asl_schema.fulltext_screening_tasks
(标题摘要初筛任务) (全文复筛任务)
```
@@ -375,61 +375,61 @@ WHERE tc.constraint_type = 'FOREIGN KEY'
AND tc.table_schema = 'asl_schema'
ORDER BY tc.table_name;
-- <EFBFBD><EFBFBD>蝏𤘪<EFBFBD>嚗?
-- <EFBFBD>?<3F><><EFBFBD>丽K<E4B8BD>?foreign_table_name <EFBFBD>賢銁 asl_schema 銝?
-- <EFBFBD>?瘝⊥<E7989D>頝究chema撘閧鍂
-- 预期结果:
-- ✅ 所有FK的 foreign_table_name 都在 asl_schema
-- ✅ 没有跨schema引用
```
---
## 🎯 关键结论
### <EFBFBD>?ASL<EFBFBD>嚗𡁜<EFBFBD><EFBFBD><EFBFBD>摨?
### ASL模块:完全健康
1. **Schema<EFBFBD>𠉛氖**嚗?00%甇<>嚗峕<E59A97><E5B395>㕑”<E39591>賢銁 `asl_schema`
2. **<EFBFBD>唳旿蝞∠<EFBFBD>**嚗𡁏<E59A97><F0A1818F>唳旿瘜<E697BF><E7989C><EFBFBD>?`public`
3. **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗𡁏<E59A97><F0A1818F>㕑挪<E39591>株楝敺<E6A59D>迤蝖?
4. **<EFBFBD>宏蝑𣇉裦**嚗𡁏<E59A97><F0A1818F>沒QL<51>𡁏𧋦嚗<F0A78BA6><E59A97><EFBFBD>典虾<E585B8>?
1. **Schema隔离**100%正确,所有表都在 `asl_schema`
2. **数据管理**:无数据泄漏到 `public`
3. **代码规范**:所有访问路径正确
4. **迁移策略**手动SQL脚本安全可控
### ⚠️ 系统级问题Public Schema污染
1. **问题性质**历史遗留与ASL无关
2. **影响范围**AIA、PKB、Platform模块
3. **解决责任**:各模块团队自行处理
4. **ASL蝑𣇉裦**嚗帋<E59A97><E5B88B>私ublic嚗𣬚恣憟質䌊撌?
4. **ASL策略**不动public管好自己
### <EFBFBD><EFBFBD><><E69298>睲犖<E79DB2><EFBFBD><E480B9>?
### 📋 开发人员指南
**<EFBFBD><EFBFBD>雿䭾糓ASL璅<EFBFBD><EFBFBD><EFBFBD>𤏸<EFBFBD>?*嚗?
- <EFBFBD>?蝏抒賒靽脲<E99DBD>敶枏<E695B6><E69E8F><EFBFBD>chema<6D>𠉛氖摰噼殿
- <EFBFBD>?雿輻鍂<E8BCBB>见𢆡SQL<51>𡁏𧋦餈𥡝<E9A488><F0A5A19D>唳旿摨栞<E691A8>蝘?
- <EFBFBD>?<3F><><EFBFBD>㕑”<E39591><EFBFBD>撱箏銁 `asl_schema`
- <EFBFBD>?銝滩<E98A9D>撠肽<E692A0><EFBFBD><E79A9C> `public` schema
**如果你是ASL模块开发者**
- ✅ 继续保持当前的Schema隔离实践
- ✅ 使用手动SQL脚本进行数据库迁移
- ✅ 所有表都创建在 `asl_schema`
- ✅ 不要尝试清理 `public` schema
**<EFBFBD><EFBFBD>雿䭾糓<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𤏸<EFBFBD>?*嚗?
**如果你是其他模块开发者**
- 🟡 检查自己模块的Schema隔离状况
- <EFBFBD><20><EFBFBD><E596B3>臬炏<E887AC><E7828F><EFBFBD><E996AC><EFBFBD>?`public` 銝剔<EFBFBD><EFBFBD><EFBFBD>銵?
- <EFBFBD><20><><EFBFBD><EFBFBD>SL<53><4C><EFBFBD>蝘餌<E89D98><E9A48C><EFBFBD><E4BC90>见𢆡SQL嚗?
- 🟡 决定是否需要清理 `public` 中的重复表
- 🟡 参考ASL的迁移策略手动SQL
- 🟡 不要依赖ASL团队清理public
---
## 📚 相关文档
- [蝟餌<EFBFBD><EFBFBD><EFBFBD>霈曇恣 - <20>唳旿摨𤘪沲<F0A498AA><E6B2B2><EFBFBD>筕(../../../../00-蝟餌<E89D9F><E9A48C><EFBFBD>霈曇恣/03-<2D>唳旿摨𤘪沲<F0A498AA><E6B2B2><EFBFBD>?md)
- [ASL<EFBFBD> - <20>唳旿摨栞挽霈(../../02-<2D><><EFBFBD>航挽霈?01-<2D>唳旿摨栞挽霈?md)
- [鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD><EFBFBD>(../../../../04-<EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md)
- [Day 2-3<EFBFBD><EFBFBD>𤏸扇敶騟(./2025-11-22_Day2-Day3_LLM<EFBFBD>滚𦛚銝𡡞<EFBFBD><EFBFBD>頂蝏笔<EFBFBD><EFBFBD>?md)
- [系统总体设计 - 数据库架构说明](../../../../00-系统总体设计/03-数据库架构说明.md)
- [ASL模块 - 数据库设计](../../02-技术设计/01-数据库设计.md)
- [云原生开发规范](../../../../04-开发规范/08-云原生开发规范.md)
- [Day 2-3开发记录](./2025-11-22_Day2-Day3_LLM服务与验证系统开发.md)
---
**<EFBFBD><EFBFBD>﹝蝏湔擪**嚗?
**文档维护**
- 数据库结构变更时更新
- 发现新问题时记录
- 定期审查Schema隔离状况
**<EFBFBD><EFBFBD><EFBFBD>擧凒<EFBFBD>?*嚗?025-11-23
**<EFBFBD>湔鰵鈭?*嚗鋫SL撘<4C><E69298>穃𣪧<E7A983>?
**銝𧢲活摰⊥䰻**嚗帋<E59A97>甈⊥㺭<E28AA5><EFBFBD><EFBFBD><EFBFBD>?
**最后更新**2025-11-23
**更新人**ASL开发团队
**下次审查**:下次数据库迁移时