- Implement 5 core API endpoints (create task, get progress, get results, update decision, export Excel) - Add FulltextScreeningController with Zod validation (652 lines) - Implement ExcelExporter service with 4-sheet report generation (352 lines) - Register routes under /api/v1/asl/fulltext-screening - Create 31 REST Client test cases - Add automated integration test script - Fix PDF extraction fallback mechanism in LLM12FieldsService - Update API design documentation to v3.0 - Update development plan to v1.2 - Create Day 5 development record - Clean up temporary test files
11 KiB
11 KiB
平台基础设施(Platform Infrastructure)
版本: V1.0
创建日期: 2025-11-17
状态: ✅ 实施完成
📋 概述
平台基础设施提供了一套通用的、云原生的基础能力,支持本地开发和云端部署无缝切换。
核心设计原则:适配器模式(Adapter Pattern)
所有业务模块(ASL、AIA、PKB等)都应该使用这些平台能力,而不是重复实现。
🏗️ 模块清单
| 模块 | 路径 | 状态 | 说明 |
|---|---|---|---|
| 存储服务 | common/storage/ |
✅ 完成 | 文件上传下载(本地/OSS) |
| 数据库连接池 | config/database.ts |
✅ 完成 | Prisma连接池配置 |
| 日志系统 | common/logging/ |
✅ 完成 | 结构化日志(JSON) |
| 环境配置 | config/env.ts |
✅ 完成 | 统一配置管理 |
| 异步任务 | common/jobs/ |
✅ 完成 | 长时间任务异步处理 |
| 缓存服务 | common/cache/ |
✅ 完成 | 内存/Redis缓存 |
| 健康检查 | common/health/ |
✅ 完成 | SAE健康检查端点 |
| 监控指标 | common/monitoring/ |
✅ 完成 | 关键指标监控 |
📦 依赖安装
在使用之前,需要安装必需的依赖:
# 进入backend目录
cd backend
# 安装winston日志库
npm install winston
npm install -D @types/winston
可选依赖(云端部署时安装):
# 阿里云OSS(当STORAGE_TYPE=oss时)
npm install ali-oss
npm install -D @types/ali-oss
# Redis(当CACHE_TYPE=redis时)
npm install ioredis
npm install -D @types/ioredis
🚀 快速开始
1. 存储服务
import { storage } from '@/common/storage'
// 上传文件
const buffer = await readFile('example.pdf')
const url = await storage.upload('literature/123.pdf', buffer)
// 下载文件
const data = await storage.download('literature/123.pdf')
// 删除文件
await storage.delete('literature/123.pdf')
环境切换:
# 本地开发
STORAGE_TYPE=local
# 云端部署
STORAGE_TYPE=oss
OSS_REGION=oss-cn-hangzhou
OSS_BUCKET=aiclinical-prod
OSS_ACCESS_KEY_ID=your-key-id
OSS_ACCESS_KEY_SECRET=your-key-secret
2. 日志系统
import { logger } from '@/common/logging'
// 基础日志
logger.info('User logged in', { userId: 123 })
logger.error('Database error', { error: err.message })
// 带上下文的日志
const aslLogger = logger.child({ module: 'ASL', projectId: 456 })
aslLogger.info('Screening started', { count: 100 })
输出格式:
- 本地开发:彩色可读格式
- 生产环境:JSON格式(便于阿里云SLS解析)
3. 异步任务
import { jobQueue } from '@/common/jobs'
// 创建任务(立即返回)
const job = await jobQueue.push('asl:screening', {
projectId: 123,
literatureIds: [1, 2, 3]
})
// 返回任务ID给前端
res.send({ jobId: job.id })
// 注册处理函数
jobQueue.process('asl:screening', async (job) => {
for (const id of job.data.literatureIds) {
await processLiterature(id)
await jobQueue.updateProgress(job.id, ...)
}
return { success: true }
})
// 查询任务状态
const status = await jobQueue.getJob(job.id)
4. 缓存服务
import { cache } from '@/common/cache'
// 缓存用户数据(5分钟)
await cache.set('user:123', userData, 60 * 5)
const user = await cache.get<User>('user:123')
// 缓存LLM响应(1小时)
const cacheKey = `llm:${model}:${hash(prompt)}`
const cached = await cache.get(cacheKey)
if (!cached) {
const response = await llm.chat(prompt)
await cache.set(cacheKey, response, 60 * 60)
}
环境切换:
# 本地开发
CACHE_TYPE=memory
# 云端部署
CACHE_TYPE=redis
REDIS_HOST=r-xxx.redis.aliyuncs.com
REDIS_PORT=6379
REDIS_PASSWORD=your-password
5. 数据库连接
import { prisma } from '@/config/database'
// 直接使用(已配置连接池)
const users = await prisma.user.findMany()
// 获取连接数(监控用)
import { getDatabaseConnectionCount } from '@/config/database'
const count = await getDatabaseConnectionCount()
云原生配置:
DATABASE_URL=postgresql://user:pass@host:5432/db
DB_MAX_CONNECTIONS=400 # RDS最大连接数
MAX_INSTANCES=20 # SAE最大实例数
6. 健康检查
import { registerHealthRoutes } from '@/common/health'
// 注册路由(在应用启动时)
await registerHealthRoutes(app)
端点:
GET /health/liveness- SAE存活检查GET /health/readiness- SAE就绪检查GET /health- 详细健康检查(开发用)
7. 监控指标
import { Metrics, requestTimingHook, responseTimingHook } from '@/common/monitoring'
// 注册中间件(自动记录API响应时间)
app.addHook('onRequest', requestTimingHook)
app.addHook('onResponse', responseTimingHook)
// 启动定期监控
Metrics.startPeriodicMonitoring(60000) // 每分钟
// 手动记录指标
await Metrics.recordDBConnectionCount()
Metrics.recordMemoryUsage()
// 记录LLM调用
Metrics.recordLLMCall('deepseek', 'chat', 1500, true, {
prompt: 100,
completion: 200,
total: 300
})
🌍 多环境支持
本地开发(.env.development)
# 应用配置
NODE_ENV=development
PORT=3001
LOG_LEVEL=debug
# 数据库
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ai_clinical
# 存储(本地)
STORAGE_TYPE=local
LOCAL_STORAGE_DIR=uploads
# 缓存(内存)
CACHE_TYPE=memory
# 任务队列(内存)
QUEUE_TYPE=memory
云端部署(.env.production)
# 应用配置
NODE_ENV=production
PORT=8080
LOG_LEVEL=info
# 数据库(阿里云RDS)
DATABASE_URL=postgresql://user:pass@rm-xxx.pg.rds.aliyuncs.com:5432/aiclinical
DB_MAX_CONNECTIONS=400
MAX_INSTANCES=20
# 存储(阿里云OSS)
STORAGE_TYPE=oss
OSS_REGION=oss-cn-hangzhou
OSS_BUCKET=aiclinical-prod
OSS_ACCESS_KEY_ID=your-key-id
OSS_ACCESS_KEY_SECRET=your-key-secret
# 缓存(阿里云Redis)
CACHE_TYPE=redis
REDIS_HOST=r-xxx.redis.aliyuncs.com
REDIS_PORT=6379
REDIS_PASSWORD=your-password
# 任务队列(数据库)
QUEUE_TYPE=database
📊 架构示意图
┌─────────────────────────────────────────────────────────┐
│ 业务模块层 │
│ ASL | AIA | PKB | DC | SSA | ST | UAM │
│ 只关注业务逻辑,复用平台能力 │
└─────────────────────────────────────────────────────────┘
↓ import from '@/common/'
┌─────────────────────────────────────────────────────────┐
│ 平台基础设施层(Adapter Pattern) │
├─────────────────────────────────────────────────────────┤
│ 存储:LocalAdapter ←→ OSSAdapter │
│ 缓存:MemoryCacheAdapter ←→ RedisCacheAdapter │
│ 任务:MemoryQueueAdapter ←→ DatabaseQueueAdapter │
│ 日志:ConsoleLogger ←→ 阿里云SLS │
│ 数据库:本地PostgreSQL ←→ 阿里云RDS(连接池) │
└─────────────────────────────────────────────────────────┘
↓ 环境变量切换
┌─────────────────────────────────────────────────────────┐
│ 部署环境(零代码改动) │
│ 本地开发 | 云端SaaS | 私有化部署 | 单机版 │
└─────────────────────────────────────────────────────────┘
✅ 验收标准
功能完整性
- 存储服务:LocalAdapter实现完成,OSSAdapter预留
- 数据库:连接池配置,优雅关闭
- 日志系统:Winston配置,JSON格式
- 异步任务:MemoryQueue实现完成
- 缓存服务:MemoryCacheAdapter实现完成,RedisCacheAdapter预留
- 健康检查:liveness/readiness端点
- 监控指标:数据库连接数、内存、API响应时间
多环境支持
- 本地开发:LocalAdapter + MemoryCache + MemoryQueue
- 云端部署:OSSAdapter(预留)+ RedisCache(预留)+ DatabaseQueue(预留)
- 零代码切换:通过环境变量切换
🚨 注意事项
1. Winston未安装
当前状态: 代码已完成,但winston包未安装
安装方法:
npm install winston
npm install -D @types/winston
2. OSS/Redis待实现
当前状态: 接口和工厂类已完成,具体实现预留
实施时机: 云端部署前
实施步骤:
- 安装依赖:
npm install ali-oss ioredis - 取消注释:
OSSAdapter.ts、RedisCacheAdapter.ts - 测试验证
3. Legacy模块兼容性
策略: Legacy模块(PKB、AIA、DC)保持现状,新模块(ASL)使用平台基础设施
迁移: 可选,按需迁移(预计5小时)
📚 相关文档
🎯 下一步
选项1:安装依赖并测试(推荐)
cd backend
npm install winston
npm run dev
选项2:开始ASL模块开发
平台基础设施已完成,可以开始ASL模块开发:
- 使用
storage上传PDF - 使用
logger记录日志 - 使用
jobQueue处理异步筛选任务 - 使用
cache缓存LLM响应
平台基础设施实施完成! ✅
总耗时: 约3小时(Day 1: 2小时,Day 2: 1小时)
代码量: 约2000行
模块数: 8个核心模块
下一步:安装winston依赖,开始ASL模块开发! 🚀