2.1 前端技术栈选择

2.1.1 框架对比分析

主流前端框架比较

框架 优势 劣势 适用场景
Vue.js 学习曲线平缓、双向绑定、组件化 生态相对较小 中小型项目、快速开发
React 生态丰富、性能优秀、社区活跃 学习成本高、配置复杂 大型项目、高性能要求
Angular 完整框架、TypeScript原生支持 体积大、学习成本高 企业级应用

推荐技术栈:Vue 3 + TypeScript

选择理由: 1. 开发效率高:Vue的模板语法和响应式系统便于快速开发 2. 组件化友好:天然支持组件化开发模式 3. TypeScript支持:提供更好的类型安全和开发体验 4. 生态完善:Vue Router、Pinia、Vite等工具链成熟

2.1.2 核心依赖选择

package.json 配置

{
  "name": "lowcode-platform-frontend",
  "version": "1.0.0",
  "description": "Low-code platform frontend application",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "test": "vitest",
    "test:ui": "vitest --ui",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
    "type-check": "vue-tsc --noEmit"
  },
  "dependencies": {
    "vue": "^3.3.4",
    "vue-router": "^4.2.4",
    "pinia": "^2.1.6",
    "@vueuse/core": "^10.3.0",
    "element-plus": "^2.3.8",
    "@element-plus/icons-vue": "^2.1.0",
    "axios": "^1.4.0",
    "lodash-es": "^4.17.21",
    "dayjs": "^1.11.9",
    "monaco-editor": "^0.41.0",
    "sortablejs": "^1.15.0",
    "fabric": "^5.3.0",
    "konva": "^9.2.0",
    "vue-konva": "^3.0.2"
  },
  "devDependencies": {
    "@types/node": "^20.4.5",
    "@types/lodash-es": "^4.17.8",
    "@types/sortablejs": "^1.15.1",
    "@vitejs/plugin-vue": "^4.2.3",
    "@vue/eslint-config-prettier": "^8.0.0",
    "@vue/eslint-config-typescript": "^11.0.3",
    "@vue/test-utils": "^2.4.1",
    "@vue/tsconfig": "^0.4.0",
    "eslint": "^8.45.0",
    "eslint-plugin-vue": "^9.15.1",
    "jsdom": "^22.1.0",
    "prettier": "^3.0.0",
    "typescript": "~5.1.6",
    "vite": "^4.4.6",
    "vitest": "^0.33.0",
    "vue-tsc": "^1.8.6"
  }
}

核心依赖说明

// 依赖说明和使用场景
interface DependencyInfo {
  name: string;
  purpose: string;
  usage: string;
  alternatives?: string[];
}

const coreDependencies: DependencyInfo[] = [
  {
    name: 'vue',
    purpose: '核心框架',
    usage: '组件开发、响应式数据、模板渲染'
  },
  {
    name: 'vue-router',
    purpose: '路由管理',
    usage: '页面导航、路由守卫、动态路由'
  },
  {
    name: 'pinia',
    purpose: '状态管理',
    usage: '全局状态、组件通信、数据持久化',
    alternatives: ['vuex']
  },
  {
    name: 'element-plus',
    purpose: 'UI组件库',
    usage: '基础组件、表单组件、布局组件',
    alternatives: ['ant-design-vue', 'naive-ui']
  },
  {
    name: 'monaco-editor',
    purpose: '代码编辑器',
    usage: '代码编辑、语法高亮、智能提示',
    alternatives: ['codemirror']
  },
  {
    name: 'fabric',
    purpose: '画布操作',
    usage: '拖拽操作、图形绘制、交互处理',
    alternatives: ['konva', 'paper.js']
  },
  {
    name: 'sortablejs',
    purpose: '拖拽排序',
    usage: '组件排序、列表重排、树形拖拽'
  }
];

2.1.3 项目结构设计

lowcode-platform-frontend/
├── public/                     # 静态资源
│   ├── favicon.ico
│   └── index.html
├── src/
│   ├── assets/                 # 资源文件
│   │   ├── images/
│   │   ├── icons/
│   │   └── styles/
│   ├── components/             # 通用组件
│   │   ├── common/             # 基础组件
│   │   ├── designer/           # 设计器组件
│   │   └── runtime/            # 运行时组件
│   ├── views/                  # 页面组件
│   │   ├── designer/           # 设计器页面
│   │   ├── preview/            # 预览页面
│   │   └── admin/              # 管理页面
│   ├── stores/                 # 状态管理
│   │   ├── designer.ts         # 设计器状态
│   │   ├── components.ts       # 组件状态
│   │   └── user.ts             # 用户状态
│   ├── utils/                  # 工具函数
│   │   ├── api.ts              # API封装
│   │   ├── canvas.ts           # 画布工具
│   │   └── validator.ts        # 验证工具
│   ├── types/                  # 类型定义
│   │   ├── component.ts        # 组件类型
│   │   ├── designer.ts         # 设计器类型
│   │   └── api.ts              # API类型
│   ├── plugins/                # 插件系统
│   │   ├── component-loader.ts # 组件加载器
│   │   └── theme-manager.ts    # 主题管理器
│   ├── router/                 # 路由配置
│   │   └── index.ts
│   ├── App.vue                 # 根组件
│   └── main.ts                 # 入口文件
├── tests/                      # 测试文件
│   ├── unit/                   # 单元测试
│   └── e2e/                    # 端到端测试
├── docs/                       # 文档
├── vite.config.ts              # Vite配置
├── tsconfig.json               # TypeScript配置
├── eslint.config.js            # ESLint配置
└── package.json                # 项目配置

2.2 后端架构设计

2.2.1 技术栈选择

Node.js + Express + TypeScript

选择理由: 1. 开发效率:JavaScript全栈开发,减少语言切换成本 2. 生态丰富:npm生态系统提供丰富的第三方库 3. 性能优秀:事件驱动、非阻塞I/O模型 4. 类型安全:TypeScript提供静态类型检查

核心依赖配置

{
  "name": "lowcode-platform-backend",
  "version": "1.0.0",
  "description": "Low-code platform backend service",
  "scripts": {
    "dev": "nodemon --exec ts-node src/app.ts",
    "build": "tsc",
    "start": "node dist/app.js",
    "test": "jest",
    "test:watch": "jest --watch",
    "lint": "eslint src/**/*.ts --fix",
    "migrate": "typeorm migration:run",
    "seed": "ts-node src/database/seeds/index.ts"
  },
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "helmet": "^7.0.0",
    "compression": "^1.7.4",
    "express-rate-limit": "^6.8.1",
    "typeorm": "^0.3.17",
    "mysql2": "^3.6.0",
    "redis": "^4.6.7",
    "jsonwebtoken": "^9.0.1",
    "bcryptjs": "^2.4.3",
    "joi": "^17.9.2",
    "multer": "^1.4.5-lts.1",
    "sharp": "^0.32.4",
    "nodemailer": "^6.9.4",
    "winston": "^3.10.0",
    "socket.io": "^4.7.2",
    "bull": "^4.11.3",
    "ioredis": "^5.3.2"
  },
  "devDependencies": {
    "@types/express": "^4.17.17",
    "@types/cors": "^2.8.13",
    "@types/compression": "^1.7.2",
    "@types/jsonwebtoken": "^9.0.2",
    "@types/bcryptjs": "^2.4.2",
    "@types/multer": "^1.4.7",
    "@types/nodemailer": "^6.4.9",
    "@types/node": "^20.4.5",
    "@types/jest": "^29.5.3",
    "@typescript-eslint/eslint-plugin": "^6.2.1",
    "@typescript-eslint/parser": "^6.2.1",
    "eslint": "^8.45.0",
    "jest": "^29.6.1",
    "ts-jest": "^29.1.1",
    "ts-node": "^10.9.1",
    "nodemon": "^3.0.1",
    "typescript": "^5.1.6"
  }
}

2.2.2 微服务架构设计

// 服务架构定义
interface ServiceArchitecture {
  services: ServiceDefinition[];
  gateway: GatewayConfig;
  database: DatabaseConfig;
  cache: CacheConfig;
  messageQueue: MessageQueueConfig;
}

interface ServiceDefinition {
  name: string;
  port: number;
  responsibilities: string[];
  dependencies: string[];
  database?: string;
}

const architecture: ServiceArchitecture = {
  services: [
    {
      name: 'api-gateway',
      port: 3000,
      responsibilities: [
        '请求路由',
        '身份认证',
        '限流控制',
        'API文档'
      ],
      dependencies: ['auth-service', 'designer-service']
    },
    {
      name: 'auth-service',
      port: 3001,
      responsibilities: [
        '用户认证',
        '权限管理',
        'JWT令牌',
        '用户管理'
      ],
      dependencies: [],
      database: 'auth_db'
    },
    {
      name: 'designer-service',
      port: 3002,
      responsibilities: [
        '页面设计',
        '组件管理',
        '模板管理',
        '版本控制'
      ],
      dependencies: ['component-service'],
      database: 'designer_db'
    },
    {
      name: 'component-service',
      port: 3003,
      responsibilities: [
        '组件注册',
        '组件库管理',
        '组件版本',
        '组件市场'
      ],
      dependencies: [],
      database: 'component_db'
    },
    {
      name: 'runtime-service',
      port: 3004,
      responsibilities: [
        '应用运行',
        '数据绑定',
        '事件处理',
        '性能监控'
      ],
      dependencies: ['data-service'],
      database: 'runtime_db'
    },
    {
      name: 'data-service',
      port: 3005,
      responsibilities: [
        '数据源管理',
        'API代理',
        '数据转换',
        '缓存管理'
      ],
      dependencies: [],
      database: 'data_db'
    },
    {
      name: 'workflow-service',
      port: 3006,
      responsibilities: [
        '工作流引擎',
        '流程设计',
        '任务调度',
        '审批流程'
      ],
      dependencies: ['notification-service'],
      database: 'workflow_db'
    },
    {
      name: 'notification-service',
      port: 3007,
      responsibilities: [
        '消息推送',
        '邮件发送',
        '短信通知',
        '系统通知'
      ],
      dependencies: []
    }
  ],
  gateway: {
    port: 3000,
    routes: [
      { path: '/api/auth/*', service: 'auth-service' },
      { path: '/api/designer/*', service: 'designer-service' },
      { path: '/api/components/*', service: 'component-service' },
      { path: '/api/runtime/*', service: 'runtime-service' },
      { path: '/api/data/*', service: 'data-service' },
      { path: '/api/workflow/*', service: 'workflow-service' }
    ]
  },
  database: {
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    databases: [
      'auth_db',
      'designer_db',
      'component_db',
      'runtime_db',
      'data_db',
      'workflow_db'
    ]
  },
  cache: {
    type: 'redis',
    host: 'localhost',
    port: 6379,
    clusters: [
      { name: 'session', db: 0 },
      { name: 'cache', db: 1 },
      { name: 'queue', db: 2 }
    ]
  },
  messageQueue: {
    type: 'redis',
    host: 'localhost',
    port: 6379,
    queues: [
      'email-queue',
      'notification-queue',
      'export-queue',
      'import-queue'
    ]
  }
};

2.2.3 项目结构设计

lowcode-platform-backend/
├── services/                   # 微服务目录
│   ├── api-gateway/           # API网关
│   │   ├── src/
│   │   │   ├── middleware/    # 中间件
│   │   │   ├── routes/        # 路由配置
│   │   │   ├── utils/         # 工具函数
│   │   │   └── app.ts         # 应用入口
│   │   ├── Dockerfile
│   │   └── package.json
│   ├── auth-service/          # 认证服务
│   │   ├── src/
│   │   │   ├── controllers/   # 控制器
│   │   │   ├── services/      # 业务逻辑
│   │   │   ├── models/        # 数据模型
│   │   │   ├── middleware/    # 中间件
│   │   │   ├── routes/        # 路由
│   │   │   └── app.ts
│   │   ├── Dockerfile
│   │   └── package.json
│   ├── designer-service/      # 设计器服务
│   ├── component-service/     # 组件服务
│   ├── runtime-service/       # 运行时服务
│   ├── data-service/          # 数据服务
│   ├── workflow-service/      # 工作流服务
│   └── notification-service/  # 通知服务
├── shared/                    # 共享代码
│   ├── types/                 # 类型定义
│   ├── utils/                 # 工具函数
│   ├── middleware/            # 通用中间件
│   └── database/              # 数据库配置
├── scripts/                   # 脚本文件
│   ├── build.sh              # 构建脚本
│   ├── deploy.sh             # 部署脚本
│   └── migrate.sh            # 迁移脚本
├── docker/                    # Docker配置
│   ├── docker-compose.yml    # 开发环境
│   ├── docker-compose.prod.yml # 生产环境
│   └── nginx.conf            # Nginx配置
├── docs/                      # 文档
│   ├── api/                  # API文档
│   └── deployment/           # 部署文档
└── package.json              # 根配置

2.3 数据库选型

2.3.1 关系型数据库:MySQL

数据库设计

-- 用户管理相关表
CREATE DATABASE auth_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE auth_db;

-- 用户表
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    full_name VARCHAR(100),
    avatar_url VARCHAR(500),
    status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
    role_id BIGINT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    last_login_at TIMESTAMP NULL,
    INDEX idx_username (username),
    INDEX idx_email (email),
    INDEX idx_status (status)
);

-- 角色表
CREATE TABLE roles (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) UNIQUE NOT NULL,
    description TEXT,
    permissions JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 设计器相关表
CREATE DATABASE designer_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE designer_db;

-- 项目表
CREATE TABLE projects (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    owner_id BIGINT NOT NULL,
    config JSON,
    status ENUM('draft', 'published', 'archived') DEFAULT 'draft',
    version VARCHAR(20) DEFAULT '1.0.0',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_owner (owner_id),
    INDEX idx_status (status),
    INDEX idx_name (name)
);

-- 页面表
CREATE TABLE pages (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    project_id BIGINT NOT NULL,
    name VARCHAR(100) NOT NULL,
    path VARCHAR(200) NOT NULL,
    config JSON NOT NULL,
    meta JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
    UNIQUE KEY uk_project_path (project_id, path),
    INDEX idx_project (project_id)
);

-- 组件库相关表
CREATE DATABASE component_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE component_db;

-- 组件表
CREATE TABLE components (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    category VARCHAR(50) NOT NULL,
    version VARCHAR(20) NOT NULL,
    config JSON NOT NULL,
    schema JSON NOT NULL,
    preview_url VARCHAR(500),
    author_id BIGINT,
    status ENUM('draft', 'published', 'deprecated') DEFAULT 'draft',
    download_count INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_name_version (name, version),
    INDEX idx_category (category),
    INDEX idx_status (status),
    INDEX idx_author (author_id)
);

-- 组件依赖表
CREATE TABLE component_dependencies (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    component_id BIGINT NOT NULL,
    dependency_name VARCHAR(100) NOT NULL,
    dependency_version VARCHAR(20) NOT NULL,
    type ENUM('runtime', 'build') DEFAULT 'runtime',
    FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE,
    INDEX idx_component (component_id)
);

TypeORM 实体定义

// src/entities/User.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Role } from './Role';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn('increment')
  id: number;

  @Column({ unique: true, length: 50 })
  username: string;

  @Column({ unique: true, length: 100 })
  email: string;

  @Column({ name: 'password_hash', length: 255 })
  passwordHash: string;

  @Column({ name: 'full_name', length: 100, nullable: true })
  fullName?: string;

  @Column({ name: 'avatar_url', length: 500, nullable: true })
  avatarUrl?: string;

  @Column({
    type: 'enum',
    enum: ['active', 'inactive', 'suspended'],
    default: 'active'
  })
  status: 'active' | 'inactive' | 'suspended';

  @Column({ name: 'role_id', nullable: true })
  roleId?: number;

  @ManyToOne(() => Role)
  @JoinColumn({ name: 'role_id' })
  role?: Role;

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;

  @Column({ name: 'last_login_at', nullable: true })
  lastLoginAt?: Date;
}

// src/entities/Project.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { Page } from './Page';

@Entity('projects')
export class Project {
  @PrimaryGeneratedColumn('increment')
  id: number;

  @Column({ length: 100 })
  name: string;

  @Column({ type: 'text', nullable: true })
  description?: string;

  @Column({ name: 'owner_id' })
  ownerId: number;

  @Column({ type: 'json', nullable: true })
  config?: any;

  @Column({
    type: 'enum',
    enum: ['draft', 'published', 'archived'],
    default: 'draft'
  })
  status: 'draft' | 'published' | 'archived';

  @Column({ length: 20, default: '1.0.0' })
  version: string;

  @OneToMany(() => Page, page => page.project)
  pages: Page[];

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}

// src/entities/Component.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { ComponentDependency } from './ComponentDependency';

@Entity('components')
export class Component {
  @PrimaryGeneratedColumn('increment')
  id: number;

  @Column({ length: 100 })
  name: string;

  @Column({ length: 50 })
  category: string;

  @Column({ length: 20 })
  version: string;

  @Column({ type: 'json' })
  config: any;

  @Column({ type: 'json' })
  schema: any;

  @Column({ name: 'preview_url', length: 500, nullable: true })
  previewUrl?: string;

  @Column({ name: 'author_id', nullable: true })
  authorId?: number;

  @Column({
    type: 'enum',
    enum: ['draft', 'published', 'deprecated'],
    default: 'draft'
  })
  status: 'draft' | 'published' | 'deprecated';

  @Column({ name: 'download_count', default: 0 })
  downloadCount: number;

  @OneToMany(() => ComponentDependency, dependency => dependency.component)
  dependencies: ComponentDependency[];

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}

2.3.2 缓存数据库:Redis

Redis 配置和使用

// src/config/redis.ts
import Redis from 'ioredis';

interface RedisConfig {
  host: string;
  port: number;
  password?: string;
  db: number;
  keyPrefix?: string;
}

class RedisManager {
  private clients: Map<string, Redis> = new Map();

  constructor() {
    this.initializeClients();
  }

  private initializeClients() {
    const configs: Record<string, RedisConfig> = {
      session: {
        host: process.env.REDIS_HOST || 'localhost',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        db: 0,
        keyPrefix: 'session:'
      },
      cache: {
        host: process.env.REDIS_HOST || 'localhost',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        db: 1,
        keyPrefix: 'cache:'
      },
      queue: {
        host: process.env.REDIS_HOST || 'localhost',
        port: parseInt(process.env.REDIS_PORT || '6379'),
        db: 2,
        keyPrefix: 'queue:'
      }
    };

    Object.entries(configs).forEach(([name, config]) => {
      const client = new Redis(config);
      this.clients.set(name, client);
    });
  }

  getClient(name: string): Redis {
    const client = this.clients.get(name);
    if (!client) {
      throw new Error(`Redis client '${name}' not found`);
    }
    return client;
  }

  async disconnect() {
    await Promise.all(
      Array.from(this.clients.values()).map(client => client.disconnect())
    );
  }
}

export const redisManager = new RedisManager();

// 缓存服务
export class CacheService {
  private redis: Redis;

  constructor() {
    this.redis = redisManager.getClient('cache');
  }

  async get<T>(key: string): Promise<T | null> {
    const value = await this.redis.get(key);
    return value ? JSON.parse(value) : null;
  }

  async set(key: string, value: any, ttl?: number): Promise<void> {
    const serialized = JSON.stringify(value);
    if (ttl) {
      await this.redis.setex(key, ttl, serialized);
    } else {
      await this.redis.set(key, serialized);
    }
  }

  async del(key: string): Promise<void> {
    await this.redis.del(key);
  }

  async exists(key: string): Promise<boolean> {
    const result = await this.redis.exists(key);
    return result === 1;
  }

  async keys(pattern: string): Promise<string[]> {
    return await this.redis.keys(pattern);
  }

  // 组件缓存
  async cacheComponent(componentId: string, component: any, ttl = 3600): Promise<void> {
    await this.set(`component:${componentId}`, component, ttl);
  }

  async getCachedComponent(componentId: string): Promise<any> {
    return await this.get(`component:${componentId}`);
  }

  // 页面配置缓存
  async cachePageConfig(pageId: string, config: any, ttl = 1800): Promise<void> {
    await this.set(`page:${pageId}`, config, ttl);
  }

  async getCachedPageConfig(pageId: string): Promise<any> {
    return await this.get(`page:${pageId}`);
  }

  // 用户会话缓存
  async cacheUserSession(userId: string, session: any, ttl = 7200): Promise<void> {
    await this.set(`user:session:${userId}`, session, ttl);
  }

  async getUserSession(userId: string): Promise<any> {
    return await this.get(`user:session:${userId}`);
  }
}

2.4 开发环境配置

2.4.1 Docker 开发环境

docker-compose.yml

version: '3.8'

services:
  # MySQL 数据库
  mysql:
    image: mysql:8.0
    container_name: lowcode-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: lowcode_platform
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./docker/mysql/init:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    networks:
      - lowcode-network

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: lowcode-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    networks:
      - lowcode-network

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    container_name: lowcode-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./docker/nginx/conf.d:/etc/nginx/conf.d
      - ./docker/ssl:/etc/nginx/ssl
    depends_on:
      - api-gateway
    networks:
      - lowcode-network

  # API 网关
  api-gateway:
    build:
      context: ./services/api-gateway
      dockerfile: Dockerfile.dev
    container_name: lowcode-gateway
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      MYSQL_HOST: mysql
      REDIS_HOST: redis
    volumes:
      - ./services/api-gateway/src:/app/src
      - /app/node_modules
    depends_on:
      - mysql
      - redis
    networks:
      - lowcode-network

  # 认证服务
  auth-service:
    build:
      context: ./services/auth-service
      dockerfile: Dockerfile.dev
    container_name: lowcode-auth
    ports:
      - "3001:3001"
    environment:
      NODE_ENV: development
      MYSQL_HOST: mysql
      REDIS_HOST: redis
    volumes:
      - ./services/auth-service/src:/app/src
      - /app/node_modules
    depends_on:
      - mysql
      - redis
    networks:
      - lowcode-network

  # 设计器服务
  designer-service:
    build:
      context: ./services/designer-service
      dockerfile: Dockerfile.dev
    container_name: lowcode-designer
    ports:
      - "3002:3002"
    environment:
      NODE_ENV: development
      MYSQL_HOST: mysql
      REDIS_HOST: redis
    volumes:
      - ./services/designer-service/src:/app/src
      - /app/node_modules
    depends_on:
      - mysql
      - redis
    networks:
      - lowcode-network

  # 前端开发服务器
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    container_name: lowcode-frontend
    ports:
      - "5173:5173"
    environment:
      NODE_ENV: development
      VITE_API_BASE_URL: http://localhost:3000
    volumes:
      - ./frontend/src:/app/src
      - ./frontend/public:/app/public
      - /app/node_modules
    networks:
      - lowcode-network

volumes:
  mysql_data:
  redis_data:

networks:
  lowcode-network:
    driver: bridge

Dockerfile.dev 示例

# services/api-gateway/Dockerfile.dev
FROM node:18-alpine

WORKDIR /app

# 安装依赖
COPY package*.json ./
RUN npm ci

# 复制源码
COPY . .

# 暴露端口
EXPOSE 3000

# 开发模式启动
CMD ["npm", "run", "dev"]

2.4.2 环境变量配置

.env.development

# 应用配置
NODE_ENV=development
APP_NAME=LowCode Platform
APP_VERSION=1.0.0
APP_PORT=3000

# 数据库配置
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=root123
DB_DATABASE=lowcode_platform
DB_SYNCHRONIZE=true
DB_LOGGING=true

# Redis 配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB_SESSION=0
REDIS_DB_CACHE=1
REDIS_DB_QUEUE=2

# JWT 配置
JWT_SECRET=your-super-secret-jwt-key-here
JWT_EXPIRES_IN=7d
JWT_REFRESH_EXPIRES_IN=30d

# 文件上传配置
UPLOAD_MAX_SIZE=10485760
UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/gif,image/webp
UPLOAD_DEST=./uploads

# 邮件配置
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_SECURE=false
MAIL_USER=your-email@gmail.com
MAIL_PASS=your-app-password
MAIL_FROM=noreply@lowcode-platform.com

# 日志配置
LOG_LEVEL=debug
LOG_FILE=./logs/app.log
LOG_MAX_SIZE=20m
LOG_MAX_FILES=14d

# 安全配置
CORS_ORIGIN=http://localhost:5173
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX=100

# 外部服务
AI_SERVICE_URL=http://localhost:8080
AI_SERVICE_API_KEY=your-ai-service-key

# 监控配置
MONITORING_ENABLED=true
METRICS_PORT=9090
HEALTH_CHECK_INTERVAL=30000

环境变量验证

// src/config/env.ts
import Joi from 'joi';

interface EnvConfig {
  NODE_ENV: 'development' | 'production' | 'test';
  APP_NAME: string;
  APP_VERSION: string;
  APP_PORT: number;
  
  DB_TYPE: string;
  DB_HOST: string;
  DB_PORT: number;
  DB_USERNAME: string;
  DB_PASSWORD: string;
  DB_DATABASE: string;
  
  REDIS_HOST: string;
  REDIS_PORT: number;
  
  JWT_SECRET: string;
  JWT_EXPIRES_IN: string;
  
  UPLOAD_MAX_SIZE: number;
  UPLOAD_DEST: string;
}

const envSchema = Joi.object({
  NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
  APP_NAME: Joi.string().required(),
  APP_VERSION: Joi.string().required(),
  APP_PORT: Joi.number().port().default(3000),
  
  DB_TYPE: Joi.string().default('mysql'),
  DB_HOST: Joi.string().required(),
  DB_PORT: Joi.number().port().default(3306),
  DB_USERNAME: Joi.string().required(),
  DB_PASSWORD: Joi.string().required(),
  DB_DATABASE: Joi.string().required(),
  
  REDIS_HOST: Joi.string().required(),
  REDIS_PORT: Joi.number().port().default(6379),
  
  JWT_SECRET: Joi.string().min(32).required(),
  JWT_EXPIRES_IN: Joi.string().default('7d'),
  
  UPLOAD_MAX_SIZE: Joi.number().default(10485760),
  UPLOAD_DEST: Joi.string().default('./uploads')
}).unknown();

export function validateEnv(): EnvConfig {
  const { error, value } = envSchema.validate(process.env);
  
  if (error) {
    throw new Error(`Environment validation error: ${error.message}`);
  }
  
  return value;
}

export const env = validateEnv();

2.4.3 开发工具配置

VS Code 配置

// .vscode/settings.json
{
  "typescript.preferences.importModuleSpecifier": "relative",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.workingDirectories": [
    "frontend",
    "services/api-gateway",
    "services/auth-service",
    "services/designer-service"
  ],
  "files.associations": {
    "*.vue": "vue"
  },
  "emmet.includeLanguages": {
    "vue": "html"
  }
}

// .vscode/extensions.json
{
  "recommendations": [
    "vue.volar",
    "vue.vscode-typescript-vue-plugin",
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
    "ms-vscode.vscode-typescript-next",
    "bradlc.vscode-tailwindcss",
    "ms-vscode-remote.remote-containers"
  ]
}

启动脚本

#!/bin/bash
# scripts/dev.sh

echo "🚀 启动低代码平台开发环境..."

# 检查 Docker 是否运行
if ! docker info > /dev/null 2>&1; then
    echo "❌ Docker 未运行,请先启动 Docker"
    exit 1
fi

# 检查端口是否被占用
check_port() {
    if lsof -Pi :$1 -sTCP:LISTEN -t >/dev/null ; then
        echo "⚠️  端口 $1 已被占用"
        return 1
    fi
    return 0
}

ports=(3000 3001 3002 3306 6379 5173)
for port in "${ports[@]}"; do
    if ! check_port $port; then
        echo "请释放端口 $port 后重试"
        exit 1
    fi
done

# 创建必要的目录
mkdir -p logs uploads

# 启动服务
echo "📦 启动 Docker 容器..."
docker-compose up -d mysql redis

echo "⏳ 等待数据库启动..."
sleep 10

# 运行数据库迁移
echo "🗄️  运行数据库迁移..."
npm run migrate

# 启动后端服务
echo "🔧 启动后端服务..."
docker-compose up -d api-gateway auth-service designer-service

# 启动前端服务
echo "🎨 启动前端服务..."
cd frontend && npm run dev &

echo "✅ 开发环境启动完成!"
echo "📱 前端地址: http://localhost:5173"
echo "🔌 API地址: http://localhost:3000"
echo "📊 监控面板: http://localhost:3000/health"

# 等待用户输入退出
read -p "按 Enter 键停止所有服务..."

echo "🛑 停止服务..."
docker-compose down
killall node 2>/dev/null || true

echo "👋 开发环境已停止"

2.5 小结

本章详细介绍了低代码平台的技术栈选择和环境搭建,包括:

核心要点

  1. 前端技术栈:选择 Vue 3 + TypeScript + Vite 构建现代化前端应用
  2. 后端架构:采用 Node.js + Express + TypeScript 微服务架构
  3. 数据存储:MySQL 作为主数据库,Redis 作为缓存和会话存储
  4. 开发环境:使用 Docker 容器化部署,提供一致的开发体验

技术选型原则

  • 开发效率:选择学习曲线平缓、开发效率高的技术
  • 生态完善:优先选择生态系统成熟、社区活跃的技术
  • 性能优秀:考虑技术的性能表现和扩展能力
  • 类型安全:使用 TypeScript 提供更好的开发体验

架构设计

  • 微服务架构:将功能拆分为独立的服务,便于开发和维护
  • 容器化部署:使用 Docker 实现环境一致性和快速部署
  • 数据分离:不同服务使用独立的数据库,避免数据耦合
  • 缓存策略:合理使用 Redis 缓存提升系统性能

开发体验

  • 热重载:前后端都支持热重载,提升开发效率
  • 类型检查:TypeScript 提供编译时类型检查
  • 代码规范:ESLint + Prettier 保证代码质量
  • 调试工具:完善的调试和监控工具链

下一章我们将深入学习平台架构设计,了解如何设计一个可扩展、高性能的低代码平台架构。