# 模块独立部署与单机版方案 > **文档版本:** 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