Files
QR-master/DEPLOY_TESTUMGEBUNG_ANLEITUNG.md
Timo Knuth a9057b25dd Add a copy-paste command list to the staging runbook
The runbook explained every step but had no way to just work through it. Adds a checklist
and all commands in one block up front, with the prose below as the reference for what a
step does and how it fails.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 22:29:35 +02:00

12 KiB

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.

Kurzfassung zum Abhaken

Wer die Begründungen nicht braucht, arbeitet diese Liste ab. Die ausführlichen Abschnitte darunter erklären jeden Schritt und was schiefgehen kann.

  • 1. Repo klonen, Branch test, eigenes Verzeichnis neben der Produktion
  • 2. .env.test von Timo dort ablegen und die vier Kernwerte prüfen
  • 3. Stack bauen und starten (-p qrmaster-test)
  • 4. Schema aus Prod dumpen und einspielen - kein prisma migrate
  • 5. Testaccount per SQL anlegen (Registrierungsformular funktioniert nicht)
  • 6. Caddy-Block ergänzen und neu laden
  • 7. Abnahme: DB-Trennung, keine Migrationen, robots.txt, Browser-Test

Alle Befehle am Stück

# 1 - Checkout (NICHT im Produktionsverzeichnis)
git clone -b test https://git.bizmatch.net/tknuth/QR-master.git qrmaster-test
cd qrmaster-test
git branch --show-current          # muss "test" zeigen

# 2 - .env.test hier ablegen, dann pruefen
grep -E "NEXT_PUBLIC_WWW_URL|NEXT_PUBLIC_APP_URL|AUTH_COOKIE_NAME|POSTGRES_DB" .env.test
# Erwartet: beide URLs auf testmodul, AUTH_COOKIE_NAME=userId_test,
# POSTGRES_DB=qrmaster_test. Steht dort app./www. -> STOPP, siehe Schritt 2.

# 3 - Stack starten
docker compose -p qrmaster-test --env-file .env.test \
  -f docker-compose.yml -f docker-compose.test.yml up -d --build
docker ps --filter "name=qrmaster-test" --format "table {{.Names}}\t{{.Status}}"

# 4 - Schema (nur Struktur, keine Kundendaten)
docker exec qrmaster-db pg_dump -U postgres --schema-only qrmaster > schema.sql
docker exec -i qrmaster-test-db psql -U postgres -d qrmaster_test < schema.sql
docker exec qrmaster-test-db psql -U postgres -d qrmaster_test -c "\dt" | head -20

# 5 - Testaccount: erst Hash erzeugen, dann in den INSERT einsetzen
docker exec qrmaster-test-web node -e "console.log(require('bcryptjs').hashSync('DEIN_TESTPASSWORT',12))"
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());"

# 6 - Caddy: Block ergaenzen (siehe Schritt 6), dann
caddy reload --config /etc/caddy/Caddyfile

# 7 - Abnahme
docker exec qrmaster-test-db psql -U postgres -d qrmaster_test -c 'SELECT count(*) FROM "User";'
docker exec qrmaster-db psql -U postgres -d qrmaster -c 'SELECT count(*) FROM "User";'
docker logs qrmaster-test-web 2>&1 | head -20
curl -s https://testmodul.qrmaster.net/robots.txt

Die beiden count(*) müssen sich unterscheiden, in den Logs darf kein "Applying Prisma migrations" stehen, und robots.txt muss Disallow: / liefern.

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:

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.

cd qrmaster-test

Prüfen, dass der richtige Branch ausgecheckt ist - es muss test erscheinen:

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:

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

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:

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):

docker exec qrmaster-db pg_dump -U postgres --schema-only qrmaster > schema.sql

In die Testdatenbank einspielen:

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:

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):

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:

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:

testmodul.qrmaster.net {
    reverse_proxy qrmaster-test-web:3000
}

Konfiguration neu laden:

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:

docker exec qrmaster-test-db psql -U postgres -d qrmaster_test -c 'SELECT count(*) FROM "User";'
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:

docker logs qrmaster-test-web 2>&1 | head -20

c) Suchmaschinen ausgesperrt. Muss Disallow: / liefern:

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:

git pull
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:

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:

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