Multi-Tenant Application Domain Configuration Architecture
Multi-Tenant Application Domain Configuration Architecture
Section titled “Multi-Tenant Application Domain Configuration Architecture”1. Executive Summary & Design Principles
Section titled “1. Executive Summary & Design Principles”In the SiteSwarm multi-tenant monorepo, dozens of independent client web applications coexist. Each client web application represents an autonomous business entity with its own branding, deployment lifecycle, database instances, and custom domains.
To prevent cross-tenant configuration blast radius and avoid accidental domain collisions between clients (e.g. accidentally assigning Client A’s domain to Client B), all custom domain and routing configurations are strictly colocated at the application level.
There is no central or global domain registry table in SiteSwarm. Instead:
- Each application defines its own environment names and custom domain routes inside its own
wrangler.jsonc. - Each application defines its persistent infrastructure (D1 databases, custom domain DNS records, SSL certificates) inside its colocated
apps/<app>/infra/Terraform module. - CI/CD workflows dynamically discover each app’s domain and routing configuration directly from that app’s
wrangler.jsoncat deployment time.
2. Platform Domain Standard (jacobmiller22.com)
Section titled “2. Platform Domain Standard (jacobmiller22.com)”Until a client application provisions its own dedicated branded domain (e.g. greenleafbakery.com), client applications default to subdomains under the active platform domain: jacobmiller22.com.
Cloudflare Universal SSL Single-Level Invariant
Section titled “Cloudflare Universal SSL Single-Level Invariant”Cloudflare’s default Universal SSL certificate covers the root domain (example.com) and a single level of wildcard (*.example.com). It does not cover multi-level subdomains (such as staging.bakery.example.com) without purchasing Cloudflare Advanced Certificate Manager ($10/month).
To guarantee 100% out-of-the-box SSL certificate coverage with zero additional monthly costs, SiteSwarm mandates single-level subdomains under jacobmiller22.com:
| Environment | Subdomain Convention | Example URL | SSL Coverage |
|---|---|---|---|
| Production | <app>.<domain> |
https://bakery.jacobmiller22.com |
*.jacobmiller22.com (Universal SSL) |
| Staging | <app>-staging.<domain> |
https://bakery-staging.jacobmiller22.com |
*.jacobmiller22.com (Universal SSL) |
| PR Preview | <app>-preview-pr-<N>.<domain> |
https://bakery-preview-pr-86.jacobmiller22.com |
*.jacobmiller22.com (Universal SSL) |
| PR Preview (workers.dev) | <worker-name>.<workers-subdomain>.workers.dev |
https://bakery-preview-pr-86.jacobmillerdev.workers.dev |
*.workers.dev (Native Cloudflare) |
3. Application-Level Configuration Specification
Section titled “3. Application-Level Configuration Specification”3.1 Runtime Specification (apps/<app>/wrangler.jsonc)
Section titled “3.1 Runtime Specification (apps/<app>/wrangler.jsonc)”Each app specifies its runtime environment isolation and routes under env:
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "green-leaf-bakery", "compatibility_date": "2026-09-29", "compatibility_flags": ["nodejs_compat"], "d1_databases": [ { "binding": "DB", "database_name": "green-leaf-bakery-prod-d1", "database_id": "<prod-uuid>" } ], "env": { "preview": { "vars": { "ENVIRONMENT": "preview" }, "d1_databases": [ { "binding": "DB", "database_name": "green-leaf-bakery-d1", "database_id": "<preview-uuid>" } ] }, "staging": { "name": "green-leaf-bakery-staging", "vars": { "ENVIRONMENT": "staging" }, "d1_databases": [ { "binding": "DB", "database_name": "green-leaf-bakery-staging-d1", "database_id": "<staging-uuid>" } ], "routes": [ { "pattern": "bakery-staging.jacobmiller22.com", "custom_domain": true } ] }, "production": { "name": "green-leaf-bakery", "vars": { "ENVIRONMENT": "production" }, "d1_databases": [ { "binding": "DB", "database_name": "green-leaf-bakery-prod-d1", "database_id": "<prod-uuid>" } ], "routes": [ { "pattern": "bakery.jacobmiller22.com", "custom_domain": true } ] } }}3.2 Infrastructure Specification (apps/<app>/infra/)
Section titled “3.2 Infrastructure Specification (apps/<app>/infra/)”The colocated Terraform module exposes variables for staging and production domains:
variable "staging_domain" { description = "Custom domain hostname for Staging" type = string default = "bakery-staging.jacobmiller22.com"}
variable "production_domain" { description = "Custom domain hostname for Production" type = string default = "bakery.jacobmiller22.com"}4. Runbook: Assigning a Dedicated Client Domain
Section titled “4. Runbook: Assigning a Dedicated Client Domain”When a client purchases their own domain (e.g. greenleafbakery.com) and delegates nameservers to Cloudflare:
- Step 1: Update App Configuration (
apps/<app>/wrangler.jsonc): Change thepatterninenv.stagingandenv.production:"env": {"staging": {"routes": [{ "pattern": "staging.greenleafbakery.com", "custom_domain": true }]},"production": {"routes": [{ "pattern": "greenleafbakery.com", "custom_domain": true }]}} - Step 2: Update App Infrastructure (
apps/<app>/infra/variables.tf): Updatestaging_domainandproduction_domaindefaults or terraform tfvars. - Step 3: Verification:
Submit a PR. Ephemeral preview deploys will test routing, merge to
maindeploys to the new staging domain, and automated health checks verify HTTP 200 and version hash equivalence before opening the gate.