docs(quick-261008-mzu): Modul Dateien (Nextcloud-Client)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+136
@@ -0,0 +1,136 @@
|
||||
---
|
||||
phase: quick-261008-mzu
|
||||
plan: 01
|
||||
subsystem: nextcloud-files
|
||||
tags: [nextcloud, webdav, login-flow-v2, chunked-upload, file-browser, nestjs, nextjs, rls]
|
||||
requires:
|
||||
- module-registry (UseModule, ModuleManage, Freigabestufen)
|
||||
- nextcloud-status (normalizeCloudUrl, parseNextcloudStatus)
|
||||
- CryptoService (AES-256-GCM)
|
||||
provides:
|
||||
- Modul "Dateien" (slug nextcloud-files, Gruppe Infrastruktur): eine Nextcloud je Organisation, ein Konto je Benutzer
|
||||
- Anmeldung per Passwort (App-Passwort) und per Login Flow v2 (Zwei-Faktor), Abmelden mit Widerruf
|
||||
- Dateiansicht (Liste/Raster, Vorschau, Quota), Anlegen/Umbenennen/Verschieben/Loeschen in den Papierkorb
|
||||
- Hochladen als Datenstrom (8-MiB-Stuecke, Chunked Upload v2), Herunterladen, ZIP
|
||||
- Nextcloud-Kennung (Name, Logo, Farbe) auf dem Anmeldebildschirm
|
||||
affects: [web-ui, api, docs, changelog]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- einzige Transportschicht ncRequest (feste Pfadanfaenge, Segmentcodierung, keine Weiterleitungen, keine Cookies)
|
||||
- prozessweite Aufrufsperre (429 haelt den Ursprung an, erstes 401 toetet den Zugangsschluessel)
|
||||
- mapNcFailure als einzige Fehlerabbildung, nie 401/403 an den Browser
|
||||
- RLS auf Mandant UND Benutzer (current_user_id)
|
||||
key-files:
|
||||
created:
|
||||
- apps/api/src/nextcloud-files/ (Transport, Aufrufsperre, Anmelde-Client, Kontodienst, Dateidienst, Transferdienst, Serverkennung)
|
||||
- apps/api/prisma/migrations/20261008180000_nextcloud_files/migration.sql
|
||||
- apps/api/prisma/migrations/20261008183000_*/migration.sql
|
||||
- apps/web/src/app/(portal)/modules/nextcloud-files/ (Seite, Komponenten)
|
||||
- apps/web/src/lib/nextcloud-files-api.ts, nextcloud-files-upload.ts
|
||||
- apps/web/src/components/nextcloud-files/ (Dateitypen, Auswahl, Pfade, Formate, Uebertragungen)
|
||||
- .planning/quick/261008-mzu-modul-nextcloud-dateien-eigenstaendiger-/e2e/ (Testaufbau und vier e2e-Skripte)
|
||||
modified:
|
||||
- CHANGELOG.md, docs/anleitung-anwender.md, docs/anleitung-administration.md, docs/anleitung-betrieb.md
|
||||
- apps/web/src/messages/de.json, en.json, apps/web/src/app/globals.css
|
||||
decisions:
|
||||
- "Eine Nextcloud-Adresse je Organisation (Verwalten); interne Adressen erlaubt, dafuer enge Eingrenzung statt Public-URL-Pruefung (SSRF-Schutz ueber feste Pfade, keine Weiterleitungen, nie URL aus Antworten)"
|
||||
- "App-Passwort gilt nur fuer den Anmeldenamen der Ausstellung (Spalte ncLoginName, gemessen: E-Mail-Anmeldung gegen Nextcloud 34)"
|
||||
- "401 auf getapppassword ist doppeldeutig (falsches Passwort oder Zwei-Faktor) und heisst credentialsOrTwoFactor mit Weg ueber den Browser"
|
||||
- "Login Flow: poll.endpoint und login-Ursprung der Antwort werden verworfen; Abfrage immer auf {Basis}/index.php/login/v2/poll, Link aus Basis und Token neu gebaut"
|
||||
- "Eigene Anmeldebremse 3/15 min je Benutzer und 8/30 min je Server unter Nextclouds 10/30; jedes 429 pausiert alle Aufrufe an den Ursprung"
|
||||
- "Hochladen in 8-MiB-Stuecken wegen 10-MiB-Klonlimit und 30-s-Proxyzeit von Next.js; Zusammenbau asynchron mit abfragbarem Zustand"
|
||||
- "Serverkennung: Name aus status.php, Farbe aus anonymen capabilities (nur #rrggbb), Logo nur von zwei festen Pfaden, Bildtyp aus den Bytes, SVG nur mit CSP-Sandbox, 10 Minuten Zwischenspeicher je Organisation und Adresse"
|
||||
- "Kein Dashboard-Widget (L-08); Etappe 2 bleibt offen"
|
||||
metrics:
|
||||
duration: "Task 6: etwa 70 Minuten; gesamt ueber sechs Aufgaben am 2026-10-08"
|
||||
completed: 2026-10-08
|
||||
status: complete
|
||||
commits: 6
|
||||
plan_head_before: 83b842b72cdd2be7d6e70286708753ab22038271
|
||||
plan_head_after: 630398fe93596e96a65891381b3844a91c4ed49a
|
||||
actuals:
|
||||
tokens: 191000
|
||||
tasks: 6
|
||||
commits: 6
|
||||
---
|
||||
|
||||
# Phase quick-261008-mzu Plan 01: Modul Nextcloud-Dateien (Etappe 1) Summary
|
||||
|
||||
Neues Modul „Dateien“: Jeder Benutzer arbeitet in seiner eigenen Nextcloud (Konto per Passwort oder Browser-Anmeldung mit Zwei-Faktor), mit Dateiansicht, Hoch- und Herunterladen großer Dateien durch den Next.js-Proxy, Papierkorb-Löschen, und einem gestalteten Anmeldebildschirm mit Name, Logo und Farbe der Nextcloud.
|
||||
|
||||
## Commits
|
||||
|
||||
| Aufgabe | Commit | Inhalt |
|
||||
|---|---|---|
|
||||
| 1 | 9606967 | Modul, Migration (Config + Account mit Zeilenschutz Mandant UND Benutzer), Transportschicht, Aufrufsperre, Einstellungen, Registrierung |
|
||||
| 2 | d00b6ff | Anmeldung per Passwort und Login Flow v2, Anmeldebremse, Abmelden mit Widerruf, Verbindungsbildschirm, Spalte ncLoginName |
|
||||
| 3 | 8bee65c | PROPFIND, WebDAV-Schicht, Dateidienst (list, preview, folders, move, delete), mapNcFailure, sendUpstreamStream |
|
||||
| 4 | 4d4a0b3 | Hochladen als Datenstrom (einzeln und in Stücken), Download mit Range, ZIP, Browser-Uploader |
|
||||
| 5 | 86fbe8f | Dateiansicht (Liste/Raster, Typkacheln, Auswahl, Tastatur, Menüs, Dialoge, Ziehen und Ablegen, Übertragungsleiste) |
|
||||
| 6 | 630398f | Serverkennung (API + Web), gestaltete Anmeldekarte, Anleitungen, Changelog, Fokusfang, e2e wiederholbar |
|
||||
|
||||
## Aufgabe 6 im Detail
|
||||
|
||||
- API: `nextcloud-server-info.ts` (`NextcloudServerInfoService`) mit `GET server` und `GET server/logo` (Benutzen-Ebene, statisch vor dem Parameterblock, Controller- und Manage-Handler-Spec erweitert). 21 neue Tests (fake Transport, echte Aufrufsperre, fake Uhr): feste Pfade, Farbfilter, Logoerkennung nach Bytes, 512-KiB-Grenze, Zwischenspeicher 10 min, Adresswechsel leert, gesperrter Ursprung = keine Anfrage, 429 mitten in der Abfrage wird nicht gemerkt, Antwortköpfe des Logos.
|
||||
- Web: `ServerIdentity.tsx` (`ServerTile`, `ServerIdentity`), Anmeldekarte neu gestaltet (Kennungskopf mit Akzentlinie in der Themenfarbe, Hinweis zum Passwort am Kartenfuß mit Schloss), kleine Kachel in der Kontoleiste; 6 neue Seitentests; Texte de + en.
|
||||
- Registrierungen geprüft (app.module, module-loader, module-identity `folder`, nav-store, layouts-Test, Seed); `WIDGET_MODULE_SLUGS` ohne `nextcloud-files`.
|
||||
- Doku: CHANGELOG (vier Einträge unter „Neu“), Anwenderanleitung „Dateien (Nextcloud)“ mit Tastaturtabelle, Administrationshandbuch „Dateien: Nextcloud anbinden“ (Brute-Force-Ausnahme mit occ-Befehl, Adresswechsel, verwaiste App-Passwörter nach Benutzer-Löschung), Betriebshandbuch „Dateien (Nextcloud)“ in Kapitel 3 (NODE_EXTRA_CA_CERTS, Proxy-Grenzen, Zustand im Arbeitsspeicher) plus Fehlerbild-Zeile.
|
||||
|
||||
## Verifikation
|
||||
|
||||
- api-Suite 151 Dateien / 2922 Tests grün, web-Suite 143 Dateien / 1633 Tests grün (nach der letzten Änderung erneut), beide `tsc --noEmit` ohne Fehler, `biome lint` ohne Fehler (nur schon vorhandene Warnungen).
|
||||
- Rollen-Decorator-Grep, de/en-Parität und Wortprüfung, Widget-Prüfung, Changelog-/Anleitungs-Greps grün.
|
||||
- Stack neu gebaut (`docker compose up -d --build api web`), /health 200, Seed-Zeile „Nextcloud files module seeded in registry“, Routen `server` und `server/logo` vor den Parameterrouten abgebildet.
|
||||
- Alle e2e-Skripte auf dem neu gebauten Stack grün und zweimal hintereinander wiederholbar: nc-test-setup, e2e-settings (inkl. Serverkennung: Name, Rechnername, Version, Logo mit CSP/nosniff), e2e-connect, e2e-files, e2e-transfer.
|
||||
- Browserprüfung (playwright-core, Dunkel und Hell, echte Test-Nextcloud): Kennung mit Name „Nextcloud“, Logo und Themenfarbe rgb(0,103,158); 2FA-Wartezustand mit Link auf die Nextcloud; Fehler credentialsOrTwoFactor mit Browser als Hauptknopf; 30-MB-Upload über den Dateiauswahldialog mit Fortschritt und Namenskonflikt-Zeile (Überspringen); Umbenennen per F2, Verschieben nach „Rechnungen & Belege“, Löschen mit Rückfrage (in der Nextcloud-Papierkorb nachgewiesen), Datei-Download (PDF) und Ordner-ZIP („PK“), Enter/Rücktaste/Strg+A.
|
||||
- Screenshots unter `.playwright-mcp/nextcloud-files/`: dunkel `t6-dark-{connect,connect-waiting,connect-error,list,grid,selection,drop-overlay,transfers,move-dialog,empty,delete-dialog,mobile,mobile-connect,mobile-list}.png`, hell `t6-light-{connect,connect-waiting,list,grid,selection,drop-overlay,transfers,move-dialog,empty}.png`. Gegen L-09 geprüft: ruhige Liste, Streifen nur beim Ziehen, lesbare Typkacheln in beiden Modi, keine Großbuchstaben-Beschriftungen, keine Mittelpunkte.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Rücktaste ging in leeren Ordnern verloren**
|
||||
- **Found during:** Aufgabe 6 (Browserprüfung, Screenshot „empty“)
|
||||
- **Issue:** In einem leeren Ordner gibt es keine Zeile, die den Fokus aufnimmt; der Fokus fiel auf die Seite zurück und die Tastenbelegung der Dateiansicht griff nicht mehr.
|
||||
- **Fix:** Die Dateikarte ist ein Fokusfang (`tabIndex={-1}`, Klasse `nc-files-root`); in globals.css ohne Rahmen, im dunklen Modus bleibt die Haarlinie erhalten.
|
||||
- **Files modified:** FileBrowser.tsx, globals.css
|
||||
- **Commit:** 630398f
|
||||
|
||||
**2. [Rule 1 - Bug] e2e-Skripte hingen vom Anfangszustand ab**
|
||||
- **Found during:** Aufgabe 6 (Wiederholung auf dem neu gebauten Stack)
|
||||
- **Issue:** `e2e-settings.sh` erwartete eine noch nicht gespeicherte Adresse (ein unveränderter Wert antwortet bewusst ohne Prüfung); `e2e-connect.sh` scheiterte an übrig gebliebenen Tessera-Zugängen in der Nextcloud (ein Adresswechsel lässt Konten ablaufen, ohne zu widerrufen, siehe Administrationshandbuch).
|
||||
- **Fix:** e2e-settings stellt erst auf eine andere Adresse; e2e-lib bekommt `e2e_nc_purge_tokens`, e2e-connect räumt vor dem Start auf. Dazu Prüfung der Serverkennung in e2e-settings.
|
||||
- **Commit:** 630398f
|
||||
|
||||
**3. [Rule 2 - Missing critical] Doku zum Brute-Force-Befehl vorsichtig formuliert**
|
||||
- Der occ-Befehl `config:app:set bruteForce whitelist_0` und `security:bruteforce:reset` stehen in den Handbüchern; Aussagen über die Oberfläche der Nextcloud zur Ermittlung der Absenderadresse wurden bewusst weggelassen (nicht gemessen), stattdessen der Hinweis auf das Zugriffsprotokoll des Webservers.
|
||||
|
||||
### Hinweise ohne Abweichung
|
||||
|
||||
- Bildschirmaufnahmen mit playwright-core statt Playwright MCP (mit Absprache aus der Übergabe von Aufgabe 5); gleiche Prüfungen, gleiche Ablage.
|
||||
- Das Projekt-`biome format` weist in Dateien aus früheren Aufgaben (module-loader.ts, packages/shared) Formatabweichungen aus; Projektvorgabe ist `biome lint`, daher unverändert gelassen.
|
||||
- Die RLS-Dokumentation musste in Aufgabe 6 nicht neu gezählt werden (keine neuen Tabellen oder Richtlinien).
|
||||
|
||||
## Known Stubs
|
||||
|
||||
Keine. (Das Modul hat bewusst kein Dashboard-Widget; Etappe 2 ist offen und nicht Teil dieses Plans.)
|
||||
|
||||
## Threat Flags
|
||||
|
||||
Keine neuen Flächen gegenüber dem Bedrohungsmodell. Die Serverkennung (T-mzu-01/T-mzu-08) ist enthalten: feste Pfade, keine Weiterleitung, Logo nach Bytes erkannt, SVG nur mit CSP-Sandbox.
|
||||
|
||||
## Prüfliste für die echte Umgebung (vom Benutzer)
|
||||
|
||||
1. **Desktop-App:** Neue Fassung herunterladen und prüfen, dass der Link „Anmeldung bei Nextcloud öffnen“ in der Desktop-App den System-Browser öffnet (Opener-Skript fängt `target=_blank`), und dass nach „Zugriff gewähren“ die Dateiansicht erscheint.
|
||||
2. **Nginx Proxy Manager (Tessera-Adresse):** `client_max_body_size` mindestens `10m` (besser `64m`) und Lese-/Sendezeitlimits mindestens 120 s für die Tessera-Adresse (alpha und live) setzen, dann eine Datei über 10 MB hochladen. Ohne das bricht der Upload beim ersten 8-MiB-Stück ab (Betriebshandbuch, Fehlerbild).
|
||||
3. **Nextcloud Brute-Force-Ausnahme:** Auf der echten Nextcloud die Adresse des Tessera-Servers eintragen: `occ config:app:set bruteForce whitelist_0 --value=<IP des Tessera-Servers>` (bei Proxy dessen Adresse; die tatsächlich ankommende Adresse im Zugriffsprotokoll prüfen). Danach in Tessera unter Dateien → Einstellungen die Adresse eintragen und „Verbindung prüfen“ klicken.
|
||||
4. **Zertifikat:** Nutzt die echte Nextcloud eine interne Zertifizierungsstelle, `NODE_EXTRA_CA_CERTS` im api-Container setzen (Betriebshandbuch Kapitel 3), sonst meldet die Prüfung ein Zertifikatsproblem.
|
||||
5. **Zwei-Faktor-Anmeldung:** Mit einem Konto mit Zwei-Faktor-Anmeldung „Im Browser anmelden“ durchspielen; ein Konto ohne Zwei-Faktor per Passwort anmelden; danach „Abmelden“ und in der Nextcloud unter Sicherheit prüfen, dass der Eintrag „Tessera“ verschwunden ist.
|
||||
6. **Modul freischalten:** Im Marktplatz „Dateien“ aktivieren und die Freigabe erteilen (Benutzen für alle, Verwalten für die, die die Adresse pflegen). Beim Deployen daran denken: `up` baut nicht neu, `--build` bzw. neue Abbilder ziehen; die Migrationen laufen beim Start der API.
|
||||
7. **Ablage-Kachel mit echtem Logo:** Prüfen, dass Name, Logo und Farbe der echten Nextcloud auf dem Anmeldebildschirm stimmen (bei dunklem Logo auf dunkler Themenfarbe ggf. den Eindruck bewerten).
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Dateien vorhanden: nextcloud-server-info.ts, nextcloud-server-info.spec.ts, ServerIdentity.tsx, Screenshots t6-dark (14) und t6-light (9).
|
||||
- Commits in der Historie: 9606967, d00b6ff, 8bee65c, 4d4a0b3, 86fbe8f, 630398f.
|
||||
Reference in New Issue
Block a user