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
| Property | Type | Required | Description |
|---|---|---|---|
initialState | object | Yes | Default values for this slice |
persist | boolean | Yes | Save 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
| Property | Type | Description |
|---|---|---|
prop | string | Prop name on the component |
storePath | string | Dot-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
Related Documentation
- Environment Variables - Runtime configuration
- Examples - Configuration templates
- Data Flow - State management