Feature ID: PF-95Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Status: ✅ Complete (Phase 1–3; Phase 4 email branding deferred)
Spec: PF-95-tenant-white-labeling-theming.md (v1.2.0) Last Updated: 2026-03-25
Overview
PF-95 adds per-tenant visual theming (CSS custom properties), optionalpf_organizations.subdomain, subdomain_verified, prefer_subdomain_redirect, and coordination with email branding. It extends the platform foundation without introducing cross-core imports. Consumers use @/platform/theming (planned) for theme resolution and CSS variable injection.
Integration Points (from Spec)
| Point | Type | Document / Spec |
|---|---|---|
| PF-01 (Organizations) | Data | pf_organizations; subdomain, subdomain_verified, prefer_subdomain_redirect |
| PF-74 (Org URL Routing) | Platform internal | Implements Canonical redirect matrix (R1–R5) on primary host; path org routing unchanged |
| PF-77 (Tenant Domain Management) | Platform / external | Vercel host + SSL; custom apex domain out of scope for PF-95 |
| PF-81 (Multi-Tenant Host & URL Strategy) | Reference | Strategy umbrella; normative redirect table lives in PF-95 spec |
| PF-86 (Email Signatures) | Platform Layer | Theme color tokens for HTML notification templates (Phase 4) |
| PF-77 / Vercel | External infra | Subdomain SSL and hostname configuration |
Platform Layer / Event / API Contracts
- Platform layer (planned):
@/platform/theming—TenantThemeProvider,useTenantTheme,useTenantThemeForLogin(or equivalent) calling RPCs below for pre-auth, shared types aligned withpf_tenant_themesrows. - Pre-auth (database): Call
pf_public_login_branding_by_subdomain(subdomain_label)when the request host is a tenant subdomain; callpf_public_login_branding_by_slug(slug)when resolving branding from PF-74 path slug (e.g. login with org context). Do not expose anonymousSELECTonpf_tenant_themes. Functions return a fixed JSON projection (login-safe fields only); see spec Data Model. - Authenticated: Standard Supabase CRUD on
pf_tenant_themeswith RLS; org subdomain flags updated via existing org update patterns andpf.subdomain.manage. - Event contracts: None planned for MVP.
- Single active theme: Partial unique index
(organization_id) WHERE is_active+BEFOREtrigger to deactivate sibling rows (spec DDL).
Canonical redirect matrix (normative summary)
Eligibility:subdomain IS NOT NULL and subdomain_verified = true and prefer_subdomain_redirect = true.
| Rule | Request | Action |
|---|---|---|
| R1 | Primary app host + /o/{slug}/… | If org for slug meets eligibility → 308 to https://{subdomain}.{apex}/o/{slug}/… (preserve path + query). |
| R2 | Tenant subdomain host + /o/{slug}/… | No redirect. |
| R3 | Primary host, path without /o/:slug | No PF-95 redirect. |
| R4 | Unknown subdomain host | No PF-95 redirect (platform default). |
| R5 | Wrong subdomain host for resolved org (optional) | 308 to canonical tenant host (recommended; PF-74 may defer with implementation log). |
Security & Tenancy
- All theme rows scoped by
organization_id; RLS viapf_has_org_access(SECURITY DEFINER helper; no inline role-assignment queries in policies). - Permission keys (PF-30):
pf.theme.view,pf.theme.manage,pf.subdomain.manage— constants + seeds with feature UI. - No arbitrary CSS/HTML injection; colors validated to safe formats; assets via approved upload paths.
- Pre-auth: Only
pf_public_login_branding_*RPCs; fixed column allowlist;search_pathpinned inside functions. - Redirects: Gated on
subdomain_verifiedto avoid redirect loops to hosts without valid TLS.
Related Docs
- CROSS_CORE_INTEGRATIONS.md
- PF-74 Integration — implements redirect matrix
- PF-81 Integration
- PF-77 Integration
- PF-86 Integration
- PF-95 Spec