Files
AIclinicalresearch/docs/09-架构实施/01-Schema隔离架构设计(10个).md
HaHafeng 66255368b7 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
2026-01-16 13:42:10 +08:00

901 lines
31 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Schema隔离架构设计10个Schema
> **文档版本:** V1.0
> **制定日期:** 2025-11-09
> **实施策略:** 3个详细迁移 + 7个空Schema预留
> **架构原则:** Just-in-time设计聚焦当前需求架构预留扩展
---
## 📋 目录
1. [架构概述](#架构概述)
2. [10个Schema全景](#10个schema全景)
3. [Schema依赖关系](#schema依赖关系)
4. [详细设计3个迁移Schema](#详细设计3个迁移schema)
5. [预留7个空Schema](#预留7个空schema)
6. [迁移策略](#迁移策略)
7. [现有表分配方案](#现有表分配方案)
8. [外键和跨Schema引用](#外键和跨schema引用)
9. [Prisma配置策略](#prisma配置策略)
---
## 架构概述
### 设计目标
1. **模块化隔离** - 每个业务模块独立Schema支持独立部署
2. **数据安全** - Schema级别的权限控制
3. **扩展性强** - 新模块快速接入只需创建新Schema
4. **渐进式实施** - 优先迁移核心3个Schema其余按需扩展
### 实施策略3详细+7空 ⭐
```
Week 1重点
┌─────────────────────────────────────────────┐
│ 3个详细Schema完整设计+数据迁移) │
│ ✅ platform_schema - 1个表users
│ ✅ aia_schema - 5个表对话相关
│ ✅ pkb_schema - 5个表知识库相关
├─────────────────────────────────────────────┤
│ 7个空Schema只创建命名空间
│ 📋 asl_schema - Week 3再设计表 │
│ 📋 common_schema - 需要时再创建表 │
│ 📋 dc_schema - 数据清洗模块 │
│ 📋 rvw_schema - 审稿系统(含现有表) │
│ 📋 admin_schema - 运营管理(含现有表) │
│ 📋 ssa_schema - 智能统计分析 │
│ 📋 st_schema - 统计分析工具 │
└─────────────────────────────────────────────┘
```
### 核心原则
-**聚焦当前** - 只详细设计和迁移现在需要的Platform/AIA/PKB
-**架构预留** - 创建7个空Schema命名空间占位
-**Just-in-time** - ASL等模块在开发前再详细设计避免过度设计
-**降低风险** - Week 1工作量从2天降到1.5天
---
## 10个Schema全景
| # | Schema名称 | 中文名称 | 状态 | 用途 | Week 1任务 |
|---|-----------|---------|------|------|-----------|
| 1 | `platform_schema` | 平台基础层 | ✅ 详细设计 | 用户、权限、认证 | 迁移1个表 |
| 2 | `aia_schema` | AI智能问答 | ✅ 详细设计 | 对话、项目管理 | 迁移5个表 |
| 3 | `pkb_schema` | 个人知识库 | ✅ 详细设计 | 知识库、文档、批处理 | 迁移5个表 |
| 4 | `asl_schema` | AI智能文献 | 📋 空Schema | 文献筛选 | 只创建Schema |
| 5 | `common_schema` | 通用能力层 | 📋 空Schema | LLM使用记录、Feature Flags | 只创建Schema |
| 6 | `dc_schema` | 数据清洗 | 📋 空Schema | 数据清洗工具 | 只创建Schema |
| 7 | `rvw_schema` | 审稿系统 | 📋 空Schema | 稿件审查 | 只创建Schema+迁移1表 |
| 8 | `admin_schema` | 运营管理 | 📋 空Schema | 管理后台、日志 | 只创建Schema+迁移1表 |
| 9 | `ssa_schema` | 智能统计分析 | 📋 空Schema | 智能数据分析 | 只创建Schema |
| 10 | `st_schema` | 统计分析工具 | 📋 空Schema | 统计工具集 | 只创建Schema |
---
## Schema依赖关系
### 层级结构 ⭐
```
┌─────────────────────────────────────────────────────────────┐
│ L3: 业务模块层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐│
│ │ AIA │ │ PKB │ │ ASL │ │ RVW │ │ ADMIN ││
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬───┘│
│ │ │ │ │ │ │
│ └───────────┴───────────┴───────────┴───────────┘ │
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ L2: 通用能力层 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Common │ │ DC/SSA/ST │ │
│ │ (通用数据) │ │ (通用工具) │ │
│ └──────┬───────┘ └──────────────┘ │
│ │ │
│ └───────────────────────────────────────────────────│
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ L1: 平台基础层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Platform Schema │ │
│ │ - 用户管理 (users) │ │
│ │ - 权限控制 (RBAC) │ │
│ │ - 认证服务 (JWT/Session) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 引用关系说明
**核心规则:单向依赖,向下引用**
1. **所有业务模块 → platform_schema.users**
- 所有表的 `user_id` 字段引用 `platform_schema.users(id)`
- 跨Schema外键PostgreSQL支持
2. **业务模块内部表之间**
- 同Schema内的表可以相互引用如aia_schema.conversations → aia_schema.projects
3. **禁止反向依赖**
- platform_schema **不能**引用业务模块Schema
- 业务模块之间**不应**相互引用(保持独立性)
---
## 详细设计3个迁移Schema
### 1⃣ platform_schema平台基础层
**用途:** 用户管理、权限控制、认证服务
**迁移表:** 1个
- `users` - 从 `public.users` 迁移
#### 表结构users
| 字段名 | 类型 | 说明 | 索引 |
|-------|------|------|------|
| `id` | UUID | 主键 | PK |
| `email` | VARCHAR(255) | 邮箱(唯一) | UNIQUE, INDEX |
| `password` | VARCHAR(255) | 密码哈希 | - |
| `name` | VARCHAR(255) | 用户名 | - |
| `avatar_url` | VARCHAR(500) | 头像URL | - |
| `role` | VARCHAR(50) | 角色user/admin | INDEX |
| `status` | VARCHAR(50) | 状态active/inactive | INDEX |
| `kb_quota` | INT | 知识库配额 | - |
| `kb_used` | INT | 已使用配额 | - |
| `trial_ends_at` | TIMESTAMP | 试用结束时间 | - |
| `is_trial` | BOOLEAN | 是否试用 | - |
| `last_login_at` | TIMESTAMP | 最后登录时间 | - |
| `created_at` | TIMESTAMP | 创建时间 | INDEX |
| `updated_at` | TIMESTAMP | 更新时间 | - |
**SQL DDL**
```sql
CREATE SCHEMA IF NOT EXISTS platform_schema;
CREATE TABLE platform_schema.users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
name VARCHAR(255),
avatar_url VARCHAR(500),
role VARCHAR(50) NOT NULL DEFAULT 'user',
status VARCHAR(50) DEFAULT 'active',
kb_quota INT DEFAULT 3,
kb_used INT DEFAULT 0,
trial_ends_at TIMESTAMP,
is_trial BOOLEAN DEFAULT true,
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 索引
CREATE INDEX idx_users_email ON platform_schema.users(email);
CREATE INDEX idx_users_role ON platform_schema.users(role);
CREATE INDEX idx_users_status ON platform_schema.users(status);
CREATE INDEX idx_users_created_at ON platform_schema.users(created_at);
```
---
### 2⃣ aia_schemaAI智能问答
**用途:** AI对话、项目管理、通用对话
**迁移表:** 5个
- `projects` - 从 `public.projects` 迁移
- `conversations` - 从 `public.conversations` 迁移
- `messages` - 从 `public.messages` 迁移
- `general_conversations` - 从 `public.general_conversations` 迁移
- `general_messages` - 从 `public.general_messages` 迁移
#### 表结构概览
**1. projects项目表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `name` | VARCHAR(255) | 项目名称 | - |
| `background` | TEXT | 研究背景 | - |
| `research_type` | VARCHAR(50) | 研究类型 | - |
| `conversation_count` | INT | 对话数 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
| `deleted_at` | TIMESTAMP | 删除时间(软删除) | - |
**2. conversations对话表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `project_id` | UUID | 项目ID | → `aia_schema.projects(id)` |
| `agent_id` | VARCHAR(100) | 智能体ID | - |
| `title` | VARCHAR(255) | 对话标题 | - |
| `model_name` | VARCHAR(50) | 模型名称 | - |
| `message_count` | INT | 消息数 | - |
| `total_tokens` | INT | 总Token数 | - |
| `metadata` | JSONB | 元数据 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
| `deleted_at` | TIMESTAMP | 删除时间 | - |
**3. messages消息表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `conversation_id` | UUID | 对话ID | → `aia_schema.conversations(id)` |
| `role` | VARCHAR(20) | 角色user/assistant | - |
| `content` | TEXT | 消息内容 | - |
| `model` | VARCHAR(50) | 使用的模型 | - |
| `metadata` | JSONB | 元数据 | - |
| `tokens` | INT | Token数 | - |
| `is_pinned` | BOOLEAN | 是否置顶 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
**4. general_conversations通用对话表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `title` | VARCHAR(255) | 对话标题 | - |
| `model_name` | VARCHAR(50) | 模型名称 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
| `deleted_at` | TIMESTAMP | 删除时间 | - |
**5. general_messages通用消息表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `conversation_id` | UUID | 对话ID | → `aia_schema.general_conversations(id)` |
| `role` | VARCHAR(20) | 角色 | - |
| `content` | TEXT | 消息内容 | - |
| `model` | VARCHAR(50) | 使用的模型 | - |
| `metadata` | JSONB | 元数据 | - |
| `tokens` | INT | Token数 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
**SQL DDL**
```sql
CREATE SCHEMA IF NOT EXISTS aia_schema;
-- 1. projects
CREATE TABLE aia_schema.projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL, -- 引用platform_schema.users
name VARCHAR(255) NOT NULL,
background TEXT DEFAULT '',
research_type VARCHAR(50) DEFAULT 'observational',
conversation_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE
);
-- 2. conversations
CREATE TABLE aia_schema.conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
project_id UUID,
agent_id VARCHAR(100) NOT NULL,
title VARCHAR(255) NOT NULL,
model_name VARCHAR(50) DEFAULT 'deepseek-v3',
message_count INT DEFAULT 0,
total_tokens INT DEFAULT 0,
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES aia_schema.projects(id) ON DELETE CASCADE
);
-- 3. messages
CREATE TABLE aia_schema.messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL,
role VARCHAR(20) NOT NULL,
content TEXT NOT NULL,
model VARCHAR(50),
metadata JSONB,
tokens INT,
is_pinned BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES aia_schema.conversations(id) ON DELETE CASCADE
);
-- 4. general_conversations
CREATE TABLE aia_schema.general_conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
title VARCHAR(255) NOT NULL,
model_name VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE
);
-- 5. general_messages
CREATE TABLE aia_schema.general_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL,
role VARCHAR(20) NOT NULL,
content TEXT NOT NULL,
model VARCHAR(50),
metadata JSONB,
tokens INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (conversation_id) REFERENCES aia_schema.general_conversations(id) ON DELETE CASCADE
);
-- 索引
CREATE INDEX idx_aia_projects_user_id ON aia_schema.projects(user_id);
CREATE INDEX idx_aia_projects_created_at ON aia_schema.projects(created_at);
CREATE INDEX idx_aia_conversations_user_id ON aia_schema.conversations(user_id);
CREATE INDEX idx_aia_conversations_project_id ON aia_schema.conversations(project_id);
CREATE INDEX idx_aia_messages_conversation_id ON aia_schema.messages(conversation_id);
CREATE INDEX idx_aia_general_conversations_user_id ON aia_schema.general_conversations(user_id);
CREATE INDEX idx_aia_general_messages_conversation_id ON aia_schema.general_messages(conversation_id);
```
---
### 3⃣ pkb_schema个人知识库
**用途:** 知识库管理、文档管理、批处理任务
**迁移表:** 5个
- `knowledge_bases` - 从 `public.knowledge_bases` 迁移
- `documents` - 从 `public.documents` 迁移
- `batch_tasks` - 从 `public.batch_tasks` 迁移
- `batch_results` - 从 `public.batch_results` 迁移
- `task_templates` - 从 `public.task_templates` 迁移
#### 表结构概览
**1. knowledge_bases知识库表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `name` | VARCHAR(255) | 知识库名称 | - |
| `description` | TEXT | 描述 | - |
| `dify_dataset_id` | VARCHAR(255) | Dify知识库ID | - |
| `file_count` | INT | 文件数 | - |
| `total_size_bytes` | BIGINT | 总大小(字节) | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
**2. documents文档表** ⭐ 包含Phase 2全文阅读字段
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `kb_id` | UUID | 知识库ID | → `pkb_schema.knowledge_bases(id)` |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `filename` | VARCHAR(255) | 文件名 | - |
| `file_type` | VARCHAR(50) | 文件类型 | - |
| `file_size_bytes` | BIGINT | 文件大小 | - |
| `file_url` | TEXT | 文件URL | - |
| `dify_document_id` | VARCHAR(255) | Dify文档ID | - |
| `status` | VARCHAR(50) | 状态 | - |
| `progress` | INT | 进度0-100 | - |
| `error_message` | TEXT | 错误信息 | - |
| `segments_count` | INT | 分段数 | - |
| `tokens_count` | INT | Token数 | - |
| **Phase 2字段** | | | |
| `extraction_method` | VARCHAR(50) | 提取方法pymupdf/nougat/mammoth/direct | - |
| `extraction_quality` | FLOAT | 提取质量0-1 | - |
| `char_count` | INT | 字符数 | - |
| `language` | VARCHAR(20) | 语言chinese/english | - |
| `extracted_text` | TEXT | 提取的文本 | - |
| `uploaded_at` | TIMESTAMP | 上传时间 | - |
| `processed_at` | TIMESTAMP | 处理完成时间 | - |
**3. batch_tasks批处理任务表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `kb_id` | UUID | 知识库ID | → `pkb_schema.knowledge_bases(id)` |
| `name` | VARCHAR(255) | 任务名称 | - |
| `template_type` | VARCHAR(50) | 模板类型 | - |
| `template_id` | VARCHAR(100) | 模板ID | - |
| `prompt` | TEXT | 提示词 | - |
| `status` | VARCHAR(50) | 状态 | - |
| `total_documents` | INT | 总文档数 | - |
| `completed_count` | INT | 完成数 | - |
| `failed_count` | INT | 失败数 | - |
| `model_type` | VARCHAR(50) | 模型类型 | - |
| `concurrency` | INT | 并发数 | - |
| `started_at` | TIMESTAMP | 开始时间 | - |
| `completed_at` | TIMESTAMP | 完成时间 | - |
| `duration_seconds` | INT | 执行时长(秒) | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
**4. batch_results批处理结果表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `task_id` | UUID | 任务ID | → `pkb_schema.batch_tasks(id)` |
| `document_id` | UUID | 文档ID | → `pkb_schema.documents(id)` |
| `status` | VARCHAR(50) | 状态 | - |
| `data` | JSONB | 结构化数据 | - |
| `raw_output` | TEXT | 原始输出 | - |
| `error_message` | TEXT | 错误信息 | - |
| `processing_time_ms` | INT | 处理时长(毫秒) | - |
| `tokens_used` | INT | Token使用量 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
**5. task_templates任务模板表**
| 字段名 | 类型 | 说明 | 外键 |
|-------|------|------|------|
| `id` | UUID | 主键 | - |
| `user_id` | UUID | 用户ID | → `platform_schema.users(id)` |
| `name` | VARCHAR(255) | 模板名称 | - |
| `description` | TEXT | 描述 | - |
| `prompt` | TEXT | 提示词 | - |
| `output_fields` | JSONB | 输出字段定义 | - |
| `is_public` | BOOLEAN | 是否公开 | - |
| `created_at` | TIMESTAMP | 创建时间 | - |
| `updated_at` | TIMESTAMP | 更新时间 | - |
**SQL DDL**
```sql
CREATE SCHEMA IF NOT EXISTS pkb_schema;
-- 1. knowledge_bases
CREATE TABLE pkb_schema.knowledge_bases (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
dify_dataset_id VARCHAR(255) NOT NULL,
file_count INT DEFAULT 0,
total_size_bytes BIGINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE
);
-- 2. documents (包含Phase 2字段)
CREATE TABLE pkb_schema.documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
kb_id UUID NOT NULL,
user_id UUID NOT NULL,
filename VARCHAR(255) NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_size_bytes BIGINT NOT NULL,
file_url TEXT NOT NULL,
dify_document_id VARCHAR(255) NOT NULL,
status VARCHAR(50) DEFAULT 'uploading',
progress INT DEFAULT 0,
error_message TEXT,
segments_count INT,
tokens_count INT,
-- Phase 2字段
extraction_method VARCHAR(50),
extraction_quality FLOAT,
char_count INT,
language VARCHAR(20),
extracted_text TEXT,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
processed_at TIMESTAMP,
FOREIGN KEY (kb_id) REFERENCES pkb_schema.knowledge_bases(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE
);
-- 3. batch_tasks
CREATE TABLE pkb_schema.batch_tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
kb_id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
template_type VARCHAR(50) NOT NULL,
template_id VARCHAR(100),
prompt TEXT NOT NULL,
status VARCHAR(50) NOT NULL,
total_documents INT NOT NULL,
completed_count INT DEFAULT 0,
failed_count INT DEFAULT 0,
model_type VARCHAR(50) NOT NULL,
concurrency INT DEFAULT 3,
started_at TIMESTAMP,
completed_at TIMESTAMP,
duration_seconds INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE,
FOREIGN KEY (kb_id) REFERENCES pkb_schema.knowledge_bases(id) ON DELETE CASCADE
);
-- 4. batch_results
CREATE TABLE pkb_schema.batch_results (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
task_id UUID NOT NULL,
document_id UUID NOT NULL,
status VARCHAR(50) NOT NULL,
data JSONB,
raw_output TEXT,
error_message TEXT,
processing_time_ms INT,
tokens_used INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (task_id) REFERENCES pkb_schema.batch_tasks(id) ON DELETE CASCADE,
FOREIGN KEY (document_id) REFERENCES pkb_schema.documents(id) ON DELETE CASCADE
);
-- 5. task_templates
CREATE TABLE pkb_schema.task_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
prompt TEXT NOT NULL,
output_fields JSONB NOT NULL,
is_public BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES platform_schema.users(id) ON DELETE CASCADE
);
-- 索引
CREATE INDEX idx_pkb_knowledge_bases_user_id ON pkb_schema.knowledge_bases(user_id);
CREATE INDEX idx_pkb_documents_kb_id ON pkb_schema.documents(kb_id);
CREATE INDEX idx_pkb_documents_user_id ON pkb_schema.documents(user_id);
CREATE INDEX idx_pkb_documents_status ON pkb_schema.documents(status);
CREATE INDEX idx_pkb_batch_tasks_user_id ON pkb_schema.batch_tasks(user_id);
CREATE INDEX idx_pkb_batch_tasks_kb_id ON pkb_schema.batch_tasks(kb_id);
CREATE INDEX idx_pkb_batch_results_task_id ON pkb_schema.batch_results(task_id);
CREATE INDEX idx_pkb_task_templates_user_id ON pkb_schema.task_templates(user_id);
```
---
## 预留7个空Schema
### 创建策略 ⭐
**只执行 `CREATE SCHEMA`,不创建表结构**
```sql
-- 4. AI智能文献Week 3再详细设计
CREATE SCHEMA IF NOT EXISTS asl_schema;
COMMENT ON SCHEMA asl_schema IS 'AI智能文献筛选模块 - Week 3开发前再设计表结构';
-- 5. 通用能力层(需要时再创建表)
CREATE SCHEMA IF NOT EXISTS common_schema;
COMMENT ON SCHEMA common_schema IS '通用能力层 - LLM使用记录、Feature Flags等';
-- 6. 数据清洗模块
CREATE SCHEMA IF NOT EXISTS dc_schema;
COMMENT ON SCHEMA dc_schema IS '数据清洗工具模块';
-- 7. 审稿系统包含现有review_tasks表
CREATE SCHEMA IF NOT EXISTS rvw_schema;
COMMENT ON SCHEMA rvw_schema IS '稿件审查系统模块';
-- 8. 运营管理包含现有admin_logs表
CREATE SCHEMA IF NOT EXISTS admin_schema;
COMMENT ON SCHEMA admin_schema IS '运营管理后台模块';
-- 9. 智能统计分析
CREATE SCHEMA IF NOT EXISTS ssa_schema;
COMMENT ON SCHEMA ssa_schema IS '智能统计分析模块';
-- 10. 统计分析工具
CREATE SCHEMA IF NOT EXISTS st_schema;
COMMENT ON SCHEMA st_schema IS '统计分析工具集模块';
```
### 各空Schema的用途
| Schema | 用途说明 | 何时设计表结构 |
|--------|---------|--------------|
| `asl_schema` | AI智能文献筛选 | **Week 3 Day 1** - ASL开发前详细设计 |
| `common_schema` | 通用能力LLM使用记录、Feature Flags | 需要时再设计 |
| `dc_schema` | 数据清洗工具 | Week 5+或按需 |
| `rvw_schema` | 稿件审查系统 | Week 1迁移review_tasks其他表按需 |
| `admin_schema` | 运营管理后台 | Week 1迁移admin_logs其他表按需 |
| `ssa_schema` | 智能统计分析 | Week 5+或按需 |
| `st_schema` | 统计分析工具集 | Week 5+或按需 |
---
## 迁移策略
### 迁移优先级
| 优先级 | Schema | 表数量 | 数据量估算 | 迁移时间 |
|-------|--------|--------|-----------|---------|
| **P0** | platform_schema | 1 | ~10条 | 15分钟 |
| **P0** | aia_schema | 5 | ~500条 | 30分钟 |
| **P0** | pkb_schema | 5 | ~100条 | 30分钟 |
| **P1** | rvw_schema | 1review_tasks | ~20条 | 10分钟 |
| **P1** | admin_schema | 1admin_logs | ~50条 | 10分钟 |
### 迁移步骤4步法
**Step 1创建10个Schema5分钟**
```sql
-- 执行脚本001-create-all-10-schemas.sql
-- 创建10个Schema3详细+7空
```
**Step 2创建表结构30分钟**
```sql
-- 执行脚本:
-- 002-migrate-platform.sql - 创建platform_schema.users
-- 003-migrate-aia.sql - 创建aia_schema的5个表
-- 004-migrate-pkb.sql - 创建pkb_schema的5个表
```
**Step 3迁移数据30分钟**
```sql
-- 使用 INSERT INTO ... SELECT FROM 方式
-- 保持ID不变确保引用关系不变
```
**Step 4验证30分钟**
```sql
-- 执行脚本005-validate-all.sql
-- 验证数据完整性、外键约束
```
### 数据迁移示例
**platform_schema.users**
```sql
INSERT INTO platform_schema.users
SELECT * FROM public.users;
```
**aia_schema.projects**
```sql
INSERT INTO aia_schema.projects
SELECT * FROM public.projects;
```
**验证:**
```sql
-- 验证数据量
SELECT 'users' AS table_name, COUNT(*) FROM platform_schema.users
UNION ALL
SELECT 'projects', COUNT(*) FROM aia_schema.projects
UNION ALL
SELECT 'conversations', COUNT(*) FROM aia_schema.conversations;
```
---
## 现有表分配方案
### 当前public schema中的13个表
| # | 表名 | 目标Schema | 迁移时机 | 说明 |
|---|------|-----------|---------|------|
| 1 | `users` | `platform_schema` | Week 1 | ✅ P0核心表 |
| 2 | `projects` | `aia_schema` | Week 1 | ✅ P0核心表 |
| 3 | `conversations` | `aia_schema` | Week 1 | ✅ P0核心表 |
| 4 | `messages` | `aia_schema` | Week 1 | ✅ P0核心表 |
| 5 | `general_conversations` | `aia_schema` | Week 1 | ✅ P0核心表 |
| 6 | `general_messages` | `aia_schema` | Week 1 | ✅ P0核心表 |
| 7 | `knowledge_bases` | `pkb_schema` | Week 1 | ✅ P0核心表 |
| 8 | `documents` | `pkb_schema` | Week 1 | ✅ P0核心表 |
| 9 | `batch_tasks` | `pkb_schema` | Week 1 | ✅ P0核心表 |
| 10 | `batch_results` | `pkb_schema` | Week 1 | ✅ P0核心表 |
| 11 | `task_templates` | `pkb_schema` | Week 1 | ✅ P0核心表 |
| 12 | `review_tasks` | `rvw_schema` | Week 1或保留 | 📋 P1可选 |
| 13 | `admin_logs` | `admin_schema` | Week 1或保留 | 📋 P1可选 |
**说明:**
- **优先迁移11个表**到3个详细SchemaPlatform/AIA/PKB
- **review_tasks和admin_logs**可以:
- 选项AWeek 1一并迁移到对应的空Schema简单
- 选项B暂时保留在public需要时再迁移务实
- **建议选项A**:一次性迁移完成,避免残留
---
## 外键和跨Schema引用
### PostgreSQL跨Schema外键支持 ✅
PostgreSQL **完全支持**跨Schema的外键约束
```sql
-- 示例aia_schema.projects 引用 platform_schema.users
CREATE TABLE aia_schema.projects (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
name VARCHAR(255),
FOREIGN KEY (user_id)
REFERENCES platform_schema.users(id)
ON DELETE CASCADE
);
```
### 引用规则
**✅ 允许的引用:**
- 业务模块Schema → `platform_schema.users(id)`
- 同Schema内的表相互引用
**❌ 禁止的引用:**
- `platform_schema` → 业务模块Schema反向依赖
- 业务模块Schema之间相互引用保持独立性
### 数据一致性保证
1. **CASCADE删除** - 用户删除时,关联数据自动删除
2. **外键索引** - 所有外键字段创建索引
3. **事务保护** - 迁移在事务中执行,全成功或全失败
---
## Prisma配置策略
### Week 1的Prisma配置
**在schema.prisma中**
1. **启用multiSchema预览特性**
```prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["multiSchema"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = [
"platform_schema",
"aia_schema",
"pkb_schema",
"asl_schema", // 空Schema预留
"common_schema", // 空Schema预留
"dc_schema", // 空Schema预留
"rvw_schema", // 空Schema预留
"admin_schema", // 空Schema预留
"ssa_schema", // 空Schema预留
"st_schema" // 空Schema预留
]
}
```
2. **只为3个详细Schema定义模型**
```prisma
// Platform Schema
model User {
// ...
@@map("users")
@@schema("platform_schema")
}
// AIA Schema
model Project {
// ...
@@map("projects")
@@schema("aia_schema")
}
// PKB Schema
model KnowledgeBase {
// ...
@@map("knowledge_bases")
@@schema("pkb_schema")
}
```
3. **7个空Schema不定义模型**
- 只在schemas列表中声明
- Week 3再为asl_schema添加模型
- 其他按需添加
**详细Prisma配置参考**
- 见V2.2完整版文档的 Day 4 Prisma配置示例
---
## 📊 工作量估算
| 任务 | 预计时间 | 说明 |
|------|---------|------|
| **Day 1-2上午架构规划与设计** | 8小时 | 本文档 + 3个Schema SQL |
| **Day 2下午编写迁移脚本** | 1.5小时 | 5个SQL脚本 |
| **Day 3上午执行迁移** | 2-3小时 | 备份 + 迁移 + 验证 |
| **Day 3下午功能测试** | 2小时 | 测试现有功能 |
| **Day 4Prisma配置** | 3小时 | 更新schema.prisma |
| **总计** | **约16-17小时2天** | ✅ |
---
## 🎯 成功标准
Week 1结束时应达到
- [ ] ✅ 10个Schema全部创建成功
- [ ] ✅ 3个详细Schema的11个表数据100%迁移
- [ ] ✅ 所有外键约束正确建立
- [ ] ✅ 现有功能AIA、PKB正常运行
- [ ] ✅ Prisma Client生成成功
- [ ] ✅ 7个空Schema验证通过可查询、可创建表
---
## 📝 后续步骤
### Week 2
- 前端统一架构
- 后端代码分层
- 适配新的Schema结构
### Week 3
- **详细设计asl_schema** ⭐
- 为asl_schema创建表结构
- 开发ASL核心功能
### Week 5+
- 按需为其他空Schema设计表结构
- LLM网关统一
- 其他模块开发
---
**文档制定:** AI助手
**审核:** 待审核
**最后更新:** 2025-11-09
**核心策略:聚焦当前 + 架构预留 + Just-in-time设计** ⭐⭐⭐