Files
marcandClaude Opus 5 ea90f43e77 refactor(frontend): PdfViewer und FileBrowser aufteilen, Tests dazu
FileBrowser 1177 -> 712 Zeilen, PdfViewer 1193 -> 848. Herausgeloest
wurde, was fuer sich zusammenhaengt:

  hooks/useUploads            Warteschlange, Ordnerbaeume, Ablage
  components/files/           Werkzeugleiste, Dialoge, Menues, Reihenfolge
  components/pdf/             Werkzeugleiste, Zoomstufen, Seitenmasse, Suche
  src/format.ts               formatBytes -- lag in einer *Seite*

Dabei gefundene und behobene Fehler:

* Ordner-Upload haengte Fortschritt und Fehler an die falsche Zeile,
  sobald in einem Ordner Dateien *nach* einem Unterordner lagen: Die
  Zeilen standen in Fundreihenfolge, hochgeladen wurde nach Ordnern
  gruppiert, und ein mitlaufender Zaehler verband beides falsch.
* formatBytes gab es zweimal, zeichengleich (Dateibrowser + Admin).
* Beide Sortierungen liefen bei *jedem* Bild -- der Rahmen beim Ziehen
  ist eines je Mausbewegung. Jetzt gemerkt.
* Die Suche im PDF las bei jedem Tastendruck den Text aller Seiten neu.
  Jetzt 160 ms Wartezeit; "Searching..." bleibt auch bei einem Fehler
  nicht mehr stehen.
* Seitenmasse werden in Buendeln statt streng nacheinander geholt.

Pruefinfrastruktur: vitest stand auf 'jsdom', ohne dass jsdom je
installiert war -- "npm test" brach ab, bevor es etwas ausfuehrte. Jetzt
'node' und 32 Tests fuer die herausgeloesten reinen Funktionen. Das
Abbild baut nur noch mit gruenen Tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 22:23:21 +02:00

72 lines
3.5 KiB
Docker
Raw Permalink 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.
# ── Stage 1: Frontend build ───────────────────────────────────────────────────
FROM node:20-alpine AS frontend-builder
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
# Erst prüfen, dann bauen: Die Tests decken die Stellen ab, die sich ohne
# Browser prüfen lassen – Reihenfolgen, Zoomstufen, Suche im Text. Sie laufen
# in einer halben Sekunde; ein Abbild mit einer kaputten Sortierung kostet mehr.
RUN npm test && npm run build
# ── Stage 2: Backend build ────────────────────────────────────────────────────
FROM golang:1.25-alpine AS backend-builder
WORKDIR /app
RUN apk add --no-cache git
COPY backend/go.mod backend/go.sum ./
RUN go mod download
COPY backend/ ./
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o aether ./cmd/aether
# ── Stage 3: Final image ──────────────────────────────────────────────────────
FROM alpine:3.20
# ocrmypdf, tesseract und poppler machen den Inhalt von PDFs und Scans
# durchsuchbar (internal/documents). Sie wiegen zusammen rund 330 MB – der
# Löwenanteil des Images. Wer das nicht braucht, kann die zweite apk-Zeile
# streichen und OCR_ENABLED=false setzen; der Server prüft beim Start selbst,
# ob die Programme da sind, und läuft sonst ohne Volltextsuche weiter.
#
# tesseract-ocr-data-deu/-eng sind die Sprachmodelle. Ohne sie startet
# tesseract zwar, erkennt aber nichts – das Paket tesseract-ocr allein bringt
# keine mit.
RUN apk add --no-cache ca-certificates tzdata && \
apk add --no-cache ocrmypdf tesseract-ocr tesseract-ocr-data-deu \
tesseract-ocr-data-eng poppler-utils && \
addgroup -S aether && adduser -S aether -G aether && \
mkdir -p /data/users /data/thumbs /data/tmp && \
chown -R aether:aether /data
WORKDIR /app
# Wo die Blobs liegen. Steht **hier**, nicht nur in der .env: Die Voreinstellung
# im Code ist "./data" – richtig für ein Binary, das man von Hand startet,
# falsch im Container, wo daraus /app/data würde. Genau das ist beim ersten
# Aufbau aus der schlanken .env passiert: Migrationen liefen durch, dann
# "mkdir /app/data: permission denied". Das Abbild kennt seine eigene
# Verzeichnisstruktur besser als jede Beispieldatei; eine .env darf es
# weiterhin überschreiben.
ENV STORAGE_PATH=/data \
TMP_PATH=/data/tmp
# Tesseract vermisst beim allerersten Aufruf die OpenCL-Geräte und schreibt
# dabei einen langen Diagnoseblock nach stderr. ocrmypdf ruft davor
# `tesseract --list-langs` auf und liest die Antwort – der Block bringt seinen
# Parser aus dem Tritt, und der Aufruf endet mit „Tesseract failed to report
# available languages" (Exit 3).
#
# Das Ergebnis der Vermessung landet als .dat im Arbeitsverzeichnis; ab dann ist
# die Ausgabe kurz genug. Ohne diese Zeile scheitert deshalb genau das erste
# Dokument nach jedem Neustart eines frischen Containers – gemessen, nicht
# vermutet: Versuch 1 Exit 3, Versuch 2 erfolgreich. Der Wiederholungszähler
# fängt es zwar auf, aber ein Fehlschlag, den man einbauen kann, gehört nicht
# in den Log.
RUN tesseract --list-langs >/dev/null 2>&1 || true
COPY --from=backend-builder /app/aether ./aether
COPY --from=frontend-builder /app/frontend/dist ./static
RUN chown -R aether:aether /app
USER aether
EXPOSE 8080
ENTRYPOINT ["./aether"]