# 平台基础设施规划（Platform Infrastructure Plan）

> **文档版本：** V1.0  
> **创建日期：** 2025-11-16  
> **适用对象：** 架构师、后端开发、运维  
> **文档状态：** 实施规划  
> **维护者：** 架构团队

---

## 📋 文档说明

本文档是壹证循AI科研平台的**平台基础设施规划文档**，定义了：

1. **核心需求**：平台基础设施需要解决的问题
2. **设计方案**：技术架构和实现方案
3. **实施计划**：分阶段的实施路线图
4. **验收标准**：每个模块的验收标准

**核心目标：**
- ✅ 支持本地开发和云端部署无缝切换
- ✅ 支持PRD定义的4种部署形态（云端SaaS、私有化、单机版、混合）
- ✅ 支持模块化组合售卖（专业版、高级版、旗舰版）
- ✅ 提供通用能力，所有业务模块直接复用

---

## 🎯 需求背景

### 1. 业务需求（来自PRD）

根据 [09-总体需求文档(PRD).md](../00-系统总体设计/09-总体需求文档(PRD).md)，平台必须支持：

| 需求ID | 需求描述 | 技术挑战 |
|--------|---------|---------|
| **NFR-1.1** | 云端SaaS版（多租户、高可用） | Serverless架构、自动扩缩容 |
| **NFR-1.2** | 私有化部署（数据不出内网） | 本地存储、本地数据库 |
| **NFR-1.3** | 单机版（100%本地化） | 离线运行、本地文件系统 |
| **NFR-1.4** | 混合部署（部分本地+部分云端） | 灵活的配置切换 |
| **NFR-2.1** | SaaS多版本（专业版、高级版、旗舰版） | Feature Flag、模块化 |
| **NFR-2.2** | 模块化售卖（任何模块可独立售卖） | 松耦合架构 |
| **NFR-2.3** | AI成本可控（动态切换LLM） | 适配器模式 |

### 2. 技术需求（来自云原生架构）

根据云原生部署架构（阿里云 Serverless + RDS + OSS），平台必须：

| 技术需求 | 说明 | 优先级 |
|---------|------|--------|
| **无状态应用** | 不依赖本地文件系统或内存状态 | P0 |
| **存储抽象** | 支持本地存储和OSS无缝切换 | P0 |
| **数据库连接池** | 防止Serverless扩容导致连接数超限 | P0 |
| **标准化日志** | 输出到stdout，支持集中收集 | P0 |
| **异步任务** | 长时间任务必须异步处理（避免超时） | P0 |
| **分布式缓存** | 多实例共享缓存 | P1 |
| **健康检查** | SAE存活和就绪检查 | P1 |
| **监控指标** | 数据库连接数、任务队列等 | P1 |

---

## 🏗️ 设计方案

### 核心设计原则

> **平台基础设施通过适配器模式（Adapter Pattern）实现多环境支持**

```
┌─────────────────────────────────────────────────────────┐
│                   业务模块层                             │
│   ASL | AIA | PKB | DC | SSA | ST | UAM                │
│   只关注业务逻辑，复用平台能力                            │
└─────────────────────────────────────────────────────────┘
                    ↓ import from '@/common/'
┌─────────────────────────────────────────────────────────┐
│              平台基础设施层（Adapter Pattern）            │
├─────────────────────────────────────────────────────────┤
│ 存储：LocalAdapter ←→ OSSAdapter                        │
│ 缓存：MemoryCacheAdapter ←→ RedisCacheAdapter           │
│ 任务：MemoryQueueAdapter ←→ DatabaseQueueAdapter        │
│ 日志：ConsoleLogger ←→ 阿里云SLS                         │
│ 数据库：本地PostgreSQL ←→ 阿里云RDS（连接池）            │
└─────────────────────────────────────────────────────────┘
                    ↓ 环境变量切换
┌─────────────────────────────────────────────────────────┐
│         部署环境（零代码改动）                            │
│  本地开发 | 云端SaaS | 私有化部署 | 单机版               │
└─────────────────────────────────────────────────────────┘
```

---

## 📦 平台基础设施模块清单

### 模块总览

| 模块 | 路径 | 优先级 | 说明 |
|------|------|--------|------|
| **存储服务** | `common/storage/` | P0 | 文件上传下载（本地/OSS） |
| **数据库连接池** | `config/database.ts` | P0 | Prisma连接池配置 |
| **日志系统** | `common/logging/` | P0 | 标准化日志输出 |
| **环境配置** | `config/env.ts` | P0 | 环境变量管理 |
| **异步任务** | `common/jobs/` | P0 | 长时间任务异步处理 |
| **缓存服务** | `common/cache/` | P1 | 分布式缓存 |
| **健康检查** | `common/health/` | P1 | SAE健康检查端点 |
| **监控指标** | `common/monitoring/` | P1 | 关键指标监控 |

---

## 📐 详细设计

### 1. 存储服务（Storage Service）

#### 设计目标
- ✅ 支持本地开发（LocalAdapter）
- ✅ 支持云端部署（OSSAdapter）
- ✅ 业务代码零改动切换

#### 目录结构
```
backend/src/common/storage/
├── StorageAdapter.ts      # 接口定义
├── LocalAdapter.ts        # 本地实现
├── OSSAdapter.ts          # OSS实现
├── StorageFactory.ts      # 工厂类
└── index.ts               # 统一导出
```

#### 接口定义
```typescript
// backend/src/common/storage/StorageAdapter.ts
export interface StorageAdapter {
  upload(key: string, buffer: Buffer): Promise<string>
  download(key: string): Promise<Buffer>
  delete(key: string): Promise<void>
  getUrl(key: string): string
}
```

#### 环境切换
```bash
# 本地开发
STORAGE_TYPE=local

# 生产环境
STORAGE_TYPE=oss
OSS_REGION=oss-cn-hangzhou
OSS_BUCKET=aiclinical-prod
```

#### 业务模块使用
```typescript
import { storage } from '@/common/storage'

// 使用（不关心本地还是OSS）
const url = await storage.upload('literature/123.pdf', buffer)
```

---

### 2. 数据库连接池（Database Connection Pool）

#### 设计目标
- ✅ 防止Serverless扩容导致连接数超限
- ✅ 优雅关闭连接
- ✅ 连接数监控

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

#### 连接池配置
```typescript
// 计算公式：每实例连接数 = RDS最大连接数 / SAE最大实例数
// 示例：400连接 / 20实例 = 20连接/实例

import { PrismaClient } from '@prisma/client'

const connectionLimit = Math.floor(
  Number(process.env.DB_MAX_CONNECTIONS || 400) / 
  Number(process.env.MAX_INSTANCES || 20)
)

export const prisma = new PrismaClient({
  log: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
})

// 优雅关闭
process.on('SIGTERM', async () => {
  await prisma.$disconnect()
  process.exit(0)
})
```

#### 环境变量
```bash
DB_MAX_CONNECTIONS=400      # RDS最大连接数
MAX_INSTANCES=20            # SAE最大实例数
DATABASE_URL=postgresql://...
```

---

### 3. 日志系统（Logging）

#### 设计目标
- ✅ 云原生：只输出到stdout（不写本地文件）
- ✅ JSON格式（便于阿里云SLS解析）
- ✅ 统一的日志格式

#### 目录结构
```
backend/src/common/logging/
├── logger.ts              # 日志工具
└── index.ts               # 导出
```

#### 实现
```typescript
// backend/src/common/logging/logger.ts
import winston from 'winston'

export const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: {
    service: 'aiclinical-backend',
    env: process.env.NODE_ENV,
    instance: process.env.HOSTNAME
  },
  transports: [
    new winston.transports.Console({
      format: winston.format.json()  // ⭐ JSON格式
    })
  ]
})
```

#### 业务模块使用
```typescript
import { logger } from '@/common/logging'

logger.info('Screening started', { projectId, count: 100 })
logger.error('LLM API failed', { error: err.message })
```

---

### 4. 环境配置（Environment Config）

#### 设计目标
- ✅ 统一的配置管理
- ✅ 本地开发：.env文件
- ✅ 生产环境：SAE环境变量
- ✅ 启动时验证必需配置

#### 文件位置
```
backend/src/config/env.ts
```

#### 实现
```typescript
// backend/src/config/env.ts
import { config } from 'dotenv'

// 只在本地开发加载 .env 文件
if (process.env.NODE_ENV !== 'production') {
  config()
}

export const env = {
  // 应用配置
  NODE_ENV: process.env.NODE_ENV || 'development',
  PORT: Number(process.env.PORT) || 3001,
  
  // 数据库配置
  DATABASE_URL: process.env.DATABASE_URL!,
  DB_MAX_CONNECTIONS: Number(process.env.DB_MAX_CONNECTIONS) || 400,
  MAX_INSTANCES: Number(process.env.MAX_INSTANCES) || 20,
  
  // 存储配置
  STORAGE_TYPE: process.env.STORAGE_TYPE || 'local',
  OSS_REGION: process.env.OSS_REGION,
  OSS_BUCKET: process.env.OSS_BUCKET,
  
  // 缓存配置
  CACHE_TYPE: process.env.CACHE_TYPE || 'memory',
  REDIS_HOST: process.env.REDIS_HOST,
  
  // LLM配置
  DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
  QWEN_API_KEY: process.env.QWEN_API_KEY,
  
  // 功能开关
  ENABLED_MODULES: process.env.ENABLED_MODULES?.split(',') || [],
}

// 启动时验证
export function validateEnv() {
  const required = ['DATABASE_URL']
  for (const key of required) {
    if (!process.env[key]) {
      throw new Error(`Missing required env var: ${key}`)
    }
  }
}
```

---

### 5. 异步任务（Async Jobs）

#### 设计目标
- ✅ 长时间任务（>10秒）异步处理
- ✅ 避免Serverless超时（30秒）
- ✅ 支持进度查询

#### 目录结构
```
backend/src/common/jobs/
├── JobQueue.ts            # 任务队列接口
├── MemoryQueue.ts         # 本地开发（内存队列）
├── DatabaseQueue.ts       # 生产环境（数据库队列）
├── JobProcessor.ts        # 任务处理器
└── index.ts
```

#### 接口定义
```typescript
// backend/src/common/jobs/JobQueue.ts
export interface Job<T = any> {
  id: string
  type: string
  data: T
  status: 'pending' | 'processing' | 'completed' | 'failed'
  progress: number
  result?: any
  error?: string
  createdAt: Date
  updatedAt: Date
}

export interface JobQueue {
  push<T>(type: string, data: T): Promise<Job<T>>
  process<T>(type: string, handler: (job: Job<T>) => Promise<void>): void
  getJob(id: string): Promise<Job | null>
  updateProgress(id: string, progress: number): Promise<void>
}
```

#### 业务模块使用（ASL模块示例）
```typescript
import { jobQueue } from '@/common/jobs'

// 1. 创建任务（立即返回）
app.post('/screening/start', async (req, res) => {
  const job = await jobQueue.push('asl:screening', {
    projectId: req.body.projectId,
    literatureIds: req.body.literatureIds
  })
  
  res.send({ jobId: job.id })  // ⭐ 立即返回，不等待完成
})

// 2. 查询进度
app.get('/screening/jobs/:id', async (req, res) => {
  const job = await jobQueue.getJob(req.params.id)
  res.send({
    status: job.status,
    progress: job.progress,  // 0-100
    result: job.result
  })
})

// 3. 处理任务（后台）
jobQueue.process('asl:screening', async (job) => {
  const { projectId, literatureIds } = job.data
  
  for (let i = 0; i < literatureIds.length; i++) {
    await screenLiterature(literatureIds[i])
    await jobQueue.updateProgress(job.id, (i + 1) / literatureIds.length * 100)
  }
})
```

---

### 6. 缓存服务（Cache Service）

#### 设计目标
- ✅ 支持本地开发（MemoryCacheAdapter）
- ✅ 支持生产环境（RedisCacheAdapter）
- ✅ 多实例共享缓存

#### 目录结构
```
backend/src/common/cache/
├── CacheAdapter.ts        # 接口定义
├── MemoryCacheAdapter.ts  # 本地实现
├── RedisCacheAdapter.ts   # Redis实现
├── CacheFactory.ts        # 工厂类
└── index.ts
```

#### 接口定义
```typescript
export interface CacheAdapter {
  get<T>(key: string): Promise<T | null>
  set(key: string, value: any, ttl?: number): Promise<void>
  delete(key: string): Promise<void>
  clear(): Promise<void>
}
```

#### 环境切换
```bash
# 本地开发
CACHE_TYPE=memory

# 生产环境
CACHE_TYPE=redis
REDIS_HOST=r-***.redis.aliyuncs.com
```

---

### 7. 健康检查（Health Check）

#### 设计目标
- ✅ SAE存活检查（/health/liveness）
- ✅ SAE就绪检查（/health/readiness）
- ✅ 检查依赖服务（数据库）

#### 目录结构
```
backend/src/common/health/
├── healthCheck.ts
└── index.ts
```

#### 实现
```typescript
import { FastifyInstance } from 'fastify'
import { prisma } from '@/config/database'

export async function registerHealthRoutes(app: FastifyInstance) {
  // 存活检查
  app.get('/health/liveness', async () => {
    return { status: 'ok', timestamp: Date.now() }
  })
  
  // 就绪检查
  app.get('/health/readiness', async () => {
    try {
      await prisma.$queryRaw`SELECT 1`
      return {
        status: 'ready',
        checks: { database: 'ok' }
      }
    } catch (error) {
      return {
        status: 'not_ready',
        checks: { database: 'failed' }
      }
    }
  })
}
```

---

### 8. 监控指标（Monitoring）

#### 设计目标
- ✅ 数据库连接数监控
- ✅ 关键指标告警

#### 目录结构
```
backend/src/common/monitoring/
├── metrics.ts
└── index.ts
```

#### 实现
```typescript
import { prisma } from '@/config/database'
import { logger } from '@/common/logging'
import { env } from '@/config/env'

export class Metrics {
  static async recordDBConnectionCount() {
    const result = await prisma.$queryRaw`
      SELECT count(*) as count 
      FROM pg_stat_activity 
      WHERE datname = current_database()
    `
    
    const count = result[0].count
    logger.info('DB connection count', { count })
    
    // 告警：连接数超过80%
    if (count > env.DB_MAX_CONNECTIONS * 0.8) {
      logger.warn('DB connection pool near limit', {
        current: count,
        max: env.DB_MAX_CONNECTIONS
      })
    }
    
    return count
  }
}
```

---

## 📅 实施计划

### 总体时间规划

**预计总耗时：2.5天（20小时）**

```
Day 1: 核心基础设施（P0模块）         8小时
Day 2: 辅助基础设施（P1模块）+ 测试   8小时
Day 3: 文档更新                      4小时
```

---

### Day 1：核心基础设施（P0模块）

#### 上午（4小时）

**Task 1.1：存储服务（2小时）**
- [ ] 创建 `backend/src/common/storage/` 目录
- [ ] 实现 `StorageAdapter.ts`（接口定义）
- [ ] 实现 `LocalAdapter.ts`（本地实现）
- [ ] 实现 `OSSAdapter.ts`（OSS实现，预留）
- [ ] 实现 `StorageFactory.ts`（工厂类）
- [ ] 创建 `index.ts`（统一导出）

**验收标准**：
- ✅ LocalAdapter 可正常 upload/download
- ✅ 通过环境变量 `STORAGE_TYPE` 切换
- ✅ 单元测试通过

**Task 1.2：数据库连接池（2小时）**
- [ ] 更新 `backend/src/config/database.ts`
- [ ] 添加连接池配置
- [ ] 添加优雅关闭逻辑
- [ ] 添加环境变量验证

**验收标准**：
- ✅ Prisma Client 正确配置连接池
- ✅ 启动时验证环境变量
- ✅ SIGTERM信号优雅关闭

---

#### 下午（4小时）

**Task 1.3：日志系统（2小时）**
- [ ] 创建 `backend/src/common/logging/` 目录
- [ ] 实现 `logger.ts`（winston配置）
- [ ] 配置JSON格式输出
- [ ] 创建 `index.ts`（导出）

**验收标准**：
- ✅ 日志输出到stdout（JSON格式）
- ✅ 包含timestamp、service、env等元信息
- ✅ 支持不同日志级别（info/warn/error）

**Task 1.4：异步任务（2小时）**
- [ ] 创建 `backend/src/common/jobs/` 目录
- [ ] 实现 `JobQueue.ts`（接口定义）
- [ ] 实现 `MemoryQueue.ts`（内存队列）
- [ ] 实现 `DatabaseQueue.ts`（数据库队列，预留）
- [ ] 实现 `JobProcessor.ts`（任务处理器）

**验收标准**：
- ✅ 可创建任务并立即返回
- ✅ 可查询任务进度
- ✅ 可在后台处理任务

---

### Day 2：辅助基础设施（P1模块）+ 测试

#### 上午（4小时）

**Task 2.1：环境配置（1小时）**
- [ ] 更新 `backend/src/config/env.ts`
- [ ] 统一环境变量定义
- [ ] 添加启动验证函数

**验收标准**：
- ✅ 所有环境变量集中管理
- ✅ 启动时自动验证必需配置
- ✅ 支持本地开发和生产环境

**Task 2.2：缓存服务（2小时）**
- [ ] 创建 `backend/src/common/cache/` 目录
- [ ] 实现 `CacheAdapter.ts`（接口定义）
- [ ] 实现 `MemoryCacheAdapter.ts`（内存实现）
- [ ] 实现 `RedisCacheAdapter.ts`（Redis实现，预留）
- [ ] 实现 `CacheFactory.ts`（工厂类）

**验收标准**：
- ✅ MemoryCacheAdapter 可正常 get/set
- ✅ 通过环境变量切换
- ✅ 支持TTL过期

**Task 2.3：健康检查（1小时）**
- [ ] 创建 `backend/src/common/health/` 目录
- [ ] 实现 `healthCheck.ts`
- [ ] 注册 `/health/liveness` 端点
- [ ] 注册 `/health/readiness` 端点

**验收标准**：
- ✅ liveness端点正常返回
- ✅ readiness端点检查数据库连接
- ✅ 错误时返回正确状态

---

#### 下午（4小时）

**Task 2.4：监控指标（1小时）**
- [ ] 创建 `backend/src/common/monitoring/` 目录
- [ ] 实现 `metrics.ts`
- [ ] 实现数据库连接数监控
- [ ] 实现告警逻辑

**验收标准**：
- ✅ 可查询数据库连接数
- ✅ 连接数超过80%时告警
- ✅ 日志输出正确

**Task 2.5：集成测试（3小时）**
- [ ] 编写存储服务单元测试
- [ ] 编写日志系统单元测试
- [ ] 编写缓存服务单元测试
- [ ] 编写异步任务单元测试
- [ ] 集成测试（所有模块）

**验收标准**：
- ✅ 所有单元测试通过
- ✅ 集成测试通过
- ✅ 代码覆盖率 > 80%

---

### Day 3：文档更新

#### 上午（4小时）

**Task 3.1：更新架构文档（2小时）**
- [ ] 更新 `01-系统架构分层设计.md`
  - 在"平台基础层"章节中详细化各服务
  - 添加适配器模式说明
- [ ] 更新 `前后端模块化架构设计-V2.md`
  - 更新 backend 目录结构
  - 体现新增的 common/ 子模块

**Task 3.2：更新实施文档（1小时）**
- [ ] 更新 `09-架构实施/03-云原生部署架构指南.md`
  - 添加平台基础设施章节
  - 更新环境变量配置示例

**Task 3.3：简化ASL文档（1小时）**
- [ ] 更新 `03-业务模块/ASL-AI智能文献/04-开发计划/02-标题摘要初筛开发计划.md`
  - 移除"创建存储抽象层"任务
  - 添加"前置条件：平台已提供"
- [ ] 更新 `03-业务模块/ASL-AI智能文献/04-开发计划/03-任务分解.md`
  - 移除存储抽象层任务
  - 更新验收标准

---

## 🎯 验收标准

### 总体验收标准

- [ ] **功能完整性**：所有P0模块实现完成
- [ ] **测试覆盖**：单元测试覆盖率 > 80%
- [ ] **文档完整性**：所有架构文档更新完成
- [ ] **多环境支持**：本地开发和云端部署验证通过
- [ ] **业务模块验证**：ASL模块可正常使用平台能力

### 环境验证矩阵

| 验证项 | 本地开发 | 云端SaaS | 私有化部署 | 单机版 |
|-------|---------|---------|-----------|--------|
| 存储服务 | ✅ LocalAdapter | ✅ OSSAdapter | ✅ LocalAdapter | ✅ LocalAdapter |
| 数据库连接 | ✅ 本地PostgreSQL | ✅ 阿里云RDS | ✅ 内网PostgreSQL | ✅ SQLite |
| 缓存服务 | ✅ Memory | ✅ Redis | ✅ 内网Redis | ✅ Memory |
| 日志系统 | ✅ Console | ✅ 阿里云SLS | ✅ Console | ✅ Console |
| 异步任务 | ✅ MemoryQueue | ✅ DatabaseQueue | ✅ DatabaseQueue | ✅ MemoryQueue |
| 健康检查 | ✅ OK | ✅ OK | ✅ OK | N/A |

---

## 🚀 实施后的收益

### 1. 开发效率提升

| 指标 | 改造前 | 改造后 | 提升 |
|------|-------|-------|------|
| 业务模块开发时间 | 需要实现存储等基础设施 | 直接使用平台能力 | **节省30%** |
| 新模块上手时间 | 需要学习基础设施 | 只需关注业务逻辑 | **节省50%** |
| 代码复用率 | 每个模块重复实现 | 所有模块复用 | **提升80%** |

### 2. 部署灵活性

| 部署形态 | 支持情况 | 切换成本 |
|---------|---------|---------|
| 云端SaaS | ✅ 完全支持 | 修改环境变量 |
| 私有化部署 | ✅ 完全支持 | 修改环境变量 |
| 单机版 | ✅ 完全支持 | 修改环境变量 |
| 混合部署 | ✅ 完全支持 | 按模块配置 |

### 3. 商业模式灵活性

| 商业模式 | 支持情况 |
|---------|---------|
| 专业版（部分模块） | ✅ Feature Flag控制 |
| 高级版（组合模块） | ✅ Feature Flag控制 |
| 旗舰版（全部模块） | ✅ Feature Flag控制 |
| 单模块售卖 | ✅ Docker镜像分层 |

### 4. 技术债务降低

- ✅ 避免重复代码
- ✅ 统一的架构风格
- ✅ 易于维护和升级
- ✅ 新人快速上手

---

## 📚 相关文档

- [09-总体需求文档(PRD).md](../00-系统总体设计/09-总体需求文档(PRD).md) - 业务需求来源
- [01-系统架构分层设计.md](../00-系统总体设计/01-系统架构分层设计.md) - 总体架构设计
- [前后端模块化架构设计-V2.md](../00-系统总体设计/前后端模块化架构设计-V2.md) - 代码组织架构
- [03-云原生部署架构指南.md](./03-云原生部署架构指南.md) - 云原生部署详细指南
- [08-云原生开发规范.md](../04-开发规范/08-云原生开发规范.md) - 开发规范

---

## 📝 变更记录

| 日期 | 版本 | 变更内容 | 变更人 |
|------|------|---------|--------|
| 2025-11-16 | V1.0 | 初始版本，定义平台基础设施规划 | 架构团队 |

---

**文档结束**

