# 模块独立部署与单机版方案

> **文档版本：** v1.0  
> **创建日期：** 2025-11-06  
> **最后更新：** 2025-11-06  
> **文档状态：** 架构设计  
> **作者：** 技术架构师

---

## 📋 核心问题

1. **如何实现每个模块独立部署？**
   - 模块依赖平台层和通用能力层，如何独立？
   - 如何变成独立产品销售？
   - 如何实现本地化部署？

2. **如何开发单机版？**
   - 如何利用Electron框架？
   - 如何复用现有代码？
   - 架构如何设计？

---

## 🎯 Part 1：模块独立部署方案

### 核心理念：独立部署 ≠ 完全孤立

**关键洞察：**
```
独立部署的真正含义：
✅ 可以单独打包
✅ 可以单独运行
✅ 可以单独销售
✅ 可以单独升级

但不是：
❌ 完全不依赖其他代码
❌ 完全不共享基础设施
```

**类比：**
```
就像一个独立的手机App：
- 它依赖操作系统（Android/iOS）
- 它依赖系统API（摄像头、定位等）
- 但它可以独立下载、安装、运行、卸载

模块独立部署也是一样：
- 它依赖平台层（用户认证、存储等）
- 它依赖通用能力层（LLM网关、文档处理等）
- 但它可以独立打包、部署、销售
```

---

## 📦 方案一：完整打包（推荐用于独立产品）

### 适用场景

- ✅ 模块作为独立产品销售（如审稿系统）
- ✅ 客户要求完全本地化部署
- ✅ 不依赖其他模块或平台

### 核心思路

**将依赖的平台层和通用能力层一起打包**

```
审稿系统独立产品包：
┌─────────────────────────────────────────┐
│    RVW审稿系统独立产品                    │
│                                          │
│  ┌────────────────────────────────────┐ │
│  │  业务模块层                          │ │
│  │  RVW（稿件审查）                     │ │
│  └────────────────────────────────────┘ │
│                                          │
│  ┌────────────────────────────────────┐ │
│  │  通用能力层（必需部分）              │ │
│  │  - LLM网关                          │ │
│  │  - 文档处理引擎                      │ │
│  └────────────────────────────────────┘ │
│                                          │
│  ┌────────────────────────────────────┐ │
│  │  平台基础层（必需部分）              │ │
│  │  - 用户认证（简化版）                │ │
│  │  - 存储服务                          │ │
│  │  - 监控日志                          │ │
│  └────────────────────────────────────┘ │
│                                          │
│  ┌────────────────────────────────────┐ │
│  │  独立数据库                          │ │
│  │  PostgreSQL（Docker）                │ │
│  └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
```

---

### 技术实现

#### Step 1: 代码组织（Monorepo）

```
AIclinicalresearch/
  ├── packages/                    # Monorepo包管理
  │   │
  │   ├── platform-core/           # 平台核心（可复用）
  │   │   ├── auth/                # 用户认证
  │   │   ├── storage/             # 存储服务
  │   │   ├── monitoring/          # 监控日志
  │   │   └── index.ts
  │   │
  │   ├── capabilities-core/       # 通用能力核心（可复用）
  │   │   ├── llm-gateway/         # LLM网关
  │   │   ├── document-processor/  # 文档处理
  │   │   ├── rag-engine/          # RAG引擎
  │   │   └── index.ts
  │   │
  │   ├── module-aia/              # AI问答模块
  │   │   ├── backend/
  │   │   ├── frontend/
  │   │   └── package.json
  │   │
  │   ├── module-asl/              # AI文献模块
  │   │   ├── backend/
  │   │   ├── frontend/
  │   │   └── package.json
  │   │
  │   ├── module-review/           # 审稿系统模块
  │   │   ├── backend/
  │   │   ├── frontend/
  │   │   └── package.json
  │   │
  │   └── ...
  │
  ├── products/                    # 独立产品打包
  │   │
  │   ├── review-system/           # 审稿系统独立产品 ⭐
  │   │   ├── docker-compose.yml
  │   │   ├── deploy.sh
  │   │   ├── README.md
  │   │   └── package.json         # 依赖关系
  │   │
  │   ├── literature-system/       # AI文献独立产品 ⭐
  │   │   └── ...
  │   │
  │   └── full-platform/           # 完整平台
  │       └── ...
  │
  └── ...
```

---

#### Step 2: 依赖管理（package.json）

**审稿系统独立产品的依赖：**
```json
// products/review-system/package.json
{
  "name": "@yizhengxun/review-system",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    // 平台核心（必需）
    "@yizhengxun/platform-core": "workspace:*",
    
    // 通用能力（必需）
    "@yizhengxun/capabilities-core": "workspace:*",
    
    // 业务模块
    "@yizhengxun/module-review": "workspace:*"
  },
  "scripts": {
    "build": "node build.js",
    "deploy": "sh deploy.sh"
  }
}
```

**平台核心的选择性导出：**
```typescript
// packages/platform-core/index.ts

// 完整导出（用于完整平台）
export * from './auth';
export * from './storage';
export * from './monitoring';
export * from './notification';

// 精简导出（用于独立产品）
export { 
  // 只导出必需的认证功能
  authMiddleware, 
  jwtService 
} from './auth';

export { 
  // 只导出必需的存储功能
  uploadFile, 
  downloadFile 
} from './storage';

export { 
  // 只导出必需的监控功能
  logError, 
  logAudit 
} from './monitoring';
```

---

#### Step 3: 打包脚本

**审稿系统独立打包：**
```javascript
// products/review-system/build.js

const { build } = require('esbuild');
const { dependencies } = require('./package.json');

async function buildReviewSystem() {
  console.log('构建审稿系统独立产品...');
  
  // 1. 构建后端
  await build({
    entryPoints: ['../../packages/module-review/backend/src/index.ts'],
    bundle: true,
    platform: 'node',
    target: 'node18',
    outfile: 'dist/backend/index.js',
    external: ['pg', 'fastify', 'prisma'],  // 不打包这些大库
    
    // 自动包含依赖
    plugins: [
      // 自动解析workspace依赖
      resolveWorkspaceDependencies()
    ]
  });
  
  // 2. 构建前端
  await build({
    entryPoints: ['../../packages/module-review/frontend/src/main.tsx'],
    bundle: true,
    platform: 'browser',
    outfile: 'dist/frontend/index.js',
    loader: { '.tsx': 'tsx' }
  });
  
  // 3. 复制必要文件
  copyFiles([
    'docker-compose.yml',
    'README.md',
    'deploy.sh'
  ]);
  
  console.log('构建完成！');
}

buildReviewSystem();
```

---

#### Step 4: Docker部署配置

**审稿系统独立部署：**
```yaml
# products/review-system/docker-compose.yml

version: '3.8'

services:
  # PostgreSQL数据库（独立）
  postgres:
    image: postgres:15-alpine
    container_name: review-system-postgres
    environment:
      POSTGRES_DB: review_system
      POSTGRES_USER: review
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - review-network

  # 后端服务（包含平台层和通用能力层）
  backend:
    build:
      context: ./dist/backend
    container_name: review-system-backend
    environment:
      DATABASE_URL: postgresql://review:${DB_PASSWORD}@postgres:5432/review_system
      LLM_API_KEY: ${LLM_API_KEY}
    depends_on:
      - postgres
    networks:
      - review-network

  # 前端服务
  frontend:
    build:
      context: ./dist/frontend
    container_name: review-system-frontend
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - review-network

volumes:
  postgres_data:

networks:
  review-network:
    driver: bridge
```

---

#### Step 5: 一键部署脚本

```bash
#!/bin/bash
# products/review-system/deploy.sh

echo "======================================"
echo "  审稿系统独立部署脚本"
echo "======================================"

# 1. 检查Docker
if ! command -v docker &> /dev/null; then
    echo "错误：未安装Docker"
    exit 1
fi

# 2. 设置环境变量
read -p "请输入数据库密码: " DB_PASSWORD
read -p "请输入LLM API密钥: " LLM_API_KEY

export DB_PASSWORD
export LLM_API_KEY

# 3. 启动服务
docker-compose up -d

# 4. 等待服务启动
echo "等待服务启动..."
sleep 10

# 5. 初始化数据库
docker exec review-system-backend npx prisma migrate deploy

# 6. 创建默认管理员
docker exec review-system-backend node scripts/create-admin.js

echo "======================================"
echo "  部署完成！"
echo "  访问地址：http://localhost"
echo "  管理员账号：admin@review.com"
echo "  密码：admin123（请及时修改）"
echo "======================================"
```

---

### 关键技术点

#### 1. 平台层的精简和适配

**完整平台的用户认证（复杂）：**
```typescript
// 完整平台
- 多租户支持
- RBAC权限控制
- SSO单点登录
- 第三方登录（微信、企业微信等）
- 复杂的权限树
```

**审稿系统的用户认证（简化）：**
```typescript
// 审稿系统独立产品
- 简化的用户认证（邮箱+密码）
- 简单的角色（管理员、编辑、审稿人）
- 基于JWT的Token认证
- 无SSO、无多租户
```

**实现方式：**
```typescript
// packages/platform-core/auth/simple-auth.ts
// 为独立产品提供简化版认证

export class SimpleAuthService {
  // 只保留核心功能
  async login(email: string, password: string) { }
  async register(email: string, password: string) { }
  async verifyToken(token: string) { }
  async logout(userId: string) { }
  
  // 移除复杂功能
  // ❌ async loginWithWeChat()
  // ❌ async setupSSO()
  // ❌ async multiTenantCheck()
}
```

---

#### 2. 通用能力层的精简和适配

**完整平台的LLM网关（复杂）：**
```typescript
// 完整平台
- 支持10+种模型
- Feature Flag控制
- 配额管理
- 成本分析
- A/B测试
```

**审稿系统的LLM网关（简化）：**
```typescript
// 审稿系统独立产品
- 只支持1-2种模型（DeepSeek + Claude）
- 简单的配额检查
- 无Feature Flag
- 无成本分析
```

**实现方式：**
```typescript
// packages/capabilities-core/llm-gateway/simple-llm.ts

export class SimpleLLMGateway {
  // 只保留核心功能
  async chat(params: ChatParams) { }
  async checkQuota(userId: string) { }
  
  // 移除复杂功能
  // ❌ async getCostStats()
  // ❌ async selectModelByVersion()
  // ❌ async runABTest()
}
```

---

#### 3. 数据库的隔离

**完整平台的数据库（复杂）：**
```sql
-- 平台层Schema
platform_schema.users
platform_schema.tenants
platform_schema.feature_flags
-- ...

-- 所有模块Schema
aia_schema.*
asl_schema.*
review_schema.*
-- ...
```

**审稿系统独立产品的数据库（简化）：**
```sql
-- 只包含必需的表
CREATE DATABASE review_system;

-- 简化的用户表
CREATE TABLE users (
  id UUID PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,
  role VARCHAR(50) NOT NULL,  -- admin/editor/reviewer
  created_at TIMESTAMP DEFAULT NOW()
);

-- 审稿系统的业务表
CREATE TABLE review_tasks (...);
CREATE TABLE review_journals (...);
CREATE TABLE review_reviewers (...);
-- ...
```

---

### 独立产品的优势

| 优势 | 说明 |
|------|------|
| **独立销售** | 可以单独定价、单独销售 |
| **独立部署** | 客户可以本地化部署，数据完全隔离 |
| **独立升级** | 不影响其他模块 |
| **轻量化** | 只包含必需功能，包体积小 |
| **定制化** | 可以针对特定客户定制 |

---

## 📦 方案二：共享服务（推荐用于平台内模块）

### 适用场景

- ✅ 同一客户购买多个模块
- ✅ 云端SaaS部署
- ✅ 模块之间需要共享用户和数据

### 核心思路

**平台层和通用能力层作为共享服务**

```
完整平台架构（微服务版）：

┌─────────────────────────────────────────────────────────┐
│                    API网关（Kong/Traefik）                │
│              路由：/aia/* /asl/* /review/*               │
└─────────────────────────────────────────────────────────┘
         │              │              │
         ↓              ↓              ↓
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AIA模块服务  │ │ ASL模块服务  │ │ RVW模块服务  │
│ (独立部署)   │ │ (独立部署)   │ │ (独立部署)   │
└─────────────┘ └─────────────┘ └─────────────┘
         │              │              │
         └──────────────┴──────────────┘
                      ↓
         ┌───────────────────────────┐
         │    共享服务（平台层）        │
         │  - 用户认证服务              │
         │  - 存储服务                 │
         │  - 监控服务                 │
         └───────────────────────────┘
                      ↓
         ┌───────────────────────────┐
         │  共享服务（通用能力层）      │
         │  - LLM网关服务              │
         │  - 文档处理服务              │
         │  - RAG引擎服务              │
         └───────────────────────────┘
                      ↓
         ┌───────────────────────────┐
         │    共享数据库               │
         │  - PostgreSQL (多Schema)   │
         └───────────────────────────┘
```

---

### 技术实现

#### Step 1: 服务拆分

**平台基础服务（独立部署）：**
```yaml
# services/platform/docker-compose.yml

services:
  # 用户认证服务
  auth-service:
    image: yizhengxun/auth-service:latest
    ports:
      - "3001:3000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
      JWT_SECRET: ${JWT_SECRET}

  # 存储服务
  storage-service:
    image: yizhengxun/storage-service:latest
    ports:
      - "3002:3000"
    environment:
      OSS_ENDPOINT: ${OSS_ENDPOINT}

  # 监控服务
  monitoring-service:
    image: yizhengxun/monitoring-service:latest
    ports:
      - "3003:3000"
```

**通用能力服务（独立部署）：**
```yaml
# services/capabilities/docker-compose.yml

services:
  # LLM网关服务
  llm-gateway:
    image: yizhengxun/llm-gateway:latest
    ports:
      - "3010:3000"
    environment:
      DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY}
      QWEN_API_KEY: ${QWEN_API_KEY}

  # 文档处理服务
  document-processor:
    image: yizhengxun/document-processor:latest
    ports:
      - "3011:3000"

  # RAG引擎服务
  rag-engine:
    image: yizhengxun/rag-engine:latest
    ports:
      - "3012:3000"
```

**业务模块服务（独立部署）：**
```yaml
# services/modules/review-system/docker-compose.yml

services:
  review-system:
    image: yizhengxun/review-system:latest
    ports:
      - "4001:3000"
    environment:
      # 依赖共享服务
      AUTH_SERVICE_URL: http://auth-service:3000
      STORAGE_SERVICE_URL: http://storage-service:3000
      LLM_GATEWAY_URL: http://llm-gateway:3000
      DOCUMENT_PROCESSOR_URL: http://document-processor:3000
      
      # 自己的数据库Schema
      DATABASE_URL: postgresql://user:pass@postgres:5432/platform?schema=review_schema
```

---

#### Step 2: API网关配置

**Kong API网关配置：**
```yaml
# api-gateway/kong.yml

_format_version: "3.0"

services:
  # 用户认证服务
  - name: auth-service
    url: http://auth-service:3000
    routes:
      - name: auth-routes
        paths:
          - /api/auth

  # 审稿系统模块
  - name: review-system
    url: http://review-system:3000
    routes:
      - name: review-routes
        paths:
          - /api/review
    plugins:
      - name: jwt
        config:
          secret_is_base64: false
          key_claim_name: kid

  # AI文献模块
  - name: literature-system
    url: http://literature-system:3000
    routes:
      - name: literature-routes
        paths:
          - /api/literature
    plugins:
      - name: jwt
```

---

#### Step 3: 服务间通信

**业务模块调用共享服务：**
```typescript
// packages/module-review/backend/src/services/review.service.ts

import { AuthClient } from '@yizhengxun/platform-core/clients';
import { LLMClient } from '@yizhengxun/capabilities-core/clients';

export class ReviewService {
  private authClient: AuthClient;
  private llmClient: LLMClient;
  
  constructor() {
    // 连接到共享服务
    this.authClient = new AuthClient({
      baseURL: process.env.AUTH_SERVICE_URL
    });
    
    this.llmClient = new LLMClient({
      baseURL: process.env.LLM_GATEWAY_URL
    });
  }
  
  async createReviewTask(userId: string, file: File) {
    // 1. 验证用户（调用共享认证服务）
    const user = await this.authClient.verifyUser(userId);
    
    // 2. 上传文件（调用共享存储服务）
    const fileUrl = await this.storageClient.upload(file);
    
    // 3. AI分析（调用共享LLM网关）
    const analysis = await this.llmClient.chat({
      messages: [{ role: 'user', content: `分析这篇稿件: ${fileUrl}` }]
    });
    
    // 4. 保存到自己的数据库
    const task = await prisma.reviewTask.create({
      data: {
        userId,
        fileUrl,
        analysis: analysis.content
      }
    });
    
    return task;
  }
}
```

---

### 模块独立部署的步骤

**1. 部署共享服务（一次性）：**
```bash
# 部署平台基础服务
cd services/platform
docker-compose up -d

# 部署通用能力服务
cd services/capabilities
docker-compose up -d

# 部署API网关
cd services/api-gateway
docker-compose up -d
```

**2. 部署业务模块（按需）：**
```bash
# 只部署审稿系统模块
cd services/modules/review-system
docker-compose up -d

# 客户A购买了审稿系统，只需部署这一个模块
# 其他模块不需要部署
```

**3. 新客户购买其他模块：**
```bash
# 客户B购买了AI文献模块，再部署这个模块
cd services/modules/literature-system
docker-compose up -d

# 共享服务已经部署，不需要重复部署
# 只需增加新的业务模块
```

---

## 🖥️ Part 2：Electron单机版方案

### 为什么需要单机版？

**核心需求：**
1. **数据隐私**：医生个人数据不能上传云端
2. **离线使用**：无需网络连接
3. **便携性**：可以在任何电脑上安装使用
4. **独立运行**：不依赖外部服务器

**目标用户：**
- 个人医生
- 数据敏感的研究者
- 无网络环境的场景

---

### Electron架构与现有代码的对应关系

#### 现有架构（云端版）

```
┌─────────────────────────────────────────┐
│            浏览器 (Chrome)               │
│  ┌───────────────────────────────────┐  │
│  │   前端 (React + Vite)              │  │
│  │   http://localhost:5173            │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
              ↓ HTTP请求
┌─────────────────────────────────────────┐
│     后端 (Node.js + Fastify)            │
│     http://localhost:3001               │
│  ┌───────────────────────────────────┐  │
│  │  API路由、业务逻辑、Prisma ORM     │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  PostgreSQL (Docker)                    │
│  localhost:5432                         │
└─────────────────────────────────────────┘
```

---

#### Electron架构（单机版）

```
┌───────────────────────────────────────────────────────────┐
│                  Electron 应用                              │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │            渲染进程 (Chromium)                        │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │   前端 (React)  ⭐ 复用现有代码                 │  │  │
│  │  │   file://app/index.html                       │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                      ↓ IPC通信                            │
│  ┌─────────────────────────────────────────────────────┐  │
│  │            主进程 (Node.js)                          │  │
│  │  ┌───────────────────────────────────────────────┐  │  │
│  │  │  API逻辑、业务逻辑 ⭐ 复用现有代码              │  │  │
│  │  │  Prisma ORM、本地文件系统                      │  │  │
│  │  └───────────────────────────────────────────────┘  │  │
│  └─────────────────────────────────────────────────────┘  │
│                      ↓                                     │
│  ┌─────────────────────────────────────────────────────┐  │
│  │     SQLite (嵌入式数据库)                            │  │
│  │     ~/Documents/YizhengxunData/app.db               │  │
│  └─────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐  │
│  │     子进程 (Python/R)                                │  │
│  │     文档提取、数据分析                                │  │
│  └─────────────────────────────────────────────────────┘  │
└───────────────────────────────────────────────────────────┘
```

---

### 核心技术方案

#### 1. 前端代码复用（90%+ 复用）

**现有前端代码（Web版）：**
```typescript
// frontend/src/api/client.ts
const API_BASE_URL = 'http://localhost:3001';

export const apiClient = {
  async get(url: string) {
    return fetch(`${API_BASE_URL}${url}`);
  },
  async post(url: string, data: any) {
    return fetch(`${API_BASE_URL}${url}`, {
      method: 'POST',
      body: JSON.stringify(data)
    });
  }
};
```

**Electron版前端（修改API调用方式）：**
```typescript
// electron-frontend/src/api/client.ts

// 使用Electron的IPC通信，而不是HTTP
const { ipcRenderer } = window.require('electron');

export const apiClient = {
  async get(url: string) {
    // 通过IPC发送到主进程
    return ipcRenderer.invoke('api-request', {
      method: 'GET',
      url
    });
  },
  async post(url: string, data: any) {
    return ipcRenderer.invoke('api-request', {
      method: 'POST',
      url,
      data
    });
  }
};
```

**React组件完全不需要改：**
```typescript
// 业务组件完全不变 ✅
function UserList() {
  const [users, setUsers] = useState([]);
  
  useEffect(() => {
    // API调用方式不变，底层自动适配
    apiClient.get('/api/users').then(setUsers);
  }, []);
  
  return <div>{/* ... */}</div>;
}
```

**复用率：90%+ ✅**
- ✅ 所有React组件
- ✅ 所有UI库（Ant Design）
- ✅ 所有状态管理（Zustand）
- ✅ 所有路由（React Router）
- ⚠️ 只需修改API调用层（1个文件）

---

#### 2. 后端代码复用（80%+ 复用）

**现有后端代码（Web版）：**
```typescript
// backend/src/routes/users.ts
import { FastifyInstance } from 'fastify';

export async function userRoutes(fastify: FastifyInstance) {
  // GET /api/users
  fastify.get('/api/users', async (request, reply) => {
    const users = await prisma.user.findMany();
    return users;
  });
  
  // POST /api/users
  fastify.post('/api/users', async (request, reply) => {
    const user = await prisma.user.create({
      data: request.body
    });
    return user;
  });
}
```

**Electron版后端（主进程）：**
```typescript
// electron-backend/src/ipc-handlers.ts
import { ipcMain } from 'electron';
import { prisma } from './prisma-client';

// 复用业务逻辑 ⭐
import { UserService } from '../../../backend/src/services/user.service';

export function setupIpcHandlers() {
  const userService = new UserService(prisma);
  
  // 将HTTP路由转换为IPC Handler
  ipcMain.handle('api-request', async (event, { method, url, data }) => {
    // 路由分发（简化版的Fastify）
    if (url === '/api/users' && method === 'GET') {
      return userService.findAll();
    }
    
    if (url === '/api/users' && method === 'POST') {
      return userService.create(data);
    }
    
    // ... 其他路由
  });
}
```

**核心业务逻辑完全复用：**
```typescript
// backend/src/services/user.service.ts
// 这个文件在Web版和Electron版完全共享 ✅

export class UserService {
  constructor(private prisma: PrismaClient) {}
  
  async findAll() {
    return this.prisma.user.findMany();
  }
  
  async create(data: CreateUserDto) {
    // 业务逻辑
    const hashedPassword = await bcrypt.hash(data.password, 10);
    return this.prisma.user.create({
      data: {
        ...data,
        password: hashedPassword
      }
    });
  }
}
```

**复用率：80%+ ✅**
- ✅ 所有Service层（业务逻辑）
- ✅ 所有Prisma Model和查询
- ✅ 所有工具函数
- ⚠️ 需要适配：HTTP路由 → IPC Handler
- ⚠️ 需要替换：PostgreSQL → SQLite

---

#### 3. 数据库适配（PostgreSQL → SQLite）

**Prisma Schema修改（最小改动）：**
```prisma
// electron-backend/prisma/schema.prisma

datasource db {
  // Web版：PostgreSQL
  // provider = "postgresql"
  // url      = env("DATABASE_URL")
  
  // Electron版：SQLite ⭐
  provider = "sqlite"
  url      = "file:./app.db"
}

// Model定义完全不变 ✅
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  password  String
  name      String?
  
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  
  @@map("users")
}
```

**注意事项：**
```typescript
// SQLite不支持某些PostgreSQL特性

// ❌ PostgreSQL支持，SQLite不支持：
- JSON列类型（需要用TEXT存储）
- 复杂的全文搜索
- 某些聚合函数

// ✅ 解决方案：
// 1. 用TEXT存储JSON（手动序列化）
model Config {
  id    String @id
  data  String  // JSON.stringify(data)
}

// 2. 简化查询（避免复杂SQL）
// 3. 在应用层实现某些功能
```

---

### 完整项目结构

```
AIclinicalresearch/
  ├── packages/                    # 共享代码（Monorepo）
  │   ├── frontend-core/           # 前端核心（Web + Electron复用）
  │   ├── backend-core/            # 后端核心（Web + Electron复用）
  │   └── shared-types/            # 共享类型定义
  │
  ├── apps/
  │   ├── web/                     # Web版（当前）
  │   │   ├── frontend/
  │   │   └── backend/
  │   │
  │   └── electron/                # Electron版 ⭐
  │       ├── main/                # 主进程（Node.js后端）
  │       │   ├── src/
  │       │   │   ├── main.ts      # Electron入口
  │       │   │   ├── ipc-handlers.ts  # IPC处理器
  │       │   │   ├── services/    # 复用backend-core
  │       │   │   └── prisma/
  │       │   │       └── schema.prisma  # SQLite版本
  │       │   └── package.json
  │       │
  │       ├── renderer/            # 渲染进程（React前端）
  │       │   ├── src/
  │       │   │   ├── main.tsx
  │       │   │   ├── api/         # IPC客户端
  │       │   │   ├── pages/       # 复用frontend-core
  │       │   │   └── components/  # 复用frontend-core
  │       │   └── package.json
  │       │
  │       ├── resources/           # 打包资源
  │       │   ├── python/          # Python运行时
  │       │   ├── r/               # R运行时（如需要）
  │       │   └── assets/
  │       │
  │       └── electron-builder.yml # 打包配置
  │
  └── ...
```

---

### 关键实现细节

#### 1. Electron主进程（main.ts）

```typescript
// apps/electron/main/src/main.ts

import { app, BrowserWindow, ipcMain } from 'electron';
import path from 'path';
import { setupIpcHandlers } from './ipc-handlers';
import { initDatabase } from './database';
import { startPythonService } from './python-service';

let mainWindow: BrowserWindow | null = null;

async function createWindow() {
  // 1. 创建浏览器窗口
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js')  // 安全的IPC桥接
    }
  });
  
  // 2. 加载前端（生产环境）
  if (app.isPackaged) {
    mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
  } else {
    // 开发环境：连接到Vite开发服务器
    mainWindow.loadURL('http://localhost:5173');
  }
  
  // 3. 初始化数据库
  await initDatabase();
  
  // 4. 启动Python文档处理服务
  await startPythonService();
  
  // 5. 设置IPC处理器
  setupIpcHandlers();
}

// Electron生命周期
app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});
```

---

#### 2. IPC处理器（ipc-handlers.ts）

```typescript
// apps/electron/main/src/ipc-handlers.ts

import { ipcMain } from 'electron';
import { prisma } from './prisma-client';

// 复用业务逻辑 ⭐
import { UserService } from '@yizhengxun/backend-core/services';
import { ProjectService } from '@yizhengxun/backend-core/services';
import { ConversationService } from '@yizhengxun/backend-core/services';

export function setupIpcHandlers() {
  // 初始化服务
  const userService = new UserService(prisma);
  const projectService = new ProjectService(prisma);
  const conversationService = new ConversationService(prisma);
  
  // 用户相关API
  ipcMain.handle('api:users:list', async () => {
    return userService.findAll();
  });
  
  ipcMain.handle('api:users:create', async (event, data) => {
    return userService.create(data);
  });
  
  // 项目相关API
  ipcMain.handle('api:projects:list', async (event, userId) => {
    return projectService.findByUser(userId);
  });
  
  ipcMain.handle('api:projects:create', async (event, data) => {
    return projectService.create(data);
  });
  
  // 对话相关API
  ipcMain.handle('api:conversations:create', async (event, data) => {
    return conversationService.create(data);
  });
  
  ipcMain.handle('api:conversations:chat', async (event, data) => {
    // 调用LLM（本地或云端API）
    return conversationService.chat(data);
  });
  
  // 文件操作
  ipcMain.handle('api:files:upload', async (event, file) => {
    // 保存到本地文件系统
    const filePath = await saveFile(file);
    return { url: filePath };
  });
}
```

---

#### 3. 前端IPC客户端（api-client.ts）

```typescript
// apps/electron/renderer/src/api/client.ts

const { ipcRenderer } = window.require('electron');

export const apiClient = {
  // 用户API
  users: {
    async list() {
      return ipcRenderer.invoke('api:users:list');
    },
    async create(data: any) {
      return ipcRenderer.invoke('api:users:create', data);
    }
  },
  
  // 项目API
  projects: {
    async list(userId: string) {
      return ipcRenderer.invoke('api:projects:list', userId);
    },
    async create(data: any) {
      return ipcRenderer.invoke('api:projects:create', data);
    }
  },
  
  // 对话API
  conversations: {
    async create(data: any) {
      return ipcRenderer.invoke('api:conversations:create', data);
    },
    async chat(data: any) {
      return ipcRenderer.invoke('api:conversations:chat', data);
    }
  },
  
  // 文件上传
  files: {
    async upload(file: File) {
      // 将File转换为Buffer
      const buffer = await file.arrayBuffer();
      return ipcRenderer.invoke('api:files:upload', {
        name: file.name,
        data: Buffer.from(buffer)
      });
    }
  }
};
```

---

#### 4. Python子进程管理

```typescript
// apps/electron/main/src/python-service.ts

import { spawn, ChildProcess } from 'child_process';
import path from 'path';
import { app } from 'electron';

let pythonProcess: ChildProcess | null = null;

export async function startPythonService(): Promise<void> {
  return new Promise((resolve, reject) => {
    // Python运行时路径（打包时包含）
    const pythonPath = app.isPackaged
      ? path.join(process.resourcesPath, 'python', 'python.exe')
      : 'python';  // 开发环境使用系统Python
    
    // Python脚本路径
    const scriptPath = app.isPackaged
      ? path.join(process.resourcesPath, 'python', 'extraction_service', 'main.py')
      : path.join(__dirname, '../../../../extraction_service/main.py');
    
    // 启动Python进程
    pythonProcess = spawn(pythonPath, [
      '-m', 'uvicorn',
      'main:app',
      '--host', '127.0.0.1',
      '--port', '8000'
    ], {
      cwd: path.dirname(scriptPath),
      stdio: 'pipe'
    });
    
    // 监听输出
    pythonProcess.stdout?.on('data', (data) => {
      console.log(`Python: ${data}`);
      if (data.toString().includes('Application startup complete')) {
        resolve();
      }
    });
    
    pythonProcess.stderr?.on('data', (data) => {
      console.error(`Python Error: ${data}`);
    });
    
    pythonProcess.on('error', reject);
  });
}

export function stopPythonService(): void {
  if (pythonProcess) {
    pythonProcess.kill();
    pythonProcess = null;
  }
}

// 应用退出时关闭Python服务
app.on('will-quit', stopPythonService);
```

---

#### 5. 打包配置（electron-builder.yml）

```yaml
# apps/electron/electron-builder.yml

appId: com.yizhengxun.aiclinical
productName: 壹证循AI科研助手

# 打包目录
directories:
  output: dist
  buildResources: resources

# Windows配置
win:
  target:
    - nsis
    - portable
  icon: resources/icon.ico

# NSIS安装程序配置
nsis:
  oneClick: false
  allowToChangeInstallationDirectory: true
  createDesktopShortcut: always
  createStartMenuShortcut: true

# Mac配置
mac:
  target:
    - dmg
    - zip
  icon: resources/icon.icns
  category: public.app-category.productivity

# 打包包含的文件
files:
  - "main/**/*"
  - "renderer/**/*"
  - "!**/*.ts"
  - "!**/*.map"

# 额外资源（Python运行时等）
extraResources:
  - from: resources/python
    to: python
  - from: ../../../../extraction_service
    to: python/extraction_service

# 打包后大小
asar: true
asarUnpack:
  - "**/*.node"
  - "resources/**/*"
```

---

### 单机版的关键技术挑战

#### 挑战1：打包体积（500MB+）

**包含内容：**
```
安装包组成：
- Electron框架：~100MB
- Node.js运行时：包含在Electron中
- 前端代码（编译后）：~10MB
- 后端代码（编译后）：~5MB
- SQLite数据库：~5MB（空库）
- Python运行时：~150MB
- Python依赖：~100MB
- R运行时（可选）：~200MB
- R依赖（可选）：~100MB

总计：500-700MB
```

**优化方案：**
1. ✅ 使用ASAR压缩（Electron默认）
2. ✅ 不包含R运行时（仅云端版需要）
3. ✅ Python依赖精简（只包含必需的包）
4. ✅ 增量更新（只下载变化的部分）

---

#### 挑战2：跨平台兼容性

**需要分别打包：**
- Windows x64
- Windows ARM64（Surface等设备）
- macOS x64
- macOS ARM64（Apple Silicon）
- Linux x64

**测试工作量：**
- 每个平台都需要独立测试
- 安装、升级、卸载流程
- 权限问题、文件路径问题

---

#### 挑战3：自动更新

**electron-updater配置：**
```typescript
// apps/electron/main/src/updater.ts

import { autoUpdater } from 'electron-updater';
import { dialog } from 'electron';

export function setupAutoUpdater() {
  // 配置更新服务器
  autoUpdater.setFeedURL({
    provider: 'generic',
    url: 'https://releases.yizhengxun.com'
  });
  
  // 检查更新
  autoUpdater.checkForUpdatesAndNotify();
  
  // 发现新版本
  autoUpdater.on('update-available', () => {
    dialog.showMessageBox({
      type: 'info',
      title: '发现新版本',
      message: '检测到新版本，是否立即下载？',
      buttons: ['是', '否']
    }).then((result) => {
      if (result.response === 0) {
        autoUpdater.downloadUpdate();
      }
    });
  });
  
  // 下载完成
  autoUpdater.on('update-downloaded', () => {
    dialog.showMessageBox({
      type: 'info',
      title: '更新已就绪',
      message: '新版本已下载，是否立即安装？',
      buttons: ['立即安装', '稍后']
    }).then((result) => {
      if (result.response === 0) {
        autoUpdater.quitAndInstall();
      }
    });
  });
}
```

---

## 📊 总结对比

### 三种部署方式对比

| 维度 | 云端SaaS | 独立产品包 | Electron单机版 |
|------|---------|----------|---------------|
| **部署方式** | 云端服务器 | Docker容器 | 本地安装 |
| **数据存储** | 云端PostgreSQL | 本地PostgreSQL | 本地SQLite |
| **网络需求** | 必须联网 | 可离线（LLM除外） | 完全离线 |
| **更新方式** | 无感知更新 | Docker镜像更新 | 应用内更新 |
| **安装难度** | 无需安装 | Docker部署 | 一键安装 |
| **代码复用** | 100% | 80%（精简版） | 90% |
| **适用客户** | 个人、小机构 | 医院、大机构 | 个人医生 |
| **商业模式** | 订阅制 | 一次性License | 一次性购买 |
| **维护成本** | 低 | 中 | 高 |

---

## 🎯 最终建议

### 分阶段实施

**阶段一（当前-6个月）：**
- ✅ 专注云端SaaS版
- ✅ 完善7个业务模块
- ✅ 建立Monorepo架构（为未来打基础）

**阶段二（6-12个月）：**
- ✅ 开发独立产品包（审稿系统、AI文献）
- ✅ 支持Docker本地化部署
- ✅ 验证商业模式

**阶段三（12-18个月）：**
- ✅ 开发Electron单机版（如有需求）
- ✅ 支持完全离线使用
- ✅ 扩展个人用户市场

---

**您想先深入哪个方案？**
1. 模块独立部署的详细实施？
2. Electron单机版的开发计划？
3. Monorepo架构的设计？















