57.1 Architecture Widget Data Binding
Documentation for Sessions
57.1 Architecture: Widget-Module Data Binding System
Date: January 20, 2026 Type: Architecture Decision Confidence: 92% (Certain)
Context
The page-builder creates visual-only widgets, but these widgets need to connect to production module CRUD operations. The question was: how do we add data functionality without embedding business logic in visual widgets?
Decision
Create a declarative data binding type system with a runtime resolver service that connects visual widgets to module CRUD operations.
Options Considered
- Embed CRUD logic directly in widgets - Violates visual-only principle
- Create widget-module binding types + resolver service ✅ CHOSEN - Clean separation
- Use props drilling from parent containers - Too coupled, poor DX
Implementation
Type System
interface WidgetModuleBinding {
id: string;
widgetId: string;
moduleRef: ModuleRef; // { moduleId, collection, version? }
action: ModuleAction; // list, get, create, update, delete, etc.
inputMappings: BindingInputMapping[]; // widget property → module parameter
outputMappings: BindingOutputMapping[]; // module response → widget property
refreshPolicy: RefreshPolicy; // on-mount, interval, on-change, manual
errorHandling?: ErrorHandlingConfig;
caching?: CachingConfig;
enabled: boolean;
}
interface WidgetEventBinding {
id: string;
widgetId: string;
eventType: WidgetEventType; // click, change, submit, etc.
action: EventAction; // module-action, navigate, emit-event
confirmation?: ConfirmationConfig;
enabled: boolean;
}
interface WidgetDataConfig {
moduleBindings: WidgetModuleBinding[];
eventBindings: WidgetEventBinding[];
staticData?: Record<string, unknown>;
loadingState?: LoadingStateConfig;
emptyState?: EmptyStateConfig;
}
Runtime Resolver (WidgetDataBindingService)
- Initializes bindings when widget mounts
- Resolves JSONPath-like input/output mappings
- Handles refresh policies (ON_MOUNT, ON_INTERVAL, ON_CHANGE, MANUAL)
- Executes event bindings on widget interactions
- Manages caching and error handling
Properties Panel Data Tab
Added new "Data" tab in Properties Panel with:
- Module bindings list (add/remove/edit)
- Event bindings list (add/remove)
- Test button to verify bindings
- Visual badge showing binding count
Example Usage
// Widget configuration
const tableWidget = {
id: 'customers-table',
type: 'table',
config: {
dataConfig: {
moduleBindings: [{
moduleRef: { moduleId: '@modules/customers-management', collection: 'customers' },
action: 'list',
inputMappings: [
{ source: '$.widget.page', target: 'page', defaultValue: 1 },
{ source: '$.widget.pageSize', target: 'pageSize', defaultValue: 10 }
],
outputMappings: [
{ source: '$.data', target: '$.widget.rows' },
{ source: '$.total', target: '$.widget.totalCount' }
],
refreshPolicy: { triggers: ['on-mount', 'on-change'], debounceMs: 300 },
enabled: true
}],
eventBindings: [{
eventType: 'click',
action: { type: 'module-action', moduleAction: { action: 'delete', ... } },
confirmation: { title: 'Delete?', message: 'Are you sure?', destructive: true }
}]
}
}
};
Alignment with Session 56 Decisions
Session 56 decided:
- editor2 UI is superior and should remain unchanged
- Integration should enhance backend, not replace frontend
This aligns because:
- Page-builder widgets remain visual-only (superior UI unchanged)
- Data operations are configured declaratively, not coded into widgets
- WidgetDataBindingService routes to existing backend module APIs
- When PhaseExecutor is integrated, generated widgets can include data binding configs
Files
libs/libs-foundational/core-models/src/lib/types/widget-data-binding.types.ts(NEW)libs/libs-structural/page-builder/src/lib/services/widget-data-binding.service.ts(NEW)libs/libs-structural/page-builder/src/lib/components/properties-panel/*(MODIFIED)
Consequences
Positive:
- Clean separation of visual and data concerns
- Widgets remain reusable and testable
- Configuration is declarative and serializable
- Easy to generate from AI (JSON config)
Neutral:
- Adds complexity to widget configuration
- Requires understanding of JSONPath-like syntax
Negative:
- Runtime resolution has small performance overhead
- Advanced transformations may need custom functions