Files
ColaFlow/docs/DOCKER-DEVELOPMENT-ENVIRONMENT.md
Yaojia Wang 08b317e789
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Add trace files.
2025-11-04 23:28:56 +01:00

38 KiB
Raw Permalink Blame History

ColaFlow Docker 开发环境方案

版本: 1.0 日期: 2025-11-04 状态: 设计完成,待实施 作者: ColaFlow Architecture Team


一、方案概述

本方案为 ColaFlow 前端开发者提供一键启动的完整后端开发环境,通过 Docker 容器化技术实现:

  • 后端 API (.NET 9)
  • PostgreSQL 数据库
  • Redis 缓存
  • SignalR 实时通信
  • 开发工具pgAdmin, Redis Commander

1.1 设计目标

目标 指标 当前状态
启动速度 < 60秒 待优化
配置复杂度 单命令启动 已实现
数据持久化 支持重启保留数据 已实现
热重载 前端代码变更自动刷新 待实现
资源占用 < 4GB RAM 待测试

1.2 架构图

┌─────────────────────────────────────────────────────────────┐
│                     Host Machine (Windows)                  │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              colaflow-network (Bridge)                 │ │
│  │                                                        │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │ │
│  │  │ PostgreSQL   │  │    Redis     │  │   Backend    │ │ │
│  │  │   :5432      │  │    :6379     │  │   :8080      │ │ │
│  │  │ (postgres)   │  │   (redis)    │  │  (.NET 9)    │ │ │
│  │  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘ │ │
│  │         │                  │                  │         │ │
│  │         └──────────────────┴──────────────────┘         │ │
│  │                            │                            │ │
│  │                  ┌─────────┴──────────┐                │ │
│  │                  │     Frontend       │                │ │
│  │                  │      :3000         │                │ │
│  │                  │    (Next.js 15)    │                │ │
│  │                  └────────────────────┘                │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                             │
│  ┌────────────────┐         ┌────────────────┐             │
│  │  localhost:5000│◄────────┤  Frontend Dev  │             │
│  │  (API Access)  │         │   (Browser)    │             │
│  └────────────────┘         └────────────────┘             │
└─────────────────────────────────────────────────────────────┘

二、当前问题分析

2.1 已发现的问题

问题 严重性 影响 状态
Dockerfile 项目路径过时 🔴 CRITICAL 后端容器无法构建 待修复
缺少前端 Dockerfile 🔴 CRITICAL 前端无法容器化 待创建
缺少数据库初始化脚本 🟡 MEDIUM 首次启动需手动迁移 待创建
缺少种子数据 🟡 MEDIUM 开发环境无测试数据 待创建
缺少 .env.example 🟡 MEDIUM 开发者不知道配置项 待创建
缺少开发者文档 🟢 LOW 上手成本高 待创建

2.2 项目结构变化

旧结构 (Dockerfile 中的路径):

src/
├── ColaFlow.Domain/
├── ColaFlow.Application/
├── ColaFlow.Infrastructure/
└── ColaFlow.API/

新结构 (实际项目结构):

src/
├── ColaFlow.API/                   # 主 API 项目
├── Modules/
│   ├── Identity/                   # 身份认证模块
│   ├── ProjectManagement/          # 项目管理模块
│   └── IssueManagement/            # 问题管理模块
├── Shared/
│   └── ColaFlow.Shared.Kernel/     # 共享内核
└── (已废弃的旧结构)

三、技术方案设计

3.1 后端 Dockerfile 优化

3.1.1 多阶段构建策略

# Stage 1: Build (完整 SDK 镜像)
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# 优化:先复制项目文件,利用 Docker 缓存层
COPY ["ColaFlow.sln", "./"]
COPY ["Directory.Build.props", "./"]
COPY ["Directory.Packages.props", "./"]

# 复制所有 .csproj 文件(模块化单体结构)
COPY ["src/ColaFlow.API/*.csproj", "src/ColaFlow.API/"]
COPY ["src/Modules/Identity/ColaFlow.Modules.Identity.Domain/*.csproj", "src/Modules/Identity/ColaFlow.Modules.Identity.Domain/"]
COPY ["src/Modules/Identity/ColaFlow.Modules.Identity.Application/*.csproj", "src/Modules/Identity/ColaFlow.Modules.Identity.Application/"]
COPY ["src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/*.csproj", "src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/"]
COPY ["src/Modules/ProjectManagement/**/*.csproj", "src/Modules/ProjectManagement/"]
COPY ["src/Modules/IssueManagement/**/*.csproj", "src/Modules/IssueManagement/"]
COPY ["src/Shared/ColaFlow.Shared.Kernel/*.csproj", "src/Shared/ColaFlow.Shared.Kernel/"]

# 恢复依赖(利用 Docker 缓存)
RUN dotnet restore

# 复制源代码
COPY . .

# 构建
WORKDIR /src/src/ColaFlow.API
RUN dotnet build -c Release -o /app/build --no-restore

# Stage 2: Publish
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish --no-restore --no-build

# Stage 3: Runtime (最小化运行时镜像)
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
WORKDIR /app

# 安装健康检查工具
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

# 复制发布文件
COPY --from=publish /app/publish .

# 配置环境
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Development

EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \
  CMD curl -f http://localhost:8080/health || exit 1

ENTRYPOINT ["dotnet", "ColaFlow.API.dll"]

3.1.2 优化要点

优化项 方法 效果
构建缓存 先复制 .csproj 再恢复依赖 依赖未变时跳过 restore节省 80% 时间
镜像大小 使用 aspnet 运行时而非 SDK 减少 500MB
多阶段分离 build → publish → runtime 最终镜像不含构建工具
健康检查 curl 探测 /health 端点 确保容器真正可用

3.2 前端 Dockerfile 设计

3.2.1 Next.js 15 多阶段构建

# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app

# 复制 package 文件
COPY package.json package-lock.json ./

# 安装依赖
RUN npm ci --only=production && \
    npm cache clean --force

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app

# 复制依赖
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# 构建 Next.js 应用
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# Stage 3: Development (用于开发环境)
FROM node:20-alpine AS development
WORKDIR /app

# 复制全部源码和 node_modules
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NODE_ENV=development
ENV PORT=3000

EXPOSE 3000

# 开发模式启动(支持热重载)
CMD ["npm", "run", "dev"]

# Stage 4: Production
FROM node:20-alpine AS production
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

# 复制构建产物
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

3.2.2 Next.js 配置更新

需要在 next.config.ts 中启用 standalone 输出:

const nextConfig: NextConfig = {
  // 生产环境使用 standalone 模式
  output: process.env.NODE_ENV === 'production' ? 'standalone' : undefined,

  // 其他配置...
};

3.3 Docker Compose 优化

3.3.1 完整的 docker-compose.yml

version: '3.8'

services:
  # PostgreSQL 16 - 主数据库
  postgres:
    image: postgres:16-alpine
    container_name: colaflow-postgres
    environment:
      POSTGRES_DB: colaflow
      POSTGRES_USER: colaflow
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-colaflow_dev_password}
      PGDATA: /var/lib/postgresql/data/pgdata
    ports:
      - "${POSTGRES_PORT:-5432}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init-db.sql
      - ./scripts/seed-data.sql:/docker-entrypoint-initdb.d/02-seed-data.sql
    networks:
      - colaflow-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U colaflow -d colaflow"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    restart: unless-stopped

  # Redis 7 - 缓存和会话存储
  redis:
    image: redis:7-alpine
    container_name: colaflow-redis
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-colaflow_redis_password}
    ports:
      - "${REDIS_PORT:-6379}:6379"
    volumes:
      - redis_data:/data
    networks:
      - colaflow-network
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 5s
    restart: unless-stopped

  # ColaFlow 后端 API (.NET 9)
  backend:
    build:
      context: ./colaflow-api
      dockerfile: Dockerfile
      target: runtime
    container_name: colaflow-api
    ports:
      - "${BACKEND_PORT:-5000}:8080"
    environment:
      # ASP.NET Core
      ASPNETCORE_ENVIRONMENT: Development
      ASPNETCORE_URLS: http://+:8080

      # Database
      ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=colaflow;Username=colaflow;Password=${POSTGRES_PASSWORD:-colaflow_dev_password};Include Error Detail=true"

      # Redis
      ConnectionStrings__Redis: "redis:6379,password=${REDIS_PASSWORD:-colaflow_redis_password},abortConnect=false"

      # JWT Settings
      JwtSettings__SecretKey: ${JWT_SECRET_KEY:-ColaFlow-Development-Secret-Key-Min-32-Characters-Long-2025}
      JwtSettings__Issuer: "ColaFlow"
      JwtSettings__Audience: "ColaFlow-Clients"
      JwtSettings__ExpirationHours: 24

      # Logging
      Logging__LogLevel__Default: Information
      Logging__LogLevel__Microsoft.AspNetCore: Warning
      Logging__LogLevel__Microsoft.EntityFrameworkCore: ${EF_LOG_LEVEL:-Information}

      # CORS
      CorsSettings__AllowedOrigins: "http://localhost:3000,http://localhost:${FRONTEND_PORT:-3000}"

    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - colaflow-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

  # ColaFlow 前端 (Next.js 15)
  frontend:
    build:
      context: ./colaflow-web
      dockerfile: Dockerfile
      target: development
    container_name: colaflow-web
    ports:
      - "${FRONTEND_PORT:-3000}:3000"
    environment:
      # Next.js
      NODE_ENV: development
      PORT: 3000
      NEXT_TELEMETRY_DISABLED: 1

      # API 配置
      NEXT_PUBLIC_API_URL: http://localhost:${BACKEND_PORT:-5000}
      NEXT_PUBLIC_WS_URL: ws://localhost:${BACKEND_PORT:-5000}/hubs/project

      # 内部 API URL服务端渲染使用
      API_URL: http://backend:8080

      # Feature Flags
      NEXT_PUBLIC_ENABLE_ANALYTICS: "false"
      NEXT_PUBLIC_ENABLE_DEBUG: "true"

    depends_on:
      backend:
        condition: service_healthy
    networks:
      - colaflow-network
    volumes:
      # 热重载:挂载源代码
      - ./colaflow-web:/app
      - /app/node_modules
      - /app/.next
    restart: unless-stopped

  # pgAdmin (可选,开发工具)
  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: colaflow-pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL:-admin@colaflow.com}
      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin}
      PGADMIN_CONFIG_SERVER_MODE: 'False'
    ports:
      - "${PGADMIN_PORT:-5050}:80"
    depends_on:
      - postgres
    networks:
      - colaflow-network
    restart: unless-stopped
    profiles:
      - tools  # 默认不启动,使用 --profile tools 启动

  # Redis Commander (可选,开发工具)
  redis-commander:
    image: rediscommander/redis-commander:latest
    container_name: colaflow-redis-commander
    environment:
      REDIS_HOSTS: "local:redis:6379:0:${REDIS_PASSWORD:-colaflow_redis_password}"
    ports:
      - "${REDIS_COMMANDER_PORT:-8081}:8081"
    depends_on:
      - redis
    networks:
      - colaflow-network
    restart: unless-stopped
    profiles:
      - tools

volumes:
  postgres_data:
    driver: local
  redis_data:
    driver: local

networks:
  colaflow-network:
    driver: bridge

3.3.2 环境变量管理

创建 .env.example 文件:

# ColaFlow Development Environment Variables
# Copy this file to .env and update values as needed

# =============================================================================
# Database Configuration
# =============================================================================
POSTGRES_PASSWORD=colaflow_dev_password
POSTGRES_PORT=5432

# =============================================================================
# Redis Configuration
# =============================================================================
REDIS_PASSWORD=colaflow_redis_password
REDIS_PORT=6379

# =============================================================================
# Backend Configuration
# =============================================================================
BACKEND_PORT=5000
JWT_SECRET_KEY=ColaFlow-Development-Secret-Key-Min-32-Characters-Long-2025
EF_LOG_LEVEL=Information  # Options: Trace, Debug, Information, Warning, Error

# =============================================================================
# Frontend Configuration
# =============================================================================
FRONTEND_PORT=3000

# =============================================================================
# Development Tools (Optional)
# =============================================================================
PGADMIN_EMAIL=admin@colaflow.com
PGADMIN_PASSWORD=admin
PGADMIN_PORT=5050
REDIS_COMMANDER_PORT=8081

3.4 数据库初始化和种子数据

3.4.1 初始化脚本 (scripts/init-db.sql)

-- ColaFlow Database Initialization Script
-- This script runs automatically when PostgreSQL container starts for the first time

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";  -- For full-text search

-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE colaflow TO colaflow;

-- Log initialization
DO $$
BEGIN
    RAISE NOTICE 'ColaFlow database initialized successfully';
END $$;

3.4.2 种子数据脚本 (scripts/seed-data.sql)

-- ColaFlow Development Seed Data
-- Provides sample data for frontend development and testing

-- NOTE: EF Core migrations should run before this script
-- This script assumes all tables have been created

DO $$
DECLARE
    tenant_id uuid;
    owner_user_id uuid;
    member_user_id uuid;
    project_id uuid;
    epic_id uuid;
    story_id uuid;
BEGIN
    -- Check if data already exists
    IF EXISTS (SELECT 1 FROM "Tenants" LIMIT 1) THEN
        RAISE NOTICE 'Seed data already exists, skipping...';
        RETURN;
    END IF;

    -- Create demo tenant
    INSERT INTO "Tenants" ("Id", "Name", "Slug", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        'Demo Company',
        'demo-company',
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO tenant_id;

    -- Create demo users
    -- Owner user (password: Admin123!)
    INSERT INTO "Users" ("Id", "Email", "PasswordHash", "FirstName", "LastName", "IsActive", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        'owner@demo.com',
        '$2a$11$XCKz5yZQJ5Z5Z5Z5Z5Z5ZuZQJ5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z',  -- Hash of "Admin123!"
        'Demo',
        'Owner',
        true,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO owner_user_id;

    -- Member user (password: Member123!)
    INSERT INTO "Users" ("Id", "Email", "PasswordHash", "FirstName", "LastName", "IsActive", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        'member@demo.com',
        '$2a$11$YCKz5yZQJ5Z5Z5Z5Z5Z5ZuZQJ5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Y',  -- Hash of "Member123!"
        'Demo',
        'Member',
        true,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO member_user_id;

    -- Create tenant members
    INSERT INTO "TenantMembers" ("Id", "TenantId", "UserId", "Role", "JoinedAt")
    VALUES
        (gen_random_uuid(), tenant_id, owner_user_id, 'Owner', CURRENT_TIMESTAMP),
        (gen_random_uuid(), tenant_id, member_user_id, 'Member', CURRENT_TIMESTAMP);

    -- Create demo project
    INSERT INTO "Projects" ("Id", "TenantId", "Name", "Code", "Description", "Status", "CreatedById", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        tenant_id,
        'Demo Project',
        'DEMO',
        'A sample project for development and testing',
        'Active',
        owner_user_id,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO project_id;

    -- Create demo Epic
    INSERT INTO "Epics" ("Id", "ProjectId", "TenantId", "Title", "Description", "Status", "Priority", "CreatedById", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        project_id,
        tenant_id,
        'User Authentication',
        'Implement complete user authentication system',
        'InProgress',
        'High',
        owner_user_id,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO epic_id;

    -- Create demo Story
    INSERT INTO "Stories" ("Id", "EpicId", "ProjectId", "TenantId", "Title", "Description", "Status", "Priority", "AssigneeId", "CreatedById", "CreatedAt", "UpdatedAt")
    VALUES (
        gen_random_uuid(),
        epic_id,
        project_id,
        tenant_id,
        'Login Page',
        'Create login page with email/password authentication',
        'InProgress',
        'High',
        member_user_id,
        owner_user_id,
        CURRENT_TIMESTAMP,
        CURRENT_TIMESTAMP
    ) RETURNING "Id" INTO story_id;

    -- Create demo Tasks
    INSERT INTO "WorkTasks" ("Id", "StoryId", "ProjectId", "TenantId", "Title", "Description", "Status", "Priority", "AssigneeId", "EstimatedHours", "CreatedById", "CreatedAt", "UpdatedAt")
    VALUES
        (gen_random_uuid(), story_id, project_id, tenant_id, 'Design login form UI', 'Create responsive login form design', 'Done', 'High', member_user_id, 4.0, owner_user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
        (gen_random_uuid(), story_id, project_id, tenant_id, 'Implement login API', 'Create backend API for login', 'InProgress', 'High', member_user_id, 8.0, owner_user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
        (gen_random_uuid(), story_id, project_id, tenant_id, 'Add form validation', 'Validate email and password format', 'Todo', 'Medium', member_user_id, 2.0, owner_user_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);

    RAISE NOTICE 'Seed data created successfully';
    RAISE NOTICE 'Tenant ID: %', tenant_id;
    RAISE NOTICE 'Owner User: owner@demo.com / Admin123!';
    RAISE NOTICE 'Member User: member@demo.com / Member123!';
END $$;

3.5 开发工作流脚本

3.5.1 PowerShell 启动脚本 (scripts/dev-start.ps1)

#!/usr/bin/env pwsh
# ColaFlow Development Environment Startup Script

param(
    [switch]$Tools,     # Launch dev tools (pgAdmin, Redis Commander)
    [switch]$Clean,     # Clean rebuild
    [switch]$Logs,      # Show logs after start
    [switch]$Reset      # Reset all data (WARNING: deletes volumes)
)

Write-Host "🚀 ColaFlow Development Environment" -ForegroundColor Cyan
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host ""

# Check if Docker is running
try {
    docker info | Out-Null
} catch {
    Write-Host "❌ Docker is not running. Please start Docker Desktop." -ForegroundColor Red
    exit 1
}

# Load environment variables
if (-Not (Test-Path ".env")) {
    Write-Host "📝 Creating .env file from .env.example..." -ForegroundColor Yellow
    Copy-Item ".env.example" ".env"
    Write-Host "✅ .env file created. Please review and update if needed." -ForegroundColor Green
}

# Reset data if requested
if ($Reset) {
    Write-Host "⚠️  WARNING: This will DELETE all data!" -ForegroundColor Yellow
    $confirm = Read-Host "Are you sure? (yes/no)"
    if ($confirm -eq "yes") {
        Write-Host "🗑️  Stopping containers and removing volumes..." -ForegroundColor Yellow
        docker-compose down -v
        Write-Host "✅ Data reset complete." -ForegroundColor Green
    } else {
        Write-Host "❌ Reset cancelled." -ForegroundColor Red
        exit 0
    }
}

# Build arguments
$buildArgs = @()
if ($Clean) {
    Write-Host "🧹 Clean rebuild requested..." -ForegroundColor Yellow
    $buildArgs += "--build", "--force-recreate", "--no-cache"
} else {
    $buildArgs += "--build"
}

# Profile arguments
$profileArgs = @()
if ($Tools) {
    Write-Host "🛠️  Launching development tools..." -ForegroundColor Yellow
    $profileArgs += "--profile", "tools"
}

# Start containers
Write-Host "🐳 Starting Docker containers..." -ForegroundColor Cyan
$startCommand = "docker-compose up -d $($buildArgs -join ' ') $($profileArgs -join ' ')"
Invoke-Expression $startCommand

if ($LASTEXITCODE -ne 0) {
    Write-Host "❌ Failed to start containers." -ForegroundColor Red
    exit 1
}

# Wait for services to be healthy
Write-Host ""
Write-Host "⏳ Waiting for services to be ready..." -ForegroundColor Yellow
Write-Host "   This may take 30-60 seconds on first run..." -ForegroundColor Gray

$maxWait = 120
$elapsed = 0
$checkInterval = 5

while ($elapsed -lt $maxWait) {
    $backendHealth = docker inspect --format='{{.State.Health.Status}}' colaflow-api 2>$null

    if ($backendHealth -eq "healthy") {
        Write-Host "✅ All services are ready!" -ForegroundColor Green
        break
    }

    Start-Sleep -Seconds $checkInterval
    $elapsed += $checkInterval
    Write-Host "   Still waiting... ($elapsed/$maxWait seconds)" -ForegroundColor Gray
}

if ($elapsed -ge $maxWait) {
    Write-Host "⚠️  Services are taking longer than expected." -ForegroundColor Yellow
    Write-Host "   Check logs with: docker-compose logs" -ForegroundColor Gray
}

# Run database migrations
Write-Host ""
Write-Host "🗄️  Running database migrations..." -ForegroundColor Cyan
docker-compose exec -T backend dotnet ef database update --no-build

# Display access information
Write-Host ""
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host "✅ ColaFlow Development Environment Ready!" -ForegroundColor Green
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "📍 Service URLs:" -ForegroundColor White
Write-Host "   Frontend:  http://localhost:3000" -ForegroundColor Cyan
Write-Host "   Backend:   http://localhost:5000" -ForegroundColor Cyan
Write-Host "   Swagger:   http://localhost:5000/swagger" -ForegroundColor Cyan
Write-Host ""
Write-Host "🔐 Demo Credentials:" -ForegroundColor White
Write-Host "   Email:     owner@demo.com" -ForegroundColor Cyan
Write-Host "   Password:  Admin123!" -ForegroundColor Cyan
Write-Host ""

if ($Tools) {
    Write-Host "🛠️  Development Tools:" -ForegroundColor White
    Write-Host "   pgAdmin:         http://localhost:5050" -ForegroundColor Cyan
    Write-Host "   Redis Commander: http://localhost:8081" -ForegroundColor Cyan
    Write-Host ""
}

Write-Host "📚 Useful Commands:" -ForegroundColor White
Write-Host "   View logs:        docker-compose logs -f" -ForegroundColor Gray
Write-Host "   Stop services:    docker-compose down" -ForegroundColor Gray
Write-Host "   Restart backend:  docker-compose restart backend" -ForegroundColor Gray
Write-Host "   Reset data:       .\scripts\dev-start.ps1 -Reset" -ForegroundColor Gray
Write-Host ""

if ($Logs) {
    Write-Host "📋 Showing logs (Ctrl+C to exit)..." -ForegroundColor Yellow
    docker-compose logs -f
}

3.5.2 Bash 启动脚本 (scripts/dev-start.sh)

#!/bin/bash
# ColaFlow Development Environment Startup Script (Linux/Mac)

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# Parse arguments
TOOLS=false
CLEAN=false
LOGS=false
RESET=false

while [[ $# -gt 0 ]]; do
    case $1 in
        --tools) TOOLS=true ;;
        --clean) CLEAN=true ;;
        --logs) LOGS=true ;;
        --reset) RESET=true ;;
        *) echo "Unknown option: $1"; exit 1 ;;
    esac
    shift
done

echo -e "${CYAN}🚀 ColaFlow Development Environment${NC}"
echo -e "${CYAN}=====================================${NC}"
echo ""

# Check Docker
if ! docker info > /dev/null 2>&1; then
    echo -e "${RED}❌ Docker is not running. Please start Docker.${NC}"
    exit 1
fi

# Load environment
if [ ! -f ".env" ]; then
    echo -e "${YELLOW}📝 Creating .env file from .env.example...${NC}"
    cp .env.example .env
    echo -e "${GREEN}✅ .env file created.${NC}"
fi

# Reset if requested
if [ "$RESET" = true ]; then
    echo -e "${YELLOW}⚠️  WARNING: This will DELETE all data!${NC}"
    read -p "Are you sure? (yes/no): " confirm
    if [ "$confirm" = "yes" ]; then
        echo -e "${YELLOW}🗑️  Removing volumes...${NC}"
        docker-compose down -v
        echo -e "${GREEN}✅ Data reset complete.${NC}"
    else
        echo -e "${RED}❌ Reset cancelled.${NC}"
        exit 0
    fi
fi

# Build arguments
BUILD_ARGS="--build"
if [ "$CLEAN" = true ]; then
    echo -e "${YELLOW}🧹 Clean rebuild requested...${NC}"
    BUILD_ARGS="--build --force-recreate --no-cache"
fi

# Profile arguments
PROFILE_ARGS=""
if [ "$TOOLS" = true ]; then
    echo -e "${YELLOW}🛠️  Launching development tools...${NC}"
    PROFILE_ARGS="--profile tools"
fi

# Start containers
echo -e "${CYAN}🐳 Starting Docker containers...${NC}"
docker-compose up -d $BUILD_ARGS $PROFILE_ARGS

# Wait for health
echo ""
echo -e "${YELLOW}⏳ Waiting for services to be ready...${NC}"
echo -e "   ${NC}This may take 30-60 seconds on first run...${NC}"

MAX_WAIT=120
ELAPSED=0
CHECK_INTERVAL=5

while [ $ELAPSED -lt $MAX_WAIT ]; do
    BACKEND_HEALTH=$(docker inspect --format='{{.State.Health.Status}}' colaflow-api 2>/dev/null || echo "starting")

    if [ "$BACKEND_HEALTH" = "healthy" ]; then
        echo -e "${GREEN}✅ All services are ready!${NC}"
        break
    fi

    sleep $CHECK_INTERVAL
    ELAPSED=$((ELAPSED + CHECK_INTERVAL))
    echo -e "   ${NC}Still waiting... ($ELAPSED/$MAX_WAIT seconds)${NC}"
done

# Run migrations
echo ""
echo -e "${CYAN}🗄️  Running database migrations...${NC}"
docker-compose exec -T backend dotnet ef database update --no-build

# Display info
echo ""
echo -e "${CYAN}=====================================${NC}"
echo -e "${GREEN}✅ ColaFlow Development Environment Ready!${NC}"
echo -e "${CYAN}=====================================${NC}"
echo ""
echo -e "${NC}📍 Service URLs:${NC}"
echo -e "   ${CYAN}Frontend:  http://localhost:3000${NC}"
echo -e "   ${CYAN}Backend:   http://localhost:5000${NC}"
echo -e "   ${CYAN}Swagger:   http://localhost:5000/swagger${NC}"
echo ""
echo -e "${NC}🔐 Demo Credentials:${NC}"
echo -e "   ${CYAN}Email:     owner@demo.com${NC}"
echo -e "   ${CYAN}Password:  Admin123!${NC}"
echo ""

if [ "$TOOLS" = true ]; then
    echo -e "${NC}🛠️  Development Tools:${NC}"
    echo -e "   ${CYAN}pgAdmin:         http://localhost:5050${NC}"
    echo -e "   ${CYAN}Redis Commander: http://localhost:8081${NC}"
    echo ""
fi

echo -e "${NC}📚 Useful Commands:${NC}"
echo -e "   View logs:        ${NC}docker-compose logs -f${NC}"
echo -e "   Stop services:    ${NC}docker-compose down${NC}"
echo -e "   Restart backend:  ${NC}docker-compose restart backend${NC}"
echo ""

if [ "$LOGS" = true ]; then
    echo -e "${YELLOW}📋 Showing logs (Ctrl+C to exit)...${NC}"
    docker-compose logs -f
fi

3.5.3 Package.json 快捷命令

colaflow-web/package.json 中添加:

{
  "scripts": {
    "docker:dev": "cd .. && docker-compose up -d",
    "docker:dev:tools": "cd .. && docker-compose --profile tools up -d",
    "docker:stop": "cd .. && docker-compose down",
    "docker:logs": "cd .. && docker-compose logs -f",
    "docker:restart": "cd .. && docker-compose restart backend frontend",
    "docker:rebuild": "cd .. && docker-compose up -d --build",
    "docker:clean": "cd .. && docker-compose down -v && docker-compose up -d --build"
  }
}

四、开发者工作流

4.1 首次启动

# Windows
.\scripts\dev-start.ps1

# Linux/Mac
chmod +x scripts/dev-start.sh
./scripts/dev-start.sh

首次启动流程:

  1. 检查 Docker 是否运行
  2. 创建 .env 文件(如果不存在)
  3. 拉取并构建所有镜像(约 5-10 分钟)
  4. 启动所有容器
  5. 等待健康检查通过
  6. 运行 EF Core 迁移
  7. 自动插入种子数据
  8. 显示访问信息

4.2 日常开发

# 前端开发者典型工作流

# 1. 启动后端服务
npm run docker:dev

# 2. 前端本地开发(热重载)
cd colaflow-web
npm run dev

# 3. 查看后端日志
npm run docker:logs

# 4. 重启后端(修改配置后)
npm run docker:restart

# 5. 停止所有服务
npm run docker:stop

4.3 常见场景

场景 1后端代码变更

# 后端代码变更需要重新构建
docker-compose up -d --build backend

场景 2数据库迁移变更

# 应用新迁移
docker-compose exec backend dotnet ef database update

# 回滚迁移
docker-compose exec backend dotnet ef database update <previous-migration-name>

场景 3重置开发数据

# Windows
.\scripts\dev-start.ps1 -Reset

# Linux/Mac
./scripts/dev-start.sh --reset

场景 4启用开发工具

# Windows
.\scripts\dev-start.ps1 -Tools

# Linux/Mac
./scripts/dev-start.sh --tools

场景 5调试后端 API

# 查看实时日志
docker-compose logs -f backend

# 进入容器
docker-compose exec backend bash

# 查看数据库连接
docker-compose exec backend dotnet ef dbcontext info

4.4 前端环境变量配置

创建 colaflow-web/.env.local:

# 连接到本地 Docker 容器的后端
NEXT_PUBLIC_API_URL=http://localhost:5000
NEXT_PUBLIC_WS_URL=ws://localhost:5000/hubs/project

# 开发模式设置
NEXT_PUBLIC_ENABLE_DEBUG=true
NEXT_PUBLIC_ENABLE_ANALYTICS=false

# 可选:连接到远程后端
# NEXT_PUBLIC_API_URL=https://dev-api.colaflow.com

五、性能优化

5.1 构建缓存优化

优化项 方法 效果
Docker 层缓存 先复制 package.json/csproj 依赖未变时跳过安装
多阶段构建 分离 build 和 runtime 减少最终镜像大小 50%
npm ci 使用 clean install 比 npm install 快 2-3x
BuildKit 启用 Docker BuildKit 并行构建,提升 30%

5.2 启用 BuildKit

.env 中添加:

DOCKER_BUILDKIT=1
COMPOSE_DOCKER_CLI_BUILD=1

5.3 资源限制

docker-compose.yml 中添加资源限制:

services:
  backend:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

  frontend:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

5.4 容器启动时间优化

服务 目标启动时间 优化方法
PostgreSQL < 5s 使用 alpine 镜像
Redis < 3s 使用 alpine 镜像
Backend < 30s 多阶段构建 + 健康检查
Frontend < 15s npm ci + 缓存 node_modules

六、故障排查

6.1 常见问题

问题 1容器无法启动

症状:

Error: Cannot start service backend: ...

解决:

# 查看详细日志
docker-compose logs backend

# 检查端口占用
netstat -ano | findstr :5000

# 强制重建
docker-compose up -d --build --force-recreate

问题 2数据库连接失败

症状:

Npgsql.NpgsqlException: Connection refused

解决:

# 检查 PostgreSQL 健康状态
docker-compose ps postgres

# 查看 PostgreSQL 日志
docker-compose logs postgres

# 重启 PostgreSQL
docker-compose restart postgres

问题 3前端无法连接后端

症状:

Failed to fetch: http://localhost:5000/api/...

解决:

  1. 检查 .env.local 中的 NEXT_PUBLIC_API_URL
  2. 确认后端健康检查通过:docker-compose ps backend
  3. 检查 CORS 配置:docker-compose logs backend | grep CORS

问题 4热重载不工作

症状: 修改前端代码后浏览器不自动刷新

解决:

# 确认 volume 挂载正确
docker-compose config | grep -A 5 "frontend.*volumes"

# 重启前端容器
docker-compose restart frontend

6.2 诊断命令

# 检查所有服务状态
docker-compose ps

# 查看资源使用
docker stats

# 检查网络连接
docker-compose exec backend curl http://postgres:5432

# 查看环境变量
docker-compose exec backend env | grep CONNECTION

# 进入容器调试
docker-compose exec backend bash
docker-compose exec postgres psql -U colaflow

七、安全考虑

7.1 开发环境安全清单

检查项 状态 说明
使用 .env 文件 推荐 不提交到 Git
强密码策略 推荐 生产环境必须更改
⚠️ 暴露端口 注意 仅开发环境,生产环境需修改
⚠️ CORS 宽松配置 注意 仅开发环境,生产环境需限制
使用 root 用户 禁止 前端已使用非 root 用户

7.2 .gitignore 配置

确保以下文件不被提交:

# Environment variables
.env
.env.local

# Docker volumes (if using bind mounts)
.data/
postgres_data/
redis_data/

# Development certificates
*.pfx
*.pem

八、CI/CD 集成

8.1 GitHub Actions 示例

name: Docker Build Test

on:
  pull_request:
    branches: [ main, develop ]

jobs:
  docker-build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Build backend image
        run: |
          docker build -t colaflow-api:test ./colaflow-api

      - name: Build frontend image
        run: |
          docker build -t colaflow-web:test ./colaflow-web --target development

      - name: Test docker-compose
        run: |
          docker-compose up -d
          sleep 30
          docker-compose ps
          docker-compose logs
          docker-compose down

九、下一步计划

9.1 实施优先级

任务 优先级 估时 负责人
1. 修复后端 Dockerfile 🔴 P0 1h Backend
2. 创建前端 Dockerfile 🔴 P0 2h Frontend
3. 创建数据库脚本 🟡 P1 2h Backend
4. 创建启动脚本 🟡 P1 2h DevOps
5. 编写开发者文档 🟢 P2 3h PM
6. 性能测试和优化 🟢 P2 4h QA

9.2 验收标准

  • 前端开发者可以在 5 分钟内启动完整后端环境
  • 首次启动时间 < 60 秒(包含构建)
  • 后续启动时间 < 30 秒
  • 前端热重载工作正常
  • 种子数据自动加载
  • 所有服务健康检查通过
  • 文档完整且易于理解
  • 支持 Windows、Linux、macOS

十、参考资料

10.1 官方文档

10.2 最佳实践


附录

A. 完整文件清单

实施本方案需要创建/修改以下文件:

product-master/
├── colaflow-api/
│   └── Dockerfile (需修改)
├── colaflow-web/
│   ├── Dockerfile (需创建)
│   ├── .dockerignore (需创建)
│   ├── .env.local.example (需创建)
│   └── next.config.ts (需修改)
├── scripts/
│   ├── init-db.sql (需创建)
│   ├── seed-data.sql (需创建)
│   ├── dev-start.ps1 (需创建)
│   └── dev-start.sh (需创建)
├── docker-compose.yml (需修改)
├── docker-compose.override.yml (可选修改)
├── .env.example (需创建)
├── .dockerignore (需创建)
└── docs/
    ├── DOCKER-DEVELOPMENT-ENVIRONMENT.md (本文档)
    └── DOCKER-QUICKSTART.md (需创建,简化版)

B. 估时总结

阶段 任务 估时
Phase 1 后端 Dockerfile 修复 1h
Phase 2 前端 Dockerfile 创建 2h
Phase 3 数据库脚本编写 2h
Phase 4 启动脚本开发 2h
Phase 5 文档编写 3h
Phase 6 测试和调试 4h
总计 14h

文档版本: 1.0 最后更新: 2025-11-04 维护者: ColaFlow Architecture Team