Files
Laufzettel/Dockerfile
T
Florian WildeandClaude Opus 5 f3950847f3
Prüfung / pruefung (push) Waiting to run
Prüfung / e2e (push) Blocked by required conditions
feat(laeufe): Uebergabeprotokoll als PDF (#041)
Neben "Drucken" steht am Lauf "Als PDF", im Archiv an jedem Treffer "Protokoll
als PDF" — dasselbe Blatt als fertige Datei, zum Verschicken oder Abheften.
Unten darauf jetzt zwei Unterschriftsfelder mit Zeile fuer Ort, Datum und Namen;
wo eine Vier-Augen-Freigabe erteilt wurde, steht sie mit im Kopf.

Erzeugt wird es, indem der Server seine eigene Druckansicht ueber 127.0.0.1
laedt und druckt — mit dem Sitzungscookie des Anfragenden. Damit gibt es genau
eine Vorlage fuer Papier und Datei, und fuer das PDF gilt dieselbe Rechte- und
Mandantenpruefung wie fuer die Seite. Ein zweites Layout waere billiger und
wuerde frueher oder spaeter abweichen, ohne dass es jemandem auffaellt.

Ein eigener Browser-Kontext je PDF, kein geteilter: er traegt die fremde
Sitzung, und ein geteilter gaebe sie an das naechste PDF weiter. Gespeichert
wird nichts — ein abgelegtes PDF waere eine zweite Wahrheit neben dem Lauf.
Ein erzeugtes Passwort steht auch hier nie darauf, geprueft am extrahierten
Text des fertigen PDF und nicht an den Bytes: der Inhalt ist komprimiert, dort
nichts zu finden bewiese nichts.

Chromium bleibt optional, und die gemessene Zahl ist der Grund: das
Laufzeitbild waechst von 370 MB auf 1,52 GB, Alpines chromium kostet allein
1,13 GB. Er kommt nur mit `--build-arg MIT_PDF=1` beziehungsweise
`deploy/install.sh --mit-pdf` mit. Fehlt er, erscheint der Knopf gar nicht
erst — ein Knopf, der zuverlaessig in eine Fehlermeldung fuehrt, ist schlimmer
als keiner. Ein direkter Aufruf bekommt 503 mit einer Meldung, die sagt, was
fehlt und wo es steht; ein leeres PDF gibt es in keinem Fall.

Meine Schaetzung lag um das Dreieinhalbfache daneben: "+328 MB" war das
.apk-Paket, nicht das Bild, und stand schon im Dockerfile-Kommentar, bevor ich
gebaut hatte. Jetzt steht die gemessene Zahl an drei Stellen.

1545 Vitest-Tests (vorher 1526): 15 in tests/pdf.test.ts, die den Handler echt
fahren, 3 in tests/pdf-grenze.test.ts fuer die Obergrenze mit gestelltem
Browser, einer in tests/archiv.test.ts. Dazu drei E2E-Ablaeufe; volle Suite
gruen mit 118 bestanden. Ein Blatt wurde wirklich erzeugt und angesehen.

Sechs Gegenproben, alle angeschlagen — darunter ein echtes Passwort auf dem
Blatt und die Freigabe des Zaehlers aus dem finally genommen, der Fall, in dem
ein Fehlschlag die PDF-Erzeugung bis zum Neustart leise stilllegt.

Closes #41

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-25 11:14:25 +01:00

70 lines
2.5 KiB
Docker
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# syntax=docker/dockerfile:1
# ---------- Basis ----------
FROM node:24-alpine AS basis
WORKDIR /app
# tini beendet Prozesse sauber, openssl wird fuer die Geheimnis-Erzeugung gebraucht.
RUN apk add --no-cache tini openssl
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
RUN corepack enable pnpm
# ---------- Abhaengigkeiten ----------
FROM basis AS abhaengigkeiten
# pnpm-workspace.yaml muss mit, sonst blockiert pnpm 12 die erlaubten Build-Skripte.
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY prisma ./prisma
COPY prisma.config.ts ./
RUN pnpm install --frozen-lockfile
# ---------- Bauen ----------
FROM abhaengigkeiten AS bauen
ARG APP_VERSION=0.0.0
ARG GIT_SHA=""
ENV NEXT_PUBLIC_APP_VERSION=$APP_VERSION
ENV NEXT_PUBLIC_GIT_SHA=$GIT_SHA
COPY . .
RUN pnpm exec prisma generate && pnpm build
# ---------- Laufzeit ----------
FROM basis AS laufzeit
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# ---------------------------------------------------------------------------
# Chromium fuer das PDF-Uebergabeprotokoll – optional, und das mit Absicht (#041).
#
# Gemessen am 2026-10-25, und die Zahl ist der Grund fuer den Schalter:
#
# ohne Chromium 370 MB
# mit Chromium 1,52 GB
#
# Alpines `chromium` kostet allein 1,13 GB – mehr als das dreifache der
# gesamten Anwendung. Die meisten Installationen brauchen es nicht: die
# Druckansicht gibt dasselbe Blatt ueber den Browser des Anwenders aus.
#
# `font-noto` sind davon nur 20 MB (`ttf-dejavu` waeren 10 MB und deckten
# weniger ab). Es muss mit: Chromium ohne jede Systemschrift stellt Zeichen als
# leere Kaesten dar, sobald eines nicht in unseren eigenen Schriften steht –
# und das PDF waere trotzdem ein gueltiges PDF. Ein Fehler, der nicht meldet,
# sondern falsch liefert.
#
# docker build --build-arg MIT_PDF=1 -t laufzettel .
#
# Ohne das Argument sagt der Endpunkt, was fehlt, und die Oberflaeche zeigt den
# Knopf gar nicht erst (docs/betrieb/pdf.md).
# ---------------------------------------------------------------------------
ARG MIT_PDF=0
RUN if [ "$MIT_PDF" = "1" ]; then \
apk add --no-cache chromium font-noto; \
fi
RUN addgroup -g 1001 -S laufzettel && adduser -S laufzettel -u 1001 -G laufzettel
COPY --from=bauen --chown=laufzettel:laufzettel /app/.next/standalone ./
COPY --from=bauen --chown=laufzettel:laufzettel /app/.next/static ./.next/static
COPY --from=bauen --chown=laufzettel:laufzettel /app/public ./public
USER laufzettel
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]