Commit Graph

4 Commits

Author SHA1 Message Date
Weapie
0134dd6db4 alangu.de fuer die Gebaerdensprach-Einbindung freigeben
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 1m33s
Der Player wird als iframe eingebunden, aber nicht als rohes HTML aus dem
Textfeld: Die Anwendung setzt die Attribute, im Admin steht nur die
Adresse. Damit laesst sich ueber das Feld nichts anderes einschleusen.

Freigegeben ist alangu.de samt Unterdomains, sonst nichts. Die Pruefung
haengt am Hostnamen, nicht an einem Textvergleich - getestet mit
boese-alangu.de.angreifer.example und evil.example/?a=alangu.de, beide
werden abgewiesen, ebenso http statt https.

Vom uebergebenen Einbettungscode weggelassen: accelerometer und
gyroscope. Ein Videoplayer braucht keine Bewegungssensoren.

Ausserdem: Die Gebaerdensprach-Seite erscheint jetzt auch ohne Text,
wenn eine Videoadresse hinterlegt ist - dort ist das Video der Inhalt.
Fusszeile und Seite entscheiden das ueber dieselbe Funktion, sonst gaebe
es eine erreichbare Seite ohne Link.

Geprueft am echten Player: laedt mit HTTP 200 samt CSS, JS und hls.js,
axe-core meldet in hell und dunkel keine Verstoesse, der Rahmen ist per
Tastatur erreichbar, und die Fusszeile verlinkt die Seite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 16:28:41 +02:00
Weapie
5aa8880190 Gebaerdensprach-Video ermoeglichen und Erklaerung anpassen
Ein DGS-Video liess sich bisher gar nicht einbinden: Der Markdown-
Prozessor laeuft mit Sanitizing, und remark reicht rohes HTML dann von
vornherein nicht durch - <video> kam als leeres <p> heraus. Eine
erweiterte Freigabeliste allein half deshalb nicht.

Statt rohes HTML fuer alle Textfelder zu oeffnen - auch fuer die 121
Erklaerungen - bekommt die Gebaerdensprach-Seite zwei eigene Felder fuer
Video- und Untertiteladresse. Ausgegeben wird ein natives <video
controls> mit <track kind="captions"> und Bildunterschrift.

Adressen werden zweimal geprueft, beim Speichern und vor der Ausgabe:
zugelassen sind nur der eigene Server und https. javascript:, data:,
protokollrelative und einfache http-Adressen werden abgewiesen. iframe
bleibt bewusst gesperrt - eine YouTube-Einbindung wuerde Besucherdaten
an Dritte uebertragen.

Erklaerung zur Barrierefreiheit entsprechend gekuerzt: Die beiden
Luecken nach § 4 BITV 2.0 entfallen, es bleibt die ungepruefte
Druckansicht.

Geprueft: Video wird mit Untertitelspur ausgeliefert und ist per Tastatur
erreichbar, axe-core meldet auf beiden neuen Seiten in hell und dunkel
keine Verstoesse, Adresspruefung weist alle acht Testfaelle korrekt zu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 16:18:09 +02:00
Weapie
3633e8a4cf Responsiv machen und Barrierefreiheit nach WCAG 2.1 AA herstellen
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 1m33s
Rechtsrahmen: § 13 Abs. 3 LBGG SH i. V. m. §§ 3 und 4 BITV 2.0. Eine
Erklaerung "nicht barrierefrei" ersetzt die Herstellungspflicht nicht,
sie dokumentiert den Stand nur voruebergehend.

Farben, alle Werte gegen die WCAG-Formel nachgerechnet:
- Sekundaertext 4.40:1 auf muted-Flaechen -> 4.55:1
- Rahmen von Eingabefeldern 1.24:1 -> 3:1 (WCAG 1.4.11); dekorative
  Trenner bleiben unveraendert
- Badge-Farben scheiterten auf der eigenen 10-Prozent-Flaeche
  (brand 4.20, success 4.18, destructive 3.88) -> jeweils ueber 4.5
- Warnfarbe im Admin 3.11:1 -> amber-700 mit 4.90:1

Fokus war faktisch unsichtbar: Der Ring wurde durchgaengig mit halber
Deckkraft gezeichnet (ring-ring/50), effektiv rund 1.5:1. Jetzt volle
Deckkraft in Markenfarbe, 12 Dateien betroffen.

Weiter: Sprungmarke zum Inhalt auf allen Seiten, Suchfelder beschriftet,
Druck-Schaltflaechen hatten als reine Icon-Buttons gar keinen
zugaenglichen Namen, Liste als echte Liste ausgezeichnet, doppelter Link
je Zeile entfernt, Trefferzahl als Live-Region.

Responsiv: Aussenabstaende und Kopfzeilen ab 320 Pixel, Listenzeilen
brechen um.

Neu nach § 4 BITV 2.0: Seiten fuer Leichte Sprache und Gebaerdensprache,
im Admin pflegbar. Leer gelassen und damit noch nicht online - die
Inhalte kommen vom Amt. In der Erklaerung als bekannte Luecke benannt.

Geprueft mit axe-core (WCAG 2.1 A und AA) ueber alle oeffentlichen Seiten
und den Adminbereich, hell und dunkel, dazu Tastaturbedienung, 200
Prozent Vergroesserung und 320 Pixel Breite: keine Verstoesse, kein
waagerechter Ueberlauf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:44:30 +02:00
61c4998a79 Datenschutzerklärungen veröffentlichungsreif machen
All checks were successful
Container-Image bauen und veröffentlichen / build-and-push (push) Successful in 1m23s
Die öffentliche API gab bei ?admin=true alle Datensätze heraus, auch die
nicht veröffentlichten: von 117 Erklärungen waren 112 Entwürfe, die jeder
Besucher abrufen konnte. Der Parameter setzt jetzt eine Admin-Sitzung
voraus, sonst kommt die öffentliche Liste. Der Einzelabruf behandelt
Entwürfe wie nicht vorhanden, damit sich über die fortlaufende ID nicht
abklopfen lässt, welche Datensätze existieren.

Markdown wurde mit sanitize: false gerendert und per
dangerouslySetInnerHTML eingesetzt. Das Standard-Schema lässt jetzt
Überschriften, Listen, Tabellen und http(s)/mailto-Links durch und
entfernt Skripte, Event-Attribute, eingebettete Rahmen und
javascript:-Ziele. Der Titel in der Druckfassung war an drei Stellen
unmaskiert.

Standardtexte
- Zehn Bausteine, die für alle Erklärungen gelten, werden einmal zentral
  gepflegt. In der Erklärung steht nur eine Abweichung; ein leeres Feld
  bedeutet "folgt dem Standard". Ein Wechsel in der Amtsleitung wirkt
  damit sofort auf alle Erklärungen, die nicht bewusst abweichen.
- Die Migration übernimmt den häufigsten Bestandswert als Standard und
  setzt übereinstimmende Felder auf NULL. Von 117 Erklärungen folgen
  danach 116 dem Standard, eine weicht ab (Online-Verfahren mit ZIT-SH
  als zusätzlichem Verantwortlichen).

Pflichtangaben nach Art. 13/14 DSGVO
- Neue Felder für Drittlandübermittlung (Art. 13 Abs. 1 lit. f),
  automatisierte Entscheidungsfindung (Art. 13 Abs. 2 lit. f),
  Datenkategorien (Art. 14 Abs. 1 lit. d) und berechtigte Interessen
  (Art. 13 Abs. 1 lit. d). Auf die ersten beiden muss auch dann
  hingewiesen werden, wenn es sie nicht gibt, deshalb sind sie
  Standardtexte mit ausdrücklichem "findet nicht statt".
- Der Hinweis auf das Widerspruchsrecht steht nach Art. 21 Abs. 4 in
  einem eigenen, abgesetzten Kasten vor allen Abschnitten, nicht als
  Zeile im Fließtext der Betroffenenrechte.
- Zweck, Rechtsgrundlage und Speicherdauer sind Pflicht. Geprüft wird
  beim Veröffentlichen, nicht beim Speichern: Ein Entwurf darf
  unvollständig sein, eine öffentlich sichtbare Erklärung nicht. So
  bleiben Bestandsdaten bearbeitbar, ohne dass die Anwendung Angaben
  erfindet, die nur die Fachabteilung kennt. Die Admin-Übersicht
  markiert unvollständige Erklärungen und nennt die fehlenden Angaben.

Öffentliche Seiten
- Jede Erklärung hat eine dauerhafte Adresse /erklaerung/<bezeichner>,
  serverseitig gerendert, zum Verlinken aus Antragsformularen. Der
  Bezeichner wird aus dem Titel abgeleitet und bleibt beim Bearbeiten
  erhalten, solange der Titel gleich bleibt. Entwürfe liefern 404.
- Impressum, Datenschutzerklärung des Portals und Erklärung zur
  Barrierefreiheit werden im Admin als Markdown gepflegt und in der
  Fußzeile verlinkt. Die Fußzeile rendert serverseitig, weil das
  Impressum ohne JavaScript erreichbar sein muss. Ein leerer Text nimmt
  die Seite vom Netz, statt eine leere Seite auszuliefern.
- Die Übersicht nutzt echte Links statt Klick-Handler und wird
  serverseitig vorbefüllt.

APP_COMPANY_NAME ersetzt den Namen der Anwendung in Kopf- und Fußzeile,
Seitentiteln, Anmeldeseite, Druckfassung und Startmeldung des
Containers. Der Wert wird zur Laufzeit gelesen, ein Neubau des Images
ist zum Umbenennen nicht nötig.

Getestet gegen die 117 Bestandsdatensätze: Migrationen angewendet, der
angezeigte Text blieb bei allen 117 x 7 Baustein-Feldern identisch. Alle
117 Bezeichner sind eindeutig und stimmen mit lib/slug.ts überein
(SQLites LOWER() kennt nur ASCII, Großumlaute werden deshalb vorher
ersetzt). ?admin=true liefert ohne Anmeldung 5 statt 117 Datensätze,
Entwürfe 404. Über die API mit Anmeldung geprüft: unvollständig als
Entwurf wird angelegt, dieselben Angaben mit isPublic abgelehnt, ebenso
fehlende Datenkategorien bei angegebener Herkunft. Ohne
APP_COMPANY_NAME erscheint "Syncova Policies", mit gesetztem Wert kein
einziges Vorkommen mehr.

Die Änderungen liegen in einem Commit, weil Schema, API-Routen und
Formulare von allen Teilen berührt werden und eine thematische Aufteilung
nicht lauffähige Zwischenstände ergäbe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:35:05 +02:00