agentjob.ioHandbook
Architecture Decision Records

ADR-0004: Custom domains via Cloudflare for SaaS, dashboard on the core domain

Tenant storefronts are served on custom hostnames through Cloudflare for SaaS by the planned storefront app; the dashboard stays isolated on app.example.com.

ADR-0004: Custom domains via Cloudflare for SaaS, dashboard on the core domain

  • Date: 2026-09-18
  • Status: Withdrawn — the public storefront and its domains were removed with the vertical (see ADR-0010). The record is kept for history.
  • Deciders: the owner, Claude (seed)
  • Tags: infra domain

Context

The original requirement: public pages on the merchant's domain, and the control panel on the project's domain. Thousands of domains need automatic SSL, fast routing, and security isolation from the dashboard.

Decision

The planned apps/storefront (a Cloudflare Worker) serves Custom Hostnames through Cloudflare for SaaS plus the wildcard *.example.com; apps/saas serves app.example.com only.

  • An edge cache (KV) maps hostname → { tenantId, siteId }; the source of truth is the domains table in Postgres.
  • Verification by CNAME / TXT, domain status shown in the dashboard, SSL managed by Cloudflare.
  • Two different origins → independent cookies, authentication, and CSP.

Consequences

  • Positive — zero-touch setup for the merchant, automatic SSL, security isolation of the dashboard.
  • Negative — a per-hostname cost for custom domains (covered by the Growth plan and above).
  • Revenue impact (monthly, confidence) — the custom domain is the lever for upgrading to the higher plan (medium confidence).

Rejected alternatives

  • A generic reverse proxy (Nginx / Caddy) on a VPS: manual certificate management that does not scale.
  • Merchant sites on a subdomain only: loses the original requirement and the trust it brings.

References

Withdrawn 2026-09-20. This record describes a surface that is no longer part of the product: the public storefront and its domains were removed with the vertical. ADR-0010 records the decision.

On this page