# Projektstatus
## E-Mail-Versand: Testmail und Protokoll in der Verwaltung (12.10.2026)
**Anlass:** huefner-gartenbau.de: Anfragen „Nicht versendet“, Ursache unbekannt (Ausnahme wurde verschluckt; vermutlich `sendmail://default` bei IONOS).
**Erledigt (ADR 121):** `App\Ops\MailCheck` für Formular und Testmail, Protokoll `var/log/mail.log` mit Meldung, deutschem Hinweis und Serverantworten (ohne Client-Zeilen, also ohne Zugangsdaten). Systemseite: Karte „E-Mail-Versand“ mit Versandweg, Testmail an frei wählbare Adresse samt Absender, letzte zehn Versuche.
**Geprüft:** `MailCheckTest` (Hinweise, Zugangsdaten bleiben draußen, Versandweg ohne Passwort), `SystemScreenTest` (Testmail, ungültige Adresse, Token, nur Administratoren); PHPUnit vollständig 678 grün (eine bekannte Warnung aus `UpdaterTest`, unabhängig davon), php-cs-fixer sauber. Im Browser auf einer Wegwerfkopie der Hüfner-Datenbank mit unerreichbarem SMTP-Server: Fehlermeldung, Hinweis „nicht erreichbar“ und Eintrag unter „Letzte Versuche“ erscheinen. Ein echter Versand über einen echten Mailserver wurde nicht ausgeführt.
**Offen:** Nicht committet, kein Release. Hüfner: `MAILER_DSN` auf SMTP umstellen (zentrales Absenderpostfach bei kant-it.de geplant), dann Testmail.
## Fassung 1.33.0: HTTPS erzwingen aus der Verwaltung (12.10.2026)
**Anlass:** Umut: HTTPS wird noch nicht erzwungen – allgemein lösen.
**Änderung (ADR 120):** System → „HTTPS“ mit „HTTPS erzwingen“, danach „HSTS einschalten“ und „Umleitung ausschalten“; Konsole `cms:https`. Eingeschaltet wird nur nach erfolgreicher Probe über HTTPS, nach dem Einschalten wird erneut geprüft und bei einer Schleife sofort zurückgenommen; die http-Antwort wird gemeldet. Mitbehoben: Der HTTPS-Block in `public/.htaccess` stand hinter der Regel für `index.php` und leitete Seiten nie um (nur Dateien), und `/.well-known/kantsites-origin` antwortete unter Apache mit 403, womit auch „Adresse speichern“ dort scheiterte. Der Git-Updater behält eingeschaltete Zeilen jetzt wie das Archiv-Update.
**Geprüft:** `tests/HttpsRedirectTest.php` (8 Tests: Probe davor/danach, Schleife zurückgenommen, Server ignoriert Regel, HSTS nur nach Umleitung, Update behält, Git-Updater zählt die Datei nicht als Änderung). Auf Apache 2.4 (XAMPP) mit der alten und neuen `.htaccess`: alt `/` und `/leistungen` 200, neu 301, mit `X-Forwarded-Proto: https` 200; `.well-known`-Probe 200, `.env`/`.htaccess`/`.htpasswd` 403; die http-Probe der Klasse erkennt 301, 200 und „keine Verbindung“. Im Browser (Hüfner lokal): Anzeige gesperrt ohne https-Adresse, eingeschalteter Zustand mit HSTS-Hinweis, „Umleitung ausschalten“ stellt die Datei byte-gleich wieder her. Nicht geprüft: der Erfolgsweg gegen ein echtes Zertifikat (lokal kein HTTPS) – das zeigt sich beim ersten Einschalten live.
**Live Hüfner:** nach dem Update auf 1.33.0 unter System → HTTPS „HTTPS erzwingen“ drücken.
## Fassung 1.32.1: Menü schließt nach einer Wahl (12.10.2026)
**Anlass:** Umut: Ein Link auf ein Sprungziel (#kontakt) im Mobilmenü ließ das Menü offen.
**Änderung (ADR 119):** `scrolled.js` schließt das aufgeklappte Menü beim Klick auf einen Link darin. Geladen wird es zusätzlich nur, wenn ein aufklappbares Menü Sprungziele derselben Seite enthält; Seiten ohne solche Links bleiben ohne Skript (Links auf andere Seiten laden neu, `no-store` verhindert ein offenes Menü nach „Zurück“).
**Geprüft:** PHPUnit 665 Tests grün, `npm test` 41 grün; im Browser auf Hüfner (iPhone): „Kontakt“, „Angebot anfragen“, „Leistungen“ schließen das Menü und springen. Bekannt und vorbestehend: `test:responsive-navigation` scheitert am Klick im Editor-Strukturbaum.
**Live Hüfner (12.10.2026):** Umut hat die Datenbank hochgeladen, ohne Medienordner – Bilder antworteten mit 404 (Kennungen vom letzten Neuaufbau). Lösung: `var/huefner-paket.zip` unter System → „Inhalte übertragen“ importieren; bringt die passenden Medien mit.
## Fassung 1.32.0: Inhaltspakete – Export und Import ohne die Konten (12.10.2026)
**Anlass:** Umut: Nach jedem Hochladen einer neu aufgebauten Datenbank galt live ein anderes Passwort; gewünscht ist ein Importer mit der Wahl, ob Benutzer/Passwort überschrieben werden („gerne auch als Plugin“).
**Neu im Kern (ADR 118):** System → „Inhalte übertragen“: Paket exportieren (Download, Konten nur mit Häkchen) und importieren (Upload oder aus `var/pakete/`, Upload-Grenze des Hostings angezeigt). Ersetzt werden Seiten mit Fassungen, Bereiche, Menüs, Medien/PDFs, Formulare, Weiterleitungen, Kategorien, Übersetzungen, Gestaltung und Einstellungen; Anfragen (neu dem Formular zugeordnet), Statistik, Aufgaben, Plugin-Stand und Turnstile-Zugangsdaten bleiben; Konten nur mit eigenem Häkchen. Vorher Sicherung, währenddessen Wartung, jede Datei und jedes Dokument geprüft. Konsole: `cms:paket:export`, `cms:paket:import`. Im Kern statt als Plugin, weil Plugins keinen Servercode ausführen. `reset-huefner.sh` schreibt zuletzt `var/huefner-paket.zip`.
**Geprüft:** PHPUnit vollständig 665 grün (neu `SitePackageTest`: Import ersetzt Inhalte und behält Konten, Anfragen, Dienst-Zugangsdaten; Konten nur mit beiden Häkchen; neuere Fassung abgelehnt; fünf manipulierte Pakete ändern nichts – fremde Datei mit `../`, Skript als Medium, veränderter Inhalt, fremde Tabelle, ungültiges Dokument). `npm test` 41, `lint:twig`, php-cs-fixer. Durchlauf auf der Konsole: Hüfner exportiert und in eine veränderte Kopie importiert (Passwort, Anfrage, Turnstile blieben, Alpakaseite kam zurück, Medienordner ersetzt). Oberfläche in der lokalen Hüfner-Verwaltung: zu großer Upload mit Hinweis abgelehnt, „Konten übernehmen“ bei Paket ohne Konten abgebrochen, Import aus `var/pakete/` abgeschlossen, danach weiter angemeldet. `test:editor` grün inklusive axe der Systemseite – ein erster Lauf parallel zu PHPUnit scheiterte, der Wiederholungslauf allein bestand.
**Veröffentlicht:** Tag `v1.32.0`, Release-Eintrag mit Archiv (3629 Dateien, 5,3 MB, gebaut aus `var/release-source-1.32.0`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt. Keine Migration.
**Nächster Schritt:** huefner-gartenbau.de auf 1.32.0 aktualisieren, dann `var/huefner-paket.zip` unter System → „Inhalte übertragen“ importieren (ohne Konten-Häkchen).
## Fassung 1.31.0: Menü schließt beim Klick daneben, Netzwerk-Symbole; Hüfner-Kopf (12.10.2026)
**Anlass:** Umut: aufgeklapptes Mobilmenü schließt nicht beim Klick daneben; bei Hüfner wirkt der Kopf auf dem iPad verloren (Menü-Knopf mittig), und Facebook, Instagram und „Angebot anfragen“ sollen ins Menü.
**Neu im Kern (ADR 117):** Klick neben das aufgeklappte Menü schließt es – reines CSS (unsichtbare Fläche am Menü-Knopf), kein Skript. Facebook, Instagram und WhatsApp im Symbolsatz (Menü-Buttons, Buttons, Symbole). Die Strichattribute der Symbole stehen jetzt als `svg.block-icon` in `site.css`/`admin.css` statt an jedem Symbol (rund 4 KB weniger HTML je Seite).
**Hüfner (nur Inhalt):** Kopf aus Logo und rechtsbündigem Menü; „Angebot anfragen“, Facebook und Instagram als Menü-Buttons. Desktop zeigt in der Zeile nur „Angebot anfragen“ (F/I stehen in der Leiste darüber), im aufgeklappten Menü stehen alle drei, die Symbole nebeneinander. Menü-Knopf auf iPad und Telefon rechts; Abstand und Schrift schrumpfen knapp über 1024 px mit, damit die Zeile nicht umbricht. Upload-Paket neu (`var/huefner-upload.zip`, braucht 1.31.0).
**Geprüft:** PHPUnit vollständig 657 grün; `npm test` 41; `lint:twig`; `test:menu-buttons` und `test:editor` grün inklusive axe; `test:browser` auf Hüfner grün (HTML Startseite rund 148 KB). Eigene Browserprüfung auf iPad quer und iPhone: öffnen, Menülinks bedienbar, Klick daneben schließt, kein waagerechtes Scrollen; Kopf bei 810, 1025, 1080, 1100, 1280 und 1366 px im Bild. **Veröffentlicht:** Tag `v1.31.0`, Release-Eintrag mit Archiv (3624 Dateien, 5,3 MB, gebaut aus `var/release-source-1.31.0`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt.
**Nächster Schritt:** huefner-gartenbau.de auf 1.31.0 aktualisieren, dann `var/huefner-upload.zip` einspielen (Reihenfolge wichtig: die Datenbank nutzt die neuen Symbole).
**Bekannt:** `test:responsive-navigation` scheitert im Editorteil am Klick auf den Strukturbaum – auch ohne diese Änderungen (Gegenprobe), vorbestehend.
## Fassung 1.30.0: Härtung nach dem Sicherheitscheck (12.10.2026)
**Anlass:** Umut: „Sicherheitscheck für KantSites … das Ding muss bombensicher sein.“ Prüfung in fünf Bereichen plus Blick von außen auf huefner-gartenbau.de und kant-it.de; Ergebnis im Chat vom 12.10.2026, Umsetzung „1.30.0, Signatur später“.
**Behoben (ADR 116):** Installationsschlüssel für den Installer (`var/install.key`, von `install.php` angelegt und angezeigt); Sperrdateien im Projektstamm und in allen internen Ordnern (`var/` legt die Website selbst an); verknüpfte Sektionen nach ihrem eigenen Schema-Stand gerendert (kein ungefiltertes HTML durch alte Sektionen); Redakteure ändern Adresse, Papierkorb, Bereiche und Beitragsdaten veröffentlichter Seiten nicht mehr; geplante Veröffentlichung mit fester Fassung (Migration `20261012000100`); Formular-Siegel je Formular, IPv6 je /64, Obergrenze je Formular und gesamt mit sichtbarem Hinweis; offene Weiterleitung per Tabulator beim Einwilligen; Update-Ziel nur `1.2.3`; eigenes CSS bleibt im Block.
**Geprüft:** PHPUnit vollständig 657 Tests: im Gesamtlauf 656 grün, ein Fehlschlag (`ArchiveUpdateTest`: die neue `.htaccess` im Projektstamm stand weder in der Ersetzungsliste noch in den bewussten Ausnahmen – jetzt als Ausnahme eingetragen, weil sie dem Betreiber gehören kann), danach die betroffenen Dateien (ArchiveUpdate, Cms, Installation, InstallFlow, SingleFileInstaller, Translation; 436 Tests) erneut grün. Neu getestet: Installer nur mit Schlüssel (falscher Schlüssel, gefälschtes Cookie, Verweis aus install.php, Löschen nach dem ersten Konto), Sperrdateien, Sektion mit altem Schema, Redakteur vs. veröffentlichte Seite, geplante Fassung, Formular-Siegel je Formular, IPv6-/64, Flut-Grenze mit Hinweis, Einwilligungs-Rücksprung mit Tabulator/Umbruch/Backslash, CSS-Geschwister/Kommentare. Gegenprobe: der Sektionstest schlägt ohne den Fix an. `npm test` 41, `lint:twig`, php-cs-fixer; `test:browser` auf Hüfner grün; `test:editor` grün inklusive axe; im Browser ein echtes Absenden des Hüfner-Formulars mit neuem Siegel (Testeinsendung danach gelöscht). Hüfner-Upload-Paket mit migrierter Datenbank (`20261012000100`) neu gebaut.
**Veröffentlicht:** Tag `v1.30.0`, Release-Eintrag mit Archiv (5,5 MB, gebaut aus `var/release-source-1.30.0`, enthält alle Sperrdateien inkl. `vendor/.htaccess`), `.sha256` und `install.php` (mit Installationsschlüssel); Prüfsumme nach dem Herunterladen bestätigt. Eine Migration (`20261012000100`), läuft mit dem Updater.
**Nächster Schritt:** Installationen auf 1.30.0 aktualisieren (huefner-gartenbau.de, kant-it.de, weitere); bei Hüfner danach das Upload-Paket einspielen und die HTTPS-Zeilen einschalten.
**Offen (niedrig):** signierte Releases; Login-Antwortzeit für unbekannte Benutzer; Trusted-Proxy-Einstellung für Hosting hinter CDN; Turnstile-Hostname; `%PDF-` ab Byte 0; archivierte PDFs bleiben abrufbar; Statistik ohne Obergrenze für erfundene Verweise; MySQL-Passwort in der Prozessliste bei Sicherungen; Theme-Vorlagen ohne Versionsprüfung. **Live:** huefner-gartenbau.de antwortet auch über `http://` ohne Umleitung und ohne HSTS – die HTTPS-Zeilen in `public/.htaccess` einschalten.
## Fassung 1.29.0: Einwilligung ohne Neuladen (12.10.2026)
**Anlass:** Umut auf der Hüfner-Seite: Beim Einwilligen ins YouTube-Video lädt die Seite komplett neu.
**Neu im Kern (ADR 115):** `public/assets/consent.js` schickt Hinweis und Knopf am eingebetteten Inhalt im Hintergrund ab (`X-Kant-Consent: 1` → 204 mit Cookie statt Weiterleitung), holt die Seite neu und tauscht nur Einbettungen und „Rechtliches“ aus; Fokus an den Rahmen bzw. an den Seitenanfang. Ohne JavaScript und bei Fehlern bleibt das Formular mit Neuladen. `frame-src` nennt die Hosts aller Einbettungen der Seite auch vor der Einwilligung (die Adresse des Inhalts weiterhin erst danach im HTML). Das Skript lädt nur, solange eine Einwilligung offen ist; `test:browser` zählt es nicht zum Budget von drei Skripten.
**Geprüft:** PHPUnit vollständig 644 grün (neu: 204-Antwort mit Cookie, kein Cookie von fremder Herkunft, Weiterleitung ohne Kopfzeile; angepasst: Skript bei offener Frage, `script-src 'none'` nach der Entscheidung, `frame-src` vor der Einwilligung), `npm test` 41, `lint:twig`, php-cs-fixer. Im Browser auf der Hüfner-Kopie: Knopf am Video, „Nur notwendige“ und „Alle akzeptieren“ ohne Neuladen, Fokus aufs Video, ohne JavaScript weiterhin mit Neuladen, keine Konsolenfehler. `test:browser` grün, Lighthouse Produktion Startseite mobil 96, Desktop 98, sonst 100. `test:editor` nicht gelaufen (Editor unverändert, Skript dort nicht eingebunden).
**Veröffentlicht:** Tag `v1.29.0`, Release-Eintrag mit Archiv (3611 Dateien, 5,3 MB, gebaut aus `var/release-source-1.29.0`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt. Keine Migration.
**Nächster Schritt:** Installationen mit Einwilligungshinweis (huefner-gartenbau.de, Immobilien DEEG) auf 1.29.0 aktualisieren.
## Fassung 1.28.1: weißer 500er bei IONOS durch die Umschreibregel (12.10.2026)
**Anlass:** huefner-gartenbau.de bei IONOS zeigte nach der Einrichtung auf jeder Adresse einen weißen 500er.
**Ursache und Änderung (ADR 114):** PHP 8.4.26 lief (`test.php`), `/index.php/install` lieferte 200, nur umgeschriebene Adressen scheiterten – Umschreibschleife in `public/.htaccess`. Neu im Kern: `RewriteBase /` und `RewriteRule ^index\.php$ - [L]` vor der `!-f`-Regel; Test in `CmsTest::testEveryPublicAnswerCarriesItsProtectiveHeaders`.
**Geprüft:** Umut hat beide Zeilen auf IONOS eingetragen, danach lädt `/install`; auch mit eingeschalteter `Options`-Zeile. PHPUnit vollständig: 643 Tests grün, eine Warnung aus `UpdaterTest` (fehlende `.env` im Testordner, unabhängig von dieser Änderung); php-cs-fixer sauber.
**Veröffentlicht:** Tag `v1.28.1`, Release-Eintrag mit Archiv (3610 Dateien, 5,3 MB, gebaut aus `var/release-source-1.28.1`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt. Keine Migration.
**Offen:** Der Installer auf huefner-gartenbau.de war bis zum Abschluss der Einrichtung öffentlich erreichbar.
**Nächster Schritt:** Bestehende IONOS-Installationen auf 1.28.1 aktualisieren.
## Hüfner: Änderungen aus dem Kundentermin (12.10.2026)
**Anlass:** Umuts handschriftliche Notizen vom Hüfner-Termin plus Antworten auf Rückfragen. Nur Inhalt und Seed-Skript, kein Kerncode.
**Erledigt (`scripts/seed-huefner.php`, `build-huefner-assets.php`, `reset-huefner.sh`):** Alle Grüntöne auf das Baumgrün des Logos (#067F30) gedreht, „Premium“ und Hervorhebungen in Baumgrün, kleine Schrift auf Dunkel weiß statt hellgrün (Kontrast). Das „💯“ als Umuts Emoji-Bild überall, wo „100“ steht, im Text (`100`: die Zahl bleibt lesbar für Vorleser und KI, sichtbar ist das Bild in Schriftgröße, geschütztes Leerzeichen vor „%“); Quelle `100-emoji.png` in den Unterlagen. „Miteinander. 💯 %.“-Abzeichen jetzt dunkel statt rot. Freistellungsbescheinigungen (§ 13b UStG, § 48b EStG) als PDF bei „Planung & Angebot“ und im Fuß, PQ-Bescheinigung unter „Über uns“ und im Fuß, Galabau-Signet und PQ-Logo. Imagevideo (YouTube, youtube-nocookie) als „Externer Inhalt“ – dafür jetzt Einwilligungshinweis (Ecke) und angepasste Datenschutzerklärung. Google-Bewertungen unter „100 % Qualität. 100 % Zufriedenheit.“ mit 4,9 / über 150 als Beleg, drei echte Rezensionen (gekürzt, Namen abgekürzt), Knopf zum Eintrag. 48-h-Angebotsgarantie in Ablauf und Kontakt, „Leistung“ aus dem Formular, Chips verlinken zum Formular, WhatsApp (0176 30387990) in Kontakt und Karriere, 25 Jahre / 7.000+ Projekte, „Bagger bis 15 t“ raus. Karriere: Facharbeiter und LKW-Fahrer C/CE (wie Instagram) als zwei gleich hohe, aufklappbare Karten (details/summary, SVG-Zeichnungen), „Ein Anruf genügt!“. Neue Seite `/alpakas` mit Umuts Text, Ergänzungen, Galerie und Plakat; „Alpakas“ im Menü, „Ablauf“ aus dem Menü raus. `browser-check.mjs`: PDFs zählen beim „erster interner Link“-Klick nicht mit.
**Geprüft:** `test:browser` auf 8102 für `/`, `/alpakas`, `/datenschutz`, `/impressum` grün (HTML Startseite 148.905 B von 150.000 – knapp). Lighthouse Produktion (`reports/lighthouse-huefner-termin`): `/` mobil 96, Desktop 99; `/alpakas` mobil 95, Desktop 100; Barrierefreiheit, Best Practices, SEO, Agentic Browsing überall 100. Im Browser: Video lädt erst nach Einwilligung, Stellenkarten klappen auf, Telefonbreite ohne waagrechtes Scrollen.
**Bekannt / offen:** Die Freistellungsbescheinigung § 13b gilt nur bis 31.12.2026 – dann neue Datei in die Unterlagen und neu aufbauen. Die Alpaka-Videos (mp4) sind nicht eingebunden (keine Videoablage im Kern). Offen von Umut: Logos der Sponsoren, „Über uns – mehr lesen“, ggf. Stellenbilder aus ChatGPT statt der SVG-Zeichnungen, genauer Verbandsname. Die Sprachtest-Kopie (`var/browser-tests/lang`) teilt `var/huefner-media` und hat nach dem Neuaufbau keine passenden Bilder mehr. Sicherung vorher: `var/backups/huefner-vor-termin-1210/`. Nebenbefund Kern: `CustomCode::parse` lehnt `url('…')` mit Anführungszeichen immer ab (optionales Anführungszeichen im regulären Ausdruck backtrackt).
**Nächster Schritt:** Umuts Durchsicht; fehlende Punkte nachliefern lassen.
## Fassung 1.28.0: Notfallseite, Fehlerprotokoll und Update mit einem Klick (09.10.2026)
**Anlass:** kantarci-reisen.de zeigt nach einer per FTP ersetzten Datenbank auf jeder Adresse eine leere 500-Seite. Umut: „Fang mit 1 und 2 an und verbessere den Update-Prozess … mach es wie bei reiseSoft.“
**Erledigt (ADR 113):** (1) Wartungsseite mit 503 statt leerem 500er, auch wenn Symfony nicht startet; (2) Fehlerprotokoll `var/log/notfall.log`, per FTP lesbar; (3) Update-Karte auf der Systemseite: sucht beim Öffnen selbst, zeigt die Release-Hinweise, ein Klick mit Bestätigung, Fortschritt in fünf Schritten live, Migration im selben Vorgang, bei Fehler automatisch zurück auf die alte Fassung samt Datenbank.
**Geprüft:** PHPUnit vollständig 643 grün (neu: `NotfallTest`, Fortschrittsdatei und vollständiges Zurückschalten in `ArchiveUpdateTest`, Endpunkte nur für Administratoren in `SystemScreenTest`), php-cs-fixer. Im Browser mit einer Installation aus dem Releasearchiv 1.27.1: erfolgreiches Update in einem Klick, Zurückschalten bei einer kaputten Testfassung.
**Veröffentlicht:** Tag `v1.28.0`, Release-Eintrag mit Archiv (3610 Dateien, 5,3 MB, gebaut aus `var/release-source-1.28.0`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt. Keine Migration.
**Bekannt:** Der neue Ablauf greift erst bei Updates, die von 1.28.0 ausgehen. kantarci-reisen.de ist noch offline (Ursache unbekannt, Datenbank lokal mit 1.27.0 lauffähig).
**Nächster Schritt:** kantarci-reisen.de wiederherstellen (Notfallschicht hochladen → Protokoll lesen, oder Sicherung zurück) und aktualisieren.
## Fassung 1.27.1: Update in einem Zug, Kantarci Reisen auf Türkisch (09.10.2026)
**Anlass:** Umut: Update auf kantarci-reisen.de gab direkt danach einen 500er, nach „zurück“ ließ sich migrieren. „Können wir den Updater besser machen, dass alles automatisch abläuft, wie bei WordPress?“ Und: „Die DB hier komplett mit Übersetzung auf Türkisch fertig machen.“
**Updater (ADR 112):** Ein Klick spielt ein, die Anfrage endet nach dem Dateitausch mit einer schlichten Seite, die den Abschluss (Migrationen, Wartung aus) selbst aufruft – kein 500er, kein zweiter Knopf. Wirkt ab Updates, die von 1.27.1 ausgehen; 1.27.0 → 1.27.1 läuft noch den alten Weg.
**Türkisch im Kern vervollständigt:** feste Vorlagentexte und Formularmeldungen komplett auf Türkisch (vorher Teile auf Englisch). Zwei Sprachwahlen auf einer Seite heißen jetzt verschieden („Sprache“ im Kopf, „Sprache wählen“ sonst) – axe meldete sonst `landmark-unique`.
**Kantarci Reisen (nur Inhalt):** `scripts/translate-kantarci-reisen.php` schaltet Türkisch ein und übersetzt Startseite (67 Texte), Künye (`/tr/kunye`), Gizlilik (`/tr/gizlilik`), 404, Kopf, Fuß, Menü und das Anfrageformular; Anrede „siz“, Rechtstexte mit dem Hinweis, dass die deutsche Fassung gilt. Sprachwahl DE · TR im Kopf (auf dem Telefon ausgeblendet, kein Platz) und „Deutsch · Türkçe“ im Fuß. `reset-kantarci-reisen.sh` ruft das Skript am Ende auf. Ausgeführt auf `var/kantarci-reisen.db` (Sicherung `var/backups/vor-1.27.0/kantarci-reisen-vor-tr.db`).
**Korrigiert:** Die DM-Sans-600-Dateien von heute Nachmittag waren doch nötig – `FontLibrary::missing()` verlangt je Stärke eine Datei, sonst gibt die Website ihre eigenen Schriften ganz auf. Neu geholt (`cms:fonts:fetch`) und diesmal mit `fonts.css` committet. Live auf kantarci-reisen.de waren sie nie weg.
**Geprüft:** PHPUnit vollständig 637 grün (neu: Abschluss per Einmalschlüssel, Rolle, falscher Schlüssel, Neuladen), `npm test`, `lint:twig`, php-cs-fixer; Update-Ende-zu-Ende in einer Archivinstallation; `test:browser` auf Reisen (8104) grün; Lighthouse Produktion (`reports/lighthouse-kantarci-reisen-tr`): `/tr`, `/tr/gizlilik`, `/` überall 100, nur Leistung mobil 99 auf `/tr` und `/`. Telefonbreite ohne waagrechtes Scrollen.
**Veröffentlicht:** Tag `v1.27.1`, Release-Eintrag mit Archiv (3607 Dateien, 5,3 MB, gebaut aus `var/release-source-1.27.1`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt. Die lokalen Installationen laufen aus diesem Repository und haben 1.27.1 (keine Migration).
**Für den Livegang der türkischen Fassung:** erst kantarci-reisen.de auf 1.27.1 aktualisieren (sonst fehlen Teile der festen türkischen Texte), dann `var/kantarci-reisen.db` hochladen. Achtung: die hochgeladene Datei ersetzt die Datenbank dort – Einsendungen und Änderungen, die es nur live gibt, gehen dabei verloren.
## Fassung 1.27.0: Mehrsprachigkeit und übersichtlichere Formulare (09.10.2026)
**Inhalt:** Mehrsprachigkeit in drei Stufen (ADR 111, Schema v27, Migration `20261009000100`) und die neue Formularverwaltung – Einzelheiten in den drei Einträgen darunter.
**Geprüft vor dem Release:** PHPUnit vollständig auf dem Release-Stand 636 grün, `npm test` 41, `lint:twig`, php-cs-fixer, `test:admin --admin-only` und `test:editor` (mit axe) grün. Lighthouse im Produktionsmodus auf der Hüfner-Testkopie mit Englisch (`reports/lighthouse-sprachen`): `/en` mobil 97/100/100/100/100, Desktop 99/100/100/100/100; `/` mobil 96, Desktop 99, sonst 100.
**Veröffentlicht:** Tag `v1.27.0`, Release-Eintrag auf git.kant-it.de mit Archiv (3605 Dateien, 5,2 MB, gebaut aus `var/release-source-1.27.0`), `.sha256` und `install.php`; Prüfsumme nach dem Herunterladen bestätigt.
**Aufgeräumt:** Zwei nicht eingebundene DM-Sans-600-Dateien aus der Reisen-Installation gelöscht (die variable 400er-Datei deckt 400–700 ab), die nur umsortierte `fonts.css` auf den committeten Stand zurückgesetzt.
**Nächster Schritt:** Installationen auf 1.27.0 aktualisieren (Migration läuft über den Updater mit). Wer eine zweite Sprache will: Einstellungen → Sprachen, Sprachwahl in den Kopfbereich.
## Formularverwaltung übersichtlicher (09.10.2026)
**Anlass:** Umut: Formulare „sehr unübersichtlich … kompakter, nicht so wuchtig und so voll“; bei mehreren Formularen erst eine Übersicht ohne Vorschau, dann in die Seite rein.
**Neu:** `/admin/forms` ist eine Übersicht – je Formular eine Zeile mit Feldern, Empfänger, Adresse, übersetzten Sprachen und Zahl der Einsendungen, darunter die Einsendungen. Bearbeitet wird auf `/admin/forms/` (neu: `/admin/forms/neu`), nach dem Speichern bleibt man dort. Im Editor ist jedes Feld eine Zeile (Beschriftung, Typ, Pflicht), alles Weitere unter „Details“ mit einer Kurzinfo darunter (technischer Name, Optionen, Hilfetext, Bedingung, „EN ✓“). Zustellung, Aussehen und je Sprache die Übersetzung sind zuklappbar mit Zusammenfassung; Erklärtexte gekürzt. Ohne JavaScript bleiben alle Felder sichtbar und bedienbar. Beim Testformular der Hüfner-Kopie: Seitenlänge von 4.913 px auf 1.274 px.
**Robuster:** Ohne weitere Sprache fasst der Kern die Tabelle `page_translation` nicht an – Speichern und Veröffentlichen funktionieren so auch, wenn nach einem Update die Migration noch aussteht (gefunden über die Pilot-Fixture, die ohne Migrationen kopiert).
**Geprüft:** PHPUnit vollständig 636 grün (vor dem Umbau), danach die betroffenen 59 (Editor-Sicherheit, Formulare, Übersetzung) grün; `npm test`, `lint:twig`, php-cs-fixer; `test:admin --admin-only` und `test:editor` grün inklusive axe auf allen Verwaltungsseiten und im Formulareditor; im Browser Übersicht, Bearbeiten, Speichern, Neu, 404 für unbekannte Adresse, Telefonbreite ohne waagrechtes Scrollen.
**Bekannt:** `test:admin` ohne `--admin-only` scheitert im Slider-Teil der Pilotseite – ebenso auf dem unveränderten Stand 1.26.0 (eigens in einem separaten Arbeitsverzeichnis geprüft), also kein Folgefehler dieser Änderungen.
## Mehrsprachigkeit, Stufe 3: Formulare, Beiträge, Einwilligung, 404 (09.10.2026)
**Neu (ADR 111, keine Migration):** Formulare je Sprache übersetzbar (in der Formularverwaltung am Feld: Beschriftung, Hilfetext, Optionen, Einheit; am Formular Button und Erfolgsmeldung), Fehlermeldungen und Schrittnavigation in der Sprache, Rückweg nach dem Absenden auf die übersetzte Seite; Einsendungen und E-Mail bleiben deutsch. Beitragslisten und Archive (`/en/beitraege`, `/en/kategorie/…`) mit übersetzten Titeln; Kategorie-/Schlagwortnamen und Einwilligungstext unter Einstellungen → Sprachen. 404 unter `/en/…` auf Englisch.
**Geprüft:** PHPUnit vollständig **636 grün** (neu: Formular in beiden Sprachen inkl. Absenden/Fehler/Weiterleitung; Beiträge, Archive, Kategorienamen, Einwilligung, 404), `npm test` 41, `lint:twig`, php-cs-fixer. Browser (Testkopie Hüfner): Formularübersetzung gespeichert, `/en` zeigt „Your name (EN) * (required)“ und „Send“, `/` unverändert. **Nicht geprüft:** Formularversand per E-Mail, Lighthouse/axe auf `/en`.
**Bekannt:** Feed, `/einwilligung`, Datumsformat und Archiv-Präfixe bleiben deutsch.
## Mehrsprachigkeit, Stufe 2: Kopf, Fuß, Menüs, feste Texte (09.10.2026)
**Anlass:** Umut: „Bilder lassen wir, mach weiter.“ Bilder bleiben für alle Sprachen gleich.
**Neu (ADR 111, keine weitere Migration):**
- **Kopf, Fuß und Sektionen** übersetzen: im Bereichs-Editor derselbe Umschalter DE | EN, die Liste zeigt nur die Texte (keine Adresse, kein Seitentitel). Gespeichert gilt sofort.
- **Menüs:** je Eintrag ein Feld „Beschriftung Englisch“ (leer = deutsch). Auf `/en/…` zeigen die Einträge ihre englische Beschriftung und führen auf die englischen Seiten.
- **Feste Texte** wie „Zum Inhalt springen“, „Menü“, „Hauptnavigation“, „Impressum/Datenschutz“ in der Rechtszeile, Einwilligungsknöpfe, „Weiterlesen“, „Nach oben“ erscheinen auf englischen Seiten englisch (Französisch/Türkisch teilweise, sonst Englisch).
**Geprüft:** PHPUnit vollständig **634 grün**, darunter neu ein Test für Kopfbereich, Menü und feste Texte in beiden Sprachen; `npm test` 41 grün; `lint:twig`; php-cs-fixer. Im Browser (Testkopie Hüfner, Port 8111): Menü mit „Services“/„References“ gespeichert, `/en` zeigt sie mit Zielen `/en#…`, „Skip to content“, „Main navigation“; Kopfbereich im Editor auf Englisch, „Request a quote“ in Vorschau und auf `/en`, `/` weiter „Angebot anfragen“. **Nicht geprüft:** Lighthouse/axe auf `/en`.
**Bekannt:** Formulare, Beiträge/Archive, Einwilligungstext aus den Einstellungen und die 404-Seite noch einsprachig. Nach einem Kern-Update cached die App-Vorschau alte Editor-Skripte (gleiche Fassungsnummer) – erst nach Neuladen der Assets sieht man Änderungen.
**Nächster Schritt:** Stufe 3 – Formulare (Felder, Meldungen, Bestätigungsmail) und Beiträge mit Archiven übersetzbar machen; danach Lighthouse/axe einer `/en`-Seite.
## Mehrsprachigkeit, Stufe 1: Seiten übersetzen statt neu bauen (09.10.2026)
**Anlass:** Umut: weitere Sprache hinzufügen und zu jedem Feld die 2. Sprache eintragen, ohne die Seite für die 2. Sprache neu zu bauen; Adressen mit `/en/`-Präfix und übersetzten Slugs.
**Neu (Kern, Schema v27, Migration `20261009000100`, ADR 111):**
- **Einstellungen → Sprachen:** Hauptsprache bleibt Deutsch, weitere Sprachen per Häkchen (10 zur Wahl, höchstens 5). Ohne Häkchen ist nirgends etwas zu sehen.
- **Editor:** Umschalter DE | EN oben. In EN zeigt die Seitenleiste alle Texte der Seite mit Original, Zustand (fehlt / übersetzt / Original geändert), Filter, „Original übernehmen“, „Übersetzung passt“; dazu Adresse und Suchtitel. Vorschau in der Sprache, Klick springt zum Text. Aufbau und Gestaltung sind in EN gesperrt. Undo, Speichern und Veröffentlichen wie gewohnt – für alle Sprachen gemeinsam.
- **Website:** `/en` und `/en/<übersetzte-adresse>`, `lang="en"`, Canonical, `hreflang` + `x-default`, `og:locale`, Sitemap. Links auf übersetzte Seiten führen zur Übersetzung. Nicht übersetzte Seiten: 404 unter `/en/…`. Neuer Baustein **„Sprachwahl“** (Kürzel oder Namen).
**Geprüft:** PHPUnit vollständig (633, ein Fehler durch die Änderung gefunden und behoben, danach die betroffenen 426 Tests erneut grün), neu `tests/TranslationTest.php` (Überlagerung, Prüfung wie Hauptsprache, Adressen beim Veröffentlichen/Verschieben mit Weiterleitung, Kollisionen, HTTP mit hreflang/Links/Sitemap/404). `npm test` 41 grün, neu `tests/translate.test.mjs` (Fingerabdruck gleich PHP, Feldliste gleich Server, Undo). `lint:twig`, php-cs-fixer. Im Browser auf einer Kopie der Hüfner-Datenbank (`var/browser-tests/lang/`, Startkonfiguration `sprachen-test`, Port 8111): Sprache eingeschaltet, Startseite übersetzt, Undo/Redo, Speichern, Veröffentlichen, `/en` mit englischem Titel und `hreflang`, `/en/impressum` 404, Sitemap mit `/en`. **Nicht geprüft:** Lighthouse und axe einer `/en`-Seite und des Bausteins „Sprachwahl“, Tastaturfokus beim Klick in die Vorschau (das Browserfenster der Prüfung hatte keinen Fokus).
**Bekannt (Stufe 2):** Kopf/Fuß, Menübeschriftungen, Formulare, Beiträge/Archive, Einwilligung, 404 und feste Vorlagentexte bleiben auf englischen Seiten deutsch. Eigenes HTML und Plugin-Bausteine unübersetzbar, Bilder nicht je Sprache. Ändert der Server beim Speichern formatierten Text der Hauptsprache, können Übersetzungen fälschlich als „Original geändert“ erscheinen. Dokumente mit Übersetzungen oder Sprachwahl brauchen einen Kern mit Schema v27.
**Nächster Schritt:** Stufe 2 – Menüs und Kopf-/Fußbereiche übersetzen, danach Formulare und Beiträge. Vorher mit Umut klären, ob Bilder je Sprache austauschbar sein sollen.
## Zehnte Installation „Kantarci Reisen“ (08.10.2026)
**Anlass:** Umut: neue Website nach dem Mockup `Downloads/Kantarci-Reisen-Komplettpaket.zip`, DB und Medienordner nach gleichem Muster, Inhalte dürfen individualisiert werden. Inhaber I. Kantarci, Ooser Hauptstraße 51, 76532 Baden-Baden, info@kantarci-reisen.de. Für reiseSoft ein echter Screenshot aus `Downloads/reiseSoft`, Plattform unter reisesoft.kantarci-reisen.de.
**Neu (nur Inhalt, kein Kerncode):** Datenbank `var/kantarci-reisen.db`, Medien `var/kantarci-reisen-media`, Bildquellen `var/kantarci-reisen-assets`, Startkonfigurationen `kantarci-reisen` (Port 8104, dev) und `kantarci-reisen-prod` (8105). `sh scripts/reset-kantarci-reisen.sh ` schneidet Logo und Seitensymbol zu (`build-kantarci-reisen-assets.php`), baut mit `seed-kantarci-reisen.php` alles neu und holt DM Sans auf den eigenen Server. Ohne Argumente nimmt es die vorbereiteten Bilder.
- **Startseite** wie das Mockup: geteilter Hero (Petrol/Küstenfoto), drei Angebote als ganz klickbare Karten (ohne Nummern, auf Umuts Wunsch), „Gute Reisen beginnen mit einem Gespräch“ mit Anschrift, neu „So läuft’s“ in drei Schritten, Anfrage auf Petrol mit CMS-Formular `reiseanfrage` (Versand an info@kantarci-reisen.de, dazu Telefon, Reisezeitraum, Personen), reiseSoft mit echtem Screenshot im Browserrahmen und Knopf zur Plattform. Dazu Impressum (Reisevermittlung), Datenschutz, 404, klebender Kopf, Einblendungen.
- **„Reise anfragen“** ist ein Menü-Button (ADR 110) mit Pfeil, auf dem Telefon neben dem Menü-Knopf. Eigenes Menü-CSS darf `.menu-list a` kein Polster geben, ohne es dem Button zurückzugeben (`.menu-list .menu-button`).
- **Screenshot reiseSoft:** gebaute Fassung von reiseSoft lokal (Port 4199) mit leerem Datenordner im Scratchpad gestartet, Ersteinrichtung mit Testzugang, `scripts/demodaten.mjs` (60 fiktive Vorgänge), Übersicht in 1440×900 @2x aufgenommen. Keine echten Kundendaten.
**Geprüft:** `test:browser` auf 8104 grün (HTML 66 KB). Lighthouse auf 8105 (Produktion): `/` mobil 98/100/100/100/100, Desktop 100 überall; `/impressum` überall 100 (`reports/lighthouse-kantarci-reisen`). Ganzseitige Screenshots 1440 und 390 px ohne Konsolenfehler und ohne waagrechtes Scrollen. Nicht geprüft: Formularversand per E-Mail.
**Nachtrag (08.10.2026):** Telefon 0170 2945935 (auch WhatsApp) von Umut; eine USt-IdNr. gibt es nicht. WhatsApp als Anfrageweg aus dem Baustein „Soziale Profile“ (Netzwerk in den Einstellungen, Link mit vorausgefülltem Text): Knopf unter „Über uns“ und neben dem Formular, Link im Fuß, runde Schaltfläche fest unten links (`position:fixed` im eigenen CSS). Datenschutz mit eigenem Punkt zu WhatsApp. „Inhaber“ steht nicht mehr im Fuß, nur im Impressum. Danach erneut `test:browser` grün (HTML 72 KB) und Lighthouse `/` mobil 98, sonst 100; `/datenschutz` überall 100.
**Bekannt:** Öffnungszeiten und Hoster sind unbekannt und stehen nirgends (Datenschutz nennt den Hoster allgemein). **Die Domain kantarci-reisen.de existiert am 08.10.2026 im DNS nicht** (NXDOMAIN bei Fritz.box, 1.1.1.1 und 8.8.8.8) – damit kommen weder Mails an info@kantarci-reisen.de an noch ist reisesoft.kantarci-reisen.de erreichbar. Vor dem Livegang klären. Das Reisefoto ist laut Paket KI-generiert, so im Bildnachweis. Grenzen des Kerns beim Aufbau: Textblöcke geben `` nicht aus, eigenes CSS erlaubt keine Anführungszeichen in Werten, kein `calc()` in `maxWidth`, kein `>*` und keine `?` in Attributselektoren.
**Nächster Schritt:** Inhalte mit Umut abstimmen, dann Livegang nach `docs/LIVEGANG.md`.
## Fassung 1.26.0: Menüeinträge als Button (07.10.2026)
**Anlass:** Umut: Buttons im Menü – individuell wie im Editor, mit Symbol und Farbe, auf dem Telefon im aufgeklappten Menü oder neben dem Menü-Knopf.
**Neu (ADR 110):** In der Menüverwaltung je Eintrag „Als Button darstellen“ mit Form, Darstellung, Größe, Fläche/Schrift (auch beim Überfahren), Symbolfarbe, Symbol aus dem Fenster, Bewegung, „nur Symbol“ und Anzeige auf dem Telefon (im Menü / neben dem Menü-Knopf / dort nur als Symbol). Vorschau normal und beim Überfahren.
**Geprüft:** PHPUnit vollständig, `npm test`, `npm run test:menu-buttons` (Browser, axe, 1440 und 390 px, je ein Button neben dem Menü-Knopf und im aufgeklappten Menü), `lint:twig`, php-cs-fixer.
**Bekannt:** In schmalen Kopfspalten bricht der Button in die nächste Zeile (wie jeder Menüeintrag). Kern ab 1.26.0 nötig.
## Fassung 1.25.0: 98 Symbole, Auswahlfenster, Symbol-Gestaltung unter Design (07.10.2026)
**Anlass:** Umut zu 1.24.0: „Du wolltest doch mehr Icons machen oder nicht? Und nicht alles so dort auflisten, erst onklick einblenden oder Modal das gefällt mir nicht. Dann brauche ich Icon-Einstellungen ausgefüllt, extra Farbe usw. Mach es doch durchdacht.“
**Neu (ADR 109):**
- **98 Symbole** statt 33 in sieben Kategorien, darunter Warenkorb, Euro, LKW, Paket, Karte, Kamera, Schloss, Werkzeug, Malerrolle, Baum, Solar, Strom, Auto, Warnung. Quelle `public/assets/icons.js`, `npm run build:icons` schreibt Twig und Validator.
- **Auswahlfenster:** Im Panel nur das gewählte Symbol mit „Ändern …“. Das Fenster zeigt Kategorien als Reiter und Symbole mit Namen. Gilt für Button, Symbol und Symbolkarte.
- **Design → Symbol** (je Gerät, mit Hover): Farbe, Fläche dahinter, Größe, Innenabstand und Ecken der Fläche, Drehung, Abstand zum Text.
- **Inhalt (Schema v26):** Stellung, „Beim Überfahren: Ruhig / Rückt / Erscheint“, „Nur das Symbol zeigen“ (quadratischer Knopf, Beschriftung bleibt für Vorlesesoftware).
**Geprüft:** PHPUnit vollständig (616) grün, `npm test` (38) grün, `npm run test:button-icons` (Editor im Browser, inkl. axe im Fenster und gemessenem Aussehen), `test:buttons` grün, `test:browser` auf Hüfner (Entwicklungsmodus, Port 8102) grün mit HTML 148 KB. php-cs-fixer und `lint:twig` ohne Befund. Nicht geprüft: Lighthouse.
**Bekannt:** Dokumente mit Bewegung oder „nur Symbol“ brauchen einen Kern ab 1.25.0 (Schema v26). Die Gestaltungswerte (Farbe usw.) brauchen kein neues Schema, werden von älteren Kernen aber abgelehnt (unbekannte Stileigenschaft) – Installationen zuerst aktualisieren. `test:browser` verlangt den Entwicklungsmodus (Kopf `x-kant-queries`), nicht wie in der README beschrieben den Produktionsmodus.
**Veröffentlicht:** Release v1.25.0 auf git.kant-it.de mit Archiv und `install.php`, Prüfsumme nach dem Herunterladen bestätigt.
**Hüfner aktualisiert (07.10.2026):** Die lokale Installation läuft aus diesem Repository und hat damit 1.25.0. Auf der Startseite ist das LKW-Symbol der Vorteilsleiste (`vorteil-3-icon`) jetzt der Baustein „Symbol“ mit `truck`, gestaltet wie die drei Nachbarn (32 px, `@hellgruen`), statt „Eigenes HTML“. Geändert direkt in `var/huefner.db` (veröffentlicht, Sicherung `var/huefner.db.vor-lkw`) und in `scripts/seed-huefner.php`, damit ein Neuaufbau dasselbe ergibt. Geprüft im Browser (Symbol sichtbar, keine HTML-Bausteine mehr) und mit `test:browser` (grün, HTML 148 KB).
**Nächster Schritt:** Livegang Hüfner nach `docs/LIVEGANG.md`, die übrigen Installationen auf 1.25.0 aktualisieren.
## Fassung 1.24.0: Symbol am Button wählbar, Kachelauswahl für Symbole (07.10.2026)
**Anlass:** Umut: „Buttons mit Icon? Geht das, wenn ja wo? Und einfacher Button ist ein Pfeil, wie ändere ich das?“ – dann: „Ja bitte umsetzen. Ein Satz Symbole, die man so alltäglich brauchen könnte, und schöne Vorschau-Auswahl, bitte kein Dropdown mit Suche usw.“
**Neu (Kern, Schema v25, ADR 108):**
- Button → Inhalt → **Symbol**: Kacheln mit Vorschau in drei Gruppen (Pfeile, Kontakt, Allgemein), „Kein Symbol“ vorn. Darunter **Symbol steht: Vor dem Text / Nach dem Text**, nur wenn ein Symbol gewählt ist. Ohne Wahl bleibt der schräge Pfeil hinter dem Text – bestehende Seiten sehen unverändert aus, eigenes CSS auf `.button-arrow` greift weiter.
- 13 neue Symbole im gemeinsamen Satz (Pfeil nach unten, Winkel, Kalender, Nachricht, Senden, Download, Dokument, Abspielen, Suche, Herz, Info, Plus, Person), damit 33 insgesamt.
- Symbol und Symbolkarte wählen ihr Symbol mit derselben Kachelauswahl statt der Liste mit englischen Namen.
- `public/assets/icons.js` (Pfade, deutsche Namen, Gruppen, Auswahl), in der Importmap eingetragen. Stile in `button-controls.css`. `site.css`: Hülle heißt `button-icon`.
**Geprüft:** PHPUnit vollständig (609 Tests) grün, darunter zwei neue Tests in `CmsTest` (Ausgabe mit Standardpfeil, Telefon vorn, kein Symbol; Ablehnung unbekannter Symbole und älterer Schemata). `npm test` (38) grün, dazu `tests/icons.test.mjs` (Twig, Editor und Validator kennen dieselben Symbole) und `repairSchema` hebt auf v25. `npm run test:button-icons` im Browser auf einer Kopie der Pilotdaten: Kachel wählen, Stellung umschalten, Pfeiltasten und Enter, Rückgängig/Wiederholen, kein Symbol, Speichern als v25, nach Neuladen gleich; keine Seitenfehler. Screenshots `reports/button-icons/`. php-cs-fixer und `lint:twig` ohne Befund. Nicht geprüft: Lighthouse und `test:browser` (die öffentliche Ausgabe ändert sich nur bei gewähltem Symbol um ein Inline-SVG gleicher Größe).
**Bekannt:** Ein Dokument mit Symbolwahl lässt sich auf einem Kern vor dieser Fassung nicht speichern (Schema v25) – Installationen zuerst aktualisieren. Keine Markenlogos im Satz.
**Nächster Schritt:** Push von `main` und Tag `v1.24.0`, Releasearchiv auf der Releaseseite veröffentlichen, dann die Installationen aktualisieren (vor Hüfner, damit dort Symbole gewählt werden können).
## Fassung 1.23.1: neunte Installation „Hüfner Gartenbau“, Knöpfe mit tel: und mailto:, Pfeil in der Schriftfarbe (06.10.2026)
**Anlass:** Umut: „Hier liegt ein Designentwurf für Hüfner Gartenbau. Kannst du mir db und media erstellen für KantSites bitte. […] Effekte rein. Nichts am Code ändern, sondern alles an KantSites-Designelementen anpassen/bauen. Falls was nicht geht, Rückmeldung.“ Vorlage: `Downloads/huefner-website/huefner-website` (statisches `index.html`, 16 Fotos, Logo).
**Neu (nur Inhalt, kein Kerncode):** Datenbank `var/huefner.db`, Medien `var/huefner-media`, Bildquellen `var/huefner-assets`, Startkonfigurationen `huefner` (Port 8102, dev) und `huefner-prod` (Port 8103). `sh scripts/reset-huefner.sh ` kopiert die Bilder und schneidet den Baum aus dem Logo als Seitensymbol (`build-huefner-assets.php`), baut mit `seed-huefner.php` alles neu und holt Barlow und Barlow Condensed auf den eigenen Server. Ohne Argument nimmt es die schon vorbereiteten Bilder.
- **Startseite** mit allen elf Abschnitten des Entwurfs: Hero mit Verlauf und Vorteilsband, Collage, Leistungs- und Referenzkacheln (Foto zoomt, Kachel bekommt Schatten), Chips, Ablauf mit gestrichelter Linie, Fuhrpark, Über uns, Karriere (Stellen als Links mit E-Mail-Betreff), Instagram-Raster, Abschlussband, Kontakt mit dem CMS-Formular `anfrage` (Versand an info@huefner-gartenbau.de). Dazu Impressum, Datenschutz, 404, Menü mit Sprungmarken, klebender Kopf, Einblendungen beim Scrollen.
- **Inhaltliche Ergänzungen** statt der Platzhalter der Vorlage: Öffnungszeiten Mo–Fr 8–17, Sa 8–12 (von Umut, auch als strukturierte Daten), Firmengeschichte und Impressum aus dem Handelsregister (HRB 742159, AG Mannheim, GF Florian Hüfner; Simone Hüfner war nur bis 27.04.2026 Prokuristin), Hoster IONOS, alle Fotos eigene Aufnahmen. Kennzahlen „[XX] Jahre“/„[XXX] Projekte“ ersetzt durch Aussagen der Vorlage (100 % Detailarbeit, Bagger bis 15 t, ein Team). Keine USt-IdNr. bekannt, deshalb keine Zeile.
**Grenzen des Kerns:**
- Nachtrag, gleicher Tag – auf Umuts Wunsch im Kern behoben (ADR 107): Knöpfe und andere verlinkbare Bausteine nehmen `tel:` und `mailto:` an, und der Pfeil im Knopf hat die Schriftfarbe statt der Akzentfarbe. Die Anrufknöpfe bei Hüfner sind jetzt echte Knöpfe, der Pfeil braucht keine eigene Regel mehr. Vorher: Textlink im Knopf-Aussehen und `color:inherit` im CSS des Knopfs.
- Kein LKW im Symbolsatz: Das Symbol steht als „Eigenes HTML“ mit dem SVG der Vorlage.
- Leiste und Kopf kleben gemeinsam (die Einstellung gilt für den ganzen Kopfbereich).
- Zeilen sind durchsichtig, farbige Karten deshalb Spalten mit Flex.
- Eigenes CSS ohne `@media`/`*`: gerätespezifische Werte über die Gestaltungswerte (Bildhöhe, Raster-Spalten, Ränder je Gerät).
- Das HTML-Budget von 150 KB (`test:browser`) war mit dem CSS je Kachel überschritten (152 KB). Die gemeinsamen Regeln stehen jetzt einmal am Abschnitt, Ergebnis 147,5 KB.
**Geprüft:** Lighthouse im Produktionsmodus (Port 8103, je drei Läufe, Median): Startseite mobil 97 / Desktop 98, Impressum und Datenschutz 100 / 100; Barrierefreiheit, Best Practices, SEO und agentisches Browsing überall 100. `test:links` ohne toten Verweis, `test:browser` grün (axe in sechs Ansichten, Tastatur, ohne JavaScript, Budget). Ganzseitige Bildschirmfotos bei 1440, 820 und 375 px gegen den Entwurf verglichen, kein waagerechtes Scrollen, keine Konsolenfehler. Zoom, Schatten, Chip- und Knopf-Hover sowie das Klappmenü per Playwright nachgemessen. Keine Felddaten, kein INP. Das Formular wurde nicht abgeschickt (Mailversand nicht ausprobiert).
**Nächster Schritt:** Livegang nach `docs/LIVEGANG.md` (Mailversand einmal echt testen). Die Hüfner-Datenbank braucht einen Kern mit ADR 107 (`tel:` an Knöpfen).
## Kantarci Markt: Demo der Eröffnungsseite mit Angeboten aus der App (24.09.2026)
**Anlass:** Umut: „Setze mal die demoseite um wie du es dir vorstellst ich überlasse dir alles. Links und logo zu playstore und ios app, wilhelm drapp str. in baden baden, Rest Platzhalter“. Die Angebote kommen aus der Web-Ansicht seiner App: `https://app.kantarci-markt.de/embed/angebote.php?ton=dunkel`, dazu sein Skript für die Höhe.
**Neu (nur Inhalt, kein Kern):** `/eroeffnung` im Seed-Skript, veröffentlicht, aber `noindex` und nirgends verlinkt. Aufbau: Einstieg „Jetzt geöffnet“ mit zwei Wegen (Angebote, Anfahrt) und Öffnungszeiten, Angebote als eingebettete App-Ansicht, App-Bereich mit Knöpfen für App Store und Google Play, das Versprechen, Besuch (Adresse mit „Route planen“, Öffnungszeiten, Kontakt), Abschluss. Zur Eröffnung soll dieser Inhalt als geplanter Entwurf auf die Startseite, `/eroeffnung` fällt dann weg.
- **Einwilligung:** keine nötig. `Consent::granted()` lässt jede Gruppe durch, solange die Website keine Einwilligungsleiste hat (bei Kantarci Markt aus). Meine frühere Aussage, der Baustein verlange immer eine Einwilligung, war falsch. Eine Option „Eigener Dienst“ braucht es erst, wenn die Seite einmal eine Leiste bekommt.
- **Höhe:** Umuts Skript hängt als eigenes Skript am Baustein. Es lief zu spät: Die App meldet ihre Höhe beim Laden (gemessen 332 ms), das Skript lief als `defer`-Datei erst kurz vor DOMContentLoaded (402 ms), danach meldet die App nur noch Änderungen. Jetzt fragt das Skript nach dem Start per `km-angebote-height-request` nach und lädt den Rahmen als Rückfall nach 600 ms einmal neu, falls keine Meldung kam. Die App kennt die Nachfrage noch nicht, deshalb greift derzeit der Rückfall (zweiter Abruf der Web-Ansicht).
- **Hintergrund:** Die Web-Ansicht ist für hellen Grund gebaut (dunkle Überschrift, weiße Karten), `ton=dunkel` und `ton=hell` liefern dieselbe Seite. Der Angebotsbereich steht deshalb auf Sand statt auf Waldgrün. `& iframe{border-radius:0;background:transparent}` am Baustein nimmt Rundung und Tönung aus `site.css`.
- **Platzhalter:** Öffnungszeiten (Mo–Sa 8–20 Uhr, So geschlossen), „Telefon folgt“, Store-Links auf die Suche nach „Kantarci Markt“ im jeweiligen Store, Store-Knöpfe als eigene schwarze Knöpfe ohne die Logos von Apple und Google. Alles oben im Abschnitt des Seed-Skripts.
- **`scripts/audit.mjs`** kennt `CMS_HOST_RULES` (etwa `MAP localhost 127.0.0.1`): Die App erlaubt das Einbetten nur von `kantarci-markt.de` und `http://localhost:*`, der Server lauscht auf 127.0.0.1.
**Geprüft:** Lighthouse im Produktionsmodus über `localhost:8101`, Rahmen geladen: `/eroeffnung` mobil 96 / Desktop 100, Barrierefreiheit, Best Practices und agentisches Browsing 100. SEO 69 nur wegen des gewollten `noindex` (`is-crawlable`), keine Konsolenfehler. Die Startseite blieb bei 98 / 100 und überall sonst 100. Im Browser: Rahmen 448 px (Desktop) bzw. 971 px (375 px) hoch, kein Scrollbalken, kein waagerechtes Scrollen. Sicherheitsrichtlinie der Seite: `frame-src https://app.kantarci-markt.de`, `script-src 'self'`.
**Nachtrag, gleicher Tag – Popup statt Link (App-Repository `C:\Django Project\Supermarkt`):** Umut: Angebote ohne Bild wirkten durchsichtig, „Unsere Angebote“ war weiß, und statt eines Links soll ein Popup die Einzelheiten hier zeigen. Die App-Ansicht hatte inzwischen `ton`, `titel`, `app`, `bg` bekommen; `ton=dunkel` machte die Überschrift weiß. Eingebunden ist sie jetzt mit `?titel=0&app=0` (eigene Überschrift der Seite, kein Knopf nach außen). In der App (`public/embed/angebote.php`, noch nicht committet, nicht ausgeliefert): Karten sind `` mit einem Knopf im Namen statt ``, ein natives `