Files
AIclinicalresearch/docs/09-架构实施/02-数据库连接配置.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

17 KiB
Raw Permalink Blame History

数据库连接配置

文档版本: v1.0
创建日期: 2025-11-09
维护者: 架构团队
最后更新: 2025-11-09


📋 文档说明

本文档记录Schema隔离架构实施相关的数据库连接和配置信息包括

  • 当前数据库状态
  • Schema隔离迁移配置
  • 迁移过程的连接方式
  • 验证和回滚方案

🗄️ 当前数据库状态

数据库基本信息

连接信息:

数据库类型PostgreSQL 15+
数据库名称ai_clinical_research
主机地址:  localhost
端口:      5432
用户名:    postgres
密码:      postgres

完整连接字符串:

DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research

当前Schema结构

现有Schema

  • public - 所有13个表都在这里

表清单13个

1. 平台基础2个表

public.users              -- 用户表
public.admin_logs         -- 管理日志

2. AI智能问答5个表

public.projects              -- 项目管理
public.conversations         -- 项目对话
public.messages              -- 对话消息
public.general_conversations -- 通用对话
public.general_messages      -- 通用消息

3. 个人知识库2个表

public.knowledge_bases    -- 知识库
public.documents          -- 文档

4. 批处理系统3个表

public.batch_tasks        -- 批处理任务
public.batch_results      -- 批处理结果
public.task_templates     -- 任务模板

5. 稿件审查1个表

public.review_tasks       -- 审查任务

数据库统计信息

表数量: 13个
索引数量: 约40个
外键约束: 约15个

当前数据量(估算):

  • users: ~10条
  • projects: ~20条
  • conversations: ~50条
  • messages: ~500条
  • knowledge_bases: ~5条
  • documents: ~30条
  • 其他表:测试数据

总数据量: < 10MB测试环境


🎯 Schema隔离目标架构

10个独立Schema

需要详细设计+数据迁移5个

1. platform_schema平台基础层

-- 迁移表:
public.users           platform_schema.users
public.admin_logs      platform_schema.admin_logs (暂缓,待确认)

2. common_schema通用能力层

-- 新建表:
common_schema.llm_usage         -- LLM使用记录
common_schema.feature_flags     -- Feature Flags

3. asl_schemaAI智能文献

-- 新建表:
asl_schema.literature_projects  -- 文献项目
asl_schema.pico_configs         -- PICO配置
asl_schema.literature_items     -- 文献条目
-- 更多表见ASL设计文档

4. aia_schemaAI智能问答

-- 迁移表:
public.projects               aia_schema.projects
public.conversations          aia_schema.conversations
public.messages               aia_schema.messages
public.general_conversations  aia_schema.general_conversations
public.general_messages       aia_schema.general_messages

5. pkb_schema个人知识库

-- 迁移表:
public.knowledge_bases  pkb_schema.knowledge_bases
public.documents        pkb_schema.documents

只创建空Schema5个

6. dc_schema数据清洗 - 暂无表结构
7. rvw_schema审稿系统 - 暂无表结构
8. admin_schema运营管理 - 暂无表结构
9. ssa_schema智能统计分析 - 暂无表结构
10. st_schema统计分析工具 - 暂无表结构


🔄 迁移过程连接配置

迁移前准备

1. 备份当前数据库

# Windows PowerShell
cd D:\MyCursor\AIclinicalresearch\backend

# 使用pg_dump备份
pg_dump -h localhost -U postgres -d ai_clinical_research -F c -f backup_before_schema_migration_$(Get-Date -Format 'yyyyMMdd_HHmmss').dump

# 或者使用SQL格式
pg_dump -h localhost -U postgres -d ai_clinical_research > backup_before_schema_migration_$(Get-Date -Format 'yyyyMMdd_HHmmss').sql

2. 验证备份

# 检查备份文件大小
ls -lh backup_*.dump

# 验证备份内容SQL格式
head -n 50 backup_*.sql

迁移过程连接方式

方式1使用Prisma Migrate推荐

连接配置:

# backend/.env
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research

执行迁移:

cd backend

# 创建新的迁移
npx prisma migrate dev --name schema_isolation_10_schemas

# 查看迁移状态
npx prisma migrate status

方式2直接执行SQL脚本

连接方式:

# 使用psql连接
psql -h localhost -U postgres -d ai_clinical_research

# 或使用环境变量
export PGPASSWORD=postgres
psql -h localhost -U postgres -d ai_clinical_research -f migration_script.sql

执行迁移脚本:

cd docs/09-架构实施/migration-scripts

# 按顺序执行
psql -h localhost -U postgres -d ai_clinical_research -f 001-create-all-10-schemas.sql
psql -h localhost -U postgres -d ai_clinical_research -f 002-migrate-platform.sql
psql -h localhost -U postgres -d ai_clinical_research -f 003-migrate-aia.sql
psql -h localhost -U postgres -d ai_clinical_research -f 004-migrate-pkb.sql
# ... 更多脚本

方式3使用可视化工具

pgAdmin 4

  1. 连接信息:

    • 主机localhost
    • 端口5432
    • 数据库ai_clinical_research
    • 用户postgres
    • 密码postgres
  2. 执行迁移:

    • 打开Query Tool
    • 加载SQL脚本
    • 执行

DataGrip / DBeaver

  • 同样的连接信息
  • 支持事务管理
  • 方便回滚

迁移验证

1. 检查Schema创建

SQL验证

-- 查看所有Schema
SELECT schema_name 
FROM information_schema.schemata 
WHERE schema_name NOT IN ('pg_catalog', 'information_schema')
ORDER BY schema_name;

-- 预期结果:
-- admin_schema
-- aia_schema
-- asl_schema
-- common_schema
-- dc_schema
-- pkb_schema
-- platform_schema
-- public
-- rvw_schema
-- ssa_schema
-- st_schema

2. 检查表迁移

验证platform_schema

-- 查看表
SELECT table_name 
FROM information_schema.tables 
WHERE table_schema = 'platform_schema';

-- 验证数据
SELECT COUNT(*) FROM platform_schema.users;
-- 预期与原public.users的数量一致

验证aia_schema

-- 查看所有表
SELECT table_name 
FROM information_schema.tables 
WHERE table_schema = 'aia_schema';

-- 验证数据完整性
SELECT COUNT(*) FROM aia_schema.projects;
SELECT COUNT(*) FROM aia_schema.conversations;
SELECT COUNT(*) FROM aia_schema.messages;

验证pkb_schema

SELECT COUNT(*) FROM pkb_schema.knowledge_bases;
SELECT COUNT(*) FROM pkb_schema.documents;

3. 验证外键关系

检查跨Schema外键

-- 查看所有外键约束
SELECT 
    tc.table_schema,
    tc.table_name,
    kcu.column_name,
    ccu.table_schema AS foreign_table_schema,
    ccu.table_name AS foreign_table_name,
    ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
    ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
    ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY'
    AND tc.table_schema IN ('platform_schema', 'aia_schema', 'pkb_schema', 'asl_schema', 'common_schema')
ORDER BY tc.table_schema, tc.table_name;

4. 验证索引

检查索引是否正确迁移:

-- 查看某个Schema的所有索引
SELECT 
    schemaname,
    tablename,
    indexname,
    indexdef
FROM pg_indexes
WHERE schemaname = 'aia_schema'
ORDER BY tablename, indexname;

5. Prisma验证

更新Prisma配置后验证

cd backend

# 生成Prisma Client
npx prisma generate

# 验证Prisma Client可用
npx ts-node -e "import { PrismaClient } from '@prisma/client'; const p = new PrismaClient(); p.user.count().then(console.log)"

🔙 回滚方案

场景1迁移过程中发现问题

立即回滚:

# 如果使用Prisma Migrate
npx prisma migrate reset

# 恢复备份
psql -h localhost -U postgres -d ai_clinical_research < backup_before_schema_migration_YYYYMMDD_HHMMSS.sql

场景2迁移完成后发现问题

方案A从备份恢复推荐

# 1. 删除当前数据库
dropdb -h localhost -U postgres ai_clinical_research

# 2. 重新创建
createdb -h localhost -U postgres ai_clinical_research

# 3. 恢复备份
pg_restore -h localhost -U postgres -d ai_clinical_research backup_before_schema_migration_YYYYMMDD_HHMMSS.dump

方案B手动删除新Schema保留public

-- 删除新建的Schema慎重
DROP SCHEMA IF EXISTS platform_schema CASCADE;
DROP SCHEMA IF EXISTS aia_schema CASCADE;
DROP SCHEMA IF EXISTS pkb_schema CASCADE;
DROP SCHEMA IF EXISTS asl_schema CASCADE;
DROP SCHEMA IF EXISTS common_schema CASCADE;
DROP SCHEMA IF EXISTS dc_schema CASCADE;
DROP SCHEMA IF EXISTS rvw_schema CASCADE;
DROP SCHEMA IF EXISTS admin_schema CASCADE;
DROP SCHEMA IF EXISTS ssa_schema CASCADE;
DROP SCHEMA IF EXISTS st_schema CASCADE;

-- public schema的表如果被删除了从备份恢复

📊 迁移检查清单

迁移前检查

  • 数据库已备份backup_before_schema_migration_*.dump
  • 备份文件已验证
  • Prisma配置已更新datasource.schemas
  • 迁移脚本已准备001-010.sql
  • 测试环境已验证迁移步骤

迁移中检查

  • 10个Schema创建成功
  • 表迁移无错误5个有数据的Schema
  • 数据完整性验证通过
  • 外键约束正确
  • 索引正确创建

迁移后检查

  • Prisma Client生成成功
  • 后端服务启动正常
  • 现有功能测试通过AIA、PKB
  • API调用正常
  • 前端功能正常

🔧 常见问题

问题1Schema创建失败

错误:

ERROR: schema "platform_schema" already exists

解决:

-- 检查Schema是否存在
SELECT schema_name FROM information_schema.schemata 
WHERE schema_name = 'platform_schema';

-- 如果存在但为空,可删除重建
DROP SCHEMA platform_schema CASCADE;
CREATE SCHEMA platform_schema;

问题2数据迁移失败

错误:

ERROR: duplicate key value violates unique constraint

解决:

  1. 检查数据是否已部分迁移
  2. 清理目标Schema
  3. 重新执行迁移

问题3外键约束错误

错误:

ERROR: foreign key constraint "fk_user_id" cannot be implemented

解决:

  1. 确保被引用的表已先迁移
  2. 检查外键字段类型匹配
  3. 考虑先禁用外键,迁移后重建

🔧 云原生连接池配置2025-11-16 新增)

重要更新:为支持阿里云 Serverless 部署,新增连接池配置
详细文档平台基础设施规划

背景:为什么需要连接池?

问题场景

阿里云 SAE 自动扩容:
- 初始1个实例10个连接
- 高峰100个实例1000个连接
- RDS最大连接数400 ❌ 超限!

结果:数据库连接耗尽,应用崩溃

解决方案:动态计算每实例连接数

每实例连接数 = RDS最大连接数 / SAE最大实例数
示例:400连接 / 20实例 = 20连接/实例

Prisma连接池配置

文件位置backend/src/config/database.ts

配置代码

import { PrismaClient } from '@prisma/client'

// 动态计算连接数
const dbMaxConnections = Number(process.env.DB_MAX_CONNECTIONS) || 400
const maxInstances = Number(process.env.MAX_INSTANCES) || 20
const connectionLimit = Math.floor(dbMaxConnections / maxInstances)

console.log(`📊 数据库连接池配置:每实例最多${connectionLimit}个连接`)

// 创建全局Prisma Client
export const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
  log: process.env.NODE_ENV === 'development' 
    ? ['query', 'error', 'warn'] 
    : ['error'],
  errorFormat: 'minimal',
})

// 优雅关闭连接
process.on('SIGTERM', async () => {
  console.log('📊 正在关闭数据库连接...')
  await prisma.$disconnect()
  console.log('✅ 数据库连接已关闭')
  process.exit(0)
})

process.on('SIGINT', async () => {
  console.log('📊 正在关闭数据库连接...')
  await prisma.$disconnect()
  console.log('✅ 数据库连接已关闭')
  process.exit(0)
})

// 启动时测试连接
prisma.$connect()
  .then(() => console.log('✅ 数据库连接成功'))
  .catch((err) => {
    console.error('❌ 数据库连接失败:', err)
    process.exit(1)
  })

环境变量配置

本地开发环境

# backend/.env.development
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical_research

# 本地开发无需配置连接池(单实例)
# DB_MAX_CONNECTIONS=N/A
# MAX_INSTANCES=N/A

云端生产环境

# SAE控制台 -> 环境变量配置
DATABASE_URL=postgresql://user:password@rm-xxx.aliyuncs.com:5432/prod_db
DB_MAX_CONNECTIONS=400        # 阿里云RDS最大连接数
MAX_INSTANCES=20              # SAE最大实例数

不同RDS规格的连接数

RDS规格 最大连接数 建议SAE实例数 每实例连接数
2核4GB 200 10 20
4核8GB 400 20 20
8核16GB 800 40 20

监控数据库连接数

实时查询连接数

// backend/src/common/monitoring/metrics.ts
import { prisma } from '@/config/database'
import { logger } from '@/common/logging'

export class DatabaseMetrics {
  // 查询当前连接数
  static async getConnectionCount(): Promise<number> {
    const result = await prisma.$queryRaw<Array<{ count: bigint }>>`
      SELECT count(*) as count 
      FROM pg_stat_activity 
      WHERE datname = current_database()
    `
    return Number(result[0].count)
  }
  
  // 监控并告警
  static async monitorConnections() {
    const currentConnections = await this.getConnectionCount()
    const maxConnections = Number(process.env.DB_MAX_CONNECTIONS) || 400
    const usagePercent = (currentConnections / maxConnections) * 100
    
    logger.info('数据库连接监控', {
      current: currentConnections,
      max: maxConnections,
      usage: `${usagePercent.toFixed(1)}%`
    })
    
    // 告警连接数超过80%
    if (usagePercent > 80) {
      logger.warn('⚠️ 数据库连接数告警', {
        current: currentConnections,
        max: maxConnections,
        usage: `${usagePercent.toFixed(1)}%`,
        action: '建议增加RDS规格或减少SAE实例数'
      })
    }
    
    return { currentConnections, maxConnections, usagePercent }
  }
}

定时监控(可选):

// backend/src/index.ts
import { DatabaseMetrics } from '@/common/monitoring/metrics'

// 每5分钟监控一次
setInterval(async () => {
  await DatabaseMetrics.monitorConnections()
}, 5 * 60 * 1000)

故障排查

问题1连接数耗尽

症状

Error: P1001: Can't reach database server
Error: remaining connection slots are reserved

原因

  • SAE实例数过多
  • 每实例连接数配置过高
  • 存在连接泄漏

解决方案

# 1. 查看当前连接数
SELECT count(*) FROM pg_stat_activity 
WHERE datname = 'ai_clinical_research';

# 2. 查看连接来源
SELECT client_addr, count(*) 
FROM pg_stat_activity 
WHERE datname = 'ai_clinical_research'
GROUP BY client_addr;

# 3. 调整配置
# 方案A减少SAE最大实例数
MAX_INSTANCES=10  # 从20改为10

# 方案B升级RDS规格
# 从2核4GB200连接升级到4核8GB400连接

问题2连接泄漏

症状

  • 连接数持续增长
  • 即使流量降低,连接数不下降

排查

// ❌ 错误:每次创建新实例
function getUser() {
  const prisma = new PrismaClient()  // 连接泄漏
  return prisma.user.findMany()
}

// ✅ 正确:使用全局实例
import { prisma } from '@/config/database'

function getUser() {
  return prisma.user.findMany()
}

最佳实践

DO

  1. 使用全局 prisma 实例
  2. 配置 SIGTERM 优雅关闭
  3. 定期监控连接数
  4. 设置连接数告警80%阈值)
  5. 使用连接池Prisma默认启用

DON'T

  1. 每次请求新建 PrismaClient
  2. 不关闭连接就退出进程
  3. 忽略连接数监控
  4. 设置过大的 MAX_INSTANCES
  5. 在业务代码中直接执行 $disconnect()

📚 相关文档


🔄 更新记录

日期 更新内容 更新人
2025-11-09 初始文档创建 架构团队
2025-11-16 新增云原生连接池配置章节 架构团队

文档版本: v1.0
最后更新: 2025-11-09
维护者: 架构团队