Unclassified

Subdomain-Based Tenant Routing Implementation

Overview

This implementation adds multi-tenant support to IntegrateWise via subdomain-based routing. Each tenant lives on its own subdomain (e.g., saas-corp.integratewise.com) and serves a branded landing page. The middleware handles subdomain resolution and tenant context injection, making all downstream code automatically tenant-scoped.

Architecture

1. Schema Extensions (lib/data/types.ts)

Extended the Tenant interface with branding and landing configuration:

interface Tenant {
  id: string;
  name: string;
  slug: string; // DNS-safe subdomain identifier
  industry: Industry;
  environment: Environment;
  branding?: {
    logoUrl?: string; // Emoji or URL
    primaryColor?: string; // Hex color
    backgroundColor?: string; // Hex color
    tagline?: string;
  };
  landing?: {
    headline?: string;
    subhead?: string;
    featuredPluginIds?: string[];
    featuredAgentIds?: string[];
  };
  customDomain?: string; // Optional CNAME support
  status: "active" | "suspended" | "provisioning";
}

Extended TenantRepo interface with new methods:

  • getBySlug(slug) — lookup tenant by subdomain slug
  • update(tenantId, updates) — update tenant branding/landing config
  • validateSlug(slug) — validate DNS-safe slug and check uniqueness

2. Data Provider Updates (lib/data/in-memory-provider.ts)

  • Added reserved slug validation (www, app, api, admin, docs, etc.)
  • DNS-safe slug regex validation: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
  • Seed tenants with branding configuration:
    • saas-corp: Blue (#3B82F6), SaaS-focused
    • healthtech: Green (#10B981), Healthcare-focused
    • fintech-solutions: Purple (#8B5CF6), Financial-focused
  • Implemented InMemoryTenantRepo methods for CRUD and slug validation
  • Added seed initialization in DataProvider constructor

3. Middleware Enhancement (middleware.ts)

Enhanced middleware to handle both role subdomains (existing) and tenant subdomains (new):

Routing logic:

  1. Extract subdomain from Host header
  2. Check if role subdomain (founder, sales, etc.) → rewrite to /workbench/[role]
  3. Check if reserved subdomain → allow app, deny others
  4. Look up tenant by slug from seed data
  5. If found → inject X-Tenant-Slug and X-Tenant-Id headers
  6. If not found → rewrite to 404 "workspace not found"
  7. Local dev support: *.localhost:3000 resolves to tenant subdomains

Reserved subdomains: www, app, api, admin, docs, localhost, staging, dev, mail, smtp, ftp

4. Tenant Context & Providers

TenantProvider (lib/context/tenant-context.tsx):

  • React context for tenant state management
  • Reads X-Tenant-Slug from request headers
  • Loads tenant data from DataProvider
  • Provides useTenant() and useTenantContext() hooks
  • Handles loading and error states

Tenant Route Group (app/(tenant)/layout.tsx):

  • Wraps all tenant-scoped routes with TenantProvider
  • Automatically injects tenant context to all children
  • All server components inside automatically receive tenant scope

5. Per-Tenant Landing Page

TenantLandingPage (components/tenant/landing-page.tsx):

Modern, polished landing page with:

  • Responsive navigation with tenant logo, name, and auth status
  • Hero section with customizable headline/subhead and CTA
  • Features grid showing 4 key capabilities
  • Industry-specific section with stats (templates, integrations, team members)
  • Call-to-action section with context-aware messaging
  • Footer with links and copyright

Design patterns from v0 templates:

  • CSS variables for tenant branding (primary color, background)
  • Smooth transitions and hover effects
  • Semantic HTML and accessibility
  • Mobile-first responsive design
  • Auth-aware routing (sign-out → sign-in; onboarded → /work; not-onboarded → /onboarding)

6. Tenant Picker Page

TenantPicker (components/tenant/tenant-picker.tsx):

Workspace selection hub served at app.integratewise.com:

  • Lists all active tenants with branding
  • Displays tenant logo, name, industry, tagline, status
  • Hover effects showing navigation intent
  • Status indicator (active/suspended/provisioning)
  • Empty state with helpful messaging
  • Call-to-action for workspace creation

7. Routes Created

(tenant)/                          # Tenant-scoped route group
  layout.tsx                       # TenantProvider wrapper
  page.tsx                         # Per-tenant branded landing

app/                               # Reserved subdomain (app.integratewise.com)
  page.tsx                         # Tenant picker

8. Routing Model

integratewise.com            → public ecosystem (future: marketplace, docs, etc.)
www.integratewise.com        → same as apex
{tenant}.integratewise.com   → tenant landing page + app entry
app.integratewise.com        → tenant picker (lists workspaces user can access)
*.localhost:3000             → local dev equivalent (tenant.localhost)

Data Flow

  1. Request arrives → middleware extracts subdomain
  2. Tenant lookup → middleware finds tenant by slug from DataProvider
  3. Header injection → middleware injects X-Tenant-Slug and X-Tenant-Id
  4. Route match → Next.js routes to (tenant) group
  5. TenantProvider mounts → reads headers and loads tenant from DataProvider
  6. Context available → all child components access tenant via useTenant()
  7. Branding applied → CSS variables apply tenant colors/logo
  8. Auth-aware navigation → page routes based on user session state

Key Features

Branding System

  • CSS variables for dynamic theming: --primary-color, --background-color
  • Tenant-specific logo, tagline, and visual identity
  • Consistent branding across landing page via design tokens

Industry Awareness

  • Landing copy customized by industry (SaaS/Healthcare/Fintech)
  • Pre-populated section headlines and feature descriptions
  • Differentiated messaging for each workspace type

Auth-Aware Routing

  • Unsigned users: redirect to sign-in
  • Signed-in, not-onboarded: redirect to onboarding
  • Signed-in, onboarded: redirect to workspace dashboard
  • Each page state has clear CTA

Fallback Defaults

  • Tenants without custom branding get clean defaults
  • Default colors: blue (#3B82F6)
  • Default background: light blue (#F0F9FF)
  • Sensible fallback copy and layouts

Seed Data

Three demo tenants ship with the implementation:

SlugNameIndustryPrimary ColorLogo
saas-corpSaaS Corpsaas#3B82F6🚀
healthtechHealthTech Inchealthcare#10B981⚕️
fintech-solutionsFintech Solutionsfintech#8B5CF6💰

Each includes:

  • Custom branding (color, background, tagline)
  • Industry-aware landing copy
  • Active status

Testing

Local Development

Access tenants via subdomains on localhost:

  • http://saas-corp.localhost:3000
  • http://healthtech.localhost:3000
  • http://fintech-solutions.localhost:3000
  • http://app.localhost:3000 → tenant picker

Verification Checklist

  1. ✅ Subdomain resolves to tenant landing page
  2. ✅ Branding (colors, logo, copy) applied correctly
  3. ✅ Auth-aware navigation works (signed out → sign-in CTA)
  4. ✅ Tenant picker shows all active tenants
  5. ✅ Unknown subdomain returns 404
  6. ✅ Reserved subdomains (www, api, etc.) blocked
  7. ✅ Role subdomains still work (founder.localhost → /workbench/founder)

Integration Points

All existing features automatically benefit from tenant scoping:

  • DataProvider: All data queries automatically scoped to tenant (via X-Tenant-Id header)
  • Work Router: Resolves capabilities within tenant scope
  • Onboarding: Pre-fills tenant context
  • Authentication: Sessions remain tenant-aware

Production Considerations

Custom Domains

The customDomain field supports CNAME mappings (e.g., acme.com → acme.integratewise.com). Implementation requires:

  • DNS validation flow
  • Middleware enhancement to handle custom domain → slug lookup
  • SSL certificate provisioning (via Vercel)

Database Integration

Current implementation uses in-memory storage for development. For production:

  1. Move tenant data to persistent database (Neon PostgreSQL)
  2. Add caching layer for slug → tenant lookups (Redis or in-process LRU)
  3. Implement slug availability checking in admin API
  4. Add tenant creation/deletion endpoints

Admin Interface

Future enhancement for tenant provisioning:

  • Create workspace (validate slug, generate branding options)
  • Edit branding and landing config
  • Manage team members and permissions
  • Monitor tenant health and usage

Files Changed

New Files

  • lib/context/tenant-context.tsx — Tenant context provider
  • lib/tenant-lookup.ts — Tenant lookup utility (optional)
  • components/tenant/landing-page.tsx — Branded landing page
  • components/tenant/tenant-picker.tsx — Workspace picker
  • app/(tenant)/layout.tsx — Tenant route group layout
  • app/(tenant)/page.tsx — Tenant landing route
  • app/app/page.tsx — Tenant picker route

Modified Files

  • lib/data/types.ts — Extended Tenant interface and TenantRepo
  • lib/data/in-memory-provider.ts — Added seed tenants, validation, new methods
  • middleware.ts — Enhanced for tenant subdomain routing

Performance

  • Lazy tenant lookup: Tenants loaded on first request via context provider
  • In-memory caching: Seed data cached in DataProvider
  • Header-based routing: No additional database queries in middleware
  • CSS variable theming: No re-renders for branding application

Security

  • DNS-safe slug validation prevents injection attacks
  • Reserved subdomain list prevents conflicts
  • Header injection via middleware ensures tenant context integrity
  • Future: RLS policies on database ensure tenant data isolation