--- 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=` (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.