# Canipolyon Web App 1_0_0_t – ausführliche Neuinstallationsanleitung

**Stand:** 16.10.2026  
**Ziel:** vollständige Neuinstallation auf einer neuen Testdomain oder Subdomain  
**Komponenten:** Auth-Portal `2.1.3` · Game `1_4_17` · Worldmap `1_0_8`  
**Snapshot:** `Canipolyon_Snapshot_1_0_0_t_Game_1_4_17_Worldmap_1_0_8.zip`

Diese Anleitung beschreibt eine echte Neuinstallation. Die drei verwendeten
Datenbanken müssen leer sein. Bestehende Spielstände oder Kontodaten dürfen
nicht mit den Neuinstallationsskripten überschrieben werden.

> **Freigabestatus:** Patch `1_0_0_t` ist lokal strukturell geprüft, aber noch
> nicht vollständig auf Plesk, PHP-FPM, MySQL 8, Chromium und Android
> abgenommen. Die erste Installation gehört deshalb auf eine Test-Subdomain.

---

## 1. Installationsübersicht

Für die Installation werden folgende Bestandteile benötigt:

| Bereich | Vorgabe |
| --- | --- |
| Webspace | Apache/Plesk mit `.htaccess` und `mod_rewrite` |
| PHP | PHP `8.1` oder neuer; empfohlen PHP `8.3` |
| PHP-Erweiterungen | `pdo_mysql`, `mbstring`, `ctype`, `openssl` |
| Datenbank | MySQL 8 oder kompatible MariaDB-Version mit InnoDB |
| HTTPS | gültiges Zertifikat und erzwungene HTTPS-Weiterleitung |
| Datenbanken | drei getrennte, leere Datenbanken |
| Mail | Plesk-Mailtransport oder SMTP-Zugang |
| Dateirechte | PHP-Schreibzugriff nur auf die vorgesehenen Storage-Ordner |

Die Anwendung verwendet diese drei Datenbanken:

1. Auth-Datenbank für Konten, Sitzungen, Rollen, Chat und Moderation;
2. Game-Datenbank für Spielstände, Wallets, Inventar, Pflanzen und Live-Events;
3. Worldmap-Datenbank für Grundstücke, Gebäude, Gruppen und Live-Events.

---

## 2. Vorbereitung und Sicherheitskopien

Auch bei einer Neuinstallation sollten die bisherige Testinstallation und ihre
Datenbanken vollständig gesichert werden. Die neue Installation darf nicht in
denselben Document-Root oder dieselben Datenbanken geschrieben werden.

Vor Beginn bereitlegen:

- das ZIP-Archiv von Patch `1_0_0_t`;
- den gewünschten Domainnamen, beispielsweise
  `snapshot-100t.canipolyon.net`;
- drei neue Datenbanknamen und drei sichere Datenbankkennwörter;
- die Zugangsdaten für `no-reply@canipolyon.net`, falls SMTP verwendet wird;
- vollständige Betreiber- und Datenschutzangaben;
- einen zufällig erzeugten App-Key mit 64 Hex-Zeichen.

Die Archivprüfung kann lokal oder per SSH erfolgen:

```sh
sha256sum Canipolyon_Snapshot_1_0_0_t_Game_1_4_17_Worldmap_1_0_8.zip
```

Die erwartete SHA-256-Prüfsumme des erstellten Archivs lautet:

```text
91b4e4291503b6bb7c51e0dbbdbfbc86bc3d87b0f436030e7ef40705cb78cc92
```

---

## 3. Domain und Document-Root in Plesk anlegen

1. In Plesk die gewünschte Test-Subdomain anlegen.
2. Einen neuen, leeren Dokumentenstamm auswählen, zum Beispiel
   `httpdocs_snapshot_100t`.
3. PHP-Unterstützung aktivieren und PHP `8.1` oder neuer auswählen.
4. Ein gültiges SSL/TLS-Zertifikat ausstellen.
5. HTTP dauerhaft auf HTTPS weiterleiten.
6. Den Document-Root auf den Ordner setzen, in dem nach dem Entpacken direkt
   `.htaccess`, `index.php`, `game/`, `worldmap/`, `auth-portal/` und `shared/`
   liegen.

Der Document-Root darf **nicht** direkt auf `auth-portal/public/` zeigen. Die
Web App besitzt eine gemeinsame Root-`.htaccess`, die `/auth` und `/api/v1`
kontrolliert in das Auth-Portal weiterleitet und private Verzeichnisse sperrt.

Empfohlene Plesk-Einstellungen:

- `display_errors = Off`;
- `log_errors = On`;
- `session.cookie_secure = On`;
- `session.cookie_httponly = On`;
- `max_execution_time` mindestens `30` Sekunden;
- ausreichend PHP-Prozesse für normale APIs und kurzlebige SSE-Verbindungen;
- keine Proxy- oder Komprimierungseinstellung, die `text/event-stream`
  vollständig puffert.

Die konkrete PHP-FPM- und Proxy-Konfiguration muss auf dem gewählten
ZAP-Hosting-Tarif geprüft werden. Der Live-Kanal hält eine Verbindung nur kurz
offen und fällt bei Problemen automatisch auf HTTP-Polling zurück.

---

## 4. Snapshot hochladen und entpacken

1. Das ZIP-Archiv in einen nicht öffentlichen Zwischenordner hochladen.
2. Das Archiv entpacken.
3. Den **Inhalt** des entpackten Verzeichnisses in den neuen Document-Root
   verschieben. Es darf keine zusätzliche Ebene wie
   `Canipolyon_Snapshot_.../index.php` entstehen.
4. Das hochgeladene ZIP anschließend aus dem öffentlichen Webspace entfernen.
5. Prüfen, dass `.htaccess` übertragen wurde. Manche FTP-Programme blenden
   Dateien mit führendem Punkt aus.

Im Document-Root müssen anschließend mindestens diese Einträge liegen:

```text
.htaccess
index.php
service-worker.js
manifest.webmanifest
auth-portal/
game/
worldmap/
shared/
assets/
```

---

## 5. Drei leere Datenbanken anlegen

In Plesk drei neue Datenbanken anlegen. Die tatsächlichen Namen dürfen einen
Plesk-Präfix besitzen.

| Zweck | Beispielname |
| --- | --- |
| Auth-Portal | `auth_portal_100t` |
| Game | `canipolyon_game_100t` |
| Worldmap | `canipolyon_worldmap_100t` |

Für jede Datenbank einen eigenen Benutzer mit einem starken, einmaligen
Kennwort verwenden. Kein Benutzer darf `root` sein.

Für den serverautoritativen Grundstückskauf benötigt der unter
`PLOT_PURCHASE_DB_USER` eingetragene Benutzer Zugriff auf die Game- und die
Worldmap-Datenbank. In Plesk muss daher ein geeigneter Benutzer beiden
Datenbanken zugeordnet werden. Diese Berechtigung zunächst nur auf der
Testinstallation verwenden.

Vor dem Import prüfen:

- Datenbanken enthalten keine Tabellen;
- Zeichensatz ist `utf8mb4`;
- InnoDB ist verfügbar;
- Server- und Datenbankzeit arbeiten in UTC oder werden konsistent auf UTC
  gesetzt.

---

## 6. Vollständige Datenbank-SQL-Dateien importieren

### 6.1 Wichtiger Hinweis zu den SQL-Dateien

Patch `1_0_0_t` enthält eine aktualisierte Gesamt-SQL und drei vollständige
Plesk-Einzeldateien. Alle enthalten das aktuelle Schema, die Live-Sync-Tabellen,
Trigger, Support-Rolle und zehn vorbereitete Testkonten.

Mit Berechtigung zum Erstellen von Datenbanken kann die Gesamtdatei verwendet
werden:

```text
shared/database/Canipolyon_Web_App_1_0_0_t_Alle_Datenbanken.sql
```

Stimmen die in Plesk angelegten Datenbanknamen wegen eines Präfixes nicht mit
`auth_portal`, `canipolyon_worldmap` und `canipolyon_game` überein, stattdessen
die drei Plesk-Einzeldateien verwenden.

### 6.2 Auth-Datenbank

In phpMyAdmin die leere Auth-Datenbank auswählen und die vollständige Datei
importieren:

```text
shared/database/plesk/01_auth_portal.sql
```

Das Skript enthält Auth `2.1.3`, die Sprachauswahl `de`/`en`, alle Rollen,
Berechtigungen und die vorbereiteten Testkonten.

### 6.3 Worldmap-Datenbank

In phpMyAdmin die leere Worldmap-Datenbank auswählen und importieren:

```text
shared/database/plesk/02_canipolyon_worldmap.sql
```

Die Datei enthält bereits Worldmap `1_0_8`, `wm_live_events` und die
transaktionalen Trigger. Die Einzelmigration
`worldmap/database/migrations/1_0_7_to_1_0_8.sql` ist nur für ein Upgrade einer
bestehenden Worldmap `1_0_7` gedacht.

### 6.4 Game-Datenbank

In phpMyAdmin die leere Game-Datenbank auswählen und importieren:

```text
shared/database/plesk/03_canipolyon_game.sql
```

Die Datei enthält bereits Game `1_4_17`, `game_live_events` und die Trigger für
Wallet, Crypto-Wallet, Snapshot, Inventar, Pflanzen und Mining. Die separate
Migration `game/integration/sql/014_game_live_sync_1_4_17.sql` ist nur für das
Upgrade eines bestehenden Game-Schemas bestimmt.

### 6.5 Import kontrollieren

In der Game-Datenbank:

```sql
SELECT version, applied_at
FROM game_schema_migrations
WHERE version = '014_game_live_sync_1_4_17';

SHOW TABLES LIKE 'game_live_events';
SHOW TRIGGERS LIKE 'game_%';
```

In der Worldmap-Datenbank:

```sql
SELECT version, applied_at
FROM wm_schema_migrations
WHERE version IN ('1_0_7', '1_0_8')
ORDER BY version;

SHOW TABLES LIKE 'wm_live_events';
SHOW TRIGGERS LIKE 'wm_%';
```

Erwartet werden der Game-Marker `014_game_live_sync_1_4_17`, die beiden
Worldmap-Marker `1_0_7` und `1_0_8` sowie beide Live-Event-Tabellen.

Bei einem SQL-Fehler nicht einfach erneut alle Dateien importieren. Den genauen
Fehler und den bereits erreichten Teilstand prüfen oder die leere Datenbank neu
anlegen und den Import sauber wiederholen.

---

## 7. Zentrale Konfiguration anlegen

Die zentrale Konfiguration liegt unter:

```text
shared/config/.env
```

Für die Neuinstallation `shared/config/.env.example` als Ausgangspunkt
verwenden. Die mitgelieferte `.env` darf nicht ungeprüft übernommen werden.
Alle Platzhalter, URLs, Datenbanknamen und Kennwörter müssen zur neuen
Subdomain gehören.

Beispiel für eine Testinstallation:

```dotenv
WEB_APP_BASE_PATH=/
APP_NAME=Canipolyon – Test 1_0_0_t
APP_ENV=staging
WEB_APP_TEST_MODE=true

APP_URL=https://DEINE-SUBDOMAIN.canipolyon.net/auth
GAME_URL=https://DEINE-SUBDOMAIN.canipolyon.net/game
GAME_API_URL=https://DEINE-SUBDOMAIN.canipolyon.net/api/v1/game
AUTH_API_ALLOWED_ORIGIN=https://DEINE-SUBDOMAIN.canipolyon.net

APP_KEY=HIER_64_ZUFAELLIGE_HEX_ZEICHEN_EINTRAGEN

DB_HOST=localhost
DB_PORT=3306
DB_NAME=DEINE_AUTH_DATENBANK
DB_USER=DEIN_AUTH_BENUTZER
DB_PASSWORD=DEIN_SICHERES_AUTH_KENNWORT

GAME_DB_HOST=localhost
GAME_DB_PORT=3306
GAME_DB_NAME=DEINE_GAME_DATENBANK
GAME_DB_USER=DEIN_GAME_BENUTZER
GAME_DB_PASSWORD=DEIN_SICHERES_GAME_KENNWORT

WORLDMAP_DB_DSN=mysql:host=localhost;port=3306;dbname=DEINE_WORLDMAP_DATENBANK;charset=utf8mb4
WORLDMAP_DB_USER=DEIN_WORLDMAP_BENUTZER
WORLDMAP_DB_PASSWORD=DEIN_SICHERES_WORLDMAP_KENNWORT

PLOT_PURCHASE_DB_HOST=localhost
PLOT_PURCHASE_DB_PORT=3306
PLOT_PURCHASE_DB_USER=DEIN_GEMEINSAMER_KAUF_BENUTZER
PLOT_PURCHASE_DB_PASSWORD=DEIN_SICHERES_KAUF_KENNWORT
PLOT_PURCHASE_WORLD_SCHEMA=DEINE_WORLDMAP_DATENBANK
PLOT_PURCHASE_GAME_SCHEMA=DEINE_GAME_DATENBANK

LOGIN_REDIRECT=continue.php
LOGOUT_REDIRECT=login.php
SESSION_COOKIE_NAME=__Host-canipolyon_test_session
SESSION_COOKIE_PATH=/
PASSWORD_MIN_LENGTH=12
```

Den App-Key nach Möglichkeit per SSH/PHP-CLI erzeugen:

```sh
php shared/tools/generate-app-key.php
```

Alternativ muss ein kryptografisch sicherer Wert mit genau 64 Hex-Zeichen
erzeugt werden. Kein Beispielwert aus einer Anleitung darf produktiv
übernommen werden.

### Bedeutung der wichtigsten URL-Werte

| Variable | Inhalt |
| --- | --- |
| `APP_URL` | öffentliche Auth-Route mit `/auth` |
| `GAME_URL` | öffentliche Game-Route mit `/game` |
| `GAME_API_URL` | öffentliche Game-API mit `/api/v1/game` |
| `AUTH_API_ALLOWED_ORIGIN` | nur Schema und Host, ohne Pfad |
| `WEB_APP_BASE_PATH` | bei eigener Subdomain normalerweise `/` |

Alle URLs müssen dieselbe HTTPS-Origin verwenden. Eine Prozessvariable in
Plesk kann den Wert aus `.env` überschreiben; bei unerklärlichen Abweichungen
daher auch die Plesk-Umgebungsvariablen prüfen.

---

## 8. Sichere Startschalter setzen

Für die erste Inbetriebnahme bleiben alle schreibenden Pilotfunktionen
deaktiviert:

```dotenv
GAME_INVENTORY_PLANTS_MODE=off
GAME_INVENTORY_PLANTS_WRITES=false
GAME_INVENTORY_PLANTS_PILOT_UUIDS=
GAME_INVENTORY_PLANTS_WALLET_COHERENT=false

WORLDMAP_BUILDING_WRITES=false
WORLDMAP_BUILDING_DEMOLISH=false
WORLDMAP_BUILDING_PILOT_UUIDS=
WORLDMAP_PLOT_PURCHASE_ENABLED=false
WORLDMAP_PLOT_PURCHASE_PILOT_UUIDS=
WORLDMAP_PLOT_MERGE_ENABLED=false
WORLDMAP_PLOT_MERGE_PILOT_UUIDS=
```

Diese Schalter deaktivieren neue Fachschreibvorgänge, nicht jedoch Anmeldung,
Lesen, Game-Shell oder den Live-Sync-Transport. Funktionen erst nach der
jeweiligen Pilotprüfung gezielt für echte Konto-UUIDs aktivieren.

Eine leere Pilotliste kann bei aktiviertem Hauptschalter alle Konten
freigeben. Deshalb niemals versehentlich `..._ENABLED=true` oder
`..._WRITES=true` mit leerer Pilotliste auf einer öffentlichen Instanz setzen.

---

## 9. Mailversand einrichten

Registrierung, Passwort-Reset und E-Mail-Änderungen benötigen einen echten
Mailversand. Das bereits bestätigte Administratorkonto wäre davon unabhängig;
bei einer sauberen Installation ohne Seed wird der erste Administrator jedoch
erst nach Registrierung und Bestätigung vergeben.

### Variante A: lokaler Plesk-Mailtransport

```dotenv
MAIL_TRANSPORT=mail
MAIL_FROM_ADDRESS=no-reply@canipolyon.net
MAIL_FROM_NAME=Canipolyon Test
SMTP_HOST=
SMTP_PORT=587
SMTP_AUTH=false
SMTP_USER=
SMTP_PASSWORD=
SMTP_ENCRYPTION=tls
```

### Variante B: authentifiziertes SMTP

```dotenv
MAIL_TRANSPORT=smtp
MAIL_FROM_ADDRESS=no-reply@canipolyon.net
MAIL_FROM_NAME=Canipolyon Test
SMTP_HOST=DEIN_SMTP_SERVER
SMTP_PORT=587
SMTP_AUTH=true
SMTP_USER=no-reply@canipolyon.net
SMTP_PASSWORD=DEIN_SMTP_KENNWORT
SMTP_ENCRYPTION=tls
```

Das Auth-Portal darf unter einer Subdomain wie `snapshot-100t.canipolyon.net`
laufen und trotzdem mit `no-reply@canipolyon.net` versenden. Entscheidend sind
das vorhandene Postfach beziehungsweise die erlaubte Absenderadresse sowie
korrekte SPF-, DKIM- und gegebenenfalls DMARC-Einstellungen der Hauptdomain.

Nach der Einrichtung Registrierung, Bestätigungslink, Passwort-Reset und
E-Mail-Änderung jeweils mit einem Testkonto prüfen. SMTP-Kennwörter niemals in
Screenshots, Tickets, SQL-Dateien oder öffentlich erreichbaren Dateien
speichern.

---

## 10. Rechtliche Konfiguration vervollständigen

Alle `LEGAL_*`-Werte in `shared/config/.env` müssen zum tatsächlichen Betreiber
und Hosting passen. Besonders zu prüfen sind:

- vollständiger Betreibername und ladungsfähige Anschrift;
- Kontakt- und Datenschutzadresse;
- Hostinganbieter und Serverstandort;
- Mailanbieter;
- Speicher- und Löschfristen;
- Rechtsgrundlagen und Empfänger;
- Aufsichtsbehörde;
- Auftragsverarbeitungsvertrag;
- Backup-Aufbewahrung;
- mögliche Drittlandübertragungen;
- tatsächliches Cookie- und LocalStorage-Inventar.

Die mitgelieferten Texte sind technische Vorlagen und keine automatische
rechtliche Freigabe.

---

## 11. Dateirechte setzen

Die Anwendung benötigt Schreibzugriff auf:

```text
auth-portal/storage/
auth-portal/storage/logs/
auth-portal/storage/mail/
```

Empfohlene Grundregel:

- Dateien grundsätzlich `0644`;
- Verzeichnisse grundsätzlich `0755`;
- Storage-Verzeichnisse nur so weit schreibbar machen, wie es der von Plesk
  verwendete PHP-Benutzer benötigt;
- keine pauschalen Rechte `0777` vergeben;
- `.env` so restriktiv wie möglich, idealerweise `0600` oder der engste unter
  Plesk funktionsfähige Wert.

Der Webserver muss Zugriffe auf `.env`, SQL-, Markdown-, ZIP- und interne
Quellverzeichnisse mit `403 Forbidden` abweisen. Die Root-`.htaccess` enthält
diese Sperren bereits; sie müssen auf dem Zielserver wirksam sein.

---

## 12. Vorbereitete Testkonten und Rollen

Die vollständigen Neuinstallationsdateien legen zehn aktive, bestätigte
Testkonten an. Das jeweilige Erstpasswort entspricht exakt dem Benutzernamen
und muss nach dem ersten Login geändert werden.

| Benutzername | E-Mail | Rollen | Erstpasswort |
| --- | --- | --- | --- |
| `Admin` | `admin@canipolyon.test` | member, admin | `Admin` |
| `SuperAdmin` | `superadmin@canipolyon.test` | member, admin | `SuperAdmin` |
| `Administrator2` | `administrator2@canipolyon.test` | member, admin | `Administrator2` |
| `Moderator1` | `moderator1@canipolyon.test` | member, moderator | `Moderator1` |
| `Moderator2` | `moderator2@canipolyon.test` | member, moderator | `Moderator2` |
| `Moderator3` | `moderator3@canipolyon.test` | member, moderator | `Moderator3` |
| `Support1` | `support1@canipolyon.test` | member, support | `Support1` |
| `Support2` | `support2@canipolyon.test` | member, support | `Support2` |
| `Tester1` | `tester1@canipolyon.test` | member | `Tester1` |
| `Tester2` | `tester2@canipolyon.test` | member | `Tester2` |

Die Rolle `support` besitzt ausschließlich `users.read.basic`,
`bug_tickets.read` und `bug_tickets.manage`.

Die SQL-Dateien speichern ausschließlich PHP-kompatible Bcrypt-Hashes. Da
Benutzernamen als Erstpasswörter vorhersehbar sind, dürfen diese Konten nur auf
einer abgesicherten Testinstallation verwendet werden. Direkt nach dem ersten
Login jedes Konto über `/auth/change-password.php` auf ein einmaliges Kennwort
mit mindestens zwölf Zeichen umstellen.

---

## 13. Kommandozeilenprüfungen

Falls Plesk einen SSH-/CLI-Zugang bereitstellt, im Document-Root ausführen:

```sh
php -v
php -m
php shared/tools/check-webspace.php
php auth-portal/scripts/check-environment.php --production
```

Zusätzlich alle PHP-Dateien auf Syntax prüfen:

```sh
find . -type f -name '*.php' -print0 | xargs -0 -n1 php -l
```

Der Webspace-Check verändert keine Konten oder Spielstände. Er prüft
PHP-Erweiterungen, Konfiguration, Datenbankverbindungen, Tabellen,
Storage-Rechte und wichtige PWA-Dateien.

Falls `check-webspace.php` wegen der im Snapshot älteren
`DATABASE_MANIFEST.json` nur Mindesttabellenzahlen prüft, sind zusätzlich die
beiden Live-Tabellen und Migrationsmarker aus Abschnitt 6 manuell zu
kontrollieren.

---

## 14. Erster Browser- und HTTP-Test

Die folgenden URLs nacheinander öffnen:

```text
https://DEINE-SUBDOMAIN.canipolyon.net/
https://DEINE-SUBDOMAIN.canipolyon.net/auth/login.php
https://DEINE-SUBDOMAIN.canipolyon.net/game/app.html
https://DEINE-SUBDOMAIN.canipolyon.net/worldmap/
```

Erwartetes Verhalten:

- `/` leitet kontrolliert zum Auth-Bereich oder Einstieg weiter;
- Loginseite wird über HTTPS geladen;
- nicht angemeldete Game-/Worldmap-Aufrufe führen zur Anmeldung;
- nach Anmeldung führt `continue.php` in das Game;
- Konto- und Worldmap-Schaltflächen funktionieren;
- keine Mixed-Content-, CORS- oder Cookie-Fehler erscheinen;
- Browserkonsole enthält keine 404-Fehler für Module, Icons oder Sounds.

Private Pfade müssen gesperrt sein. Stichproben:

```text
/shared/config/.env
/auth-portal/config/config.php
/game/integration/sql/014_game_live_sync_1_4_17.sql
/worldmap/database/worldmap_database.sql
/COMPONENTS.json
/VERSION
```

Diese Aufrufe müssen `403` oder eine gleichwertige Sperre liefern und dürfen
keinen Dateiinhalt anzeigen.

---

## 15. Live-Synchronisierung von Patch 1_0_0_t prüfen

### 15.1 Game-Test

1. Mit demselben Testkonto zwei Browserfenster oder zwei Geräte öffnen.
2. In beiden Sitzungen denselben Server-Spielstand auswählen.
3. In Fenster A eine kontrollierte serverseitige Änderung ausführen.
4. Prüfen, ob Fenster B die Änderung ohne vollständigen Neustart erkennt.
5. In den Entwicklertools den Aufruf von
   `/api/v1/game/live/stream.php` kontrollieren.
6. Streaming testweise blockieren oder die Verbindung unterbrechen.
7. Prüfen, ob der Client auf `/api/v1/game/live/events.php` zurückfällt.
8. Nach Wiederherstellung der Verbindung prüfen, ob Cursor und Revisionen ohne
   Doppelbuchung fortgesetzt werden.

### 15.2 Worldmap-Test

1. Zwei bestätigte Konten verwenden.
2. Beide Konten in derselben Welt positionieren.
3. Eine freigegebene Grundstücks- oder Gebäudeänderung mit Konto A ausführen.
4. Prüfen, ob Konto B den Kartenstand aktualisiert.
5. Kamera, Zoom und Feldauswahl müssen erhalten bleiben.
6. Prüfen, dass fremde private UUID-, Wallet- oder Save-Daten nicht in der
   Eventantwort erscheinen.

### 15.3 Mehrfach- und Konflikttest

- dieselbe Operation nicht doppelt buchen lassen;
- veraltete Wallet- oder Ressourcenrevision muss mit Konflikt abgewiesen
  werden;
- nach Netztrennung darf dieselbe Operations-ID keinen zweiten Beleg erzeugen;
- ein abgelaufener Cursor muss einen kontrollierten Resync auslösen;
- Game-Musik und Shell dürfen trotz Reconnect nur einmal aktiv sein.

---

## 16. Service Worker und Cache aktualisieren

Patch `1_0_0_t` verwendet eine neue Cachekennung. Nach dem ersten Aufruf:

1. Browser-Entwicklertools öffnen;
2. unter „Application“ beziehungsweise „Anwendung“ den Service Worker prüfen;
3. Seite einmal vollständig neu laden;
4. bei einem alten Stand den bisherigen Service Worker abmelden und die
   Website-Daten dieser Test-Subdomain löschen;
5. anschließend erneut anmelden und Game sowie Worldmap öffnen.

API-, Sitzungs-, Save- und Live-Sync-Antworten dürfen nicht im Cache Storage
liegen. Der Service Worker behandelt `/api/` und `/live/` ausdrücklich nicht
als Cache-Ressourcen.

---

## 17. Regelmäßige Wartung

In Plesk mindestens einmal täglich als geplante Aufgabe ausführen:

```sh
php /ABSOLUTER/PFAD/ZUM/DOCUMENT_ROOT/auth-portal/scripts/cleanup.php
```

Zusätzlich müssen abgelaufene Einträge aus `game_live_events` und
`wm_live_events` regelmäßig entfernt werden. Bis dafür ein gemeinsames
Wartungsskript bereitgestellt ist, die Bereinigung kontrolliert über die
Datenbankverwaltung oder einen abgesicherten Plesk-Task durchführen:

```sql
DELETE FROM game_live_events
WHERE expires_at < UTC_TIMESTAMP();
```

```sql
DELETE FROM wm_live_events
WHERE expires_at < UTC_TIMESTAMP();
```

Diese beiden Abfragen jeweils nur in der richtigen Datenbank ausführen. Vor
der ersten Automatisierung eine Sicherung und einen manuellen Test durchführen.
Keine noch gültigen Cursorbereiche löschen.

Regelmäßig kontrollieren:

- PHP- und Webserver-Fehlerprotokolle;
- fehlgeschlagene Logins und Rate-Limits;
- SMTP-Rückläufer;
- Größe der beiden Live-Event-Tabellen;
- Datenbank- und Dateisicherungen;
- freier Speicherplatz;
- PWA-/Service-Worker-Version;
- SSE-Abbrüche und Häufigkeit des Polling-Fallbacks.

---

## 18. Vollständige Abnahmecheckliste

### Dateien und Routing

- [ ] Snapshot-Prüfsumme stimmt.
- [ ] Dateien liegen ohne zusätzliche Unterordnerebene im Document-Root.
- [ ] Root-`.htaccess` ist vorhanden und aktiv.
- [ ] HTTPS-Weiterleitung funktioniert.
- [ ] Private Dateien liefern `403`.

### Datenbanken

- [ ] Drei neue, leere Datenbanken wurden verwendet.
- [ ] Auth-Komplettschema mit Support-Rolle und zehn Testkonten wurde importiert.
- [ ] vollständige Worldmap-SQL einschließlich `1_0_8` wurde importiert.
- [ ] vollständige Game-SQL einschließlich Migration `014` wurde importiert.
- [ ] Live-Event-Tabellen und Trigger sind vorhanden.
- [ ] Datenbankbenutzer besitzen nur notwendige Rechte.
- [ ] Datenbankübergreifender Kaufzugang wurde getrennt geprüft.

### Konfiguration

- [ ] Alle URLs zeigen auf die neue HTTPS-Subdomain.
- [ ] App-Key wurde neu erzeugt.
- [ ] Keine Platzhalter oder alten Datenbankkennwörter sind vorhanden.
- [ ] Sichere Startschalter stehen auf `false` beziehungsweise `off`.
- [ ] Rechtsangaben sind vollständig geprüft.
- [ ] Storage-Verzeichnisse sind schreibbar, übrige Dateien nicht unnötig.

### Funktionen

- [ ] Registrierung und E-Mail-Bestätigung funktionieren.
- [ ] Login, Logout und Passwort-Reset funktionieren.
- [ ] Erstes bestätigtes Konto erhielt kontrolliert die Adminrolle.
- [ ] Neues Spiel, Laden und Speichern funktionieren.
- [ ] Konto- und Worldmap-Navigation funktionieren.
- [ ] Game-Live-Sync funktioniert über SSE.
- [ ] Polling-Fallback funktioniert ohne SSE.
- [ ] Worldmap-Aktualisierung erhält Kamera und Auswahl.
- [ ] Zwei Tabs erzeugen keine Doppelbuchung.
- [ ] Service Worker speichert keine privaten API-Antworten.

### Betrieb

- [ ] PHP-/Plesk-Protokolle bleiben fehlerfrei.
- [ ] tägliche Auth-Bereinigung ist eingerichtet.
- [ ] Bereinigung abgelaufener Live-Events ist eingerichtet.
- [ ] Datei- und Datenbankbackup wurde erstellt und testweise wiederhergestellt.
- [ ] Chromium-, Android- und Mobilbrowser-Abnahme wurde dokumentiert.

---

## 19. Fehlerdiagnose

### „Not Found“ bei `/auth/login.php`

- Document-Root prüfen;
- Root-`.htaccess` prüfen;
- Apache-`mod_rewrite` und `AllowOverride` prüfen;
- sicherstellen, dass nicht `auth-portal/public/` als gemeinsamer Root gesetzt
  wurde.

### „Spieldatenbank nicht verfügbar“

- `GAME_DB_HOST`, `GAME_DB_NAME`, `GAME_DB_USER` und Kennwort prüfen;
- Plesk-Datenbankpräfix berücksichtigen;
- Benutzer der Game-Datenbank zuordnen;
- Migration `014_game_live_sync_1_4_17` prüfen.

### „Worldmap-Datenbank nicht konfiguriert“

- vollständigen `WORLDMAP_DB_DSN` prüfen;
- Semikolon innerhalb der DSN nicht entfernen;
- Datenbankname und Benutzerzuordnung prüfen;
- Worldmap-Marker `1_0_8` kontrollieren.

### Live-Sync bleibt offline

- Anmeldung und Session-Cookie prüfen;
- Endpunkte direkt über die Browser-Netzwerkanalyse prüfen;
- PHP-FPM-Laufzeit und Proxy-Pufferung prüfen;
- `Cache-Control: no-store` und `Content-Type: text/event-stream` kontrollieren;
- bei blockiertem SSE prüfen, ob der Polling-Endpunkt regelmäßig antwortet;
- PHP- und Webserverprotokoll auf Zeitüberschreitungen untersuchen.

### Anmeldung funktioniert, Registrierungsmail fehlt

- `MAIL_TRANSPORT` prüfen;
- Absenderadresse und SMTP-Zugang prüfen;
- Plesk-Mailprotokoll und Spamordner prüfen;
- SPF/DKIM der Domain prüfen;
- keine Testadresse wie `admin@canipolyon.test` als echtes Postfach erwarten.

### Änderungen erscheinen doppelt

- prüfen, ob nur ein Game-Shell-Client pro Tab läuft;
- Cursor im Session Storage und Event-IDs im Netzwerk prüfen;
- sicherstellen, dass Migrationen nicht teilweise oder Trigger doppelt
  eingerichtet wurden;
- Operations-ID und erwartete Revision des Schreibbefehls kontrollieren.

---

## 20. Rückfall und Wiederherstellung

Vor jeder Freigabe einen zusammengehörigen Stand aus Dateien sowie allen drei
Datenbanken sichern. Bei einem schweren Fehler:

1. Schreibschalter deaktivieren;
2. Testdomain in Wartung nehmen;
3. PHP-/Webserverprotokolle sichern;
4. keine einzelnen Tabellen aus unterschiedlichen Zeitständen mischen;
5. alle drei Datenbanken aus demselben Backupzeitpunkt wiederherstellen;
6. den dazugehörigen Datei-Snapshot wiederherstellen;
7. PHP-Opcode-Cache und Browser-/Service-Worker-Cache leeren;
8. Anmeldung, Save-Laden und Worldmap zunächst nur lesend prüfen.

Ein Rückfall auf ältere Dateien bei bereits neuer Datenbankstruktur ist nur als
kurzfristige Diagnose zulässig. Alte Clients kennen neue Event- und
Revisionsverträge nicht vollständig.

---

## 21. Abschluss

Die Neuinstallation ist technisch bereit, wenn alle Prüfpunkte aus Abschnitt
18 erfüllt sind. Eine Produktionsfreigabe darf erst erfolgen, nachdem
PHP-/MySQL-Integration, Plesk/PHP-FPM, SMTP, SSE/Polling-Fallback, Parallelität,
Restore sowie Desktop- und Mobilbrowser tatsächlich auf der Zielumgebung
abgenommen und dokumentiert wurden.

Bis dahin bleiben die schreibenden Pilotfunktionen deaktiviert und die Domain
als Testinstallation mit `APP_ENV=staging`, `WEB_APP_TEST_MODE=true` und
`noindex` gekennzeichnet.
