syncova-backup/apps/web/package.json
Jerrit Fritzsche b3f0a99243
Some checks failed
CI / Backend (Go) (push) Failing after 30s
CI / Frontend (React/TypeScript) (push) Successful in 44s
CI / Sicherheitsprüfungen (push) Successful in 27s
Weboberflaeche: Design-Fundament und bedienbare Auftraege
Ausgangslage, gemessen statt geschaetzt: Von 99 fachlichen Endpunkten rief die
Oberflaeche 23 auf. Schreibend waren es neun, vier davon An- und Abmeldung.
Real verwaltbar war: einen Auftrag anlegen, einen Bericht erzeugen, eine
Meldung bestaetigen. Das ist ein Leseinstrument, keine Verwaltungskonsole.

Dieser Schritt legt das Fundament und macht den ersten Bereich vollstaendig
bedienbar.

Fundament:

- Tailwind v4 und Radix-Primitive (shadcn-Muster). Alles gebuendelt, keine
  externen Ressourcen — die CSP der Auslieferung laesst sie ohnehin nicht zu.
- Farbsystem nach PROMPT.md §106: Semantische Farben ausschliesslich fuer
  Status, sonst neutral. Die Zuordnung der Fachbegriffe auf die fuenf
  Bedeutungen steht an genau **einer** Stelle (StatusBadge). Verteilt ueber die
  Seiten erschiene frueher oder spaeter irgendwo "partial_failure" gruen, und
  ein Betreiber haelt einen Teilfehler dann fuer einen Erfolg. Ein unbekannter
  Zustand wird neutral dargestellt, nie gruen.
- Neue Seitenhuelle mit fuenf Bereichen, einklappbarer Seitenleiste, Schublade
  auf schmalen Geraeten und Dark Mode ueber ein Attribut am Wurzelelement (nicht
  allein ueber die Medienabfrage — eine Konsole, die nachts waehrend einer
  Stoerung von selbst umschaltet, ist laestig).
- `useMutation` fuer schreibende Aufrufe: Doppelklickschutz, Vorgangsnummer bis
  in die Meldung, kein setState nach dem Aushaengen. `describeApiError`
  uebersetzt die bekannten Fehlercodes in Saetze **mit Abhilfe**.
- Der API-Client sendet jetzt `Idempotency-Key`. Ohne ihn erzeugt ein
  Doppelklick zwei Auftraege — und bei einer Wiederherstellung zwei
  gleichzeitige Laeufe in dasselbe Ziel.
- Fehlermeldungen nennen immer die `request_id`, kopierbar.

Auftraege (Endpunkte, die vorher keine Oberflaeche hatten):

- Lauf anstossen, anhalten, fortsetzen, loeschen, laufenden Lauf abbrechen.
- Detailseite mit Laufhistorie: Fehlercode, Fehlerklasse und die Auskunft, ob
  eine Wiederholung ueberhaupt etwas bringt — ein Anmeldefehler behebt sich
  nicht durch Warten.
- **Ein zweiter Anstoss ist kein Fehler, sondern eine Auskunft.** Der 409 wird
  als Hinweis gezeigt, nicht als Fehlschlag: Der Auftrag laeuft ja, und genau
  das wollte der Betreiber.
- **Loeschen nennt die Folgen.** Die Wiederherstellungspunkte bleiben bestehen;
  sie gehoeren zum Repository, nicht zum Auftrag. Ohne diesen Hinweis loescht
  jemand einen Auftrag in der Annahme, Platz zu schaffen.

Der Wiederherstellungs-Assistent ist gebaut (vier Schritte, Vorabpruefung als
eigener Schritt, die drei Huerden vor dem Ueberschreiben sichtbar umgesetzt),
aber noch nicht in eine Seite eingebunden.

Drei Lint-Befunde behoben, alle dieselbe Sorte wie in Phase 8 und 12:
setState im Effektkoerper und ein Schreibzugriff auf eine Referenz waehrend des
Renderns. Der Bestaetigungsdialog haelt seinen Zustand jetzt im Portalinhalt —
beim Schliessen verschwindet er von selbst, ein Zuruecksetzen im Effekt
entfaellt, und die Huerde steht beim naechsten Oeffnen wieder.

Die noch nicht umgebauten Seiten behalten vorerst das alte Stylesheet. Es faellt
weg, sobald die letzte umgebaut ist.

69 Tests gruen, tsc sauber, eslint ohne Warnung, Bau 373 KB (115 KB gzip).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:25:42 +02:00

61 lines
1.9 KiB
JSON

{
"name": "@syncova/web",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Syncova Web UI - Verwaltungsoberflaeche der Backup- und Recovery-Plattform",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"preview": "vite preview",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint . --max-warnings 0"
},
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.1.23",
"@radix-ui/react-avatar": "^1.2.6",
"@radix-ui/react-checkbox": "^1.3.11",
"@radix-ui/react-collapsible": "^1.1.20",
"@radix-ui/react-dialog": "^1.1.23",
"@radix-ui/react-dropdown-menu": "^2.1.24",
"@radix-ui/react-label": "^2.1.15",
"@radix-ui/react-popover": "^1.1.23",
"@radix-ui/react-progress": "^1.1.16",
"@radix-ui/react-radio-group": "^1.4.7",
"@radix-ui/react-scroll-area": "^1.2.18",
"@radix-ui/react-select": "^2.3.7",
"@radix-ui/react-separator": "^1.1.15",
"@radix-ui/react-slot": "^1.3.3",
"@radix-ui/react-switch": "^1.3.7",
"@radix-ui/react-tabs": "^1.1.21",
"@radix-ui/react-toast": "^1.2.23",
"@radix-ui/react-tooltip": "^1.2.16",
"@tailwindcss/vite": "^4.3.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.31.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.3"
},
"devDependencies": {
"@eslint/js": "^9.39.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.3",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.0.4",
"eslint": "^9.39.0",
"eslint-plugin-react-hooks": "^7.0.1",
"globals": "^16.5.0",
"jsdom": "^28.0.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.2",
"vite": "^7.1.12",
"vitest": "^3.2.4"
}
}