From c991f493da2528582ecbd3bf733d3f3106566246 Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Wed, 22 Jul 2026 22:42:28 +0200 Subject: [PATCH] Add Docker development workflow --- .dockerignore | 8 ++++++ Dockerfile | 12 +++++++++ README.md | 34 +++++++++++++++++++++--- compose.yaml | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ next.config.mjs | 6 +++-- package.json | 3 +++ 6 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..69951f8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.git +.agents +.codex +.next +data +dist +node_modules +npm-debug.log* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..70e7761 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:22-bookworm-slim + +WORKDIR /app + +ENV NEXT_TELEMETRY_DISABLED=1 + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . + +EXPOSE 3000 3001 diff --git a/README.md b/README.md index 4dd0d37..4fb9608 100644 --- a/README.md +++ b/README.md @@ -155,11 +155,39 @@ Die folgende Liste fasst die zentralen Anforderungen zusammen und zeigt den aktu ## Schneller Entwicklungsstart +### Mit Docker (empfohlen fuer kurze Sessions) + +Voraussetzung: Docker Desktop mit aktivem Docker-Compose-Plugin. + +1. Sicherstellen, dass keine direkt gestartete API und kein direkt gestartetes Frontend mehr auf Port 3000/3001 laufen. +2. `npm run docker:up` +3. Frontend unter `http://localhost:3001` oeffnen. + +Beim Start fuehrt der API-Container ausstehende Drizzle-Migrationen und die Circuit-First-Schemapruefung aus. Die vorhandene SQLite-Datenbank wird ueber `./data:/app/data` eingebunden und bleibt nach `npm run docker:down` erhalten. Quellcodeaenderungen unter `src/` werden von beiden Entwicklungsservern automatisch erkannt. + +Weitere Docker-Befehle: + +- `npm run docker:down` - Frontend und API stoppen +- `npm run docker:logs` - laufende Containerlogs anzeigen +- `docker compose ps` - Status und Healthchecks anzeigen +- `Invoke-WebRequest http://localhost:3000/health` - API-Healthcheck pruefen + +Bewusster Datenbank-Reset unter PowerShell: + +1. `npm run docker:down` +2. `npm run db:backup` +3. `Remove-Item -LiteralPath .\data\leistungsbilanz.db` +4. `npm run docker:up` + +Der Reset entfernt die aktive lokale Datenbank. Die zuvor erzeugte Sicherung bleibt unter `data/backups/` erhalten. + +### Ohne Docker + 1. `npm install` -2. `npm run db:generate` -3. `npm run db:migrate` +2. `npm run db:migrate` +3. `npm run db:verify:circuit-schema` 4. `npm run dev:api` (API auf Port 3000) -5. `npm run dev:web` (Frontend auf Port 3001) +5. In einem zweiten Terminal `npm run dev:web` (Frontend auf Port 3001) ## Wichtige Befehle diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..1df3ead --- /dev/null +++ b/compose.yaml @@ -0,0 +1,69 @@ +name: leistungsbilanz + +services: + api: + build: + context: . + command: + - sh + - -c + - npm run db:migrate && npm run db:verify:circuit-schema && npm run dev:api + environment: + PORT: "3000" + CHOKIDAR_USEPOLLING: "true" + init: true + ports: + - "3000:3000" + volumes: + - ./src:/app/src + - ./scripts:/app/scripts + - ./data:/app/data + - ./drizzle.config.ts:/app/drizzle.config.ts:ro + - ./tsconfig.json:/app/tsconfig.json:ro + healthcheck: + test: + - CMD + - node + - -e + - fetch('http://localhost:3000/health').then(response=>{if(!response.ok)process.exit(1)}).catch(()=>process.exit(1)) + interval: 5s + timeout: 3s + retries: 12 + start_period: 20s + + web: + build: + context: . + command: + - npm + - run + - dev:web + - -- + - --hostname + - 0.0.0.0 + environment: + API_INTERNAL_URL: http://api:3000 + WATCHPACK_POLLING: "true" + NEXT_TELEMETRY_DISABLED: "1" + init: true + depends_on: + api: + condition: service_healthy + ports: + - "3001:3001" + volumes: + - ./src:/app/src + - ./next.config.mjs:/app/next.config.mjs:ro + - ./next-env.d.ts:/app/next-env.d.ts:ro + - ./tsconfig.json:/app/tsconfig.json:ro + - ./tsconfig.next.json:/app/tsconfig.next.json:ro + healthcheck: + test: + - CMD + - node + - -e + - fetch('http://localhost:3001/').then(response=>{if(!response.ok)process.exit(1)}).catch(()=>process.exit(1)) + interval: 5s + timeout: 3s + retries: 12 + start_period: 20s diff --git a/next.config.mjs b/next.config.mjs index 637686a..e81b670 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ +const apiInternalUrl = (process.env.API_INTERNAL_URL || "http://localhost:3000").replace(/\/$/, ""); + const nextConfig = { typescript: { tsconfigPath: "./tsconfig.next.json", @@ -7,11 +9,11 @@ const nextConfig = { return [ { source: "/api/:path*", - destination: "http://localhost:3000/api/:path*", + destination: `${apiInternalUrl}/api/:path*`, }, { source: "/health", - destination: "http://localhost:3000/health", + destination: `${apiInternalUrl}/health`, }, ]; }, diff --git a/package.json b/package.json index 62f9e36..243161d 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,9 @@ "dev": "npm run dev:api", "dev:api": "tsx watch src/server/index.ts", "dev:web": "next dev -p 3001", + "docker:up": "docker compose up --build", + "docker:down": "docker compose down", + "docker:logs": "docker compose logs --follow", "build": "npm run build:api", "build:api": "tsc -p tsconfig.json", "build:web": "next build",