From 769d06e04efa2b0b217b5b93054017f3e58b09fb Mon Sep 17 00:00:00 2001 From: Timo Knuth Date: Wed, 12 Aug 2026 22:27:22 +0200 Subject: [PATCH] Add runbook for setting up the staging environment Standalone instructions for whoever sets up testmodul.qrmaster.net on the production server. Written to be followed without prior context: explicit paths, an upfront list of what must not be touched, and a stop condition in step 2 if the host URLs point at production, which would send staging clicks into the live app. Contains no credentials - .env.test is handed over separately. Co-Authored-By: Claude Opus 5 --- DEPLOY_TESTUMGEBUNG_ANLEITUNG.md | 261 +++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 DEPLOY_TESTUMGEBUNG_ANLEITUNG.md diff --git a/DEPLOY_TESTUMGEBUNG_ANLEITUNG.md b/DEPLOY_TESTUMGEBUNG_ANLEITUNG.md new file mode 100644 index 0000000..8f816fa --- /dev/null +++ b/DEPLOY_TESTUMGEBUNG_ANLEITUNG.md @@ -0,0 +1,261 @@ +# Anleitung: Testumgebung testmodul.qrmaster.net aufsetzen + +Diese Anleitung richtet auf dem Produktionsserver eine **zweite, getrennte Instanz** von +QR Master ein, erreichbar unter `testmodul.qrmaster.net`. Sie läuft auf dem Branch `test` +mit einer eigenen, leeren Datenbank. + +Die laufende Produktion wird dabei **nicht angefasst**. Alle Schritte hier legen neue +Container, ein neues Volume und ein neues Verzeichnis an. + +## Voraussetzungen + +- SSH-Zugang zum Server, auf dem QR Master läuft +- Docker und Docker Compose (mindestens v2.24 - wird für `!override` und `!reset` gebraucht; + prüfen mit `docker compose version`) +- Schreibrechte auf die Caddy-Konfiguration +- Die Datei **`.env.test`** - die kommt von Timo und ist nicht im Repository, weil sie + Passwörter enthält +- Der DNS-Eintrag `testmodul.qrmaster.net` existiert bereits (CNAME) + +## Was NICHT angefasst wird + +- Das bestehende Produktionsverzeichnis: dort **nicht** den Branch wechseln. Ein späterer + Prod-Rebuild würde sonst Testcode bauen. +- Die Produktions-`.env` +- Die bestehenden Caddy-Blöcke für `www.qrmaster.net`, `app.qrmaster.net` und `qrmaster.net` +- Die Produktionsdatenbank. Der einzige Zugriff darauf ist ein `pg_dump --schema-only`, + das ausschließlich liest. + +--- + +## 1. Zweites Checkout anlegen + +**Nicht** im Produktionsverzeichnis arbeiten. Ein eigenes Verzeichnis daneben, z.B. im +selben übergeordneten Ordner: + +```bash +git clone -b test https://git.bizmatch.net/tknuth/QR-master.git qrmaster-test +``` + +Danach in dieses Verzeichnis wechseln. **Alle weiteren Befehle laufen von dort**, sofern +nicht anders angegeben. + +```bash +cd qrmaster-test +``` + +Prüfen, dass der richtige Branch ausgecheckt ist - es muss `test` erscheinen: + +```bash +git branch --show-current +``` + +## 2. `.env.test` ablegen + +Die von Timo erhaltene Datei als `.env.test` in dieses Verzeichnis legen (also +`qrmaster-test/.env.test`). + +Kurz gegenprüfen, dass die vier wichtigsten Werte stimmen: + +```bash +grep -E "NEXT_PUBLIC_WWW_URL|NEXT_PUBLIC_APP_URL|AUTH_COOKIE_NAME|POSTGRES_DB" .env.test +``` + +Erwartet: + +``` +NEXT_PUBLIC_WWW_URL=https://testmodul.qrmaster.net +NEXT_PUBLIC_APP_URL=https://testmodul.qrmaster.net +AUTH_COOKIE_NAME=userId_test +POSTGRES_DB=qrmaster_test +``` + +Steht bei einer der URLs `app.qrmaster.net` oder `www.qrmaster.net`, **nicht starten** - +dann würden Klicks in der Testumgebung in die Produktion umleiten. + +## 3. Stack bauen und starten + +```bash +docker compose -p qrmaster-test --env-file .env.test -f docker-compose.yml -f docker-compose.test.yml up -d --build +``` + +Der erste Build dauert einige Minuten. Der Projektname `-p qrmaster-test` ist wichtig: er +sorgt dafür, dass eigene Container und ein eigenes Volume entstehen und nichts aus der +Produktion überschrieben wird. + +Läuft alles, sollten drei neue Container existieren: + +```bash +docker ps --filter "name=qrmaster-test" --format "table {{.Names}}\t{{.Status}}" +``` + +Erwartet: `qrmaster-test-db`, `qrmaster-test-redis`, `qrmaster-test-web`. + +Die Anwendung kann zu diesem Zeitpunkt noch nichts anzeigen - die Datenbank ist leer. Das +ist normal und wird im nächsten Schritt behoben. + +## 4. Datenbankschema einspielen + +Die Testdatenbank bekommt **nur die Struktur** aus der Produktion, keine Daten. Es werden +also keine Kundendaten kopiert. + +Struktur aus der Produktionsdatenbank exportieren (reiner Lesezugriff): + +```bash +docker exec qrmaster-db pg_dump -U postgres --schema-only qrmaster > schema.sql +``` + +In die Testdatenbank einspielen: + +```bash +docker exec -i qrmaster-test-db psql -U postgres -d qrmaster_test < schema.sql +``` + +> **Wichtig:** Nicht `prisma migrate` verwenden. Die Migrationsdateien im Repository sind +> seit April 2026 nicht mehr gepflegt - alle Schemaänderungen seitdem wurden per SQL +> gemacht. Ein `migrate deploy` würde ein veraltetes Schema erzeugen, mit dem die +> Anwendung nicht läuft. Der Container startet deshalb bewusst ohne Migrationsschritt. + +Prüfen, dass Tabellen angekommen sind: + +```bash +docker exec qrmaster-test-db psql -U postgres -d qrmaster_test -c "\dt" | head -20 +``` + +## 5. Testaccount anlegen + +Die Registrierung über das Formular funktioniert hier **nicht**: die Testumgebung +verschickt bewusst keine E-Mails, und ohne Bestätigungsmail wird der Account vom System +wieder gelöscht. Der Account wird deshalb direkt in der Datenbank angelegt. + +Zuerst einen Passwort-Hash erzeugen (`DEIN_TESTPASSWORT` durch ein selbst gewähltes +Passwort ersetzen): + +```bash +docker exec qrmaster-test-web node -e "console.log(require('bcryptjs').hashSync('DEIN_TESTPASSWORT',12))" +``` + +Die Ausgabe ist eine Zeichenkette, die mit `$2a$12$` oder `$2b$12$` beginnt. Diese im +folgenden Befehl anstelle von `HIER_DER_HASH` einsetzen: + +```bash +docker exec -i qrmaster-test-db psql -U postgres -d qrmaster_test -c "INSERT INTO \"User\" (id,email,name,password,\"emailVerified\",\"updatedAt\") VALUES ('testuser1','test@qrmaster.net','Test','HIER_DER_HASH',now(),now());" +``` + +Anmeldung erfolgt danach ganz normal über `/login` mit `test@qrmaster.net` und dem +gewählten Passwort. + +## 6. Caddy konfigurieren + +Einen neuen Block in die Caddy-Konfiguration aufnehmen (Pfad ggf. anpassen). Die +bestehenden Blöcke bleiben unverändert: + +```caddyfile +testmodul.qrmaster.net { + reverse_proxy qrmaster-test-web:3000 +} +``` + +Konfiguration neu laden: + +```bash +caddy reload --config /etc/caddy/Caddyfile +``` + +Caddy holt das TLS-Zertifikat automatisch. Das kann eine Minute dauern. + +## 7. Abnahme + +**a) Datenbanken sind getrennt.** Die beiden Zahlen müssen sich unterscheiden - die +Testdatenbank enthält nur den eben angelegten Account: + +```bash +docker exec qrmaster-test-db psql -U postgres -d qrmaster_test -c 'SELECT count(*) FROM "User";' +``` + +```bash +docker exec qrmaster-db psql -U postgres -d qrmaster -c 'SELECT count(*) FROM "User";' +``` + +**b) Keine Migrationen gelaufen.** In der Ausgabe darf **nicht** "Applying Prisma +migrations" stehen: + +```bash +docker logs qrmaster-test-web 2>&1 | head -20 +``` + +**c) Suchmaschinen ausgesperrt.** Muss `Disallow: /` liefern: + +```bash +curl -s https://testmodul.qrmaster.net/robots.txt +``` + +**d) Im Browser:** + +- `https://testmodul.qrmaster.net` lädt mit gültigem Zertifikat +- Anmeldung mit dem Testaccount funktioniert +- `https://testmodul.qrmaster.net/dashboard` **bleibt auf testmodul** und springt nicht auf + `app.qrmaster.net`. Passiert das doch, sind die URLs in der `.env.test` falsch. +- In den Entwicklertools unter Application → Cookies liegen zwei getrennte Cookies: + `userId` mit Domain `.qrmaster.net` (Produktion) und `userId_test` mit Domain + `testmodul.qrmaster.net` +- Die Produktion ist weiterhin erreichbar und man ist dort weiterhin angemeldet + +--- + +## Laufender Betrieb + +Neuen Stand deployen, nachdem auf dem Branch `test` etwas gepusht wurde - aus dem +Verzeichnis `qrmaster-test`: + +```bash +git pull +``` + +```bash +docker compose -p qrmaster-test --env-file .env.test -f docker-compose.yml -f docker-compose.test.yml up -d --build +``` + +Ein Rebuild ist **immer** nötig, ein bloßer Neustart genügt nicht: die Host-URLs und der +Cookie-Name werden beim Bauen fest in die Anwendung kompiliert. + +Schemaänderungen werden weiterhin **von Hand per SQL** ausgeführt - erst auf Test, nach +erfolgreicher Prüfung dasselbe Statement auf Produktion. Es gibt keinen automatischen Weg +dazwischen. + +## Testumgebung stoppen oder entfernen + +Stoppen, Daten bleiben erhalten: + +```bash +docker compose -p qrmaster-test --env-file .env.test -f docker-compose.yml -f docker-compose.test.yml down +``` + +Vollständig entfernen inklusive Testdatenbank - der Projektname `-p qrmaster-test` sorgt +dafür, dass ausschließlich die Test-Volumes gelöscht werden: + +```bash +docker compose -p qrmaster-test --env-file .env.test -f docker-compose.yml -f docker-compose.test.yml down -v +``` + +## Wenn etwas nicht funktioniert + +| Symptom | Ursache | +|---|---| +| Build bricht ab mit `set AUTH_COOKIE_NAME in .env.test` | `.env.test` fehlt oder liegt im falschen Verzeichnis | +| `qrmaster-test-db` bleibt `unhealthy`, `web` startet nicht | In der `.env.test` steht nicht `POSTGRES_DB=qrmaster_test` | +| Caddy liefert 502 | Containername im Caddy-Block stimmt nicht, oder der Container läuft nicht - mit `docker ps` prüfen | +| Anwendung meldet `column ... does not exist` | Schema-Import aus Schritt 4 war unvollständig - erneut einspielen | +| `/dashboard` springt auf `app.qrmaster.net` | Die URLs in der `.env.test` zeigen nicht auf testmodul. Korrigieren und **neu bauen**, nicht nur neu starten. | +| Anmeldung wirkt zufällig abgelaufen | `AUTH_COOKIE_NAME` ist nicht gesetzt oder steht auf `userId` - dann kollidiert es mit dem Produktions-Cookie | +| Registrierung über das Formular schlägt fehl | Erwartet - die Testumgebung verschickt keine E-Mails. Account per SQL anlegen, Schritt 5. | + +## Bekannte Einschränkungen der Testumgebung + +Bewusst deaktiviert, weil die Umgebung nach außen nichts auslösen soll: + +- **Kein E-Mail-Versand** - Registrierung, Passwort-Reset und Benachrichtigungen funktionieren nicht +- **Kein Google-Login** - Zugangsdaten sind nicht hinterlegt +- **Keine Datei-Uploads** - der Objektspeicher (R2) ist nicht konfiguriert +- **Kein Stripe** - Checkout und Abo-Verwaltung funktionieren nicht, solange keine Testschlüssel eingetragen sind +- **Keine Analytics** - damit die Produktionszahlen nicht verfälscht werden