Commit Graph
11 Commits
Author SHA1 Message Date
kantarciandClaude Opus 5 a434e0cefc Serve every font from this server and surface open tasks in 1.14.0
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Fonts were still reachable from Google in two places. The editor and area
previews were handed `googleFonts` and no `localFonts`, so the screen used
most of the day fetched Lato from fonts.googleapis.com on every open; the
public page fell back to the same link whenever the files were missing.
Neither path remains: the template has no Google branch, `googleFontsUrl()`
is gone, and the policies name no foreign font host - `font-src 'self'`
publicly, `style-src 'self'; font-src 'self'` in administration. Without
local files a site now shows the theme's fallback and says so.

Preloading took the first two weights per family. The Kant-IT theme names
Lato 400, 700 and 900 and sets its headings on 800/900, so the one weight
that carried them loaded after the stylesheet and `font-display:swap`
swapped the heading in plain sight. Every weight of the theme is preloaded
now, latin subset, and the links sit before the stylesheet: measured cold,
all three files finish at 168 ms against a first paint at 292 ms.

Open tasks no longer hide on the screen that owns them. A strip above every
management screen names what needs a button and carries it: a new version
leads to System, missing fonts to Design. Neither asks the network - the
version comes from the daily update-check task, the fonts from a look in
the folder.

System and update was unusable on a phone: `.stack` is a grid whose
automatic column grows to its widest content, and one long database path
pushed the page sideways. It gets `minmax(0, 1fr)`, the backup table stacks
below 620px, and the prose is 45% shorter with the fine print folded away.

The device chips drew the current device with an outline, which lies outside
the box, ran under its neighbour and was clipped by the sidebar - it read as
a cut-off red frame. Used devices are filled in `#9d4e0d` now (5.6:1), the
current one carries a border inside the chip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 00:16:16 +02:00
kantarci 3391fea58b Add visual button presets, jump targets and menu controls
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
2026-09-14 13:47:49 +02:00
kantarci 495b26896e Fassung 1.7.0: verlässliche Installation, übersichtliche Verwaltung und bedienbare Bewegung
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
2026-09-14 10:49:54 +02:00
kantarciandClaude Opus 5 05ea703655 Fassung 1.6.0: der Aufgabenplan wird veroeffentlicht
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Wiederkehrende Aufgaben ohne Cronjob (ADR 073): Sicherung, Statistik kuerzen,
geplante Veroeffentlichung, Updatepruefung und Aufraeumen laufen als Plan in
der Tabelle scheduled_task - eine Zeile je Aufgabe mit Faelligkeit, Sperre und
letztem Ergebnis. Auf geteiltem Hosting gibt es oft keinen Cronjob; der Plan
haengt stattdessen an Anfragen und an einem Takt aus dem geoeffneten Backend.

Diese Arbeit entstand in einer parallel laufenden Sitzung und lag bis hierher
unveroeffentlicht im Arbeitsverzeichnis: die Releases 1.5.0 bis 1.5.5 wurden
bewusst aus dem jeweiligen Tag gebaut und enthielten sie deshalb nicht.

Vor der Veroeffentlichung geprueft, nicht bloss eingepackt:

- phpunit 452/452, npm test 28/28, npm run test:editor vollstaendig.
- Die Migration 20260914000100 legt nur die Tabelle scheduled_task an und nimmt
  sie beim Zurueckrollen wieder weg. Sie fasst keine bestehenden Daten an.
- Seit einer Stunde keine Schreibzugriffe der anderen Sitzung mehr.

Dabei zwei Fehler behoben:

- config/services.yaml verwendet !tagged_iterator. Das ist gueltiges Symfony,
  aber "lint:yaml config" kennt eigene Tags nur mit --parse-tags und gab 1
  zurueck - der CI-Lauf waere daran gescheitert. Flag ergaenzt.
- AdminHeadersSubscriber.php (aus 1.5.3) entsprach nicht dem Stil von
  php-cs-fixer; composer lint gab 8 zurueck. Behoben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 08:30:13 +02:00
kantarciandClaude Opus 5 d6d476177a Fassung 1.4.3: Update ohne Git, Verwaltung auf dem Telefon, eigene Symbole
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Vier Wuensche und ein Fund beim Nachmessen.

- Farbwaehler im Designbereich. Das Textfeld bleibt massgeblich, damit
  "@akzent" ein Verweis auf die Palette bleibt und nicht beim ersten
  Klick zu einem festen Hexwert erstarrt (ADR 066).
- Die Verwaltung auf dem Telefon: das Menue klappt unter 760 px zu und
  nennt den Bereich, in dem man steht; Ziele 44 px, kein Skript.
- Eigene SVG-Symbole statt Unicode-Zeichen - ein Telefon ersetzt die
  sonst durch Emoji in fremdem Stil. Zwei Eintraege trugen dabei
  denselben Pfad; ein Test findet beides (ADR 067).
- Update aus dem Releasearchiv: der Weg fuer Installationen ohne Git.
  Zwei Schritte, weil ein Prozess, der sich selbst ausgetauscht hat,
  mit dem alten Code weiterarbeitet. var/, .env, hochgeladene
  Schriften und das erzeugte Buendel bleiben unberuehrt; public/ wird
  dazu Datei fuer Datei zusammengefuehrt. Geprueft ohne Netz gegen
  eine Releaseseite im Speicher (ADR 068).

Beim Nachmessen der echten Startseite statt einer Testseite: das
groesste Element ueber der Falz ist dort kein <img>, sondern der
Hintergrund des ersten Abschnitts - und der steht nur im Stylesheet.
Drei Vorabverweise mit denselben Geraetegrenzen wie der Compiler holen
genau die Variante, die die Regel auch nimmt. LCP 1,3 s -> 1,1 s.
Dabei gefunden: dasselbe Bild wurde je Geraeteregel neu abgefragt -
Startseite 19 -> 15 Abfragen (ADR 069).

Geprueft: 428 Tests auf PHP 8.2 und 8.4, Editor-, Browser- und
Linkpruefung, Lighthouse auf drei echten Seiten (alles ausser der
Leistung der Startseite 100).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 23:01:32 +02:00
kantarciandClaude Opus 5 5a8d67a638 Fassung 1.0.1: die laufende Fassung steht in der Verwaltung
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Eine kleine, von außen sichtbare Änderung - sie ist der Prüfstein für das
Update: nach dem Einspielen muss in der Seitenleiste 1.0.1 stehen, und der
Weg dorthin muss die Schritte gegangen sein, die der Updater verspricht.

Die Fassung kommt über eine Twig-Funktion in die Vorlage, nicht über einen
globalen Dienst: die Vorlagen bekommen genau diese eine lesende Antwort und
nicht einen Updater mit update() darauf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 20:11:21 +02:00
kantarciandClaude Opus 5 52f0ab3807 Updater: neue Fassung über Git, mit Vorprüfung und Rückweg
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Aus dem Plan in docs/UPDATE.md ist Code geworden: cms:update, cms:health, der
Bildschirm "System" und der Wartungszustand.

Die Vorprüfung ist die halbe Arbeit. Sie fragt nach proc_open, Git, sauberer
Arbeitskopie, Herkunft, Schreibrechten und Platz - und danach, ob Datenbank
und Medienordner wirklich von Git ausgenommen sind. Das ist der Punkt, an dem
ein Update Inhalte zerstören könnte, also wird er geprüft und nicht
angenommen. Jede Prüfung sagt, was zu tun ist, nicht bloß "fehlgeschlagen".

Der Rückweg ist Teil des Wegs: scheitert ein Schritt, wird auf den vorherigen
Commit zurückgesetzt. Die Datenbank nur dann zurückgeschrieben, wenn die
Migration schon begonnen hatte - sonst verlöre der Rückweg Inhalte, die
während des Updates entstanden sind. Antwortet der alte Stand im Rauchtest,
geht die Website wieder online; antwortet er nicht, bleibt der Wartungszustand,
weil eine kaputte Seite schlechter ist als eine ehrliche Meldung.

Der Rauchtest läuft als eigener Prozess, denn nur ein frischer Prozess führt
den neuen Code aus. Ein Test im laufenden Prozess hätte den alten geprüft und
"alles in Ordnung" gemeldet.

Kein symfony/process: der Runner sind dreißig Zeilen über proc_open mit dem
Befehl als Array - kein Shell, nichts zu maskieren, und "proc_open ist
abgeschaltet" wird die erste Antwort statt der Überraschung im dritten
Schritt.

285 PHP-Tests / 1244 Assertions. Sechs davon fahren den Updater gegen echte
Git-Repositorys in einem Temp-Verzeichnis, mit Platzhalterskripten für die
zwei Befehle - inklusive des Fehlschlags, nach dem Code und Datenbank
zurückgesetzt sein müssen. Nicht gegen dieses Projekt: ein Test, der die
Arbeitskopie auscheckt, in der er läuft, ist ein Weg, Arbeit zu verlieren.

Offen bleibt die Sicherung einer MySQL-Datenbank per mysqldump - dafür fehlt
die Installation; der Updater sagt das im Schritt "Sicherung".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 20:08:48 +02:00
kantarciandClaude Opus 5 99bad61179 Statistik: Zähler statt Protokoll, deshalb ohne Einwilligung
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
"Wieviel wann wo wie die Seite benutzt" - naheliegend wäre ein Analysewerkzeug
gewesen, das eine Einwilligung braucht und damit genau die Besucher verliert,
die ablehnen. Also andersherum: eine Messung, die niemanden wiedererkennt.

Gespeichert wird ein Zähler je (Tag, Stunde, Pfad, Status, Verweis-Domain),
kein Datensatz je Aufruf. Keine IP-Adresse, keine Kennung, kein Cookie - auch
nicht gehasht, denn der Hash einer IP-Adresse bleibt ein Personenbezug. Ein
Test liest die Spaltenliste der Tabelle und vergleicht sie mit dieser Zusage,
damit sie beim nächsten Ausbau nicht unbemerkt fällt. Vom Verweis bleibt nur
der Host: die volle Adresse kann einen Suchbegriff oder einen Namen tragen.

Gezählt wird auf kernel.terminate, nach der Antwort - die Messung darf keine
Anfrage verlangsamen, und ein Fehler beim Zählen kostet einen Zähler, nicht
eine Seite. Nur GET auf HTML mit 200 oder 404; Verwaltung, Assets, Feed,
Sitemap und Einwilligungsseite sind ausgenommen, erkennbare Maschinen über
ihre Kennung. Das ist eine Heuristik, deshalb heißt die Zahl auf dem
Bildschirm nicht "Besucher". Erfundene Crawler-Adressen laufen gesammelt unter
(sonstige), sonst wächst die Tabelle mit jedem geprobten Pfad.

Die Diagramme zeichnet der Server als SVG mit Klassen statt Stilattributen:
kein Diagrammwerkzeug, kein Skript, und die Richtlinie bleibt streng. Die
Zahlen stehen zusätzlich in einer Tabelle, weil ein Balken für einen
Screenreader nichts ist.

Was die Zahlen nicht sagen, steht auf dem Bildschirm: Aufrufe statt Besucher,
keine Verweildauer, keine Absprungrate, kein Klickweg, kein Land. Das ist die
Folge der Entscheidung, nicht eine Lücke.

Aufbewahrung: nach 60 Tagen werden die Stunden eines Tages verschmolzen, nach
425 Tagen gelöscht - gut ein Jahr, damit der Vorjahresmonat vergleichbar
bleibt. cms:stats:prune macht beides und gehört in einen Cronjob.

279 PHP-Tests / 1119 Assertions unter PHP 8.2.12 und 8.4.22, axe auf zwölf
Verwaltungsbildschirmen ohne Verstöße. Dabei kam eine PHP-8.4-Verwarnung zu
fputcsv() heraus, jetzt mit ausdrücklichem Escape-Parameter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 19:50:08 +02:00
kantarciandClaude Opus 5 84d471acd9 Das System heißt KantSites
Umut hat den Namen festgelegt: aus dem Arbeitstitel "Kant CMS" wird KantSites.
Geändert in allen Seitentiteln der Verwaltung, im Wortmarken-Schriftzug von
Anmeldung und Seitenleiste, in den Fußzeilen, in den Demoinhalten für eine
frische Installation, in package.json, .claude/launch.json und der
Dokumentation. Die Bezeichnung der Website in der Datenbank heißt jetzt
ebenfalls KantSites.

Nicht angefasst: die bereits gespeicherten Demoinhalte der lokalen
Installation. Titel wie "Die Grundlage · Kant CMS" und der Text im
Kopfbereich sind Inhalt, nicht Systemname - die gehören in den Editor, nicht
in ein Skript, das Revisionen umschreibt.

219 PHP-Tests / 881 Assertions grün, Playwright-Editortest grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 18:36:50 +02:00
kantarciandClaude Opus 5 14031a5880 Benutzerverwaltung in der Oberfläche, Mediathek als eigene Seite
Konten gab es bisher nur über die Konsole. Unter "Benutzer" legt ein
Administrator jetzt Konten an, ändert Rollen, setzt Passwörter und löscht
Konten; unter "Mein Konto" ändert jeder sein eigenes Passwort, aber nur mit
dem aktuellen in der Hand.

Eine Rolle je Konto: Administrator, Veröffentlicher, Redakteur. Ein Passwort
oder eine Rolle zu ändern meldet jede offene Sitzung dieses Kontos ab - dafür
war nichts zu bauen, CmsUser::isEqualTo vergleicht Hash und Rollen mit der
Datenbank. Genau eine Sitzung überlebt: die, die ihr eigenes Passwort geändert
hat. "Jemanden sofort aussperren" ist damit dasselbe wie "Passwort setzen".

Es bleibt immer ein Administrator übrig, nicht über eine Zählung, sondern weil
niemand sein eigenes Konto löschen oder herabstufen kann und jede Änderung die
Administratorrolle voraussetzt. Die zusätzliche Prüfung auf einen zweiten
Administrator war damit unerreichbar und ist wieder heraus.

Mediathek (Umut: "das sollte direkt laden in pagination"): /admin/media zeigt
die Bilder jetzt selbst, 24 je Seite, neueste zuerst, mit Blättern und einem
Schalter für archivierte. Hochladen und Bildangaben laufen über gewöhnliche
Formulare ohne JavaScript; der Dialog bleibt der Weg, beim Bearbeiten ein Bild
auszuwählen. Die Bild-ID steht in jeder Karte, weil Beitragsbild und
Teilen-Vorschau genau diese ID erwarten.

Die Migrationsliste der Testfixtures stand dreimal da und steht jetzt einmal
in tests/TestSchema.php.

217 PHP-Tests / 845 Assertions unter PHP 8.2.12 und 8.4.22. axe deckt jetzt
elf Bildschirme ab statt drei - alle Verwaltungsseiten, nicht nur Anmeldung,
Seitenliste und Editor -, null Verstöße. Nicht geprüft: kein Screenreader;
Blättern und Upload sind mit zwei Bildern geprüft, nicht mit einer großen
Bibliothek.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 18:14:50 +02:00
kantarciandClaude Opus 5 4841bf65bc Verwaltung neu gestaltet: ein Rahmen statt sieben Kopfzeilen
Jede Verwaltungsseite trug bisher ihre eigene Kopfzeile und ihre eigene,
unvollständige Liste von Links auf die anderen Seiten - die Seitenübersicht
verlinkte sieben Bereiche, das Menü fünf, die Fassungen drei. Wo man war,
stand nirgends.

Jetzt gibt es einen Rahmen für alle: eine feste Seitenleiste mit der
Navigation, der aktive Eintrag über aria-current markiert, und eine Kopfzeile
mit Titel, einem Satz Erklärung und Platz für die Hauptaktion. Jede Seite
füllt nur noch heading, lead, actions und content. Auf schmalen Fenstern wird
die Seitenleiste zu einer scrollbaren Leiste, ohne JavaScript.

Die Seitenübersicht zeigt je Seite eine Zeile mit dem Alltäglichen und einem
Aufklappfeld "Einstellungen", das darunter an seinem Platz öffnet - vorher
waren es sechs Aufklappfelder, deren Inhalt als absolut positionierter Kasten
über den Rand der Karte hinausragte. Tabellen scrollen seitlich, statt die
Karte aus dem Fenster zu schieben.

Das Stylesheet ist geteilt: die Editorregeln stehen in editor.css, das nur
Editor und Mediathek laden; admin.css ist neu geschrieben und lesbar. Der
Editor behält seinen Aufbau und übernimmt die neue Gestaltung - Systemschrift,
gleiche Radien, gleiche Schaltflächen, und ein paar Panelgrößen, die zum Lesen
zu klein waren.

Beim Zerlegen des Stylesheets schnitt mein Skript am Ende jedes @media-Blocks
alle schließenden Klammern ab statt nur einer. editor.css war damit ab dem
ersten Medienblock ungültig: der Browser behielt 29 von 202 Regeln. Gefunden
hat das der Browsertest, an einer Vorschaubreite von 1236 statt 1240 Pixeln -
vier Pixel als einziges Anzeichen dafür, dass dreiviertel des Stylesheets
fehlte.

201 PHP-Tests / 716 Assertions unter PHP 8.2.12 und 8.4.22, Playwright-
Editortest mit axe ohne Verstöße auf Anmeldung, Seitenübersicht und Editor,
öffentliche Browserprüfung grün. Zwei Testselektoren zeigten auf umbenannte
Klassen und prüfen dieselbe Sache nun über den neuen Namen. Nicht geprüft:
kein Screenreader, und die Bildschirme Menüs, Formulare, Bereiche, Design,
Einstellungen und Fassungen sind nur von Hand bedient, nicht automatisiert
geprüft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:41:22 +02:00