From 8dd6ba236ec4964d54c51c83a7ad9c5ad3ae39e5 Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Fri, 17 Jul 2026 18:26:36 +0200 Subject: [PATCH] Docker-Setup: App-Image (standalone), PostgreSQL-Dienst mit Auto-Import, Dev-Profil --- .dockerignore | 11 ++++++++ Dockerfile | 41 ++++++++++++++++++++++++++++++ README.md | 39 ++++++++++++++++++++++------ docker-compose.yml | 63 ++++++++++++++++++++++++++++++++++++++++++++++ next.config.ts | 2 ++ 5 files changed, 149 insertions(+), 7 deletions(-) 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..3bf1d9e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +node_modules +.next +.git +.claude +.env* +!.env.example +ZUGANGSDATEN.md +supabase/local +Dockerfile +docker-compose.yml +README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7a6835f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# ============================================================= +# Next.js-App als eigenständiges Produktions-Image (Multi-Stage) +# Build: docker compose --env-file .env.local build +# ============================================================= + +# ---------- Abhängigkeiten ---------- +FROM node:24-alpine AS deps +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci + +# ---------- Build ---------- +FROM node:24-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# NEXT_PUBLIC_*-Variablen werden zur Build-Zeit ins Client-Bundle eingebacken +ARG NEXT_PUBLIC_SUPABASE_URL +ARG NEXT_PUBLIC_SUPABASE_ANON_KEY +ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL +ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY + +RUN npm run build + +# ---------- Runtime ---------- +FROM node:24-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 + +RUN addgroup -S nodejs && adduser -S nextjs -G nodejs + +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 +CMD ["node", "server.js"] diff --git a/README.md b/README.md index ca2d9be..ce1ce06 100644 --- a/README.md +++ b/README.md @@ -38,14 +38,24 @@ scripts/ Hilfsskripte (DB-Migration, lokaler Sync) ## Entwicklung +Voraussetzung in beiden Varianten: `.env.local` mit den Werten aus +`.env.example` (liegt lokal bereits vor und ist per `.gitignore` vom +Repo ausgeschlossen). + +**Variante A – Docker (nichts vorinstallieren außer Docker):** + +```bash +docker compose --env-file .env.local --profile dev up dev +# http://localhost:3000 (Hot-Reload, Quellcode wird gemountet) +``` + +**Variante B – lokal installiertes Node.js:** + ```bash npm install npm run dev # http://localhost:3000 ``` -Voraussetzung: `.env.local` mit den Werten aus `.env.example` -(liegt lokal bereits vor und ist per `.gitignore` vom Repo ausgeschlossen). - ## Umgebungsvariablen (Live-Betrieb) Beim Webserver/Hoster müssen genau diese drei Variablen hinterlegt werden @@ -57,7 +67,16 @@ Beim Webserver/Hoster müssen genau diese drei Variablen hinterlegt werden | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Öffentlicher anon-Key (RLS schützt die Daten) | nein | | `SUPABASE_SERVICE_ROLE_KEY` | Service-Role-Key für die Benutzerverwaltung | **ja – niemals im Browser/Repo!** | -Build & Start auf dem Server: +Build & Start auf dem Server – **mit Docker** (empfohlen, Node.js und +PostgreSQL müssen nicht installiert sein): + +```bash +docker compose --env-file .env.local up -d --build +# App: Port 3000 (hinter Reverse-Proxy mit HTTPS betreiben) +# Lokale DB-Kopie: Port 5432 (Dienst "db", optional) +``` + +Oder klassisch ohne Docker: ```bash npm ci @@ -97,9 +116,15 @@ Sicherheitsmodell (Row Level Security): ### Lokale PostgreSQL-Kopie -Auf dem Entwicklungsrechner läuft PostgreSQL 17 mit der Datenbank -`speisekarte` (Kopie von Schema + Daten aus Supabase, inkl. Minimal-Stubs -für `auth`/`storage`). Neu aufbauen bzw. aktualisieren: +Die Datenbank `speisekarte` (Kopie von Schema + Daten aus Supabase, inkl. +Minimal-Stubs für `auth`/`storage`) gibt es in zwei Varianten: + +**Per Docker:** Der Dienst `db` aus `docker-compose.yml` spielt die +Skripte aus `supabase/local/` beim ersten Start automatisch ein +(PostgreSQL 17, Port 5432, Passwort über `LOCAL_PG_PASSWORD`). + +**Nativ:** Auf dem Entwicklungsrechner läuft PostgreSQL 17 mit derselben +Datenbank. Neu aufbauen bzw. aktualisieren: ```powershell $env:SUPABASE_DB_PASSWORD = "" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ad7e448 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,63 @@ +# ============================================================= +# Speisekarte – Docker-Setup +# +# Produktion (App + lokale PostgreSQL-Kopie): +# docker compose --env-file .env.local up -d --build +# +# Entwicklung (Dev-Server mit Hot-Reload, kein lokales Node nötig): +# docker compose --env-file .env.local --profile dev up dev +# +# Die --env-file-Angabe speist NEXT_PUBLIC_* in den Build und +# SUPABASE_SERVICE_ROLE_KEY in die Laufzeit-Umgebung. +# ============================================================= + +services: + # ---------- Next.js-App (Produktions-Build) ---------- + app: + build: + context: . + args: + NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL} + NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY} + environment: + NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL} + NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY} + SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY} + ports: + - "3000:3000" + restart: unless-stopped + + # ---------- Lokale PostgreSQL-Kopie (Ablage/Auswertungen) ---------- + # Beim ersten Start werden die Skripte aus supabase/local + # automatisch in alphabetischer Reihenfolge eingespielt. + db: + image: postgres:17-alpine + environment: + POSTGRES_DB: speisekarte + POSTGRES_PASSWORD: ${LOCAL_PG_PASSWORD:-speisekarte} + ports: + - "5432:5432" + volumes: + - pgdata:/var/lib/postgresql/data + - ./supabase/local:/docker-entrypoint-initdb.d:ro + restart: unless-stopped + + # ---------- Dev-Server (nur mit --profile dev) ---------- + dev: + image: node:24-alpine + profiles: ["dev"] + working_dir: /app + command: sh -c "npm install && npm run dev" + environment: + NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL} + NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY} + SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY} + ports: + - "3000:3000" + volumes: + - .:/app + - dev_node_modules:/app/node_modules + +volumes: + pgdata: + dev_node_modules: diff --git a/next.config.ts b/next.config.ts index 2973fa9..8f2caea 100644 --- a/next.config.ts +++ b/next.config.ts @@ -15,6 +15,8 @@ const securityHeaders = [ ]; const nextConfig: NextConfig = { + // Für den Docker-Betrieb: minimales, eigenständiges Server-Bundle + output: "standalone", async headers() { return [ {