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 |
|
v3:sha256:324f20c51c56325030b045e7413ef53d5aa7c3d742f7aac80c85bcbe0aa91f6a | 0 | 0 |
|
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 |
Key Link Verification
| 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:
- 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.
- 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. - 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)