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>
72 lines
3.5 KiB
Docker
72 lines
3.5 KiB
Docker
# ── 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"]
|