test(cypress): Suite auf staging-Stand aktualisieren — Reparaturen + neue Feature-Tests - #237
Merged
Merged
Conversation
…ute split Abgedeckte Funktion: - App.tsx Admin-Short-Circuit + neue admin-Route-Struktur mit ProtectedRoute Getesteter Nutzerfluss: - Admin ohne OpenStack-Projekt besucht /dashboard → Dashboard rendert - Admin besucht /admin/projects → AdminProjectOverview rendert (ProtectedRoute requireAdmin lässt durch) Getestete Fachlogik: - Non-Lecturer-Branch überspringt listOpenstackProjects() (0 Calls) - needsSetup bleibt false → kein /setup-Redirect Geprüfte Fehlerfälle: - (n/a) Geprüfte Edge Cases: - Auch bei explizit leerer Projektliste kein Setup-Zwang Betroffene Komponenten: - src/App.tsx, src/components/ProtectedRoute.tsx, src/pages/AdminProjectOverview.tsx Warum dieser Test wichtig ist: - Nach dem Admin-Rework (Split von /admin in /admin/projects|templates|lecturers) sichert der Test, dass Admins weiterhin ohne Projekt in den Adminbereich kommen. Aktualisierung: alte /admin-Route + AdminMonitoring-Heading existieren nicht mehr; Test zielt jetzt auf /admin/projects + Projektübersicht.
…ute split Abgedeckte Funktion: - AdminTemplateApprovals Approval-Queue (aus AdminMonitoring herausgelöst) Getesteter Nutzerfluss: - Admin → /admin/templates → Queue mit zwei pending Versions → Schnell genehmigen → Row verschwindet Getestete Fachlogik: - getTemplateVersionsQueue() lädt Queue - approveTemplateVersion() POSTet /template-versions/<id>/approve - Row-Removal via lokalem State (kein Refetch) Geprüfte Fehlerfälle: - (n/a — happy path) Geprüfte Edge Cases: - Korrekte Row wird approved, andere bleibt sichtbar Betroffene Komponenten: - src/pages/AdminTemplateApprovals.tsx, src/api/github.ts Warum dieser Test wichtig ist: - Approval ist der einzige Weg, public Templates in den AppStore-Katalog zu bringen. Aktualisierung: Route /admin → /admin/templates nach dem Admin-Rework; Selektoren/Endpunkte/Fixture unverändert gültig.
… gating Abgedeckte Funktion: - DeploymentDetails Delete-Flow unter neuem Owner-Only-Gate (fix/126) Getesteter Nutzerfluss: - Owner-Lecturer öffnet /deployment/<id> → Löschen → Bestätigen → DELETE → /dashboard Getestete Fachlogik: - canManageDeployment = deployment.ownerId === currentUser.userId - Delete-Button ist nur für den Owner (oder Admin) aktiv Geprüfte Fehlerfälle: - (n/a — happy path) Geprüfte Edge Cases: - owner_id der Fixture == sub der lecturer-Fixture (user-lec-1) aktiviert die Aktion Betroffene Komponenten: - src/pages/DeploymentDetails.tsx, src/pages/DeploymentDetailsPage.tsx, cypress/fixtures/deployments/detail-running.json Warum dieser Test wichtig ist: - Nach Einführung des Owner-Gates würde der Delete-Button ohne passendes owner_id in der Fixture deaktiviert bleiben; der Test würde falsch-negativ fehlschlagen. Fixture spiegelt jetzt einen Owner-Zugriff wider. Hinweis: detail-running.json wird von mehreren Detail-Specs geteilt; owner_id aktiviert nur owner-gebundene Aktionen und lässt Rendering-Assertions unberührt (mit dashboard-row-click, detail-renders-status-and-phases gegengeprüft).
…e (gate fixed) Abgedeckte Funktion: - ProtectedRoute requireAdmin-Guard auf admin-Routen Getesteter Nutzerfluss: - Lecturer ruft /admin/templates direkt auf → Redirect zu /dashboard, kein Admin-Content Getestete Fachlogik: - ProtectedRoute: requireAdmin && !isAdmin → Navigate /dashboard replace - AdminTemplateApprovals mountet nicht → loadQueue()-Effect feuert nicht - Template-Freigaben-Heading nicht im DOM Geprüfte Fehlerfälle: - (n/a — permission gate) Geprüfte Edge Cases: - Defense-in-Depth: echter Redirect statt CSS-Hide; queue-Fetch = 0 Calls Betroffene Komponenten: - src/components/ProtectedRoute.tsx, src/App.tsx, src/pages/AdminTemplateApprovals.tsx Warum dieser Test wichtig ist: - Der zuvor dokumentierte Privilege-Escalation-Befund (SECURITY-FINDINGS.md #1) ist durch den Admin-Rework behoben. Der zuvor geskippte Test ist jetzt aktiv und sichert den Guard gegen Regression ab. SECURITY-FINDINGS.md #1 auf RESOLVED aktualisiert.
Erfasst die Reparaturen bestehender Tests nach dem großen staging-Update und die geplanten neuen Feature-Tests (Student-Self-Service, Lecturer- Verwaltung, Admin-Rework, Redeploy, Kurs-Filter, 36-Monate, Expiry-Tiers, Mobile-Nav). Grundlage für die folgende Test-Implementierung.
Bereitet die Student-Self-Service-Tests vor: cy.loginAs("student", url)
nutzt die vorhandene keycloak/student.json-Fixture (roles=["student"]).
Reine Test-Infrastruktur, kein Produktivcode.
…ent CourseGroupsCard Abgedeckte Funktion: - CourseGroupsCard "Ohne Gruppe"-Sektion + nachträgliche Gruppenzuweisung (Feat #207) Getesteter Nutzerfluss: - Owner-Lecturer öffnet Deployment-Detail → Karte "Gruppen & Mitglieder" aufklappen → gruppenloses Mitglied in "Ohne Gruppe" → Gruppe wählen → Hinzufügen → POST addGroupMembers Getestete Fachlogik: - Kurs course-alpha hat 3 aktive Mitglieder; cm-1 in grp-1, cm-2 in grp-2, cm-3 (u3-neu) in keiner Gruppe → cm-3 erscheint korrekt in der amber "Ohne Gruppe"-Sektion - Hinweistext "Der Student erhält erst Zugriff…" wird angezeigt - "Hinzufügen"-Button ist ohne Gruppenauswahl disabled, nach Auswahl von "Gruppe A" aktiv - POST addGroupMembers sendet exakt { member_ids: ["cm-3"] } Geprüfte Fehlerfälle: - keine Geprüfte Edge Cases: - Gruppenloses Mitglied (cm-3) erscheint separat und verschwindet nach Zuweisung Betroffene Komponenten: - src/pages/DeploymentDetails.tsx (CourseGroupsCard), cypress/e2e/detail/detail-issue-207-ungrouped-members.cy.ts Warum dieser Test wichtig ist: - Sichert das #207-Feature: gruppenlose Studierende bekommen sonst nie Zugriff. Reparatur: Der Karten-Titel <h4> lag unterhalb des Falzes in einem Scroll-Container mit overflow und war zwar im DOM, aber nicht sichtbar. scrollIntoView vor der Visibility-Assertion (und vor dem Klick auf "Anzeigen") ergänzt; keine Produktionsänderung, keine Fixture-Änderung nötig.
Abgedeckte Funktion: - Student-Self-Service Dashboard (StudentDashboard) + Rollen-Routing Getesteter Nutzerfluss: - Pure Student besucht / → Redirect /student/dashboard → GET /api/v1/student/deployments → Deployment-Karten sichtbar Getestete Fachlogik: - App.tsx pure-student Routing (student && !lecturer && !admin) - getStudentDeployments() lädt die zugewiesenen Deployments - StatusBadge-Mapping (running→Läuft etc.) - Sidebar zeigt nur "Meine Deployments" + Rolle "Student" Geprüfte Fehlerfälle: - (n/a — success path) Geprüfte Edge Cases: - Mehrere Deployments mit unterschiedlichem Status Betroffene Komponenten: - src/pages/StudentDashboard.tsx, src/pages/StudentDashboardPage.tsx, src/api/student.ts, src/layouts/Sidebar.tsx, src/App.tsx Warum dieser Test wichtig ist: - Sichert den Kernpfad des neuen Student-Bereichs. Bricht das Routing oder der Fetch, sehen Studierende ihre zugewiesenen Umgebungen nicht.
Abgedeckte Funktion: - App.tsx pure-student Routing-Guard Getesteter Nutzerfluss: - Pure Student ruft /dashboard und /appstore auf → beide Male Redirect zu /student/dashboard Getestete Fachlogik: - student && !lecturer && !admin bekommt nur die Student-Routes + Catch-all - Lecturer/Admin-Endpoints (deployments, templates) feuern NICHT für den Studenten Geprüfte Fehlerfälle: - (n/a — permission gate) Geprüfte Edge Cases: - Direktes Aufrufen einer Nicht-Student-Route landet über Catch-all wieder im Student-Dashboard Betroffene Komponenten: - src/App.tsx, src/pages/StudentDashboard.tsx Warum dieser Test wichtig ist: - Verhindert, dass Studierende Lecturer-/Admin-Oberflächen sehen. Bricht das Routing, könnten Studenten in nicht für sie gedachte Bereiche gelangen.
Abgedeckte Funktion: - Student-Deployment-Detailseite + CredentialInstanceCard (mode=student) Getesteter Nutzerfluss: - Student öffnet /student/deployment/:id → Liste wird gefiltert → Credentials geladen → VMs + Zugangsdaten sichtbar Getestete Fachlogik: - getStudentDeployments() + client-seitige Filterung nach id - getStudentDeploymentCredentials() lädt Instanzen + Accesses - CredentialInstanceCard rendert Zugangsdaten (mode=student) Geprüfte Fehlerfälle: - (n/a — success path; 403/404 in eigenem potenziellen Folgetest) Geprüfte Edge Cases: - Mehrere Access-Typen (ssh + web_url) in einer Instanz Betroffene Komponenten: - src/pages/StudentDeploymentDetails.tsx, src/pages/StudentDeploymentDetailsPage.tsx, src/components/credentials/CredentialInstanceCard.tsx, src/api/student.ts Warum dieser Test wichtig ist: - Ohne funktionierende Credentials-Anzeige können Studierende nicht auf ihre zugewiesenen VMs zugreifen — der Kernnutzen des Student-Bereichs.
Abgedeckte Funktion:
- Admin Lecturer-Verwaltung (Liste + Detail-Dialog)
Getesteter Nutzerfluss:
- Admin → /admin/lecturers → Tabelle geladen → Zeile klicken → Detail-Dialog mit Ressourcen-Sektionen
Getestete Fachlogik:
- listLecturers() GET /api/v1/lecturers?skip&limit
- getLecturer(id) GET /api/v1/lecturers/{id} beim Öffnen des Dialogs
- Tabellen-Header + Detail-Sektionen (Templates/Deployments/OpenStack-Projekte)
Geprüfte Fehlerfälle:
- (n/a — success path)
Geprüfte Edge Cases:
- Mehrere Lecturer in der Liste; korrekte Detail-Zuordnung per id
Betroffene Komponenten:
- src/pages/LecturerManagement.tsx, src/components/LecturerDetailDialog.tsx, src/api/lecturers.ts
Warum dieser Test wichtig ist:
- Die Lecturer-Verwaltung ist der Admin-Kanal für Nutzer-Übersicht und
Cascade-Delete. Bricht Liste oder Detail-Fetch, ist Admin blind.
Abgedeckte Funktion:
- Lecturer Cascade-Delete: Type-to-confirm + 202 + Poll bis 404
Getesteter Nutzerfluss:
- Admin → Lecturer-Detail → Account löschen → Namen tippen → Endgültig löschen → DELETE 202 → Poll → 404 → Erfolgstoast
Getestete Fachlogik:
- DeleteLecturerConfirmDialog Type-to-confirm (exakter Name aktiviert Button)
- deleteLecturer() DELETE /api/v1/lecturers/{id} → 202 enqueue
- LecturerDetailDialog Poll GET /{id} alle 2s; 404 = Erfolg → Toast + Refetch + Close
Geprüfte Fehlerfälle:
- (n/a — happy path)
Geprüfte Edge Cases:
- Button erst bei exakt passendem Bestätigungsnamen aktiv
- Poll-Übergang 200→404 löst Erfolg aus
Betroffene Komponenten:
- src/components/DeleteLecturerConfirmDialog.tsx, src/components/LecturerDetailDialog.tsx, src/api/lecturers.ts
Warum dieser Test wichtig ist:
- Cascade-Delete ist destruktiv + asynchron. Bricht der Poll oder das
Confirm-Gate, löscht der Admin evtl. versehentlich oder bekommt kein Feedback.
Abgedeckte Funktion: - AdminProjectOverview globale Deployment-Übersicht (Admin-Rework) Getesteter Nutzerfluss: - Admin → /admin/projects → Stat-Cards + Gruppierungs-Ansicht geladen aus getAllDeployments(null) Getestete Fachlogik: - getAllDeployments(null) ohne openstack_project_id (Admin sieht alles) - Stat-Cards Gesamt/Aktiv/Inaktiv - View-Selector Nach Dozent/Kurs/Datum; Teacher-Extraktion aus deployment_parameters Geprüfte Fehlerfälle: - (n/a — success path) Geprüfte Edge Cases: - Deployments mit unterschiedlichem Status (aktiv/inaktiv) fließen in die Zählung Betroffene Komponenten: - src/pages/AdminProjectOverview.tsx, src/api/deployments.ts Warum dieser Test wichtig ist: - Die Projektübersicht ist das zentrale Admin-Monitoring nach dem Rework. Bricht der globale Fetch oder die Gruppierung, verliert der Admin den Überblick.
Abgedeckte Funktion:
- AdminTemplateApprovals Reject-Flow mit Begründung
Getesteter Nutzerfluss:
- Admin → /admin/templates → Ablehnen → Begründung eingeben → absenden → POST /reject mit reason → Row verschwindet
Getestete Fachlogik:
- rejectTemplateVersion(id, reason) POSTet /template-versions/<id>/reject mit {reason}
- Row-Removal via lokalem State nach Erfolg
Geprüfte Fehlerfälle:
- (n/a — happy path)
Geprüfte Edge Cases:
- Begründungstext landet exakt im Request-Body
- Korrekte Row wird abgelehnt, andere bleibt sichtbar
Betroffene Komponenten:
- src/pages/AdminTemplateApprovals.tsx, src/api/github.ts
Warum dieser Test wichtig ist:
- Ohne funktionierendes Reject-mit-Begründung bekommen Template-Autoren kein
Feedback, warum ihre Version abgelehnt wurde.
Abgedeckte Funktion: - RedeployDialog Config-Override für ein laufendes Deployment Getesteter Nutzerfluss: - Owner öffnet running Deployment → Neu deployen → Parameter ändern → absenden → POST /redeploy Getestete Fachlogik: - canManageDeployment (owner) schaltet "Neu deployen" frei - RedeployDialog rendert Felder aus deployment_parameters.parameters - Nur geänderte Keys landen in deployment_parameter_overrides - preserve_credentials default true; POST /deployments/<id>/redeploy?openstack_project_id Geprüfte Fehlerfälle: - (n/a — happy path; Fehler/Permission separat) Geprüfte Edge Cases: - Nur der geänderte Parameter wird als Override gesendet (Diff-Logik) Betroffene Komponenten: - src/pages/DeploymentDetails.tsx, src/components/deployments/RedeployDialog.tsx, src/api/deployments.ts Warum dieser Test wichtig ist: - Redeploy mit Config-Override ist ein neues Kernfeature (#192). Bricht die Diff-Logik oder der POST, deployen Dozenten mit falschen Parametern neu.
Abgedeckte Funktion: - Courses Kurs-Filter-Chips (client-seitige Filterung) Getesteter Nutzerfluss: - Lecturer → /courses → Filter-Chip klicken → Kursliste verengt sich → Alle anzeigen setzt zurück Getestete Fachlogik: - listCourseFilters() lädt die Chips - Client-seitige OR-Filterung, case-insensitive Substring auf Kurs-/Gruppenname - aria-pressed spiegelt aktiven Filter; "Alle anzeigen" leert den Filter-Set Geprüfte Fehlerfälle: - (n/a — state/UI) Geprüfte Edge Cases: - Nur Kurse mit Deployments werden überhaupt angezeigt - Toggle an/aus verändert die sichtbare Liste konsistent Betroffene Komponenten: - src/pages/Courses.tsx, src/api/courseFilters.ts, src/api/courses.ts Warum dieser Test wichtig ist: - Bei vielen Kursen ist die Chip-Filterung die zentrale Navigationshilfe; bricht sie, wird die Kursliste unbrauchbar.
Abgedeckte Funktion:
- Courses Kurs-Filter-Verwaltung (Admin: Anlegen + Löschen)
Getesteter Nutzerfluss:
- Admin → /courses → Filter "Docker" anlegen (POST) → erscheint; Filter "Web" löschen (DELETE) → verschwindet
Getestete Fachlogik:
- Admin-gated Controls sichtbar (isAdmin)
- createCourseFilter POST {name}; deleteCourseFilter DELETE /{id}
- loadFilters() Refetch nach Mutation aktualisiert die Chip-Leiste
Geprüfte Fehlerfälle:
- (n/a — happy path; 409/422/403 optional künftig)
Geprüfte Edge Cases:
- POST-Body enthält exakt {name}; DELETE trifft die richtige Filter-id
Betroffene Komponenten:
- src/pages/Courses.tsx, src/api/courseFilters.ts
Warum dieser Test wichtig ist:
- Nur Admins verwalten die Filter-Taxonomie; bricht CRUD, kann die Chip-Leiste
nicht mehr gepflegt werden und die Kursnavigation verwahrlost.
Abgedeckte Funktion:
- DeploymentWizard 36-Monate-Laufzeit ("3 Jahre", Feat #179)
Getesteter Nutzerfluss:
- Lecturer durchläuft Wizard, wählt Laufzeit "3 Jahre" → Anwendung deployen → POST mit runtime_months: 36
Getestete Fachlogik:
- Runtime-Select bietet Wert 36 ("3 Jahre")
- Submit serialisiert runtime_months: parseInt(runtime) = 36
Geprüfte Fehlerfälle:
- (n/a — success/edge)
Geprüfte Edge Cases:
- Nicht-Default-Laufzeit (36) statt Default 4 landet korrekt im Payload
Betroffene Komponenten:
- src/pages/DeploymentWizard.tsx, src/api/deployments.ts
Warum dieser Test wichtig ist:
- Die 36-Monate-Option ist neu; ohne Test könnte ein Regressions-Bug die
Laufzeit stillschweigend auf den Default zurücksetzen.
Abgedeckte Funktion: - Dashboard Ablauf-Farbstufen (getExpiryState, Feat #180) Getesteter Nutzerfluss: - Lecturer → /dashboard → Deployment-Zeilen zeigen je nach Restlaufzeit warning/critical/expired-Indikator Getestete Fachlogik: - getExpiryState Schwellen: expired (vorbei), critical ≤42d, warning ≤90d, sonst ok - Dashboard rendert Ablauf-Icon nur bei warning/critical/expired - Kein Indikator bei weit entfernter Ablaufzeit Geprüfte Fehlerfälle: - (n/a — state/UI) Geprüfte Edge Cases: - Vier Stufen (ok/warning/critical/expired) korrekt unterschieden anhand relativer Daten Betroffene Komponenten: - src/pages/Dashboard.tsx, src/utils/deployment.ts Warum dieser Test wichtig ist: - Die Ablaufwarnung verhindert, dass Dozenten Deployments unbemerkt auslaufen lassen; falsche Schwellen/Farbstufen kosten Daten.
Abgedeckte Funktion:
- Visual-Regression-Screenshot-Harness über alle Hauptseiten (desktop + mobile)
Getesteter Nutzerfluss:
- Jede Seite in beiden Viewports laden bis Ready-Heading sichtbar, Screenshot
Getestete Fachlogik:
- Seiten rendern ihre Headings unter der aktuellen Rollen-/Routing-Struktur
Geprüfte Fehlerfälle:
- (n/a — Screenshot-Capture)
Geprüfte Edge Cases:
- Mobile-Drawer öffnet über Hamburger
Betroffene Komponenten:
- cypress/e2e/visual/visual-capture.cy.ts
Warum dieser Test wichtig ist:
- Fängt visuelle Regressionen über alle Kernseiten in zwei Viewports ab.
Reparatur:
- Reference-Path korrigiert: ../support/index.d.ts -> ../../support/index.d.ts
- Ready-Assertion auf <h1> eingegrenzt (cy.contains(ready) -> cy.contains("h1", ready)):
die Ready-Strings (Dashboard, App Store, Kurse, Projektübersicht, Template-Freigaben,
Meine Deployments) matchten sonst die auf Mobile versteckten Sidebar-Nav-Links.
- Mobile-Drawer-Test: "Dashboard" auf <h1> eingegrenzt; "Kurse" auf den offenen
Sheet-Dialog eingegrenzt ([role="dialog"] .contains("Kurse")), da die Desktop-Sidebar
(hidden md:flex) denselben Link versteckt im DOM hält.
- Keine Ready-Strings inhaltlich geändert (alle Headings stimmen), keine Intercepts nötig.
Die PageSpec.overrides-Deklaration war {fixture?; body?; statusCode?} und
damit nicht auf mockApi's InterceptOverride-Union zuweisbar (tsc TS2345).
Alle tatsächlichen Verwendungen sind {fixture}, daher den Typ darauf
verengt. Kein Verhaltensänderung, Suite bleibt 17/17 grün.
tsc --noEmit -p cypress/tsconfig.json jetzt fehlerfrei.
RamonaKT
self-requested a review
July 25, 2026 17:27
RamonaKT
approved these changes
Jul 25, 2026
LostLunaris
approved these changes
Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Was & Warum
Bringt die Cypress-Integrationstest-Suite auf den aktuellen
staging-Stand. Seit der ursprünglichen Suite (d1af1a7) sind ~7.800src/-Zeilen dazugekommen (Student-Self-Service, Admin-Rework, Redeploy, Kurs-Filter u.a.) — mehrere Tests waren dadurch veraltet und große neue Bereiche ungetestet.Ergebnis
tsc --noEmit -p cypress/tsconfig.json): 0 Fehlervite build): successdata-testidReparaturen (6)
auth-admin-bypasses-setup-gate/adminin/admin/projects|templates|lecturersgesplittet/admin/projectsadmin-approve-template-version/admin/templatesverschobendetail-delete-confirmation-flowowner_idin Fixtureauth-non-admin-cannot-access-admin-routeskip(Befund); viaProtectedRoutebehobendetail-issue-207-ungrouped-membersscrollIntoView()visual-capturecy.contains("h1", …)+ Pfad-FixNeue Feature-Tests (11)
Student-Self-Service:
student-dashboard-lists-deployments(P0),student-role-routing-guard(P0),student-deployment-details-credentials(P1)Admin:
lecturer-management-lists(P1),lecturer-delete-cascade-poll(P1),admin-project-overview-renders(P1),admin-reject-template-with-reason(P1)Deployment/Courses:
redeploy-deployment-config-override(P1),course-filters-toggle-chip(P1),course-filters-admin-crud(P1)Wizard/Dashboard:
wizard-36-months-runtime(P2),dashboard-expiry-color-tiers(P2)Sicherheits-Verbesserung bestätigt
Der zuvor in
cypress/SECURITY-FINDINGS.mddokumentierte Privilege-Escalation-Befund (/adminohne Frontend-Rollen-Gate) ist aufstagingbehoben —ProtectedRoute requireAdminleitet Nicht-Admins auf/dashboardum. Der geskippte Test ist reaktiviert und sichert den Guard; das Finding steht jetzt auf RESOLVED.Konventionen
cy.intercept+ Fixtures gemockt; Keycloak komplett gestubbt (window-Hook)cy.wait(<number>)) — nur Alias-/Assertion-TimeoutsHinweise
npm run test:e2eist noch nicht in der Pipeline verdrahtet — sollte als PR-Schritt ergänzt werden (viastart-server-and-test).cypress/REPORT-STAGING-UPDATE.md+cypress/TEST-MATRIX-DELTA.md.