Produktiv- und Testtabellen per Prefix trennen

This commit is contained in:
2026-08-22 15:29:52 +02:00
parent a31a235422
commit 213dd10dbd
11 changed files with 490 additions and 24 deletions
+41 -14
View File
@@ -9,14 +9,22 @@ Dieses Dokument beschreibt, wie die Anwendung auf den Netcup-Webspace
## Umgebungen
| Umgebung | Host | Webroot | Zweck |
| --- | --- | --- | --- |
| Staging | `testumgebung.kaffeeliste.de` | `/testumgebung.kaffeeliste.de/httpdocs/` | Vollständiger Durchlauf vor jedem Produktiv-Deploy |
| Produktion | `app.kaffeeliste.de` (App) + `kaffeeliste.de` (Marketing) | noch einzurichten | Echtbetrieb |
| Umgebung | Host | Webroot | Tabellen-Prefix | Zweck |
| --- | --- | --- | --- | --- |
| Staging | `testumgebung.kaffeeliste.de` | `/testumgebung.kaffeeliste.de/httpdocs/` | `test_` | Vollständiger Durchlauf vor jedem Produktiv-Deploy |
| Produktion | `app.kaffeeliste.de` (App) + `kaffeeliste.de` (Marketing) | noch einzurichten | `prod_` | Echtbetrieb |
Beide Umgebungen brauchen **eigene Datenbanken** und **eigene**
`env.local.php`. Die Staging-Umgebung läuft mit Stripe-Testkeys, die
Produktion mit Live-Keys.
Beide Umgebungen verwenden dieselbe physische Datenbank, aber zwingend
unterschiedliche Tabellen-Prefixe und jeweils eine eigene `env.local.php`.
Damit sind Daten, Migrationstabellen und Fremdschlüssel von Staging und
Produktion logisch getrennt. Die Staging-Umgebung läuft mit Stripe-Testkeys,
die Produktion mit Live-Keys.
Der Prefix schützt vor versehentlichem Zugriff der einen Umgebung auf die
Tabellen der anderen, ersetzt aber keine getrennte Datenbank als harte
Sicherheitsgrenze: Ein kompromittierter gemeinsamer Datenbankzugang kann
weiterhin alle Tabellen sehen. Deshalb Zugangsdaten besonders restriktiv
behandeln und immer die gesamte Datenbank sichern.
### Host-Split beachten
@@ -80,12 +88,13 @@ Die temporäre `phpinfo()`-Datei danach wieder löschen.
### 2. Datenbank anlegen
In Plesk eine leere MySQL-Datenbank samt eigenem Benutzer anlegen. Die
Zugangsdaten werden gleich in `env.local.php` eingetragen.
In Plesk eine MySQL-Datenbank samt Benutzer anlegen. Beide Umgebungen dürfen
dieselben Zugangsdaten verwenden; die Trennung erfolgt über
`DB_TABLE_PREFIX=test_` beziehungsweise `DB_TABLE_PREFIX=prod_`.
Die vorhandene Entwicklungsdatenbank **nicht** übernehmen: sie enthält
ausschließlich Testdaten inklusive des migrierten Default-Mandanten aus
der Legacy-App.
Unpräfixierte vorhandene Testdaten dürfen ausschließlich mit dem dafür
vorgesehenen Übernahmeskript nach `test_` kopiert werden. Sie dürfen niemals
nach `prod_` übernommen werden.
### 3. Dateien hochladen
@@ -121,12 +130,16 @@ putenv('APP_TIMEZONE=Europe/Berlin');
putenv('APP_DB_DRIVER=mysql');
putenv('DB_HOST=localhost');
putenv('DB_NAME=…'); putenv('DB_USER=…'); putenv('DB_PASS=…');
putenv('DB_TABLE_PREFIX=test_');
putenv('APP_SESSION_PATH=' . __DIR__ . '/var/sessions');
putenv('APP_MAIL_TRANSPORT=mail');
putenv('APP_MAIL_FROM=noreply@kaffeeliste.de');
```
Stripe-, Dolibarr- und IMAP-Werte je Umgebung ergänzen (siehe unten).
In der produktiven `env.local.php` muss stattdessen
`DB_TABLE_PREFIX=prod_` stehen. Ein leerer Prefix ist im laufenden Betrieb
nicht zulässig.
### 5. Schreibrechte für `var/`
@@ -139,7 +152,21 @@ den CSV-Import. Beide sind per `.htaccess` von außen gesperrt.
Es gibt 30 versionierte Migrationen in `database/migrations/`, angewendet
über `scripts/migrate.php`. Das Skript ist idempotent und wendet nur
fehlende Migrationen an.
fehlende Migrationen an. Es arbeitet ausschließlich im Prefix aus der
jeweiligen `env.local.php`; daher müssen Migrationen einmal in Staging und
einmal in Produktion ausgeführt werden.
Für die einmalige Übernahme vorhandener, bisher unpräfixierter Testdaten:
```bash
php scripts/migrate-table-prefix.php --target-prefix=test_ --replace
```
Das Skript migriert zuerst das `test_`-Schema, ersetzt dessen Inhalt
transaktional durch eine exakte Kopie der unpräfixierten Daten und vergleicht
pro Tabelle die Zeilenzahl. Die unpräfixierten Quelltabellen bleiben als
Rückfallmöglichkeit unverändert. Vor dem Lauf trotzdem ein vollständiges
Datenbank-Backup erstellen.
Ohne SSH-Zugang läuft das über **Plesk → Geplante Aufgaben (Scheduled
Tasks)** als einmalig ausgeführter Task vom Typ *PHP-Skript ausführen*:
@@ -348,7 +375,7 @@ Rechten der Secret-Dateien oder einer nicht angewendeten Legal-Migration.
ein Vorlauf mit `--dry-run` wurde kontrolliert
- [ ] Stündlicher Task `php scripts/purge-expired-operational-data.php` ist
eingerichtet; ein Vorlauf mit `--dry-run` wurde kontrolliert
- [ ] Frische Produktivdatenbank ohne Testdaten
- [ ] Frisches `prod_`-Schema ohne Testdaten; Staging verwendet ausschließlich `test_`
## Bewusst offen