feat: Sicherung, Anmeldebremse, Vorschaubilder -- und Schritt 5

SICHERUNG (tools/sichern.ps1, taeglich 04:30 als geplante Aufgabe).
Die Datenbank wird nicht kopiert, sondern ueber SQLites eigene
Sicherungsschnittstelle herausgeholt (server/src/backup.ts): im WAL-Modus
liegt das Zuletzte noch nicht in media.db, und selbst alle drei Dateien zu
kopieren ist nicht sicher, wenn waehrenddessen geschrieben wird. Die Bilder
kommen aus einem NUR LESEND eingehaengten Volume dazu.

Und sie prueft sich selbst: auspacken, Datenbank oeffnen, Medien/Token/
Benutzer zaehlen, mit dem laufenden Dienst vergleichen, sonst Fehler. Einmal
wirklich zurueckgespielt -- leeres Volume, zweiter Dienst, Anmeldung mit dem
echten Passwort, Bild abgerufen, Byte fuer Byte identisch. Eine Sicherung, die
nie zurueckgespielt wurde, ist eine Hoffnung.

ANMELDEBREMSE. Das Formular steht oeffentlich, und scrypt macht einen Versuch
teuer -- aber teuer ist nicht selten. Fuenf freie Versuche je Adresse, dann
Sperre ab 30 s mit Verdopplung bis 15 min, 429 samt Retry-After und einem Text,
der sagt wie lange. Erfolg setzt zurueck. Nur im Speicher: wer sich aussperrt,
startet den Container neu. Durchgemessen bis zur Erholung.

VORSCHAUBILDER. sharp erzeugt beim Upload eine 320er WebP-Fassung unter
/data/thumbs, ausgeliefert unter /t/<pfad>. Gemessen: 131502 -> 13078 Bytes,
Faktor 10; eine Galerieseite faellt von 7,5 MB auf 766 KB. KEINE Spalte in der
Datenbank -- ob es eine Vorschau gibt, sagt das Dateisystem, und die Galerie
faellt bei 404 aufs Vollbild zurueck. Eine zweite Wahrheit, die auseinander-
laufen kann, gibt es damit gar nicht erst. Ein Knopf zieht Fehlendes nach und
nennt Zahlen statt "fertig".

SCHRITT 5. Die Fivemanage-Dateien liegen in legacy/ mit Erklaerung; unsere
docker-compose.media.yml heisst jetzt docker-compose.yml. Drei Volumes und drei
Abbilder geloescht, rund 670 MB -- nachgezaehlt war vorher, dass kein Bild
darin lag.

Nebenbefund: `npm i sharp` scheitert auf diesem Rechner nicht an sharp, sondern
an better-sqlite3 -- der Host laeuft auf Node 24 (ABI 137), node-gyp uebernimmt
und findet keine Bauwerkzeuge. Genau die Falle aus dem Dockerfile. Eingetragen
wurde mit --package-lock-only, gebaut wird im Abbild auf Node 22.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 18:00:14 +02:00
co-authored by Claude Opus 5
parent 6c8ead8e15
commit aa2575bdf4
18 changed files with 1450 additions and 229 deletions
+85
View File
@@ -0,0 +1,85 @@
# Zum Ausprobieren auf Docker Desktop.
#
# Der Unterschied zur Betriebsfassung ist Absicht und in beide Richtungen:
# hier sind die Ports offen und es gibt keinen Reverse Proxy, dort ist es
# umgekehrt. Eine `beta.23` gehoert erst auf einen Rechner, an dem nichts
# haengt — und wenn sie dort traegt, auf den Server.
#
# docker compose -f docker-compose.local.yml up -d
#
# Danach: http://localhost:8080 (admin / ADMIN_PASSWORD aus .env)
# http://localhost:9001 (MinIO, lite / MINIO_ROOT_PASSWORD)
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: fivemanage_lite
POSTGRES_USER: lite
POSTGRES_PASSWORD: ${DB_PASSWORD:?bitte setzen}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U lite -d fivemanage_lite"]
interval: 5s
timeout: 5s
retries: 20
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: lite
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?bitte setzen}
# Oertlich: die Dateien liegen unter derselben Adresse, unter der MinIO
# antwortet. Erst auf dem Server tritt fivecdn.d4rkst3r.de an die Stelle.
MINIO_SERVER_URL: http://localhost:9000
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 20
lite:
# ghcr.io, NICHT Docker Hub: dort steht die Reihe bei 0.1.0-beta.16
# still, auf ghcr.io laeuft sie weiter. Die Test-Compose des Projekts
# zeigt `fivemanage/lite:latest` — das ist Docker Hub und damit alt.
image: ghcr.io/fivemanage/lite:0.1.0-beta.23
depends_on:
db:
condition: service_healthy
minio:
condition: service_healthy
environment:
PORT: "8080"
ENV: dev
DSN: postgres://lite:${DB_PASSWORD:?bitte setzen}@db:5432/fivemanage_lite?sslmode=disable
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?bitte setzen}
API_TOKEN_HMAC_SECRET: ${API_TOKEN_HMAC_SECRET:?bitte setzen}
S3_PROVIDER: minio
AWS_ENDPOINT: http://minio:9000
AWS_ACCESS_KEY_ID: lite
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD:?bitte setzen}
AWS_BUCKET: media
# Aus der Vorlage des Projekts uebernommen; fuer MinIO ist die Region
# gleichgueltig, das SDK verlangt aber eine.
AWS_REGION: eu-west-1
# Woraus die OEFFENTLICHE Adresse gebaut wird, die Lite nach dem Upload
# zurueckgibt. Steht nicht im README, nur in deren .env.template — und
# ohne sie kaemen Adressen zurueck, die nur innerhalb von Docker gelten.
#
# Endpunkt plus Bucket, wie in der Vorlage
# (BUCKET_DOMAIN=http://localhost:9000/lite-dev).
BUCKET_DOMAIN: http://localhost:9000/media
ports:
- "8080:8080"
volumes:
pgdata:
minio: