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>
Das Auswahlfeld des Browsers sah aus wie das Auswahlfeld des Browsers.
Hochgeladen wird jetzt über eine Ablagefläche: Bilder hineinziehen oder
klicken, darunter steht, welche Dateien gewählt sind und welche übersprungen
wurden.
Darunter liegt weiter ein echtes input[type=file] - unsichtbar, aber
fokussierbar, mit der Fläche als label und dem Fokusring über :focus-within.
Ohne JavaScript bleibt genau das übrig: ein Dateifeld mit Beschriftung. Das
Skript ergänzt Ziehen und benennt die Auswahl; abgeschickt wird nie von
selbst. Kein "required", weil der Browser seine Meldung nicht an etwas
Unsichtbares hängen kann - der Server weist einen leeren Upload mit einem
lesbaren Satz ab.
docs/UPDATE.md plant das Update über einen Git-Tag: Vorprüfung, Sicherung,
Wartungszustand mit 503 für die Website und offenem /admin, Checkout,
composer, Migration, Cache, Rauchtest, Protokoll - und den Rückweg in
derselben Reihenfolge rückwärts. Migrationen bleiben nicht umkehrbar, der
Rückweg ist die Sicherung. Kein Updater, der eine Adresse aus dem Formular
zieht, und kein automatisches Update im Hintergrund. Zwei Entscheidungen
hängen am Hosting: Composer auf dem Server oder vendor/ im Tag, und ob es
Shell-Zugriff gibt. Gebaut ist davon nichts.
219 PHP-Tests / 881 Assertions unter PHP 8.4.22, darunter Upload über das
Formular mit zwei Dateien, CSRF-Pflicht, Versionskonflikt, Archivfilter und
Blättern mit 26 Bildern. Playwright prüft die Ablagefläche am echten
Dateifeld; axe bleibt auf elf Bildschirmen ohne Verstöße.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>