Files
tessera-ctl/.planning/quick/261008-mzu-modul-nextcloud-dateien-eigenstaendiger-/261008-mzu-VERIFICATION.md
T
schalli 71b3f32c98
Tessera CI/CD / Lint & Type Check (push) Successful in 50s
Tessera CI/CD / Tests (push) Successful in 1m46s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 20s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m44s
docs(quick-261008-mzu): Modul Dateien (Nextcloud-Client)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 22:59:16 +02:00

12 KiB

phase, verified, status, score, covered_files, covered_digest, behavior_unverified, overrides_applied, human_verification
phase verified status score covered_files covered_digest behavior_unverified overrides_applied human_verification
quick-261008-mzu 2026-10-08T20:20:00Z human_needed 9/9 must-haves verified
.planning/quick/261008-mzu-modul-nextcloud-dateien-eigenstaendiger-/261008-mzu-PLAN.md
.planning/quick/261008-mzu-modul-nextcloud-dateien-eigenstaendiger-/261008-mzu-SUMMARY.md
apps/api/prisma/migrations/20261008180000_nextcloud_files/migration.sql
apps/api/src/nextcloud-files/nextcloud-files-account.service.ts
apps/api/src/nextcloud-files/nextcloud-files.controller.ts
apps/api/src/nextcloud-files/nextcloud-http.ts
apps/api/src/nextcloud-files/nextcloud-login-guard.ts
apps/api/src/nextcloud-files/nextcloud-upstream.ts
apps/web/src/app/(portal)/modules/nextcloud-files/components/FileBrowser.tsx
v3:sha256:324f20c51c56325030b045e7413ef53d5aa7c3d742f7aac80c85bcbe0aa91f6a 0 0
test expected why_human
Desktop-App: Link 'Anmeldung bei Nextcloud öffnen' (target=_blank) und Rückkehr nach 'Zugriff gewähren' System-Browser öffnet sich, danach zeigt die Desktop-App die Dateiansicht Tauri-Desktop-App (Opener-Skript) ist im lokalen Stack nicht prüfbar
test expected why_human
Nginx Proxy Manager vor alpha/live: client_max_body_size >= 10m und Zeitlimits >= 120 s, dann Datei > 10 MB über die echte Tessera-Adresse hochladen 8-MiB-Stücke laufen durch, kein 413 NPM-Grenzen existieren nur in der echten Umgebung; lokal läuft der Upload nur durch den Next.js-Proxy (belegt)
test expected why_human
Echte Firmen-Nextcloud: Brute-Force-Ausnahme für die Tessera-Server-IP, interne CA (NODE_EXTRA_CA_CERTS), Adresse speichern, 'Verbindung prüfen', Passwort-Anmeldung und Zwei-Faktor-Anmeldung, Abmelden und Eintrag 'Tessera' in der Nextcloud-Geräteliste prüfen Anmeldung klappt, Abmelden entfernt den App-Passwort-Eintrag, Name/Logo/Farbe der echten Nextcloud stimmen auf der Anmeldekarte Echte Nextcloud-Instanz (Version, Theming, Zertifikat, Absenderadresse) ist nur beim Benutzer verfügbar

Quick 261008-mzu: Modul Dateien (nextcloud-files), Etappe 1 - Verification Report

Goal: Neues Modul "Dateien" (Nextcloud, Etappe 1): eine Firmen-Nextcloud, eigenes Konto je Benutzer (Passwort -> App-Passwort verschlüsselt, oder Login Flow v2 bei Zwei-Faktor), Abmelden widerruft, Dateien durchblättern/Vorschau/Hoch- und Herunterladen/ZIP/Ordner-Operationen/Mehrfachauswahl/Quota/Overwrite-Schutz/Brute-Force-Schutz/Benutzertrennung, ausgeprägtes Design, Doku + CHANGELOG. Verified: 2026-10-08 Status: human_needed (alle automatisch prüfbaren Punkte erfüllt; drei Punkte brauchen die echte Umgebung) Re-verification: Nein, Erstprüfung

Goal Achievement

Observable Truths

# Truth Status Evidence
1 Eine Adresse je Organisation unter Verwalten; Prüfen per status.php; Adresswechsel mit Bestätigung lässt Konten ablaufen; Benutzen-only bekommt 403 VERIFIED Controller: GET/PUT settings, POST settings/test mit @ModuleManage, kein Rollen-Decorator. settings.service.ts Z.117-141: confirmReconnect Pflicht bei verbundenen Konten, danach status: 'EXPIRED'. e2e-settings.sh läuft grün (frisch ausgeführt).
2 Passwort-Anmeldung: einmaliger Austausch gegen App-Passwort, nur dieses AES-verschlüsselt (crypto.encrypt), echtes Passwort verworfen, nichts in Antwort/Log VERIFIED account.service.ts connectWithPassword/storeAppPassword (Z.154-194, 366-390); Spalte encryptedAppPassword, kein Passwortfeld im Schema. Logs enthalten nur Kennungen/Mandant. e2e-connect grün (Anna per Passwort und per E-Mail).
3 2FA: credentialsOrTwoFactor, Login Flow v2, Poll nur gegen {Basis}/index.php/login/v2/poll, Wartezustand mit Abbrechen, Wechsel auf verbunden VERIFIED auth-client.ts pollLoginFlow mit festem Präfix (Z.317-328, poll.endpoint verworfen). e2e-connect: zoe -> 422 credentialsOrTwoFactor, Flow Start (loginUrl auf konfigurierte Basis), pending, Abbruch. Screenshots t2-flow-waiting.png, t2-flow-connected.png, t6-dark-connect-waiting.png zeigen Wartezustand und verbundenen Zustand gegen die Test-Nextcloud.
4 Brute-Force-Schutz: 3/15 min je Benutzer, 8/30 min je Server; 429 pausiert alle Aufrufe; erstes 401 tötet Zugangsschlüssel inkl. laufender Aufrufe; Whitelist-Hinweis in Einstellungen/Handbuch VERIFIED login-guard.ts Z.26-29 (3/15, 8/30). http.ts ncRequest: gate.isDead/isPaused vor Transport, 429 -> gate.pause, 401 mit Schlüssel -> markDead, signalFor bricht laufende Aufrufe ab. Live bestätigt: wiederholte e2e-Läufe lieferten HTTP 429 tooManyAttempts (retryAfter 817 s). Handbuch Administration Z.359ff mit occ-Befehl. Call-Gate/Guard-Specs grün.
5 Abmelden widerruft App-Passwort und löscht Zeile; Wiederverbinden widerruft altes; frisch ausgestelltes, nicht speicherbares wird widerrufen; nie an fremden Host VERIFIED disconnect (nur wenn ACTIVE und Adresse gleich), revokePrevious, revokeFresh im catch von storeAppPassword. e2e-connect belegt Token-Zählung in der echten Nextcloud: 1 nach Wiederverbinden, 0 nach Trennen (auch bei E-Mail-Anmeldename).
6 Benutzertrennung: Mandant UND Benutzer (RLS + forTenant mit Token-User), zweiter Benutzer 409 notConnected VERIFIED Migration: FORCE RLS, Policy tenantId = current_tenant_id() AND (current_user_id() IS NULL OR userId = current_user_id()). Jede Methode nutzt forTenant(this.prisma, tenantId, userId), userId nur aus req.user.id. e2e-connect: e2euser sieht account:null, Trennen -> 409, Flow-IDs fremder Benutzer -> 404. rls-coverage-Spec grün, Inventar-Doku Z.185 nachgeführt.
7 Durchblättern (Breadcrumb, Liste/Raster pro Benutzer gemerkt), Typkacheln, Vorschau, Quota (-3 = unbegrenzt), Ordner anlegen/umbenennen/verschieben/löschen (Papierkorb), Mehrfachauswahl, Maus/Menü/Rechtsklick/Tastatur VERIFIED FileBrowser.tsx: localStorage je userId, Tasten Enter/Backspace/Delete/F2/Strg+A (Z.607-714). QuotaMeter zeigt bei unbegrenzt nur belegten Platz (Screenshot "3,6 MB belegt"). e2e-files grün. 169 Web-Tests grün (FileBrowser, TransferBar, Seite, Upload). Screenshots dunkel/hell: Liste, Raster, Auswahl, Verschieben-Dialog, Löschen-Dialog, leer, mobil.
8 Upload per Drag&Drop/Dateiwahl auch > 10 MiB in 8-MiB-Stücken durch /api-proxy, Fortschritt, Abbruch, Fehlertext, nie stilles Überschreiben ("Ersetzen", "Beide behalten", "Überspringen") VERIFIED dav-transfer.ts: If-None-Match: *, Ersetzen nur mit If-Match-Etag. e2e-transfer grün: 30 MB in Stücken durch Next.js-Proxy (:3000/api-proxy), byteidentischer Download, 409 nameTaken, 409 changedMeanwhile, 413 chunkTooLarge, 411, Abbruch räumt Upload-Ordner auf. Screenshot t6-dark-transfers.png: Übertragungsleiste mit Fortschritt und den drei Konfliktknöpfen.
9 Downloads ungepuffert (nosniff, ZIP für Ordner/Auswahl); jede Nextcloud-Antwort wird vor dem Pipen abgebildet, nie 401/403; nur Basis-URL, feste Pfade, keine Weiterleitung, keine Cookies, nie URL aus Antwort VERIFIED upstream.ts: sendUpstreamStream ruft mapNcFailure vor pipeline. http.ts: ALLOWED_PREFIXES, buildNcUrl mit Segment-Kodierung, 3xx -> redirect-Fehler, Header cookie/host/authorization gesperrt. e2e-transfer: Range 206, ZIP (Ordner, Auswahl, zwei Namen), .. -> 400 invalidPath, fehlende Datei -> 404 notFound, ohne Anmeldung 401 nur von Tessera.

Score: 9/9 Truths verified (0 behavior-unverified)

Required Artifacts

Artifact Status Details
migration.sql (+ ..._login_name) VERIFIED zwei Tabellen, ENABLE/FORCE RLS, Policy mit current_user_id()
nextcloud-http.ts / nextcloud-call-gate.ts VERIFIED alle genannten Exporte, im Transport verdrahtet
nextcloud-auth-client.ts, ...account.service.ts VERIFIED substantiell, in Modul und Controller verdrahtet
nextcloud-upstream.ts, ...transfer.service.ts VERIFIED mapNcFailure, sendUpstreamStream, 593 Zeilen Transferdienst
nextcloud-files-upload.ts (Web) VERIFIED Uploader mit Tests (503 Zeilen), von use-transfers.ts genutzt
FileBrowser.tsx, ConnectPanel.tsx VERIFIED in page.tsx eingebunden, Screenshots belegen Rendering mit echten Daten
Registrierung (app.module, module-loader, nav-store, module-identity, Seed) VERIFIED per grep bestätigt
From To Status
account.service -> crypto.encrypt( nur App-Passwort WIRED
auth-client pollLoginFlow -> /index.php/login/v2/poll fester Pfad WIRED
ncRequest -> NextcloudCallGate isPaused/isDead/pause/markDead WIRED
getSession -> forTenant(this.prisma, tenantId, userId) via findAccount WIRED
transfer.service -> mapNcFailure( vor dem Pipen WIRED
dav move -> Overwrite: F außer Etag-geprüftes Ersetzen WIRED

Behavioral Spot-Checks (frisch ausgeführt)

Check Ergebnis Status
API-Tests src/nextcloud-files + src/module-registry 19 Dateien, 513 Tests grün PASS
Web-Tests Modul, Lib, Komponenten, Layouts 11 Dateien, 169 Tests grün PASS
tsc --noEmit apps/api und apps/web ohne Fehler PASS
rls-coverage-Spec 5 Tests grün PASS
e2e-settings.sh, e2e-connect.sh, e2e-files.sh, e2e-transfer.sh gegen Test-Nextcloud 34.0.4 alle "ok" (nach API-Neustart) PASS

Anti-Patterns Found

Keine TBD/FIXME/XXX/TODO/HACK in den Modulverzeichnissen. Keine Stubs: Dateigrößen und Datenfluss (echte PROPFIND/DAV-Antworten bis in die Oberfläche, Screenshots mit echten Nextcloud-Dateien) belegen es.

Beobachtung Schwere Auswirkung
e2e-connect.sh ist innerhalb von 15 Minuten nach einem früheren Lauf nicht wiederholbar: der Zwei-Faktor-Versuch zählt als Fehlversuch für admin, der nächste Lauf scheitert schon beim Schritt "anna verbinden" mit 429 (Neustart der API dann nötig). Das Skript startet die API nur beim 2FA-Schritt neu. Die Aussage der SUMMARY, die Skripte seien "zweimal hintereinander wiederholbar", gilt deshalb nur mit dazwischenliegendem Neustart. Info Nur Testwerkzeug; es zeigt zugleich, dass der Brute-Force-Schutz wirkt.

Requirements Coverage

QUICK-261008-mzu: SATISFIED für alle im Zielsatz genannten Punkte (Konto, Dateien, Transfer, Schutzmaßnahmen, Design, Doku). CHANGELOG (vier Einträge unter "Neu"), Anwender-, Administrations- und Betriebshandbuch vorhanden und inhaltlich passend.

Design

Screenshots (dunkel und hell, desktop und mobil) zeigen ein eigenständiges Erscheinungsbild: Typkacheln je Dateifamilie mit Farbcodierung, Kennungskopf der Nextcloud (Name, Logo, Themenfarbe) auf der Anmeldekarte, angedockte Übertragungsleiste, Mosaik-Gelb als Akzent. Nicht generisch. Die subjektive Bewertung bleibt beim Benutzer.

Human Verification Required

Diese Punkte brauchen die echte Umgebung und sind keine Lücken:

  1. Desktop-App: Link "Anmeldung bei Nextcloud öffnen" öffnet den System-Browser, nach "Zugriff gewähren" erscheint die Dateiansicht. Grund: Tauri-Opener nur in der installierten App prüfbar.
  2. Nginx Proxy Manager: client_max_body_size >= 10m, Zeitlimits >= 120 s für alpha/live, dann Datei > 10 MB hochladen. Grund: NPM-Grenzen nur in der echten Umgebung.
  3. Echte Firmen-Nextcloud: Brute-Force-Ausnahme für die Tessera-IP, ggf. NODE_EXTRA_CA_CERTS, Adresse eintragen, Passwort- und 2FA-Anmeldung, Abmelden und Geräteliste prüfen, Name/Logo/Farbe der Anmeldekarte beurteilen.

Gaps Summary

Keine Lücken. Alle neun Truths sind gegen den Code, frisch ausgeführte Tests und die End-zu-End-Skripte gegen eine echte Test-Nextcloud belegt. Der Gesamtstatus ist human_needed nur wegen der drei Punkte, die die Produktionsumgebung erfordern.


Verified: 2026-10-08 Verifier: Claude (gsd-verifier)