Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
||||
# ISMS-Tool — Next.js App (Multi-Stage-Build)
|
||||
#
|
||||
# Base-Image: node:22-slim (Debian/glibc) statt node:22-alpine (musl).
|
||||
# Begründung (F-11): Mit einem glibc-Base greifen die im Lockfile hinterlegten
|
||||
# plattformspezifischen Optional-Deps (lightningcss/@tailwindcss/oxide *-linux-*-gnu,
|
||||
# ebenso die glibc-Prebuilds von @node-rs/argon2 und sharp) zuverlässig. Dadurch
|
||||
# funktioniert `npm ci` (Lockfile bindend, reproduzierbar) OHNE Lockfile-Änderung —
|
||||
# das package-lock.json enthält bereits alle vier Linux-Varianten (x64/arm64 × gnu/musl).
|
||||
# Der frühere Kommentar ("npm install nötig wegen fehlender musl-Binaries") entfällt damit.
|
||||
FROM node:22.14.0-slim AS deps
|
||||
WORKDIR /app
|
||||
# openssl/ca-certificates werden von Prisma (Engine) und für TLS beim npm-Install benötigt.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# npm auf 11.x pinnen: Das committete package-lock.json wurde mit npm 11 erzeugt.
|
||||
# node:22.14.0 bringt npm 10.9.2 mit, das next@16.2.12 -> @swc/helpers ANDERS auflöst
|
||||
# (erwartet 0.5.23, Lock hält 0.5.15) und `npm ci` daher mit "out of sync" abbricht.
|
||||
# Der Resolver-Gleichstand (npm 11) macht `npm ci` grün OHNE Lockfile-Änderung.
|
||||
RUN npm i -g npm@11.19.0
|
||||
COPY package.json package-lock.json ./
|
||||
COPY prisma ./prisma
|
||||
# npm ci: installiert exakt die im Lockfile gepinnten Versionen (Supply-Chain-Integrität,
|
||||
# reproduzierbare Builds). --include=optional stellt sicher, dass die plattformspezifischen
|
||||
# Native-Binaries für das Zielimage (linux/glibc) mitkommen.
|
||||
RUN npm ci --include=optional --no-audit --no-fund
|
||||
|
||||
# --- Build-Stage: kompletter Next.js-Build (standalone) ---
|
||||
FROM node:22.14.0-slim AS builder
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
# Platzhalter nur für die Build-Zeit: prisma.config.ts löst env("DATABASE_URL")
|
||||
# beim Laden auf, und Coolify reicht die Variable nur als Build-ARG rein (nicht in
|
||||
# process.env). 'prisma generate' und 'next build' (nur dynamische Routen) bauen KEINE
|
||||
# echte DB-Verbindung auf. Zur Laufzeit überschreibt der echte DATABASE_URL aus der
|
||||
# Coolify-Env diesen Wert (im migrate-/app-Container).
|
||||
ENV DATABASE_URL="postgresql://build:build@localhost:5432/build?schema=public"
|
||||
RUN npx prisma generate && npm run build
|
||||
|
||||
# --- Migrate-Stage: schlanker Job-Container für `prisma migrate deploy` (+ optional Seed/Bootstrap) ---
|
||||
# Bewusst OHNE `next build`: enthält damit weder den kompilierten Next-Server (.next/standalone)
|
||||
# noch den Build-Cache — deutlich kleinere Angriffsfläche als die builder-Stage (bisher genutzt).
|
||||
# Warum nicht "nur Prisma-CLI"? prisma/seed.ts und scripts/bootstrap-admin.ts importieren aus
|
||||
# ../src bzw. @/server (provisionTenant, rbac, modules) und laufen über tsx. Ein reiner
|
||||
# Prisma-CLI-Container würde diese Jobs brechen. Da src/** in dieser Lane nicht angefasst werden
|
||||
# darf, bleiben devDeps (tsx/prisma) + src hier nötig — eine spätere Entkopplung von Seed/Bootstrap
|
||||
# vom App-Code ist als Folgeänderung empfohlen.
|
||||
FROM node:22.14.0-slim AS migrate
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY package.json package-lock.json prisma.config.ts tsconfig.json ./
|
||||
COPY prisma ./prisma
|
||||
COPY scripts ./scripts
|
||||
COPY src ./src
|
||||
# seed/ trägt das Richtlinien-Vorlagenpaket (mapping.json + Quelldateien), das der
|
||||
# Demo-Seed (prisma/seed.ts) bzw. Bootstrap über importPolicies liest. Ohne diesen COPY
|
||||
# bricht der migrate-Job mit ENOENT auf seed/isms-vorlagenpaket-v2/mapping.json ab.
|
||||
# Einige Quelldateien liegen als 0600 vor → a+rX, damit der non-root app-User sie lesen kann.
|
||||
COPY seed ./seed
|
||||
RUN chmod -R a+rX ./seed
|
||||
# docs/wizard-uebergabe/: Fachcontent-Quelldateien, aus denen der Demo-Seed den
|
||||
# Risikokatalog (C4, import-risks.ts) und die Umsetzungshinweise (C6, import-hints.ts)
|
||||
# liest. Nur im migrate-Image nötig — die Laufzeit/runner ruft diese Importer nicht auf
|
||||
# (importManaged in provision.ts liest keine Dateien). Ohne diesen COPY bricht der
|
||||
# Demo-Seed mit ENOENT auf docs/wizard-uebergabe/.../C6_Umsetzungshinweise.md ab.
|
||||
COPY docs/wizard-uebergabe ./docs/wizard-uebergabe
|
||||
RUN chmod -R a+rX ./docs
|
||||
# Prisma-Client für Seed/Bootstrap generieren (migrate deploy selbst braucht nur schema+migrations).
|
||||
ENV DATABASE_URL="postgresql://build:build@localhost:5432/build?schema=public"
|
||||
RUN npx prisma generate
|
||||
RUN groupadd --system --gid 1001 app \
|
||||
&& useradd --system --uid 1001 --gid app --home-dir /app app
|
||||
USER app
|
||||
# Default-Kommando; im Compose (migrate-Service) überschrieben/erweitert.
|
||||
CMD ["npx", "prisma", "migrate", "deploy"]
|
||||
|
||||
# --- Runner-Stage: schlanker Produktions-Container (nur Next-Standalone) ---
|
||||
FROM node:22.14.0-slim AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
# Next.js standalone server.js bindet sonst an den von Docker gesetzten HOSTNAME
|
||||
# (= Container-ID) statt an alle Interfaces -> Healthcheck (127.0.0.1) und der
|
||||
# Coolify-/Traefik-Proxy erreichen den Container nicht (404). 0.0.0.0 behebt beides.
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
ENV PORT=3000
|
||||
# Non-root-Nutzer (Debian: groupadd/useradd statt Alpine adduser -S).
|
||||
RUN groupadd --system --gid 1001 app \
|
||||
&& useradd --system --uid 1001 --gid app --home-dir /app app
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/public ./public
|
||||
# Richtlinien-Vorlagenpaket für den Laufzeit-Import: Modul „policies" aktivieren
|
||||
# (toggleTenantModule), Mandant mit Seed anlegen (createTenant), manueller Paket-Import
|
||||
# (importPolicyPackageForTenant) lesen alle aus seed/isms-vorlagenpaket-v2/. Fehlt es,
|
||||
# wirft die App zur Laufzeit ENOENT. a+rX wegen der 0600-Quelldateien (non-root app-User).
|
||||
COPY seed ./seed
|
||||
RUN chmod -R a+rX ./seed
|
||||
# Backup-/Restore-/DSGVO-Topologie (src/server/backup/topology.ts) liest zur Laufzeit
|
||||
# prisma/schema.prisma: Prisma 7 entfernt relationFromFields aus dem Laufzeit-DMMF,
|
||||
# die FK-Relationen kommen daher aus der Schema-Datei. Der Inline-Export (Direkt-
|
||||
# Download /api/platform/backup/download) läuft in der APP → ohne diese Datei ENOENT.
|
||||
COPY prisma/schema.prisma ./prisma/schema.prisma
|
||||
RUN chmod a+rX ./prisma/schema.prisma
|
||||
USER app
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
# --- Garage-Stage: Objektspeicher-Image mit EINGEBACKENER Config ---
|
||||
# Warum nicht das Upstream-Image + Bind-Mount der deploy/garage.toml? Coolify behandelt
|
||||
# relative Bind-Mount-Quellen als Storage und legt sie als VERZEICHNIS an, wenn die Datei
|
||||
# dort (noch) nicht existiert. Garage bekommt dann /etc/garage.toml als Ordner und bricht
|
||||
# mit „IO error: Is a directory (os error 21)" ab. Das Backen der Config ins Image umgeht
|
||||
# jeden Host-Mount. Secrets bleiben draußen (rpc_secret/admin_token kommen zur Laufzeit aus
|
||||
# GARAGE_RPC_SECRET/GARAGE_ADMIN_TOKEN); nur die secret-freie Basiskonfig wird kopiert.
|
||||
FROM dxflrs/garage:v1.2.0 AS garage
|
||||
COPY deploy/garage.toml /etc/garage.toml
|
||||
Reference in New Issue
Block a user