Deploy-Anleitung + Cron-Endpoint stilllegen
Der Tarif hat jetzt SSH und Shell-Cronjobs. Damit fällt die Begründung für public/cron.php weg: der Endpoint war ausschließlich der Ersatz dafür. cron.key steht in der Produktiv-Config auf '' (403 auf jeden Aufruf), der Code bleibt als Rückweg samt Begründung stehen. docs/deploy.md beschreibt den Weg in kleinen Schritten. Kern: die neue Seite läuft erst auf einer per Verzeichnisschutz geschlossenen Test-Subdomain mit DERSELBEN Produktiv-Config, die später live geht — kein Config-Wechsel beim Umschalten. Möglich, weil die Host-Weiterleitung in public/.htaccess nur beim exakten Host ohne www greift. Die alte CMS-Seite bleibt bis zuletzt online und ist der Rückweg. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
This commit is contained in:
25
CLAUDE.md
25
CLAUDE.md
@@ -7,7 +7,8 @@ selbst gehosteter Stack ohne Abhängigkeiten von Drittanbietern.
|
|||||||
|
|
||||||
- **Frontend:** Natives HTML, Vanilla CSS, Vanilla JS. Kein Framework, keine Build-Pipeline, kein Node.
|
- **Frontend:** Natives HTML, Vanilla CSS, Vanilla JS. Kein Framework, keine Build-Pipeline, kein Node.
|
||||||
- **Backend:** Vanilla PHP ≥ 8.1, Composer nur für `phpmailer/phpmailer`. Keine Template-Engine.
|
- **Backend:** Vanilla PHP ≥ 8.1, Composer nur für `phpmailer/phpmailer`. Keine Template-Engine.
|
||||||
- **Hosting-Ziel:** Apache Shared Hosting, PHP 8.x, `.htaccess`, Cronjobs verfügbar.
|
- **Hosting-Ziel:** All-Inkl Shared Hosting, PHP 8.x, `.htaccess`, SSH **und** Shell-Cronjobs
|
||||||
|
(seit 31.07.2026 im Tarif). Deploy-Anleitung Schritt für Schritt: **`docs/deploy.md`**.
|
||||||
- **Lokales Dev:** `php -d upload_max_filesize=250M -d post_max_size=260M -S localhost:8000 -t public public/index.php`
|
- **Lokales Dev:** `php -d upload_max_filesize=250M -d post_max_size=260M -S localhost:8000 -t public public/index.php`
|
||||||
(index.php fungiert als Router-Script, weil `php -S` kein .htaccess kennt). Die beiden `-d`-Schalter
|
(index.php fungiert als Router-Script, weil `php -S` kein .htaccess kennt). Die beiden `-d`-Schalter
|
||||||
brauchst du für die Dateiablage `/dateien`: der CLI-Server liest keine `.user.ini`, und mit den
|
brauchst du für die Dateiablage `/dateien`: der CLI-Server liest keine `.user.ini`, und mit den
|
||||||
@@ -329,11 +330,21 @@ Keine rohen Werte in `base/layout/components/utilities.css` — es gibt für all
|
|||||||
- [ ] Keine Duplikate: Inhalte/Werte aus den Single-Source-Dateien beziehen
|
- [ ] Keine Duplikate: Inhalte/Werte aus den Single-Source-Dateien beziehen
|
||||||
- [ ] `php -l` sauber; Seite lokal geprüft
|
- [ ] `php -l` sauber; Seite lokal geprüft
|
||||||
|
|
||||||
## Cron-Endpoint `public/cron.php` (Ausnahme 3b)
|
## Cron-Endpoint `public/cron.php` (Ausnahme 3b) — **stillgelegt**
|
||||||
|
|
||||||
**Der Tarif kennt keine zeitgesteuerten Aufgaben** — das KAS meldet „in deinem Tarif nicht verfügbar",
|
**Seit 31.07.2026 hat der Tarif SSH und echte Shell-Cronjobs.** Damit ist der Endpoint überflüssig:
|
||||||
weder Shell- noch URL-Cronjobs (geprüft 27.07.2026). Die Sync-Skripte müssen aber getaktet laufen, also
|
er war ausschließlich der Ersatz für den fehlenden Cron. `cron.key` steht in der Produktiv-Config auf
|
||||||
kommt der Takt von außen: ein externer Cron-Dienst ruft
|
`''`, der Endpoint antwortet also auf jeden Aufruf mit 403 — ein Geheimnis weniger, das bei einem
|
||||||
|
externen Dienst liegt und leaken kann. Der Takt läuft über die Crontab-Zeilen aus
|
||||||
|
`config/config.example.php` (Weg A), der Ablauf steht in **`docs/deploy.md`**, Teil D.
|
||||||
|
|
||||||
|
**Der Code bleibt.** Er ist geprüft, kostet nichts (403 in drei Zeilen) und ist der Rückweg, falls der
|
||||||
|
Shell-Cron ausfällt: neuen Schlüssel in `cron.key`, fertig. Deshalb sind die Grenzen unten weiter
|
||||||
|
beschrieben, statt sie mit dem Code zu löschen — wer ihn je wieder aufschließt, braucht sie.
|
||||||
|
`bin/preflight.php` warnt bei leerem Schlüssel und weist damit auf genau diese Entscheidung hin;
|
||||||
|
die Warnung ist erwartet, kein Mangel.
|
||||||
|
|
||||||
|
Die Begründung von damals, weiterhin gültig für den Fall der Reaktivierung: ein externer Cron-Dienst ruft
|
||||||
`https://…/cron.php?job=matchcenter` bzw. `?job=instagram` auf, der Endpoint startet das Skript
|
`https://…/cron.php?job=matchcenter` bzw. `?job=instagram` auf, der Endpoint startet das Skript
|
||||||
serverseitig. Schlüssel aus `config('cron.key')`, per Header `X-Cron-Key` **oder** als `key`-Parameter.
|
serverseitig. Schlüssel aus `config('cron.key')`, per Header `X-Cron-Key` **oder** als `key`-Parameter.
|
||||||
|
|
||||||
@@ -363,8 +374,8 @@ Besucher keine Aktualisierung, und Fire-and-Forget ist auf Shared Hosting unzuve
|
|||||||
`$argv` wird im Endpoint gesetzt, weil es im Web-SAPI nicht existiert.
|
`$argv` wird im Endpoint gesetzt, weil es im Web-SAPI nicht existiert.
|
||||||
|
|
||||||
`bin/preflight.php` prüft Schlüssellänge, Verwechslung mit `app_secret` und ob `min_interval` den
|
`bin/preflight.php` prüft Schlüssellänge, Verwechslung mit `app_secret` und ob `min_interval` den
|
||||||
gewünschten Takt sperrt. **Wenn der Tarif je Cronjobs bekommt:** `cron.key` leeren, dann ist der
|
gewünschten Takt sperrt. Der damals hier notierte Ausstieg („wenn der Tarif je Cronjobs bekommt,
|
||||||
Endpoint zu, und der Takt läuft wieder wie in `config.example.php` dokumentiert.
|
`cron.key` leeren") ist am 31.07.2026 genau so eingetreten und vollzogen.
|
||||||
|
|
||||||
**Offen:** ob der Instagram-Scraper von der Server-IP überhaupt durchkommt. Instagram sperrt
|
**Offen:** ob der Instagram-Scraper von der Server-IP überhaupt durchkommt. Instagram sperrt
|
||||||
Rechenzentren; hier lief er nur über einen privaten Anschluss. Einmal auf dem Server prüfen. Falls er
|
Rechenzentren; hier lief er nur über einen privaten Anschluss. Einmal auf dem Server prüfen. Falls er
|
||||||
|
|||||||
320
docs/deploy.md
Normal file
320
docs/deploy.md
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
# Deploy auf All-Inkl (Shared Hosting, SSH + Cronjobs)
|
||||||
|
|
||||||
|
Schritt für Schritt vom leeren Webspace zur Live-Seite. Die Reihenfolge ist Absicht:
|
||||||
|
**die alte CMS-Seite bleibt online, bis die neue auf einer geschützten Test-Subdomain
|
||||||
|
nachweislich läuft.** Umgeschaltet wird erst am Ende, und das Umschalten ist in einer
|
||||||
|
Minute rückgängig.
|
||||||
|
|
||||||
|
Der Kern des Plans: die Test-Subdomain läuft mit **derselben** `config.php`, die
|
||||||
|
später live geht. Es gibt keinen Config-Wechsel beim Umschalten, also auch keinen
|
||||||
|
Fehler, der sich dabei einschleichen kann. Möglich ist das, weil die
|
||||||
|
Host-Weiterleitung in `public/.htaccess` nur beim exakten Host `tsv08kulmbach.de`
|
||||||
|
greift; eine Subdomain läuft unbehelligt durch. Einzige Abweichung: Canonical, OG
|
||||||
|
und Sitemap nennen auf der Test-Subdomain schon die echte Domain. Genau richtig für
|
||||||
|
den Umschaltmoment, und dank Verzeichnisschutz sieht es ohnehin keine Suchmaschine.
|
||||||
|
|
||||||
|
Legende: `[lokal]` auf deinem Mac, `[SSH]` in der Server-Shell, `[KAS]` im
|
||||||
|
All-Inkl-Kundenmenü.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil A — Vorbereitung lokal
|
||||||
|
|
||||||
|
### A1 [lokal] Die zwei offenen Werte in `config/config.production.php` setzen
|
||||||
|
|
||||||
|
`php bin/preflight.php` bricht sonst auf dem Server ab. Beides betrifft nur die
|
||||||
|
Dateiablage `/dateien`, nicht die Website selbst.
|
||||||
|
|
||||||
|
**Passwörter für die zwei Zugänge.** Als Hash, nicht als Klartext:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -r 'echo password_hash("DEIN-PASSWORT", PASSWORD_DEFAULT), "\n";'
|
||||||
|
```
|
||||||
|
|
||||||
|
Ausgabe (beginnt mit `$2y$…`) in `dateien.users.verein.password_hash` bzw.
|
||||||
|
`dateien.users.admin.password_hash` eintragen. Zwei verschiedene Passwörter: `verein`
|
||||||
|
gibt der Verein weiter, `admin` behältst du.
|
||||||
|
|
||||||
|
**Lizenzschlüssel** der Files Gallery in `dateien.license_key`. Fehlt er, läuft die
|
||||||
|
Ablage trotzdem, zeigt aber den Hinweis der unlizenzierten Version (nur eine Warnung
|
||||||
|
in `preflight`, kein Blocker).
|
||||||
|
|
||||||
|
Bereits erledigt: `cron.key` ist auf `''` gesetzt und der Endpoint `public/cron.php`
|
||||||
|
damit zu. Der Takt kommt ab jetzt aus echten Cronjobs (Teil D), der Endpoint war nur
|
||||||
|
der Ersatz für den fehlenden Cron.
|
||||||
|
|
||||||
|
### A2 [lokal] Alles gepusht?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status --porcelain # muss leer sein
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil B — Server einrichten
|
||||||
|
|
||||||
|
### B1 [SSH] Umgebung feststellen und notieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh <dein-kas-user>@<dein-server>.kasserver.com
|
||||||
|
pwd # z. B. /www/htdocs/w01ca75d → das ist HOME
|
||||||
|
which php; php -v # PHP muss >= 8.1 sein
|
||||||
|
git --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Drei Dinge, die du für später brauchst: den **Pfad aus `pwd`**, den **Pfad aus
|
||||||
|
`which php`** und die **PHP-Version**. Ist `php` älter als 8.1, prüfe nach
|
||||||
|
versionierten Binaries (`ls /usr/bin/php*`, `ls /usr/local/bin/php*`) und nimm den
|
||||||
|
passenden absoluten Pfad; die Cronjobs brauchen ihn ohnehin absolut.
|
||||||
|
|
||||||
|
### B2 [SSH] Repo klonen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~
|
||||||
|
git clone https://onion.breadcrumb-online.de/fs/tsv08kulmbach-website.git tsv08kulmbach
|
||||||
|
cd tsv08kulmbach && pwd # diesen Pfad notieren: das ist SITE
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Klon lädt gut 460 MB (Website plus das Vereinsmaterial der Dateiablage), das
|
||||||
|
dauert ein paar Minuten. Die alte CMS-Seite liegt in einem anderen Verzeichnis und
|
||||||
|
wird nicht angefasst.
|
||||||
|
|
||||||
|
### B3 [SSH] `config.php` platzieren
|
||||||
|
|
||||||
|
Die Datei ist gitignored, also nicht im Klon. Vom Mac hochladen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# [lokal], in einem zweiten Terminal
|
||||||
|
scp config/config.production.php \
|
||||||
|
<kas-user>@<server>.kasserver.com:~/tsv08kulmbach/config/config.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Wichtig: Ziel heißt `config.php`, nicht `config.production.php`. Danach [SSH]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod 600 config/config.php # enthält SMTP-Passwort und app_secret
|
||||||
|
```
|
||||||
|
|
||||||
|
### B4 [SSH] Composer-Abhängigkeiten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/tsv08kulmbach
|
||||||
|
composer install --no-dev --optimize-autoloader
|
||||||
|
```
|
||||||
|
|
||||||
|
Kennt die Shell `composer` nicht, hol ihn dir lokal ins Verzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sS https://getcomposer.org/installer | php
|
||||||
|
php composer.phar install --no-dev --optimize-autoloader
|
||||||
|
rm composer.phar
|
||||||
|
```
|
||||||
|
|
||||||
|
Es wird nur PHPMailer installiert.
|
||||||
|
|
||||||
|
### B5 [SSH] Schreibrechte prüfen
|
||||||
|
|
||||||
|
PHP läuft unter deinem Benutzer, meist passt es also schon. `preflight` sagt es dir
|
||||||
|
in Teil C4 verbindlich. Falls dort etwas fehlt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod -R u+rwX storage
|
||||||
|
```
|
||||||
|
|
||||||
|
Schreiben muss die Seite in `storage/logs`, `storage/cache`, `storage/ratelimit`,
|
||||||
|
`storage/dateien/uploads` und `storage/dateien/system`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil C — Auf der Test-Subdomain prüfen
|
||||||
|
|
||||||
|
### C1 [KAS] Subdomain anlegen und schützen
|
||||||
|
|
||||||
|
1. **Domains** → Subdomain `neu.tsv08kulmbach.de` anlegen.
|
||||||
|
2. Als Verzeichnis **`/tsv08kulmbach/public`** eintragen, nicht das Repo-Root.
|
||||||
|
Damit liegen `app/`, `config/`, `data/`, `storage/` und `vendor/` außerhalb des
|
||||||
|
Docroots und sind grundsätzlich nicht per URL erreichbar. (Die Root-`.htaccess`
|
||||||
|
ist nur ein Notnagel für Hoster, die das nicht können.)
|
||||||
|
3. **PHP-Version** für die Subdomain auf 8.1 oder neuer stellen.
|
||||||
|
4. **SSL** aktivieren (Let's Encrypt). Ohne Zertifikat läuft die Seite in eine
|
||||||
|
Endlosweiterleitung, denn `public/.htaccess` erzwingt HTTPS.
|
||||||
|
5. **Verzeichnisschutz** für die Subdomain einschalten (Basic Auth). Das ist der
|
||||||
|
Grund, warum hier nichts indexiert werden kann. Nicht weglassen.
|
||||||
|
|
||||||
|
### C2 Erreichbarkeit
|
||||||
|
|
||||||
|
`https://neu.tsv08kulmbach.de` aufrufen. Nach der Passwortabfrage muss die
|
||||||
|
Startseite kommen. Weißes Blatt oder 500er? Dann [SSH]
|
||||||
|
`tail -30 storage/logs/php-errors.log`.
|
||||||
|
|
||||||
|
### C3 [SSH] Datenstände erzeugen
|
||||||
|
|
||||||
|
`data/matchcenter.json` und `data/instagram.json` sind bewusst nicht im Repo, die
|
||||||
|
holen die Syncs. Vor dem ersten Lauf fehlen Tabellen, Spiele und der
|
||||||
|
Instagram-Block (die Seite bricht deswegen nicht, sie zeigt Ersatzinhalte).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/tsv08kulmbach
|
||||||
|
php bin/matchcenter-sync.php # Spiele, Ergebnisse, Tabellen, Wappen
|
||||||
|
php bin/instagram-sync.php # Posts und Bilder
|
||||||
|
```
|
||||||
|
|
||||||
|
**Der Instagram-Lauf ist der Wackelkandidat des ganzen Deploys.** Instagram sperrt
|
||||||
|
Rechenzentrums-IPs; bisher lief der Scraper nur über einen privaten Anschluss.
|
||||||
|
Schlägt er hier fehl, ist das kein Fehler im Deploy: dann bleibt der Weg, ihn von
|
||||||
|
zu Hause laufen zu lassen und `data/instagram.json` samt Bildern hochzuladen, oder
|
||||||
|
der Block wird redaktionell gepflegt. Die Website funktioniert in jedem Fall.
|
||||||
|
|
||||||
|
### C4 [SSH] `preflight` bis null Fehler
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/preflight.php; echo "Exit: $?"
|
||||||
|
```
|
||||||
|
|
||||||
|
Ziel ist **Exit 0**. Warnungen darfst du bewerten, Fehler nicht. Erwartbare
|
||||||
|
Warnungen hier: der Hinweis, dass `cron.key` leer ist (richtig so, siehe A1) und
|
||||||
|
die Uploadgrenze, die erst ein echter Upload beweist (C6).
|
||||||
|
|
||||||
|
### C5 Durchklicken
|
||||||
|
|
||||||
|
Die Seiten, die eigene Datenquellen haben:
|
||||||
|
|
||||||
|
- [ ] Startseite: Banner-Slider, Termin-Karte im Hero, Instagram-Block
|
||||||
|
- [ ] `/matchcenter`: Tabellen und nächste Spiele mit Wappen
|
||||||
|
- [ ] `/termine`, `/news`, `/veranstaltungen` plus eine Detailseite
|
||||||
|
- [ ] `/stadionzeitung` und die Ausgabe durchswipen — **alle Wappen und
|
||||||
|
Instagram-Bilder da?** (Sie liegen im Repo, sollten also stimmen.)
|
||||||
|
- [ ] `/stadionzeitung/aktuell` landet auf der neuesten Ausgabe
|
||||||
|
- [ ] Die Druckfassung einer Ausgabe (`?druck=1`)
|
||||||
|
- [ ] `/impressum`: Webadresse zeigt `www.tsv08kulmbach.de`, nicht die Subdomain
|
||||||
|
|
||||||
|
### C6 Dateiablage und Mailversand
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/dateien-init.php # Jahr/Abteilung-Ordner, MUSS auf dem Server laufen
|
||||||
|
php bin/smtp-test.php # nur Verbindung und Login, kein Versand
|
||||||
|
```
|
||||||
|
|
||||||
|
`dateien-init.php` gehört auf den Server, weil Umlaute per FTP zu Doppelordnern
|
||||||
|
führen (macOS NFD gegen Linux NFC).
|
||||||
|
|
||||||
|
- [ ] `/dateien` mit beiden Zugängen anmelden
|
||||||
|
- [ ] Eine große Datei hochladen (>10 MB) — beweist die 250-MB-Grenze
|
||||||
|
- [ ] Ein Formular abschicken (z. B. `/kontakt`) und die Mail im Postfach prüfen
|
||||||
|
- [ ] `php bin/logs.php` zeigt keine Fehler
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil D — Cronjobs
|
||||||
|
|
||||||
|
Erst jetzt, damit ab dem Umschalten schon frische Daten liegen. `SITE` und der
|
||||||
|
PHP-Pfad kommen aus B1/B2.
|
||||||
|
|
||||||
|
[KAS] → **Cronjobs** → eigener Cronjob (Shell), vier Einträge:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Instagram 2x/Tag
|
||||||
|
17 6,18 * * * cd SITE && PHP bin/instagram-sync.php >> storage/logs/instagram.log 2>&1
|
||||||
|
|
||||||
|
# Matchcenter Grundtakt 2x/Tag
|
||||||
|
37 7,19 * * * cd SITE && PHP bin/matchcenter-sync.php >> storage/logs/matchcenter.log 2>&1
|
||||||
|
|
||||||
|
# Matchcenter am Spieltag halbstuendlich (Sa+So 13-21 Uhr)
|
||||||
|
7,37 13-21 * * 6,0 cd SITE && PHP bin/matchcenter-sync.php >> storage/logs/matchcenter.log 2>&1
|
||||||
|
|
||||||
|
# Logpflege sonntags nachts
|
||||||
|
23 3 * * 0 cd SITE && PHP bin/log-rotate.php > /dev/null 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
`SITE` und `PHP` durch die echten absoluten Pfade ersetzen, etwa
|
||||||
|
`cd /www/htdocs/w01ca75d/tsv08kulmbach && /usr/bin/php bin/…`. Die Minuten sind
|
||||||
|
versetzt, damit sich zwei Läufe nicht überlappen. Alle Skripte sind CLI-only,
|
||||||
|
sperren sich per Lock gegen Parallelläufe und lassen bei Fehlern den letzten guten
|
||||||
|
Cache stehen — ein fehlgeschlagener Lauf schadet nie.
|
||||||
|
|
||||||
|
Am Tag nach dem ersten Cron-Lauf einmal `php bin/logs.php` ansehen. Läuft nichts,
|
||||||
|
ist fast immer der PHP-Pfad falsch oder relativ.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil E — Umschalten auf die Hauptdomain
|
||||||
|
|
||||||
|
Ab hier ist die Seite öffentlich. Alles davor muss sitzen.
|
||||||
|
|
||||||
|
### E1 Sicherheitsnetz
|
||||||
|
|
||||||
|
Notiere, auf welches Verzeichnis `www.tsv08kulmbach.de` **jetzt** zeigt (die alte
|
||||||
|
CMS-Seite). Das ist dein Rückweg. Verzeichnis und Datenbank der alten Seite bleiben
|
||||||
|
unangetastet, nicht löschen.
|
||||||
|
|
||||||
|
### E2 [KAS] Domain umstellen
|
||||||
|
|
||||||
|
**Domains** → `tsv08kulmbach.de` und `www.tsv08kulmbach.de` auf
|
||||||
|
**`/tsv08kulmbach/public`** zeigen lassen. PHP-Version prüfen, SSL muss für beide
|
||||||
|
aktiv sein.
|
||||||
|
|
||||||
|
### E3 Sofort danach prüfen
|
||||||
|
|
||||||
|
- [ ] `https://www.tsv08kulmbach.de` lädt
|
||||||
|
- [ ] `http://tsv08kulmbach.de` (ohne www, ohne s) landet per 301 auf
|
||||||
|
`https://www.tsv08kulmbach.de`
|
||||||
|
- [ ] `/sitemap.xml` und `/robots.txt` erreichbar
|
||||||
|
- [ ] `curl -sI https://www.tsv08kulmbach.de | head` — Statuszeile 200, kein
|
||||||
|
Redirect-Loop
|
||||||
|
- [ ] Ein Formular live abschicken
|
||||||
|
- [ ] **Einen gedruckten QR-Code mit dem Handy scannen.** Der Code der
|
||||||
|
Stadionzeitung zeigt auf `www.tsv08kulmbach.de/stadionzeitung/aktuell`.
|
||||||
|
Scannen ist die einzige echte Prüfung: die QR-Bibliothek arbeitet nicht
|
||||||
|
reproduzierbar, ein Bildvergleich beweist nichts.
|
||||||
|
|
||||||
|
### E4 Verzeichnisschutz der Test-Subdomain lassen
|
||||||
|
|
||||||
|
Nicht entfernen. Sonst steht die Seite zweimal im Netz und Google sieht doppelten
|
||||||
|
Inhalt. Wenn du die Subdomain nicht mehr brauchst, in KAS löschen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teil F — Danach
|
||||||
|
|
||||||
|
### F1 Der Update-Ablauf ab jetzt
|
||||||
|
|
||||||
|
**Die Reihenfolge ist nicht verhandelbar**, weil `storage/dateien/uploads/` im Repo
|
||||||
|
liegt und andere Menschen dort hochladen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. [SSH] auf dem Server: neue Uploads sichern
|
||||||
|
cd ~/tsv08kulmbach
|
||||||
|
git add -A storage/dateien/uploads && git commit -m "Uploads vom Server" && git push
|
||||||
|
|
||||||
|
# 2. [lokal] holen, dann entwickeln
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# 3. [lokal] fertig, gepusht → [SSH] ausrollen
|
||||||
|
cd ~/tsv08kulmbach && git pull && php bin/preflight.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Nie in der anderen Reihenfolge. Details und Begründung in CLAUDE.md, Abschnitt
|
||||||
|
Dateiablage.
|
||||||
|
|
||||||
|
Ändert sich `composer.json`, gehört ein `composer install --no-dev
|
||||||
|
--optimize-autoloader` dazu. Neue Formularfelder heißen: Datenschutzerklärung
|
||||||
|
mitziehen.
|
||||||
|
|
||||||
|
### F2 Rückweg, falls etwas Grundlegendes bricht
|
||||||
|
|
||||||
|
[KAS] Domain zurück auf das alte Verzeichnis aus E1. Nach ein paar Minuten ist die
|
||||||
|
alte Seite wieder da. Kein Datenverlust, weil die neue Seite in einem eigenen
|
||||||
|
Verzeichnis liegt und die alte Datenbank nicht anfasst.
|
||||||
|
|
||||||
|
### F3 Offen, nach dem Livegang
|
||||||
|
|
||||||
|
- **301-Weiterleitungen der alten URLs.** Die neue Seite hat andere Slugs; alte
|
||||||
|
Google-Treffer und fremde Links laufen ins Leere. Die alten Adressen stehen im
|
||||||
|
DB-Dump unter `.context_db`. Aufwand lohnt für die paar wichtigen Seiten, nicht
|
||||||
|
für alle.
|
||||||
|
- **Google Search Console:** Property anlegen, `sitemap.xml` einreichen.
|
||||||
|
- **Instagram-Sync** beobachten, siehe C3.
|
||||||
|
- Nach dem Sportfest (ab 07.09.2026) fallen zwei Anzeigen per `bis`-Datum aus dem
|
||||||
|
Bestand, die Stadionzeitung hat dann 38 Seiten statt 40 und ist nicht mehr durch
|
||||||
|
4 teilbar. `bin/stadionzeitung-add.php` warnt beim nächsten Lauf.
|
||||||
Reference in New Issue
Block a user