From 7bd22b53e9d7431fbae7a4088a5b4f654aa20ac4 Mon Sep 17 00:00:00 2001 From: Ronny Date: Mon, 6 Apr 2026 10:05:10 +0200 Subject: [PATCH] feat: add Docker containerization (Dockerfile, compose, dockerignore) Multi-stage build: frontend (Vite) + backend (TypeScript) in one container. Production image based on node:20-alpine with health check. Co-Authored-By: Claude Opus 4.6 (1M context) --- .dockerignore | 20 +++++++++++++++++ Dockerfile | 53 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 34 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8b50fac --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +node_modules +dist +.git +.gitignore +.DS_Store +*.md +*.docx +*.html +.vscode +.claude +.mcp.json +tools.yaml +backend/public +backend/node_modules +backend/dist +backend/.env +frontend/node_modules +frontend/dist +prototyp_*.html +projektplan_* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fd5bf5f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +# ============================================================ +# Stage 1: Build Frontend (React + Vite) +# ============================================================ +FROM node:20-alpine AS build-frontend + +WORKDIR /app/frontend +COPY frontend/package.json frontend/package-lock.json ./ +RUN npm ci +COPY frontend/ ./ +RUN npm run build +# Output: /app/frontend/../backend/public → /app/backend/public + +# ============================================================ +# Stage 2: Build Backend (TypeScript → JavaScript) +# ============================================================ +FROM node:20-alpine AS build-backend + +WORKDIR /app/backend +COPY backend/package.json backend/package-lock.json ./ +RUN npm ci +COPY backend/ ./ +RUN npx tsc + +# ============================================================ +# Stage 3: Production Image +# ============================================================ +FROM node:20-alpine AS production + +WORKDIR /app + +# Nur Production-Dependencies installieren +COPY backend/package.json backend/package-lock.json ./ +RUN npm ci --omit=dev && npm cache clean --force + +# Compiled Backend +COPY --from=build-backend /app/backend/dist ./dist + +# Frontend Build (statische Dateien) +COPY --from=build-frontend /app/backend/public ./public + +# Non-root User +RUN addgroup -S appgroup && adduser -S appuser -G appgroup +USER appuser + +ENV NODE_ENV=production +ENV PORT=3001 + +EXPOSE 3001 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD wget -qO- http://localhost:3001/health || exit 1 + +CMD ["node", "dist/index.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..889e80b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +services: + tippspiel: + build: + context: . + dockerfile: Dockerfile + container_name: wm2026-tippspiel + restart: unless-stopped + ports: + - "3301:3001" + environment: + - NODE_ENV=production + - PORT=3001 + - DATABASE_URL=${DATABASE_URL} + - SUPABASE_URL=${SUPABASE_URL} + - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY} + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + - FOOTBALL_API_KEY=${FOOTBALL_API_KEY} + - FOOTBALL_API_BASE_URL=https://api.football-data.org/v4 + - ELEVENLABS_API_KEY=${ELEVENLABS_API_KEY} + - CORS_ORIGIN=${CORS_ORIGIN:-https://app.staffbase.com,http://localhost:5173} + - STAFFBASE_PUBLIC_KEY=${STAFFBASE_PUBLIC_KEY:-} + - STAFFBASE_PLUGIN_ID=${STAFFBASE_PLUGIN_ID:-} + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3001/health"] + interval: 30s + timeout: 5s + start_period: 10s + retries: 3 + networks: + - main-network + +networks: + main-network: + external: true