diff --git a/CLAUDE.md b/CLAUDE.md index 17c0ee9..2d3776d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ Dieses Dokument beschreibt Architektur, Konventionen und wichtige Implementierun - **Einstiegspunkt:** `index.html` - **Styles:** `css/styles.css` (Layout & Komponenten) + `css/tokens.css` (Design-Tokens) - **Logik:** `js/app.js` (eine einzige Datei) -- **Aktuelle Version:** `v66` (Script-Tag: ` + ``` ### Externe Aufrufe @@ -66,7 +66,7 @@ Die App hat keinen Build-Schritt – getestet wird **die ausgelieferte App**, al ```bash npm install # nur Dev: @playwright/test (exakt gepinnt) npx playwright install chromium # einmalig -npm test # 376 Tests, ~150 s +npm test # 379 Tests, ~150 s npm run test:ui # interaktiver Modus ``` @@ -509,13 +509,21 @@ Alles Übrige – Portal, Harvesting, DCAT-AP.de, Lizenzen, Clearing, Datenschut --- +### Die DatenGraf-Brücke (`#graf-bridge`) + +Eigener Startseiten-Abschnitt **unterhalb der Modul-Karten** (`.graf-bridge`/`.graf-bridge-panel`, `.home-only`). Bis v66 war das eine graue Zeile direkt unter dem Hero-Button („Schon kartiert? DatenGraf-CSV importieren"). Sie richtet sich an eine Minderheit, stand aber an der prominentesten Stelle der Seite – und wer schon kartiert hat, sucht dort gar nicht mehr nach dem Einstieg. + +Der Abschnitt erklärt jetzt auch, **was** die Brücke leistet (`GRAF_COLUMNS` 1:1, Vorbelegung von `accessRights` und `accrualPeriodicity` aus der Kartierung, nachzuerfassen bleiben Lizenz, Schlagwörter und Adresse) und bietet zwei Wege: `#graf-bridge-import` → **direkt** `pickAndImport()` (nicht über `openInventoryModal()` – wer kartiert hat, braucht das Erklär-Modal nicht mehr) und einen Verweis auf DatenGraf für alle, die noch nicht kartiert haben. + ### Hero je Ansicht (`.view-hero`, `.hero-panel`) Jede Unterseite trägt ihren Kopf in einem eigenen weißen Container; die Startseite ebenso (`.hero-panel`). Vorher folgten Badge, Titel, Untertitel, Aktionsbutton und Einleitungstext ohne Abstand auf die Topbar – fünf Bausteine in fünf Formaten direkt untereinander. - **`.view-hero`** umschließt `.inventory-header` **und** den direkt folgenden `.inventory-hint`. Der Hinweis verliert darin seinen eigenen Kasten (sonst stünde Weiß in Weiß) und wird nur durch eine Linie abgesetzt. - **Die Aktionsbuttons bekommen im Hero eine eigene Zeile** (`flex-direction: column`). Nebeneinander hingen sie je nach Länge des Untertitels auf halber Höhe – jede Unterseite sah anders aus. Der Rhythmus ist jetzt überall: Badge → Titel → Untertitel → Aktionen → Einleitung. -- **Der Hero der Startseite trägt seit v66 nur noch den Einstieg**: Logo, Titel, Einleitung, Aktion und die Import-Zeile. Die vier Schritt-Chips und die Local-First-Zusage stehen darunter in einem **eigenen Abschnitt** (`#hero-steps`, `.steps-section`/`.steps-panel`, Überschrift als `

` – je Ansicht bleibt genau eine `

`). Vorher waren es sieben Bausteine in einem Container, die einander die Aufmerksamkeit nahmen. +- **Der Hero der Startseite trägt nur noch den Einstieg**: Logo, Marke, Claim, Einleitung und zwei Aktionen. Die vier Schritt-Chips und die Local-First-Zusage stehen seit v66 in einem **eigenen Abschnitt** (`#hero-steps`, `.steps-section`/`.steps-panel`, Überschrift als `

` – je Ansicht bleibt genau eine `

`), die DatenGraf-Zeile seit v67 in einem weiteren (`#graf-bridge`, siehe unten). Vorher waren es sieben Bausteine in einem Container, die einander die Aufmerksamkeit nahmen. +- **Marke und Claim sind seit v67 getrennt ausgezeichnet.** Die `

` enthält `.hero-brand` (46 px, `--c-accent`) und darunter `.hero-claim` (21 px, `--c-text`, abgesetzt durch eine dünne Linie) – vorher stand beides als *ein* Satz mit Doppelpunkt in einer Farbe und einer Größe, und „DatenLotse" ging darin unter. Ein Test **misst** den Unterschied (Schriftgröße und Farbe), statt ihn über Klassennamen zu behaupten; eine reine Klassenprüfung bliebe grün, wenn beide wieder gleich aussähen. +- **Zwei Einstiege im Hero** (`.hero-actions`): `#hero-kompass-btn` („Sofort loslegen" → `navTo('kompass')`) und `#hero-tour-btn` („Rundgang starten" → `startTour()`). Der Rundgang lag bis v66 nur im wegklickbaren Hinweis und in der Seitenleiste – wer sich erst orientieren wollte, fand im Hero keinen Weg dorthin. - **Titel und Einleitung benennen den Zweck.** Bis v65 stand dort „Datenmanagement verstehen, aufbauen, vertiefen" – wofür das Werkzeug gebaut ist, nämlich Daten zu **öffnen**, kam weder in der Überschrift noch im Einleitungssatz vor. Beides sagt es jetzt ausdrücklich (und die Meta-Beschreibungen ebenso); ein Test hält Titel *und* Einleitungssatz fest, weil eine Überschrift ohne den Satz darunter nur die halbe Aussage wäre. - **Die statischen Seiten teilen den Kopf** (`.static-hero`, erzeugt in `tools/generate-wissen.js`) – und seit v66 auch den **Fuß**: der Generator schrieb `class="footer"`, wofür es gar keine Regel gibt, die Linkzeile stand also ungestylt am unteren Rand. Es ist dieselbe Leiste wie in der App, also dieselbe Klasse `.site-footer` samt Marke, Trennern und GitHub-Zeichen. Ein Test prüft je Seite Grundfarbe, obere Linie und die Marke.: Brotkrumen, Titel und Lead stehen im selben weißen Container. Sie sind aus dem Fuß und aus dem Wissens-Center verlinkt und sollen wie dasselbe Produkt aussehen, nicht wie ein angehängtes Dokument. Ein Test prüft den Container je Seite. - Der Seitentitel bleibt das **einzige `

`** der Ansicht (ein Test prüft genau eine sichtbare `h1` je View) – der Hero ist ein Container, keine zusätzliche Überschrift. @@ -642,6 +650,8 @@ Nach Änderungen an `app.js` `?v=N` im Script-Tag **und** die `v{N}` im Footer e | Prüfwerkzeuge & Normtexte | `PRUEF_WERKZEUGE`, `renderWissen()` | `#wissen-sec-tools`, `#wissen-tools` | | Hero je Ansicht | `.view-hero` (App), `.hero-panel` (Start), `.static-hero` (erzeugte Seiten) | `.inventory-header`, `.inventory-hint`, `.static-crumbs` | | Startseite: Hero + Schritte getrennt | `showView()` über `.home-only` | `#hero`, `#hero-steps`, `.steps-panel`, `.steps-title`, `.hero-steps`, `.hero-trust` | +| Hero: Marke, Claim, zwei Einstiege | `startTour()`, `navTo('kompass')` | `.hero-brand`, `.hero-claim`, `.hero-actions`, `#hero-kompass-btn`, `#hero-tour-btn` | +| DatenGraf-Brücke | `pickAndImport()` | `#graf-bridge`, `#graf-bridge-import`, `.graf-bridge-panel`, `.graf-bridge-text` | | Statische Seiten & Datenschutz | `tools/generate-wissen.js`: `seite()`, `seiten()`, `eigenstaendigeSeiten()` | `/wissen/…`, `/datenschutz/`, `sitemap.xml` | | Anonyme Seitenzählung | GoatCounter – einziger externer Aufruf, im Test abgeklemmt | `gc.zgo.at`, `datenlotse.goatcounter.com` | | Persistenz | `saveState()`, `loadState()`, `clearState()` | `datenlotse_*`, `#reset-data-btn` | @@ -686,6 +696,7 @@ Nach Änderungen an `app.js` `?v=N` im Script-Tag **und** die `v{N}` im Footer e | v16 | Daten-Kompass (Herzstück) – eigene View + Hero-Haupt-CTA (Topbar-„Loslegen" zeigt ebenfalls darauf): ausführliche Open-Data-Reifegrad-Checkliste nach ODRA / EU Open Data Maturity / 5-Sterne / DCAT-AP.de / DSGVO·FAIR (7 Dimensionen, Quellenangaben), Status je Item mit Score & Ampel, Vorbelegung aus dem App-Stand, adaptive Sprünge in die passenden Bausteine, Persistenz (`datenlotse_kompass`) und PDF-Export; leeres „Loslegen"-Platzhalter-Modal entfernt | | v17 | Weiterer Ausbau (1/4) – Inventar Suche, Filter & Sortierung: `renderInventory()` in `renderInventory()` + `renderInventoryBody()` aufgeteilt; `.inv-controls` (Volltextsuche + Schutzbedarf-/Clearing-Ampel-Filter + Sortierung Titel/Vollständigkeit) über `invFilter`-State und `filteredInventory()`; der echte `idx` wird durch den Filter mitgeführt, sodass Editieren über gefilterten Teilmengen weiterhin den richtigen Datensatz trifft; Live-Meta „X von Y" + Empty-State | | v18 | Weiterer Ausbau (2/4) – Pseudonymisierung erweitert: drei neue Muster (Sozialversicherungsnummer, Steuer-ID *kontextgetriggert*, Kfz-Kennzeichen), Aktenzeichen um Geschäftszeichen/„Gz." und buchstabenhaltige Kerne erweitert, zusätzliche Geburtsdatum-Trigger („Geburtsdatum"/„Geburtstag"); Mapping-Export als CSV (`buildPseudoMappingCSV` + Button im Mapping-Kopf); Demo-Text und Grenzen-Liste aktualisiert; verifiziert auf Determinismus, Platzhalter-Konsistenz und Null-Falschtreffer auf neutralem Verwaltungstext | +| v67 | **Der Einstieg sagte nicht, wer hier spricht – und der Hauptknopf nur die Hälfte.** Drei gemeldete Punkte, alle am ersten Bildschirm. **(1)** Titel und Aussage standen als *ein* Satz mit Doppelpunkt in einer Farbe und einer Größe; die Marke „DatenLotse" ging in ihrer eigenen Überschrift unter. Jetzt trägt sie 46 px in der Akzentfarbe, der Claim steht kleiner und in der Textfarbe darunter, durch eine dünne Linie abgesetzt. Der Test **misst** Größe und Farbe – eine Prüfung auf Klassennamen bliebe grün, wenn beide wieder gleich aussähen, und genau das ist die Regression, um die es geht. **(2)** Der Hero bot nur „Daten-Kompass starten". Wer sich erst orientieren wollte, fand dort keinen Weg zum Rundgang – der lag im wegklickbaren Hinweis und in der Seitenleiste, also genau an den zwei Stellen, an denen ein Erstnutzer nicht sucht. Jetzt stehen beide Einstiege nebeneinander: „Sofort loslegen" und „Rundgang starten". **(3)** Die DatenGraf-Zeile stand als graues Kleingedrucktes unter dem Hauptknopf – an der prominentesten Stelle der Seite, für eine Minderheit, und ohne zu erklären, was die Brücke eigentlich leistet. Sie ist jetzt ein eigener Abschnitt **unterhalb der Modul-Karten** mit Erklärung (Schema 1:1, Vorbelegung aus der Kartierung, was nachzuerfassen bleibt) und zwei Wegen – Import direkt in den Dateidialog, ohne das Erklär-Modal, das hier niemand mehr braucht, und ein Verweis auf DatenGraf für alle, die noch nicht kartiert haben. 3 neue Tests, drei Mutationen einzeln geprüft. | | v66 | **Ein Darstellungs-Durchgang – und dreimal dieselbe Lehre: eine Regel, die nicht greift, fällt niemandem auf.** Der auffälligste Fund kam aus der Benutzung: im Rundgang zeichnete das hervorgehobene Zielelement **in die Karte hinein** – bei Schritt 3 stand der Fragebogentext über Titel und Knöpfen, und Klicks dort trafen den Fragebogen statt „Weiter". Ursache ist eine Eigenheit von `position: fixed`: der Layer bildet einen **eigenen Stapelkontext**, die Karte darin kann dessen `z-index` also nie überbieten, egal welchen Wert man ihr gibt. Ein höherer Wert an der Karte wäre wirkungslos geblieben – das Abdunkeln musste **aus dem Layer heraus** (jetzt `body.tour-on::before`), damit die Reihenfolge Abdunkeln < Hervorhebung < Karte überhaupt darstellbar ist. Zweiter Fund derselben Art: der Wissens-Generator schrieb ` @@ -1118,7 +1139,7 @@

Lizenz-Wegweiser

- +