77e61dc2b3
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| b50ad2b9bc |
Sitzung ueberlebt Neuladen, Umlaute, Fehlergrenze
**Sitzung.** Die Tokens lagen nur im Arbeitsspeicher — jedes Neuladen warf den
Betreiber auf die Anmeldemaske. Das war die sicherste Variante und praktisch
unbrauchbar; mitten in einer Stoerung ist es kein Sicherheitsgewinn, sondern ein
Hindernis. Jetzt `sessionStorage` (nicht `localStorage`: stirbt mit dem Tab),
begrenzt durch zwei Uhren:
- **Harte Obergrenze** von 30 Minuten ab Anmeldung, durch keine Interaktion
verschiebbar. Sonst waere "30 Minuten" keine Zusage.
- **Untaetigkeitsgrenze** von 30 Minuten.
- Der sofortige serverseitige Widerruf bleibt die eigentliche Absicherung — die
Tokens sind opak, kein JWT, und genau dafuer wurden sie gewaehlt.
Dazu die Sitzungsuhr oben rechts neben "Abmelden", unter fuenf Minuten
auffaellig. Umgesetzt mit `useSyncExternalStore`: Die Restzeit haengt an der Uhr
und am Speicher, also an zwei Dingen ausserhalb von React. Sie beim Rendern
auszurechnen waere ein unreiner Aufruf, sie in einem Effekt zu setzen eine
zweite Renderrunde je Sekunde — beides hat der Linter gemeldet.
Sechs Tests halten die Grenzen fest, zwei davon durch Mutation als fangend
bestaetigt (Obergrenze mitverschieben schlaegt fehl).
**Fehlergrenze.** Ein Fehler in einer Komponente riss bisher den gesamten Baum
ab; uebrig blieb eine leere Seite — im dunklen Thema ein schwarzer Bildschirm
ohne jeden Hinweis. Die Grenze sitzt **um den Inhalt**: Menue und Kopfzeile
bleiben stehen, der Fehlertext ist lesbar und kopierbar.
**Umlaute.** Die Oberflaeche schrieb durchgehend ae/oe/ue/ss. Jetzt aeoeuess.
Dabei ein selbst verursachter Schaden, gefunden und behoben: Eine Regel
"ue → ü" ist falsch, weil die Buchstabenfolge nicht immer ein Umlaut ist. Sie
machte aus "Quelle" ein "Qülle", aus "neue" ein "neü", aus "aktuell" ein
"aktüll", aus "Dauer" ein "Daür". Die Abbildung laeuft jetzt ueber eine
gepruefte Wortliste mit Ausschluss englischer Bezeichner (`value`, `message`,
`session`, `queued`, `true`); die 23 zerstoerten Woerter sind einzeln
zurueckgesetzt. Ein alter Tippfehler ("geprueter") ist dabei mit aufgefallen.
82 Tests gruen, tsc sauber, eslint ohne Warnung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|||
| 6e23696fcb |
Weboberflaeche: letzte Seiten auf das Design-System gezogen
Damit gibt es nur noch ein Stylesheet. Uebersicht, Meldungen, Kennzahlen, Berichte, Security Center, Wiederherstellungspunkte, Anmeldung, Backup-Assistent und Gesundheitsanzeige nutzten noch das alte — sie funktionierten, sahen aber anders aus als der Rest. Der Backup-Assistent wurde als **Klassenabbildung** umgestellt, nicht neu geschrieben: Seine Logik ist geprueft und richtig; eine Neufassung haette 500 Zeilen Verhalten ohne Not angefasst. Die elf Tests des Assistenten pruefen Verhalten und blieben unveraendert gueltig. Entfernt, weil ersetzt und nirgends mehr verwendet: JobsPanel, StatusIndicator, PageState, App.css, tokens.css und vier weitere Stylesheets. Das ausgelieferte CSS faellt von 54 auf 30 KB. Drei Funde beim Umbau, alle von Tests aufgedeckt: - **`describeApiError` warf die genauere Servermeldung weg.** Sie ersetzte sie durch den allgemeinen Satz aus der Codetabelle. Ein `SERVICE_UNAVAILABLE` mit der Meldung "Fuer diesen Bericht ist keine Sicherheitspruefung eingerichtet." wurde zu "Der Dienst ist derzeit nicht vollstaendig verfuegbar" — der Betreiber haette den Fehler bei seiner Anlage gesucht statt bei der Einrichtung dieses einen Berichts. Jetzt hat die Servermeldung Vorrang; die Tabelle springt nur ein, wenn keine mitkommt. - **Einem Fehler nach einer Handlung fehlte `role="alert"`.** Ein Screenreader haette ihn nicht angesagt. `Callout` nimmt jetzt eine Rolle entgegen; Standard bleibt `note`, weil die meisten Hinweise schon beim Oeffnen dastehen. - **Zwei Statusbeschriftungen wichen von den etablierten ab** (`Gesund` statt `Fehlerfrei`, `Nicht verbunden` statt `Nicht erreichbar`). Die etablierten gewinnen — sie stehen in Tests fest und sind treffender. Dazu zwei kleinere Korrekturen: Die Gesundheitsanzeige hing kurzzeitig in der Uebersicht und verband damit zwei Ladewege, die nichts miteinander zu tun haben; sie steht jetzt wieder daneben. Und ein frueherer Regex hatte `(row) => void | undefined` erzeugt — gemeint war eine optionale Eigenschaft, geschrieben stand "gibt void oder undefined zurueck". Nachgewiesen gegen Debian 12 mit nginx: alle 18 Seiten liefern 200, das Design-System steckt im ausgelieferten CSS samt Dark-Mode-Regeln, und vom alten Stylesheet ist kein Klassenname mehr darin. 76 Tests gruen, tsc sauber, eslint ohne Warnung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| b3f0a99243 |
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> |