Files
HiveGrid-Wireframes/hivegrid-cloud/docs/improvement-plan/11-backlog/multi-region.md
T

8.8 KiB

Multi-Region-Deployment

Status: backlog: EU-only-Markt-Annahme bricht (z.B. erster US-Customer mit Latenz-/Compliance-Anforderungen, oder APAC-Pipeline) Task-ID: #52 Phase: 11 (Backlog) Estimated Effort: 4-5 Wochen wenn aktiviert + dauerhafte Mehrkosten + ~2x Ops-Aufwand Owner: unassigned

Problem

Die Boilerplate läuft heute single-region auf Hetzner (EU). Solange alle Kunden EU-basiert sind und DSGVO/EU-Datenresidenz das wichtigste Compliance-Argument ist, ist das die richtige Wahl. Sobald ein Kunde mit Anforderungen außerhalb EU dazukommt — Latenz (US-/APAC-User), Datenresidenz-Pflicht (USA, Kanada, Australien) oder Single-Region-SLA-Bruch — muss die Architektur Multi-Region tragen können.

Vorab-Aktivierung würde dauerhafte Mehrkosten (zweite Hetzner-/Fly-Region + zweite DB-Replikation + zweiter Storage) erzeugen, ohne dass ein Kunde sie rechtfertigt.

Depends on

  • ../03-scaling-infrastructure/shared-store-package.md — Cache muss schon per-region-fähig sein (Redis-Cluster pro Region)
  • ../03-scaling-infrastructure/pgbouncer.md — DB-Connection-Pooling muss stehen, bevor regionale DB-Replikation eingeführt wird
  • ../03-scaling-infrastructure/read-write-split.md — Routing-Schicht für Read-Replicas wird zu Region-Routing erweitert
  • ../03-scaling-infrastructure/outbox-pattern.md — Cross-Region-Event-Replikation läuft über Outbox, nicht direkt
  • ../03-scaling-infrastructure/asset-cdn.md — CDN muss bereits global verteilt sein

Blocks

  • nichts (Backlog-Item, blockt keine aktive Roadmap)

Approach

Tenant-Region-Pinning + Anycast-Frontend. Begründung gegen Alternativen:

  • Active-Active Multi-Master (Postgres BDR / CockroachDB): zu komplex und teuer in Ops; Konflikt-Resolution bei multi-region Writes ist eine eigene Klasse von Bugs. Verworfen.
  • Global Read-Replicas, Single-Write-Region: löst nicht das Datenresidenz-Problem (US-Tenant-Daten würden in EU geschrieben). Verworfen.
  • Tenant-Region-Pinning (gewählt): jeder Tenant lebt komplett in einer Region. Beim Onboarding wählt Tenant-Admin die Region (EU/US/APAC), danach bleiben alle Daten + Compute dort. Klare Datenresidenz, keine Cross-Region-Writes, einfache Ops-Story.

Routing: Fly.io Anycast (oder vergleichbar — Bunny.net / Cloudflare-Load-Balancer mit Geo-DNS) für die HTTP-Container, die selbst stateless sind. Container halten lokalen Region-Cache (Redis pro Region) und delegieren DB-Calls an die regionale Postgres-Instanz.

Region-Routing: Auth-Cookie + JWT-Header tragen region-index als kleinen Claim. Reverse-Proxy / App-Middleware liest das und routet entweder lokal (Tenant ist in der Region) oder gibt 307-Redirect auf die korrekte regionale Subdomain (eu.<domain> / us.<domain>). Für nicht-authentifizierte Requests: Geo-IP-basiertes Routing auf die nächstgelegene Region, Tenant-Login forciert dann den Switch.

Storage: separate Storage-Buckets pro Region (S3-compatible, z.B. Hetzner Object Storage / AWS S3 / Cloudflare R2 — abhängig von Datenresidenz-Anforderung des Kunden). Asset-CDN aus Phase 03 cached global, Origin-Pulls gehen an den regionalen Bucket des Tenants.

Cloudflare-Workers-Edge-Adapter ist eine optionale Erweiterung für noch niedrigere Latenz bei statischen oder cache-baren Endpoints (Auth-Discovery, Pricing-Pages, Marketing-Funnel-Routes). Wird in einer späteren Iteration evaluiert, nicht Pflicht zur Aktivierung.

Cross-Region: absolutes Minimum — nur Audit-Log-Aggregation für Compliance-Reports (read-only, asynchron via Outbox → Kafka/NATS-Stream). Keine Tenant-Daten migrieren.

Implementation Steps

  1. Region-Indicator im Tenant-Modell — Tenant.region (enum: eu, us, apac), Default eu, in JWT/Session-Cookie als Claim. Commit: 11-backlog/multi-region: add tenant region pinning
  2. DB-Routing-Middleware — basierend auf JWT-Claim oder Subdomain entscheidet die Middleware, welche Postgres-Connection-Pool genutzt wird. Erweitert die Read-Write-Split-Logik aus Phase 03. Commit: 11-backlog/multi-region: db routing middleware
  3. Storage-Bucket pro Region — Storage-Adapter erweitert um region-Argument; pro Tenant-Region jeweils ein S3-Bucket. Commit: 11-backlog/multi-region: per-region storage buckets
  4. Anycast-Frontend-Routing — Fly.io (oder vergleichbar) deployt App-Container in EU + US; Geo-DNS für Initial-Routing, Cookie/JWT für authentifizierten Steady-State. Commit: 11-backlog/multi-region: anycast frontend deploy
  5. Region-Wrong-Redirect-Handler — wenn Request in falscher Region landet, 307-Redirect auf korrekte Subdomain. Commit: 11-backlog/multi-region: cross-region redirect handler
  6. Cross-Region-Audit-Aggregation — Outbox-Event-Stream pro Region wird in zentralen Compliance-Logging-Sink (eine Region, read-only) repliziert. Commit: 11-backlog/multi-region: audit log aggregation
  7. Tenant-Onboarding-Region-Auswahl — Wizard fragt beim Sign-up nach Region, schreibt Tenant.region, provisioniert in der gewählten Region. Commit: 11-backlog/multi-region: onboarding region picker
  8. Doku + Runbook — docs/operations/multi-region.md (Architektur, Region-Migration-Prozess für Tenant-Wechsel, Failover-Strategie pro Region). Commit: 11-backlog/multi-region: documentation

Test Requirements

  • Unit-Tests: Region-Resolver (Tenant.region → DB-Pool), Region-Mismatch-Detector, Cookie/JWT-Region-Claim-Parser
  • Integration-Tests: Tenant-Onboarding mit Region-Auswahl, DB-Call landet in korrekter Region, Storage-Upload landet in korrektem Bucket, Cross-Region-Request triggert 307-Redirect
  • E2E-Tests (Playwright): Sign-up mit Region US → Login von EU-IP → korrekter Redirect; Asset-Upload landet in US-Bucket; Audit-Log-Entry erscheint im Compliance-Sink
  • Coverage-Target: ≥70% für app/utils/region/* + alle touched Routing-Module
  • Test-Files: neben Source, E2E unter apps/web/playwright/multi-region/

NICHT als completed markieren bevor alle Tests grün sind.

Acceptance Criteria

  • Tenant kann beim Onboarding zwischen Regionen (mindestens EU + US) wählen
  • Alle Tenant-Daten (Postgres, Storage, Cache) liegen physisch in der gewählten Region
  • Authentifizierte Requests landen in der korrekten Region; Cross-Region-Requests werden per 307 umgeleitet
  • Latenz-Messung: Request von US-Client an US-Tenant unter 150ms TTFB (gegen EU-Tenant von US-Client wäre vergleichbar 200-300ms)
  • Audit-Log-Aggregation läuft, alle regionalen Audit-Events landen im zentralen Compliance-Sink
  • Tests grün
  • docs/operations/multi-region.md mit Architektur-Diagramm + Runbook angelegt
  • Progress-Log + PROGRESS.md aktualisiert

Rollback Strategy

  • Multi-Region kann region-weise zurückgebaut werden — z.B. US-Region down: Geo-DNS-Eintrag entfernen, US-Tenants temporär auf EU-Region failovern (Notfall, mit explizitem Tenant-Consent wegen Datenresidenz-Bruch)
  • Storage-Buckets pro Region bleiben unabhängig — kein Risiko von Daten-Vermischung
  • Feature-Flag multi_region.routing_enabled schaltet Routing-Logik ab, App fällt auf single-region (EU) zurück
  • DB-Migration: Tenant.region mit Default eu kann ohne Datenverlust droppt werden

Security Notes

  • Datenresidenz-Garantie ist Compliance-kritisch — jede Cross-Region-Datenbewegung muss audit-loggable sein, Penetration-Test sollte Routing-Bypass-Versuche prüfen
  • JWT-Region-Claim muss server-signed sein (HS256/RS256 wie bisher), Client-Tampering würde sonst Region-Pinning umgehen
  • Audit-Log-Aggregation: nur Metadaten + Tenant-IDs cross-region replizieren, niemals Tenant-Inhalt
  • Region-Failover-Runbook muss explizit machen, dass Failover Datenresidenz-Bruch ist — Customer-Notification + Consent erforderlich

Subagent Recommendations

  • Planning: Plan-Subagent mit Phase-03-Outputs (PgBouncer, Read-Write-Split, Outbox) als Input
  • Research: Explore-Subagent für Fly.io vs Cloudflare-Workers-Anycast-Vergleich, Bunny.net / Cloudflare-Load-Balancer-Optionen
  • Implementation: ein general-purpose-Subagent pro Step
  • Tests: separater general-purpose-Subagent für E2E (Multi-Region-Setup ist test-lastig)
  • Verification: gsd-verifier für Acceptance-Criteria; manueller Latenz-Test via Staging-VM in US-Region
  • Code-Review: gsd-code-reviewer nach Step 4 (Anycast) und nach Step 8 (final)

Staging-Deployment-Steps

  1. Branch agent/11-backlog-multi-region pushen
  2. Fly.io / vergleichbarer Provider in EU + US einrichten (separater Account / Region für Staging)
  3. Postgres-Instanzen pro Region provisionieren (Hetzner / Fly Postgres / RDS)
  4. Storage-Buckets pro Region
  5. Geo-DNS / Cloudflare-Load-Balancer für Staging-Subdomains konfigurieren
  6. Test-Tenants in jeder Region anlegen, Cross-Region-Routing manuell verifizieren

Deviations from Plan

(Wird vom ausführenden Agent gefüllt.)

Progress Log

(Wird vom ausführenden Agent gefüllt.)