← Tenancy

TENANCY FEATURE

Per-Tenant Configuration

One resolved tenant config reshapes branding, locale, commerce defaults, and feature flags across the same product surface.

This page is about product-shaping tenancy, not database partitioning. One tenant decision changes what the product feels like to the user.

Switch between tenants and compare what really moves: branding, locale defaults, pricing conventions, rating behavior, and capability flags. The same handler and template tree stay intact.

What this page is actually demonstrating

The point is not that a color changed. The point is that one resolved tenant config can drive multiple product decisions consistently: theme, locale, currency, rating presentation, and feature flags.

Aspect Why it matters Acme Globex Initech
Brand surface What a user notices first when the tenant changes. Blue serif storefront with premium tone Green sans-serif workspace with utilitarian tone Orange minimal UI with lighter product voice
Commerce defaults What downstream UI components can assume without passing tenant IDs around. USD, locales en/de/uk, default en EUR, locales en/de, default de UAH, locales en/uk, default uk
Interaction rules Which features appear as product capabilities rather than hard-coded if/else branches. Reviews on, wishlist on, AI chat off Reviews on, wishlist off, AI chat on Reviews off, wishlist on, AI chat off
Rendering implication How the same handler/template tree can still feel like a different product. Editorial catalog feel Operational B2B dashboard feel Lean regional product feel
// In a handler or template:
$theme = TenantContext::getLayer(ThemeLayer::class);
$color = $theme->primaryColor;   // '#1e40af' for acme
$font  = $theme->fontFamily;     // 'Georgia, serif' for acme

That is the real design goal: application code asks for the active layer, not for a tenant ID. Tenant selection happens once at the boundary; downstream code consumes capabilities.

How the resolution flow works

Think about this page as a three-step pipeline rather than a styling demo:

  1. Select the tenant once. This demo chooses the active tenant from the query parameter and resolves a single tenant config object.
  2. Build the tenant-facing layers. Theme, locale defaults, rating style, and feature flags are derived from that config instead of being scattered across controllers or templates.
  3. Let handlers and views consume capabilities. Downstream code asks for the active layer or capability and renders the correct experience without comparing tenant IDs manually.

If you had to write if ($tenantId === 'globex') inside a template, the architecture would already be losing. The demo should teach the opposite habit: resolve tenant context once, then let the rest of the stack read structured configuration.