v1.13: PDF-Upload und -Download fuer Dokumente (multer, Upload-Volume, Rechtepruefung)

This commit is contained in:
2026-10-04 12:08:18 +02:00
parent 8bef23665a
commit 39eb247456
11 changed files with 287 additions and 18 deletions
+23
View File
@@ -189,6 +189,29 @@ tar -czf mp-dist.tar.gz -C dist .
## 8. Verlauf / offene Punkte
**Erledigt 04.10. (v1.13):** Echter PDF-Upload für das Dokumentenmodul. Neue
Dep multer (^2.0.2, server/package-lock.json liegt jetzt im Repo, Docker
baut mit `npm ci`). DB: `documents` um `file_name`/`file_path` erweitert
(idempotent per `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` in db.js SCHEMA –
ACHTUNG: SCHEMA läuft als eine pool.query mit mehreren Statements,
funktioniert nur über das Simple-Query-Protokoll ohne Parameter). API:
POST /api/documents/:id/upload (adminOnly, multipart Feld „file", nur PDF,
25 MB, Datei heißt `<id>.pdf` im UPLOAD_DIR und ERSETZT die alte Datei;
`size` wird aus den echten Bytes gesetzt, `formatBytes` deutsche Anzeige);
GET /api/documents/:id/download (auth: Verwaltung immer, Mieter nur eigene
Wohnung oder Hausdokument; `path.basename` gegen Pfad-Traversal); DELETE
löscht die Datei best-effort mit. Ablage: UPLOAD_DIR env (default
./uploads), im Compose als named Volume `mp_uploads` an /app/uploads –
überlebt Container-Rekreation. nginx: `client_max_body_size 25m` für
location /api/ (war 256k!), proxy_read_timeout 60s. Frontend: Datei-Input
im Dokument-Dialog (Client-Validierung PDF/25 MB), Upload läuft NACH
Anlegen/Patchen über apiUpload (FormData, kein Content-Type setzen),
`syncDokument` ersetzt den State mit der Server-Fassung; PDF-Button ist
jetzt echter Download-Link, ohne Datei deaktiviert mit Hinweis.
E2E verifiziert: Upload/Download Byte-identisch (Admin + Mieter eigene
Wohnung), fremde Wohnung 403, Nicht-PDF 400, Upload ohne Doc 404,
Löschen entfernt Datei, Testdaten aufgeräumt.
**Erledigt 04.10. (v1.12):** Dokumente-CRUD für die Verwaltung (Schwerpunkt
Mietverträge). API (adminOnly): POST/PATCH/DELETE /api/documents(/:id) mit
Validierung (Titel nicht leer, Kategorie aus den 5 erlaubten Werten, unitId