Skip to main content

Tenant Configuration Reference

Complete reference for all tenant configuration options.

Config Structure

export interface EAIConfig {
// Required
tenantId: string;
displayName: string;
store: Record<string, StoreSlice>;
layout: LayoutConfig;

// Optional
theme?: ThemeConfig;
features?: FeatureFlags;
}

Required Fields

tenantId

Unique identifier for the tenant. Used in:

  • URL query parameter: ?tenant=my-tenant
  • API calls and logging
  • Store persistence key
tenantId: 'my-tenant'

Constraints:

  • Lowercase letters, numbers, and hyphens only
  • Must be unique across all tenants

displayName

Human-readable name shown in the UI:

displayName: 'My Application'

store

Defines the global state structure:

store: {
sliceName: {
initialState: { /* initial values */ },
persist: boolean,
},
}

StoreSlice

PropertyTypeRequiredDescription
initialStateobjectYesDefault values for this slice
persistbooleanYesSave to sessionStorage
store: {
user: {
initialState: {
name: null,
email: null,
preferences: {
theme: 'light',
notifications: true,
},
},
persist: true,
},
ui: {
initialState: {
sidebarOpen: true,
modalVisible: false,
},
persist: false,
},
}

layout

Defines component placement in four slots:

layout: {
header: ComponentConfig[],
leftPane: ComponentConfig[],
middlePane: ComponentConfig[],
rightPane: ComponentConfig[],
}

ComponentConfig

Each component in a slot has this structure:

interface ComponentConfig {
component: string;
priority: number;
props?: Record<string, any>;
storeBindings?: StoreBinding[];
showWhen?: (state: GlobalState) => boolean;
}

component

Name of the component as registered in ComponentRegistry:

component: 'Header'  // Must match registry key

priority

Render order within the slot (lower numbers render first):

priority: 1   // Renders before priority: 2

props

Static props passed to the component:

props: {
title: 'Welcome',
showLogo: true,
variant: 'primary',
}

storeBindings

Map store paths to component props:

storeBindings: [
{ prop: 'userName', storePath: 'user.name' },
{ prop: 'isOpen', storePath: 'ui.sidebarOpen' },
]

StoreBinding

PropertyTypeDescription
propstringProp name on the component
storePathstringDot-notation path in store

showWhen

Conditional rendering based on state:

showWhen: (state) => state.user?.isAuthenticated === true

Common patterns:

// Show when logged in
showWhen: (state) => !!state.user?.name

// Show in specific stage
showWhen: (state) => state.stage?.current === 'review'

// Show when has data
showWhen: (state) => state.projects?.list?.length > 0

// Always show (default)
// Omit showWhen entirely

Complete Example

import type { EAIConfig } from '../types';

export const exampleConfig: EAIConfig = {
tenantId: 'example',
displayName: 'Example Application',

store: {
user: {
initialState: {
name: null,
email: null,
role: 'guest',
},
persist: true,
},
workflow: {
initialState: {
currentStep: 'start',
completedSteps: [],
data: {},
},
persist: true,
},
ui: {
initialState: {
sidebarOpen: true,
theme: 'light',
},
persist: false,
},
},

layout: {
header: [
{
component: 'Header',
priority: 1,
props: {
logo: '/logo.svg',
showUserMenu: true,
},
storeBindings: [
{ prop: 'userName', storePath: 'user.name' },
{ prop: 'userRole', storePath: 'user.role' },
],
},
],

leftPane: [
{
component: 'Sidebar',
priority: 1,
storeBindings: [
{ prop: 'isOpen', storePath: 'ui.sidebarOpen' },
],
},
{
component: 'StepProgress',
priority: 2,
storeBindings: [
{ prop: 'currentStep', storePath: 'workflow.currentStep' },
{ prop: 'completed', storePath: 'workflow.completedSteps' },
],
},
],

middlePane: [
{
component: 'WelcomeCard',
priority: 1,
props: {
title: 'Welcome!',
message: 'Get started by signing in.',
},
showWhen: (state) => !state.user?.name,
},
{
component: 'Dashboard',
priority: 2,
showWhen: (state) => !!state.user?.name,
},
],

rightPane: [
{
component: 'HelpPanel',
priority: 1,
props: {
articles: ['/help/getting-started', '/help/faq'],
},
},
],
},
};

Registering Your Config

Add your config to src/eai.config/index.ts:

import { templateConfig } from './tenants/template.config';
import { exampleConfig } from './tenants/example.config';

const configs: Record<string, EAIConfig> = {
template: templateConfig,
example: exampleConfig, // Add your config
};

export function getTenantConfig(tenantId: string): EAIConfig {
return configs[tenantId] || configs.template;
}

Testing Your Config

Access your tenant via query parameter:

http://localhost:3000?tenant=example

Or set as default in .env.local:

TENANT_DEFAULT_ID=example