diff --git a/CLAUDE.md b/CLAUDE.md index 4151f3a..bbd4c56 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:** `v68` (Script-Tag: ` + ``` ### Externe Aufrufe @@ -37,6 +37,8 @@ Dass daraus **keine Inhalte** abfließen können, ist kein Zufall, sondern eine > ⚠️ **Die Zusagen im Markup müssen dazu passen.** Hero-Badge, Feature-Karte „Local-First" und die FAQ-Antwort „Verlassen meine Daten den Browser?" sprechen deshalb von *Inhalten*, die im Browser bleiben, und benennen die Zählung ausdrücklich. Die FAQ-Antwort steht **zweimal** in `index.html` – sichtbar und im `FAQPage`-Markup – und muss wörtlich übereinstimmen (ein Test prüft das). +> ⚠️ **Das Ladegewicht-Budget zählt den Zähl-Aufruf NICHT mit.** Bis v68 tat es das – und maß damit das Netz statt das Repo: in der CI ging der Aufruf durch und brachte rund 9 KB mit, im Entwicklungscontainer sperrt die Netzwerkrichtlinie ihn. Derselbe Commit lieferte zwei verschiedene Zahlen, und dieselbe Grenze war einmal eingehalten und einmal gerissen. Gefiltert wird **beim Zählen**, ausdrücklich nicht über `page.route()`: ein Interceptor umgeht den Speicher-Cache, danach lädt `logo.svg` (106 KB) zweimal – einmal für die Topbar, einmal für den Hero – und die Messung ist um genau diesen Betrag falsch. Die Grenze selbst (700 KB) steht seit v45 unverändert. + **Im Test abgeklemmt:** `openApp()` beantwortet die Zähl-Hosts mit einem leeren Skript (`route.fulfill`, nicht `abort` – ein abgebrochener Aufruf schriebe „Failed to load resource" in die Konsole). Sonst schriebe jeder Lauf hunderte Aufrufe in die echte Statistik. **Die statischen Wissensseiten bleiben ohne JavaScript** und damit ohne Zählung – ihre Reichweite steht in der Search Console. `tests/seo.spec.js` prüft weiterhin *null* externe Ressourcen für diese Seiten. @@ -66,7 +68,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 # 379 Tests, ~150 s +npm test # 380 Tests, ~150 s npm run test:ui # interaktiver Modus ``` @@ -88,7 +90,7 @@ npm run test:ui # interaktiver Modus | `tests/risiko.spec.js` | k-Anonymität/l-Diversität gegen Handrechnung, Trenner-Kollision, Normalisierung, Ampelschwellen, Modellfehler (sensibles Merkmal = QI), Tab/ARIA, Übergabe aus der Bereinigung | | `tests/tour.spec.js` | Rundgang: alle Schritte, Zielelemente existieren wirklich, Escape und Pfeiltasten, Schritte ohne Daten bieten den Import an | | `tests/seo.spec.js` | statische Seiten aktuell (`--check`), Metadaten je Seite, `.static-hero`, Sitemap vollständig, Google-Bestätigungsdatei, Datenschutzerklärung ohne JavaScript | -| `tests/assets.spec.js` | Icon-Zuschnitt (CSS-Abgleich, echtes Rendern auf Canvas, `font-display: swap`, keine Brands-Schrift), Ladegewicht-Budget der Startseite | +| `tests/assets.spec.js` | Icon-Zuschnitt (CSS-Abgleich, echtes Rendern auf Canvas, `font-display: swap`, keine Brands-Schrift), Ladegewicht-Budget der Startseite (**ohne** den fremden Zähl-Aufruf, siehe unten) | **Konvention:** Jeder Review-Befund bekommt einen Test, der die alte Fassung rot macht – die Kommentare im Test nennen die Version des Befunds (`Regression v28: …`). Bei App-Änderungen zuerst prüfen, ob ein bestehender Test die Regel absichert, statt sie doppelt zu implementieren. @@ -516,6 +518,8 @@ Eigener Startseiten-Abschnitt **unterhalb der Modul-Karten** (`.graf-bridge`/`.g 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. +**Das Zeichen ist seit v69 das echte DatenGraf-Logo** (`datengraf-logo.svg`, lokal im Repo – die beiden Werkzeuge teilen ihre Bildsprache, und das Logo sagt sofort, wovon die Rede ist). Runde Fassung wie `.hero-logo`, damit die beiden als Geschwister lesbar bleiben. Die Datei stammt aus dem DatenGraf-Repo und wird **lokal ausgeliefert** – ein Hotlink auf `datengraf.nozilla.net` wäre ein zweiter externer Aufruf und würde den Test „null externe Requests" rot machen. Ein Test prüft Quelle, Alt-Text und dass das Bild wirklich lädt (`naturalWidth > 0`); ein ``, das 404 liefert, sähe im Markup korrekt aus. + ### 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. @@ -697,6 +701,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 | +| v69 | **Das echte DatenGraf-Logo.** v68 musste sich mit `fa-circle-nodes` behelfen, weil die Netzwerkrichtlinie `datengraf.nozilla.net` sperrt und der Repo-Zugriff dieser Sitzung nicht über `daimpad/datenlotse` hinausreicht. Der Nutzer hat die Rohdatei-Adresse nachgereicht; das Logo liegt jetzt als `datengraf-logo.svg` **im Repo** und wird lokal ausgeliefert – ein Hotlink wäre ein zweiter externer Aufruf und machte den Test „null externe Requests" rot. Vor dem Übernehmen geprüft: kein ` - + diff --git a/index.html b/index.html index 2c9086f..f36a1e0 100644 --- a/index.html +++ b/index.html @@ -125,10 +125,10 @@ - + - - + + @@ -325,7 +325,7 @@

Risiko & Pseudonymisierung

der Stelle, an der sie die Module ohnehin überflogen haben. -->
-
+ DatenGraf

Schon mit DatenGraf kartiert?

Dann brauchen Sie hier nicht von vorn anzufangen. DatenLotse liest genau das CSV-Schema, das DatenGraf exportiert: Aus jeder Kombination aus Quelle und Datentyp wird ein Datensatz-Kandidat nach DCAT-AP.de – samt Vorbelegung von Zugriffsrechten und Aktualisierungszyklus aus Ihrer Kartierung. Sie ergänzen nur noch, was DatenGraf nicht kennt: Lizenz, Schlagwörter und die Adresse, unter der die Daten liegen.

@@ -915,7 +915,7 @@

Umsetzung besprechen

Brands-Familie und hätte dafür 116 KB Schrift nachgeladen. --> - v68 + v69 @@ -1131,7 +1131,7 @@

Lizenz-Wegweiser

- +