Files
suaveplan/openspec/archive/2026-05-26-api-tenant-resolver-subdomain/proposal.md
2026-05-27 23:29:53 +01:00

2.3 KiB

@suaveplan/api-tenant-resolver-subdomain — subdomain tenant resolver

Package: @suaveplan/api-tenant-resolver-subdomain Status: PROPOSED Type: new-package Stage: 8 — see umbrella openspec/changes/api-plugin-foundation/

Why

Per design doc §6 step 4, multi-tenant deployments commonly serve each tenant at <tenant>.api.example.com. This adapter resolves the tenant from the request's host header, completing the v1 tenant-resolver chain alongside the header adapter.

What changes

  • ADDED: createSubdomainTenantResolver({ baseDomain, validate, registry }) — reads request.host (or X-Forwarded-Host when configured), strips baseDomain, validates the remaining label, and returns { tenantId, source: "subdomain" } or null.
  • ADDED: Multi-label support — tenantLabelIndex config selects which label is the tenant (default 0 — leftmost). Supports nested deployments (<tenant>.<region>.api.example.com).
  • ADDED: Forwarded-host trust — trustForwardedHost config defaults to false (don't trust client-supplied headers); when true, consults trustedProxyCidrs to validate the upstream IP.
  • ADDED: Strict mode parity with api-tenant-resolver-header.
  • ADDED: Conformance — passes runTenantResolverConformance.
  • ADDED: Error codes (TENANT_SUBDOMAIN_*): INVALID, NOT_FOUND_IN_REGISTRY, BASE_DOMAIN_MISMATCH, FORWARDED_HOST_UNTRUSTED.

Out of scope

  • TLS / cert provisioning per tenant — operator concern.
  • Reverse-DNS resolution — out of scope; we only look at the request host.

Source mapping

Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.

Requirement Design doc section
Tenant resolver chain §6 step 4

Verification approach

  • src/resolver/resolver.test.ts — acme.api.example.com → acme; mismatched base domain → strict raises TENANT_SUBDOMAIN_BASE_DOMAIN_MISMATCH; multi-label index.
  • src/forwarded/forwarded.test.ts — trusted-proxy CIDR check; untrusted proxy ignored.
  • src/resolver/resolver.spec-conformance.test.ts — runs runTenantResolverConformance.
  • tests/dep-graph.test.ts.

Migration impact

None — additive only. api-host wires this when host.tenant.resolvers includes "subdomain".