docs: README, Datenschutztexte, Dockerfile und Sicherungsskripte
Damit ist Etappe 1 abgeschlossen und betriebsfertig dokumentiert. README mit beiden Betriebswegen. Docker Compose auf eigenem Server ist der Hauptweg; Vercel und Neon sind vollstaendig beschrieben, aber mit einer klaren Begruendung, warum ich davon abrate: beide Anbieter sind US-Unternehmen und unterliegen auch bei EU-Region potenziell dem CLOUD-Act. Bei Gesundheitsdaten einer nicht entscheidungsfaehigen Person ist das eine Abwaegung, die man bewusst treffen muss. Reverse-Proxy-Beispiele fuer Caddy, nginx und Traefik - der Proxy selbst ist nicht Teil des Compose-Setups, weil er auf dem Zielserver schon steht. Die Datenbank hat keine Portfreigabe. Sicherung: pg_dump schreibt direkt in die Verschluesselung, der Klartext landet nie auf der Platte. Danach eine Selbstpruefung - laesst sich die Datei nicht wieder entschluesseln, endet der Lauf mit Fehler statt mit einem stillen Scheinerfolg. Der jeweils erste Stand eines Monats bleibt dauerhaft stehen. Die README sagt ausdruecklich, was das Backup NICHT enthaelt: den Schluessel ENC_KEY_V1 und die Dateien im Objektspeicher. Dazu eine Anleitung, die Wiederherstellung einmal im Jahr zu ueben - mit dem letzten Schritt, in der Anwendung nachzusehen, ob die Diagnosen im Klartext erscheinen. Erst dann stimmt nicht nur die Datenbank, sondern auch der Schluessel. Verarbeitungsverzeichnis und Datenschutzhinweise als ausfuellbare Textbausteine. Die Hinweise sind in einfacher Sprache geschrieben - sie sollen der betreuten Person vorgelesen werden koennen. Die Seite /datenschutz liest denselben Text aus docs/, damit es nicht zwei Fassungen gibt, die auseinanderlaufen. Dockerfile in drei Stufen mit Tesseract, deutschen Sprachdaten und poppler-utils. Zeitzone Europe/Berlin ist gesetzt - ohne sie rechnet der Server in UTC und verschiebt Fristen um einen Tag. Etappe: 1 Phase: Fundament
This commit is contained in:
+93
@@ -0,0 +1,93 @@
|
||||
# =============================================================================
|
||||
# Betreuungs-Cockpit - Produktionsabbild
|
||||
# =============================================================================
|
||||
#
|
||||
# Drei Stufen, damit im laufenden Abbild weder Quelltext noch Bauwerkzeuge
|
||||
# liegen. Das Ergebnis ist rund 400 MB - der groesste Anteil davon sind
|
||||
# Tesseract und die deutschen Sprachdaten fuer die Texterkennung.
|
||||
#
|
||||
# Basis ist Alpine: kleiner Angriffsflaeche, und @node-rs/argon2 sowie
|
||||
# Prisma bringen fertige musl-Binaerdateien mit.
|
||||
# =============================================================================
|
||||
|
||||
# --- Stufe 1: Abhaengigkeiten -----------------------------------------------
|
||||
FROM node:22-alpine AS abhaengigkeiten
|
||||
WORKDIR /app
|
||||
|
||||
# Prisma und OpenSSL gehoeren zusammen.
|
||||
RUN apk add --no-cache libc6-compat openssl
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
COPY prisma ./prisma
|
||||
|
||||
# "npm ci" mit dem Lockfile - reproduzierbar, keine Ueberraschungen beim
|
||||
# naechsten Bau. Der postinstall-Schritt erzeugt den Prisma-Client.
|
||||
RUN npm ci --ignore-scripts \
|
||||
&& npx prisma generate
|
||||
|
||||
# --- Stufe 2: Bauen ----------------------------------------------------------
|
||||
FROM node:22-alpine AS bau
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache libc6-compat openssl
|
||||
|
||||
COPY --from=abhaengigkeiten /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Beim Bauen werden keine echten Geheimnisse gebraucht: src/lib/env.ts
|
||||
# prueft erst beim Zugriff. Diese Platzhalter erfuellen nur die Typen.
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV SKIP_ENV_VALIDATION=1
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# --- Stufe 3: Laufzeit -------------------------------------------------------
|
||||
FROM node:22-alpine AS laufzeit
|
||||
WORKDIR /app
|
||||
|
||||
# tesseract-ocr + deutsche Sprachdaten fuer die Texterkennung,
|
||||
# poppler-utils fuer pdftoppm (PDF-Seiten zu Bildern),
|
||||
# tzdata fuer Europe/Berlin - sonst rechnet der Server in UTC und
|
||||
# verschiebt Fristen um einen Tag.
|
||||
RUN apk add --no-cache \
|
||||
libc6-compat \
|
||||
openssl \
|
||||
tzdata \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-data-deu \
|
||||
poppler-utils \
|
||||
&& cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
|
||||
&& echo "Europe/Berlin" > /etc/timezone
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV TZ=Europe/Berlin
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
|
||||
# Nicht als root laufen.
|
||||
RUN addgroup --system --gid 1001 cockpit \
|
||||
&& adduser --system --uid 1001 --ingroup cockpit cockpit
|
||||
|
||||
# Der Standalone-Build von Next.js bringt nur mit, was wirklich gebraucht wird.
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/.next/standalone ./
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/.next/static ./.next/static
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/public ./public
|
||||
|
||||
# Prisma-Schema, Migrationen und SQL-Skripte fuer "prisma migrate deploy"
|
||||
# im laufenden Behaelter.
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/prisma ./prisma
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/@prisma ./node_modules/@prisma
|
||||
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/prisma ./node_modules/prisma
|
||||
|
||||
# Ablage fuer den Dateitreiber, falls kein Objektspeicher benutzt wird.
|
||||
RUN mkdir -p /app/daten/dokumente && chown -R cockpit:cockpit /app/daten
|
||||
|
||||
USER cockpit
|
||||
EXPOSE 3000
|
||||
|
||||
# Migrationen laufen beim Start, danach die Anwendung. Bewusst hier und
|
||||
# nicht in einem eigenen Behaelter: so kann die Datenbank nie hinter dem
|
||||
# Programmstand zurueckbleiben.
|
||||
CMD ["sh", "-c", "node node_modules/prisma/build/index.js migrate deploy && node server.js"]
|
||||
Reference in New Issue
Block a user