ADR-001: Config-Driven UI Architecture
Status
Accepted
Context
We need to build a multi-tenant vertical application platform where:
- Different customers (tenants) need customized UI layouts and branding
- Business users should be able to modify UI without code deployments
- Development teams need rapid prototyping capabilities
- The system must be type-safe and maintainable
Traditional approaches include:
- Hardcoded layouts: Simple but requires code changes for customization
- CMS-driven: Flexible but lacks type safety and developer experience
- Feature flags: Good for toggles but not for layout composition
Decision
We will implement a config-driven UI architecture where:
- TypeScript configuration files define tenant layouts
- Components are registered in a
ComponentRegistryby name - SlotRenderer dynamically renders components based on config
- Store bindings automatically inject state as props
- Visibility conditions control component rendering
// Example: Config defines what renders, not how
{
component: 'PropertyCard',
priority: 1,
props: { showMap: true },
storeBindings: [
{ prop: 'address', storePath: 'property.selected' }
],
showWhen: (state) => state.stage.current === 'review'
}
Consequences
Positive
- Type safety: Full TypeScript support in configs
- Rapid iteration: Change config, see results immediately
- Multi-tenancy: Each tenant gets isolated configuration
- Testability: Configs can be unit tested
- Developer experience: IDE autocomplete and validation
Negative
- Learning curve: Developers must understand the config system
- Debugging complexity: Indirection between config and rendered UI
- Component registry overhead: All components must be registered
Neutral
- Component constraints: Components must be designed for config-driven use
- State coupling: Store bindings create implicit dependencies
Related ADRs
- ADR-003: State Management - Zustand store patterns
- ADR-005: Styling - Component styling approach