5 Commits
Author SHA1 Message Date
Harlekin e0b03ea336 Gedankenstriche durch Bindestriche ersetzt
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00
Harlekin e21e478fd1 Vorlagen-JSON abweisen statt still verwerfen, Platzhalter ohne Prototypkette
Durchgesehen, was mit Text passiert, der nicht als Text ankommt. Die Grundlage
war schon in Ordnung: genau ein dangerouslySetInnerHTML mit einer Konstanten,
kein eval, kein $queryRawUnsafe, keine Weiterleitung aus einem Adressparameter,
Dateien mit nosniff und sandbox-CSP als Anhang statt inline.

Drei Ränder waren offen.

**Vorlagen.** Das zod-Schema hatte einen festen Satz Feldarten und speicherte
das Geprüfte, verwarf unbekannte Schlüssel aber stillschweigend. Mit
strictObject fällt ein `typ` statt `type` auf, statt eine Vorlage zu
hinterlassen, die nicht tut, was dasteht.

**Platzhalter lasen über die Prototypkette.** Beim Durchprobieren gefunden:
`constructor` ist ein gültiger Feldschlüssel, die Schlüsselregel erlaubt
Kleinbuchstaben. Ein Baustein mit {{constructor}} bekam den Quelltext der
geerbten Funktion in den Text geschrieben - kein ausgeführter Code, aber
Innenleben in einem Dokument, das weitergereicht wird. Jetzt Object.hasOwn.

**Farbmarken aus der Datenbank** landen als Name einer CSS-Variablen in einem
style-Attribut. Heute setzt das nur der Seed, und eine zweite Deklaration liesse
sich darüber ohnehin nicht einschleusen - aber der Kommentar sagt „im
Adminbereich pflegbar", und was aus der Datenbank in ein Stilattribut geht,
wird geprüft.

Dreizehn Prüfungen, die es mit echten Versuchen probieren. Bösartiger Text
bleibt dabei ausdrücklich erlaubt: eine Feldbeschriftung darf
<script>alert(1)</script> heissen und sieht dann genau so aus. Verboten ist,
dass daraus ein Element wird.

Nebenbei: eine Vorlagenänderung stand im Zugriffsprotokoll als roles.update.
2026-09-03 23:52:53 +02:00
Harlekin 9c24858d75 Feste Spaltenbreiten für jede Listenzeile
„Keine Textzentrierung" - die Beobachtung stimmte an einundzwanzig Stellen, und
die Ursache war überall dieselbe: die Zeilen waren Flex-Behälter, in denen
jedes Element so breit war wie sein Inhalt. Damit fing der Titel in jeder Zeile
woanders an, und die Stempelmarken hatten nur rechts eine gemeinsame Kante. Bei
„ETHIK" und „WS" untereinander sieht man es sofort.

Die Breiten stehen jetzt einmal in globals.css - record-key, record-label,
record-title, record-meta, stamp-mark - und sind über Variablen je Liste
anpassbar: eine Liste von Abteilungskürzeln braucht keine vierzehn Zeichen,
eine Liste von Aktenzeichen schon.

Zwei Dinge, die dabei mehr sind als Kosmetik:

Eine Spalte wird auch reserviert, wenn sie leer ist. Vorher hing der Dienstgrad
an einer Bedingung, und bei einer Person ohne Rang rutschte alles Folgende nach
links.

Was keine Kennung ist, gehört nicht in die Kennungsspalte. In „Zuletzt
geöffnet" stand der Name einer Person dort, wo sonst das Aktenzeichen steht: in
Mono, abgeschnitten, und der Dienstgrad wanderte an die Stelle des Titels. Für
eine Person ist der Name der Titel.

Die Stempelmarke ist überall gleich breit; ein zu langer Name wird gekürzt, die
Stufenziffer bleibt stehen - sie ist die eigentliche Auskunft. Unter 40 rem
fallen die festen Breiten weg, sonst liefen sie über.

Nachgesehen im Browser mit dem gebauten CSS, Fallakten, Abteilungen, Zuletzt
geöffnet und Beteiligte.
2026-09-03 22:53:07 +02:00
Harlekin c6401aeb4d Rollenstruktur und englische Fachbegriffe festgelegt
Der Discord-Server hat drei Sorten Rollen, die Dokumente kannten nur eine:
Zugehörigkeit (AfiS, Personalabteilung) als Türsteher, Rangrollen für die
Rechte, Zugangsrollen für die Freigabestufe. Das bestehende RoleMapping trägt
das fast, es fehlt nur der Türsteher. Die beiden Felder dafür kommen mit
Phase 1, die Struktur ist in docs/13-entscheidungen.md festgehalten.

Die Freigabestufen heißen jetzt wie die Zugangsrollen: Unclassified,
Restricted Access, Confidential Access, Sensitive Access, Critical Operations,
Executive Oversight. Fachbegriffe der Domäne bleiben englisch, auch in einer
deutschen Oberfläche.

Die Bezeichnungen sind damit Daten in ClearanceLevelConfig, nicht mehr
Oberflächentext in lib/i18n/de.ts: sie sind im Adminbereich änderbar, und was
der Leiter ändern kann, gehört nicht in eine Übersetzungsdatei. StampMark
bekommt den Namen hereingereicht.

Vier neue Tests prüfen den Zustand, den der Seed herstellt, gegen die
Datenbank statt gegen eine Konstante im Code.
2026-09-01 18:50:07 +02:00
Harlekin ade977538d Web-Anwendung: Design-Tokens, Texte, Gesundheitsendpunkt
Design-Tokens aus docs/10-design-system.md als CSS-Variablen: Grundpalette,
die sechs Klassifizierungsfarben, Eckenradius durchgehend 2 px, keine Schatten
ausser dem Fokusring. Der Schwärzungsbalken mit dem einmaligen Durchwischen
respektiert prefers-reduced-motion. Vier Tests halten die Tokens gegen das
Dokument.

IBM Plex selbst gehostet als woff2, latin und latin-ext getrennt über
unicode-range, font-display: swap, immutable-Cache.

Alle Oberflächentexte in lib/i18n/de.ts. Ein Test durchsucht app/ und
components/ nach Umlauten im JSX und schlägt fehl, wenn dort deutscher Text
steht. Er hat beim ersten Lauf gleich einen Verstoss gefunden.

/api/health prüft Datenbank, Discord-Gateway und ClamAV. Die Gesamtbewertung
fällt nur auf "down", wenn die Datenbank weg ist: die anderen Dienste haben
eigene Healthchecks im Stack, und ein ausgefallener Virenscanner soll nicht
den Web-Container als tot markieren.

Strikte CSP mit Nonce, kein unsafe-inline für Skripte. Die erste Route liegt
bei 100 kB JavaScript nach Kompression, Budget sind 120 kB.
2026-09-01 00:01:41 +02:00