feat: das Dashboard -- und die eine Regel steht im Code, nicht im Vorsatz

Schritt 4. React 18, TypeScript, Vite 5, Tailwind 4 (CSS-first), Lucide,
Zustand; kein Konsta. Quelle in server/ui, Build nach server/web (gitignored),
im Abbild von einer eigenen Docker-Stufe gebaut.

JEDER KNOPF GIBT RUECKMELDUNG -- und zwar erzwungen, nicht vorgenommen:

- api.ts haelt den EINZIGEN fetch und GENAU EINE Fehlerklasse. Der
  Fivemanage-Fehler war, zwei zu haben: geworfen wurde `new Error`, geprueft
  auf `instanceof ApiError`, und damit verschwand jeder Fehlschlag lautlos.
- store.ts haelt run(): Aktion rein, Erfolgstext rein, und es meldet bei
  Erfolg diesen und bei Fehlschlag den Text DES DIENSTES. Wer darueber geht,
  kann keinen stillen Knopf bauen.
- Jeder wartende Knopf ist gesperrt und zeigt einen Kreisel. Der zweite Klick
  eine Sekunde spaeter war der Weg zu neunzehn gleichnamigen Organisationen.
- Fehlermeldungen bleiben stehen, bis jemand sie wegklickt. Ein Fehler, der
  von allein verschwindet, ist einer, den niemand gelesen hat.

@vitejs/plugin-react ist auf ^4 festgenagelt: die 6 verlangt vite ^8. In den
peerDependencies nachgesehen -- Vite 5.4.21 liegt in der Schnittmenge von
plugin-react@4 und @tailwindcss/vite@4.

Am laufenden Container nachgemessen: / kommt als text/html, assets/*.js als
text/javascript, *.css als text/css (die MIME-Falle aus Schritt 1 traegt), und
/tokens, /speicher, /konto liefern dieselbe index.html -- die SPA-Rueckfall-
route tut, wofuer sie gebaut wurde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 17:38:38 +02:00
co-authored by Claude Opus 5
parent 65828b526c
commit 6c8ead8e15
22 changed files with 4644 additions and 15 deletions
+69 -11
View File
@@ -338,19 +338,77 @@ wird freigestellt, landet auf der Platte und liegt Sekunden später unter einer
vorhersagbaren Adresse — ohne Fivemanage, ohne PostgreSQL, ohne MinIO, ohne
einen einzigen Handgriff von Hand dazwischen.
### ✅ Fertig — Schritt 4, das Dashboard
Liegt in `server/ui`, gebaut nach `server/web` (gitignored), im Abbild von
einer eigenen Docker-Stufe. React 18, TypeScript, Vite 5, Tailwind 4
(CSS-first), Lucide, Zustand — **kein Konsta**, wie geplant.
Anmeldung · Galerie mit Vorschau, Suche, Mehrfachauswahl, Blättern · Einzel-
und Sammellöschung mit Nachfrage, die die Pfade zeigt · Speicherverbrauch nach
Ordnern · Token-Verwaltung mit Klartext genau einmal · Passwortwechsel.
> **Vite 5 bleibt, aber `@vitejs/plugin-react` ist auf `^4` festgenagelt.**
> Die 6 verlangt `vite ^8`. In den `peerDependencies` nachgesehen, nicht
> geraten: `@tailwindcss/vite@4` nimmt `^5.2 || ^6 || ^7 || ^8`, und
> `plugin-react@4` nimmt `^4.2 || ^5 || ^6 || ^7`. Vite 5.4.21 liegt in beiden
> Schnittmengen.
**Wie die eine Regel durchgesetzt wird, und nicht nur gemeint ist.** In
`api.ts` steht der einzige `fetch` und genau eine Fehlerklasse — der
Fivemanage-Fehler war, zwei zu haben (`new Error` geworfen, `instanceof
ApiError` geprüft, jeder Fehlschlag verschluckt). In `store.ts` steht `run()`:
es nimmt die Aktion und den Erfolgstext, meldet bei Erfolg diesen und bei
Fehlschlag den Text **des Dienstes**. Wer darüber geht, kann keinen stillen
Knopf bauen. Jeder Knopf, der wartet, zeigt einen Kreisel und ist gesperrt —
der zweite Klick eine Sekunde später war der Weg zu neunzehn gleichnamigen
Organisationen.
Nachgemessen am laufenden Container: `/` liefert die Oberfläche als
`text/html`, `assets/*.js` als `text/javascript`, `assets/*.css` als
`text/css` (die MIME-Falle aus Schritt 1 trägt also), und `/tokens`,
`/speicher`, `/konto` geben dieselbe `index.html` zurück — die
SPA-Rückfallroute tut, wofür sie gebaut wurde.
### ⚠️ Der Proxy hält Bilder fest — 30 Minuten lang
**Beim Nachmessen der Zwischenspeicher-Kopfzeilen gefunden, und es trifft
genau den Fotostudio-Ablauf.** NPMs `assets.conf` greift über eine Regex auf
*jede* URL, die auf `.css .js .png .webp …` endet — also auch auf
`/f/vehicles/adder.webp`. Sie setzt `proxy_cache public-cache`,
`proxy_cache_valid any 30m` und wirft unsere Kopfzeilen weg
(`proxy_ignore_headers Cache-Control`, `proxy_hide_header Cache-Control`).
Reproduziert, nicht vermutet:
```
Bild hochladen → abrufen: "ERSTE-FASSUNG"
dieselbe Datei neu → abrufen über NPM: "ERSTE-FASSUNG" ← alt
abrufen am Dienst: "ZWEITE-FASSUNG" ← neu
```
**Ein neu fotografiertes Fahrzeug sieht bis zu 30 Minuten lang aus wie das
alte**, obwohl Upload, Protokoll und Datenbank alle „fertig" sagen. Das ist
die Sorte Fehler, die man drei Ebenen tiefer sucht.
Der Gegenschnipsel gehört in NPM, Proxy Host `fivemanage.d4rkst3r.de`
*Advanced*:
```nginx
# Dateien nicht zwischenspeichern -- sie koennen sich unter derselben
# Adresse aendern. Das ^~ ist der ganze Trick: eine gewoehnliche
# Praefix-Location VERLIERT gegen die Regex aus assets.conf.
location ^~ /f/ {
proxy_cache off;
include conf.d/include/proxy.conf;
}
```
Dass `^~` nötig ist und ein blankes `location /f/` nicht reicht, ist in einem
Wegwerf-nginx nachgemessen: ohne `^~` gewinnt die Regex, mit `^~` das Präfix.
### ⬜ Als Nächstes
**4 · Dashboard.** React 18, TypeScript, Vite 5, Tailwind 4 (CSS-first),
Lucide, Zustand. **Kein Konsta** — das ist für die Handy-Oberfläche richtig,
für ein Dashboard am Monitor nicht.
Anmeldung · Galerie mit Vorschau, Suche, Mehrfachauswahl · Löschen ·
Speicherverbrauch nach Ordnern · Token-Verwaltung, Klartext genau einmal.
> **Die eine Regel:** jeder Knopf gibt Rückmeldung, auch der erfolgreiche.
> Das ist der Fehler, an dem wir bei Fivemanage einen Nachmittag verloren
> haben, und er ist billig zu vermeiden.
**5 · Umzug.** Root-`docker-compose.yml` wird unsere; die Fivemanage-Dateien
wandern nach `legacy/`.