ADR-014: Tenant Resolution
Status: Accepted
Kontext
Restaurants verwenden ByteBite-Subdomains oder eigene Domains. Der Tenant darf nicht durch einen frei manipulierbaren Client-Parameter bestimmt werden.
Entscheidung
Der Tenant wird primär über den Hostname/Domainnamen aufgelöst.
hostname
-> restaurant_domains.hostname
-> restaurant_idKonsequenzen
- Subdomains und Custom Domains verwenden denselben Mechanismus.
- Domainverifikation ist Bestandteil des Onboardings.
- Unbekannte oder nicht verifizierte Hosts werden abgelehnt.
restaurantIdaus Query, Body oder Client-Headern ist keine Tenant-Autorität.
Interne Storefront-SSR-Aufrufe
Browser-Requests (einschließlich same-origin /api) liefern den Tenant über den Host-Header. Traefik erhält den Browser-Host und leitet ihn an Fastify weiter. trustProxy ist nicht aktiv; X-Forwarded-Host von Clients wird nicht als Tenant verwendet.
Next.js Server-Komponenten rufen Fastify intern über API_INTERNAL_URL (http://api:3001). Dabei wäre der Host api / api:3001, nicht das Restaurant.
Für diesen Server-zu-Server-Pfad sendet der Storefront den originalen Host in X-ByteBite-Tenant-Host. Fastify akzeptiert diesen Header nur, wenn der Request-Host die interne API-Identität ist (api, localhost, 127.0.0.1, ::1).
Öffentliche Hosts — einschließlich api.bytebite.test und luigi.bytebite.test — ignorieren den Header. Ein Browser kann damit keinen anderen Tenant wählen.
Vertrauensgrenze (interner Pfad)
X-ByteBite-Tenant-Host ist nur auf Anfragen autoritativ, die Fastify über den privaten internen Service-Pfad erreichen (API_INTERNAL_URL → Docker-Service api:3001). Der API-Container-Hostname ist nicht öffentlich exponiert; Traefik routet Browser-Anfragen über die externe Host-Domain und leitet den Header nicht als Tenant-Autorität weiter.
Öffentliche Anfragen über Traefik leiten die Tenant-Autorität ausschließlich aus dem externen Host ab. Der interne Header kann sie nicht überschreiben. Kein Header-Signing in diesem Slice.
Fehlerverhalten bei Tenant-Auflösung
- Bekannte, aktive Domain → normaler Request
- Unbekannte Domain → öffentliche 404 (
Restaurant not found) - Inaktives Restaurant → öffentliche 404 (gleiche Antwort wie unbekannt)
- Datenbank-/Infrastrukturfehler während der Hostname-Auflösung → 503 (
Service Unavailable), ohne Datenbankdetails in der Antwort /healthund/health/dbbleiben unabhängig von der Tenant-Auflösung