Requirements
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Widget System - Requirements Specification
Especificación de requisitos para
@gograb-space/widget-system
📋 Visión General
Widget System proporciona infraestructura UI para renderizar widgets embeddables genéricos en dashboards y otros componentes. Se integra completamente con la arquitectura existente de módulos y configuración.
🎯 Objetivos del Sistema
Objetivos Primarios
- Grid Layout Responsive: Renderizar widgets en grid configurable con breakpoints
- Error Isolation: Aislar errores de widgets para no romper el dashboard
- Consistent UX: Proporcionar loading/error states uniformes
- Easy Integration: Mínimos cambios en código existente
Objetivos Secundarios (Post-MVP)
- Drag-and-drop para reordenar widgets
- Resize handles para ajustar tamaño
- Widget maximize/fullscreen mode
- Lazy loading avanzado
- Widget templates/presets
📊 Stakeholders
- Desarrolladores de Módulos: Crean widgets embeddables
- Administradores de Tenant: Configuran widgets habilitados
- Usuarios Finales: Consumen widgets en dashboard
🔧 Requisitos Funcionales
RF-01: Grid Layout Rendering
Prioridad: MUST HAVE (MVP)
Descripción: Sistema debe renderizar widgets en grid layout usando ResolvedWidgetConfig.position
Criterios de Aceptación:
- ✅ Renderiza widgets en grid CSS usando position (x, y, width, height)
- ✅ Soporta número configurable de columnas (e.g., 12 columnas)
- ✅ Gap entre widgets configurable en pixeles
- ✅ Row height configurable (px o 'auto')
- ✅ Widgets disabled no se renderizan
Entrada:
widgets: ResolvedWidgetConfig[] = [
{
id: 'widget-1',
position: { x: 0, y: 0, width: 4, height: 2 },
enabled: true,
componentType: UserStatsWidget
}
]
Salida: Widget renderizado en grid column 1-4, row 1-2
RF-02: Responsive Breakpoints
Prioridad: MUST HAVE (MVP)
Descripción: Grid debe adaptar columnas y gap según breakpoint (mobile/tablet/desktop)
Criterios de Aceptación:
- ✅ Mobile (< 768px): 1-2 columnas típicamente
- ✅ Tablet (768-1024px): 6-8 columnas típicamente
- ✅ Desktop (> 1024px): 12 columnas típicamente
- ✅ Usa Angular CDK BreakpointObserver
- ✅ Transiciones suaves entre breakpoints
Configuración:
breakpoints: {
mobile: { columns: 1, gap: 8, rowHeight: 'auto' },
tablet: { columns: 6, gap: 12, rowHeight: 100 },
desktop: { columns: 12, gap: 16, rowHeight: 100 }
}
RF-03: Error Boundary per Widget
Prioridad: MUST HAVE (MVP)
Descripción: Errores en un widget no deben romper otros widgets o el dashboard
Criterios de Aceptación:
- ✅ WidgetContainerComponent captura errores de rendering
- ✅ Muestra UI de error en lugar del widget fallido
- ✅ Otros widgets siguen funcionando
- ✅ Error se logea via LoggerService
- ✅ Opcional: botón "Retry" para reintentar carga
Error States:
- Component load error
- Runtime error en widget
- Async data fetch error
RF-04: Loading States
Prioridad: MUST HAVE (MVP)
Descripción: Widgets deben mostrar skeleton/placeholder durante carga
Criterios de Aceptación:
- ✅ WidgetPlaceholderComponent con skeleton UI
- ✅ Muestra durante carga inicial de widget
- ✅ Transición suave a widget cargado
- ✅ Accesible (aria-busy, aria-label)
RF-05: Dynamic Component Loading
Prioridad: MUST HAVE (MVP)
Descripción: Cargar widgets dinámicamente desde componentType en config
Criterios de Aceptación:
- ✅ Usa NgComponentOutlet para render dinámico
- ✅ Valida que componentType sea válido Type
- ✅ Pasa inputs al widget via ngComponentOutletInputs
- ✅ Widget no encontrado muestra error placeholder
Integración:
- Usa
ComponentRegistryService.getComponent(widgetTypeId) - componentType viene de
ModuleEmbeddableComponent.componentType
RF-06: Base Widget Component (Optional)
Prioridad: SHOULD HAVE (MVP)
Descripción: Clase base opcional con helpers para widget development
Criterios de Aceptación:
- ✅ Abstract class que widgets PUEDEN extender (no obligatorio)
- ✅ Helpers para emitir eventos via EventBusService
- ✅ Lifecycle hooks: onWidgetInit, onWidgetDestroy
- ✅ Logger child pre-configurado
- ✅ DestroyRef integration
Nota: Widgets existentes (como UserListWidgetComponent) NO necesitan cambiar
RF-07: Widget Communication via Events
Prioridad: SHOULD HAVE (MVP)
Descripción: Widgets pueden comunicarse via EventBusService existente
Criterios de Aceptación:
- ✅ Helper method:
emitWidgetEvent(eventType, data) - ✅ Helper method:
subscribeToWidgetEvent(eventType, handler) - ✅ Eventos con namespace:
widget.{eventType} - ✅ Metadata incluye widgetId en eventos
Ejemplo:
// Widget A emite
this.emitWidgetEvent('user.selected', { userId: '123' });
// Widget B escucha
this.subscribeToWidgetEvent('user.selected', (data) => {
this.filterByUser(data.userId);
});
RF-08: Widget Input Passing
Prioridad: MUST HAVE (MVP)
Descripción: Pasar inputs configurados a widgets dinámicamente
Criterios de Aceptación:
- ✅ Inputs vienen de widget config (almacenados en tenant config)
- ✅ Se pasan via ngComponentOutletInputs
- ✅ Widget recibe inputs via
input<T>() - ✅ Inputs validados según
ModuleParameterMetadata
Flow:
- Admin configura widget inputs en tenant customization
- Inputs se guardan en AppConfig
- WidgetContainer pasa inputs a widget component
- Widget recibe via
input<T>()signals
🚫 Non-Functional Requirements
NFR-01: Performance
Prioridad: MUST HAVE
Criterios:
- ✅ OnPush change detection en todos los components
- ✅ Signals para reactive state
- ✅ Lazy loading de widget components (post-MVP)
- ✅ Virtual scrolling para grids grandes (post-MVP)
- ✅ < 100ms para renderizar 10 widgets
NFR-02: Accessibility
Prioridad: MUST HAVE
Criterios:
- ✅ ARIA labels en widgets
- ✅ Keyboard navigation support
- ✅ Screen reader friendly error/loading states
- ✅ Focus management en grid
- ✅ WCAG 2.1 AA compliance
NFR-03: Browser Compatibility
Prioridad: MUST HAVE
Criterios:
- ✅ Chrome 120+
- ✅ Firefox 120+
- ✅ Safari 17+
- ✅ Edge 120+
- ✅ CSS Grid support required
NFR-04: Maintainability
Prioridad: MUST HAVE
Criterios:
- ✅ TypeScript strict mode
- ✅ Comprehensive JSDoc documentation
- ✅ Unit tests > 90% coverage
- ✅ Integration tests para grid rendering
- ✅ Storybook examples (nice to have)
NFR-05: Scalability
Prioridad: SHOULD HAVE
Criterios:
- ✅ Soporta hasta 50 widgets en dashboard
- ✅ Grid performance con 100+ widgets (post-MVP)
- ✅ Memory efficient widget cleanup
- ✅ No memory leaks en widget lifecycle
🔗 Integration Requirements
INT-01: Module Base Integration
Descripción: Integración con @gograb-space/module-base
Requisitos:
- ✅ Usa
ModuleEmbeddableComponentpara widget contracts - ✅ Usa
ComponentRegistryServicepara widget registry - ✅ NO duplica registry logic
- ✅ Respeta
ModuleParameterMetadatapara inputs
INT-02: Module Config Integration
Descripción: Integración con @gograb-space/module-config
Requisitos:
- ✅ Usa
ResolvedWidgetConfigpara widget config (NO crear nuevo tipo) - ✅ Usa
WidgetRegistryEntrypara metadata (NO duplicar) - ✅ Consume
AppConfigService.dashboardConfig()signal - ✅ NO gestiona config storage (responsabilidad de module-config)
INT-03: Event System Integration
Descripción: Integración con @gograb-space/event-system
Requisitos:
- ✅ Usa
EventBusServicepara widget communication - ✅ NO crea event bus alternativo
- ✅ Eventos con namespace
widget.* - ✅ Metadata consistente con eventos de sistema
INT-04: UI Framework Integration
Descripción: Integración con @gograb-space/ui-framework
Requisitos:
- ✅ Usa design tokens de ui-framework
- ✅ Styling consistente con sistema de diseño
- ✅ Puede reusar componentes base (buttons, cards, etc.)
- ✅ NO redefine tokens o estilos base
INT-05: Log System Integration
Descripción: Integración con @gograb-space/log-system
Requisitos:
- ✅ Usa
LoggerServicepara logging - ✅ Log levels apropiados (debug, info, error)
- ✅ Context-aware logging (widgetId, componentType)
- ✅ Performance logging con @performance decorator
✅ Success Criteria
MVP Success
El sistema será considerado exitoso si:
- ✅ Dashboard renderiza widgets en grid layout
- ✅ Widgets se posicionan según
ResolvedWidgetConfig.position - ✅ Grid responsive funciona en mobile/tablet/desktop
- ✅ Error en widget no rompe dashboard
- ✅ Loading states se muestran correctamente
- ✅ Widget communication via events funciona
- ✅ Cero duplicación de tipos/servicios existentes
- ✅ Cambios mínimos en código existente (< 50 LOC en dashboard)
- ✅ Tests > 90% coverage
- ✅ Performance < 100ms para 10 widgets
Post-MVP Success
- ⏳ Drag-and-drop funcional
- ⏳ Widget resize implementado
- ⏳ Lazy loading optimizado
- ⏳ Storybook con ejemplos
🚫 Out of Scope (Explicitly NOT Included)
NOT Included in Widget System
- ❌ Widget Configuration Storage - Responsabilidad de
module-config - ❌ Widget Registry Management - Responsabilidad de
ComponentRegistryService - ❌ Module Manifest Definitions - Responsabilidad de
module-base - ❌ Permission Checking - Responsabilidad de
securitysystem - ❌ Tenant Context Management - Responsabilidad de
module-config - ❌ Widget CRUD API - Responsabilidad de backend/mock-api
- ❌ Widget Analytics - Futuro feature, no MVP
- ❌ Widget A/B Testing - Futuro feature, no MVP
📋 Assumptions & Constraints
Assumptions
- Widgets se definen en module manifests via
embeddableComponents - Widget config se gestiona via
AppConfigService - Todos los widgets son standalone components
- Widgets usan Angular 20+ features (signals, input/output)
- Browser soporta CSS Grid
Constraints
- No Breaking Changes: Código existente debe seguir funcionando
- No Duplication: No duplicar tipos/servicios existentes
- Browser Only: Código 100% compatible con browser (no Node.js)
- No setTimeout: Usar RxJS timers/operators
- Strict TypeScript: No usar
any, usarSafeAnysi absolutamente necesario
Technical Constraints
- Angular 20.x
- TypeScript 5.8+
- OnPush change detection obligatorio
- Signals over Observables donde sea posible
- Standalone components only
📊 Acceptance Testing Scenarios
Scenario 1: Basic Widget Rendering
Given: Dashboard con 3 widgets configurados When: Usuario navega a dashboard Then:
- 3 widgets se renderizan en grid
- Posicionamiento correcto según config
- No errores en consola
Scenario 2: Widget Error Isolation
Given: Dashboard con widget que lanza error When: Widget falla durante render Then:
- Error UI se muestra en lugar de widget
- Otros widgets siguen funcionando
- Error se logea
- Dashboard no crashea
Scenario 3: Responsive Layout
Given: Dashboard en desktop con 12 columnas When: Usuario reduce ventana a mobile Then:
- Grid cambia a 1-2 columnas
- Widgets se reorganizan
- No horizontal scroll
- Layout usable
Scenario 4: Widget Communication
Given: Dashboard con 2 widgets comunicándose
When: Widget A emite evento user.selected
Then:
- Widget B recibe evento
- Widget B actualiza su estado
- No errores
Scenario 5: Loading State
Given: Widget con data fetch asíncrono When: Widget se carga Then:
- Skeleton placeholder se muestra
- Transición suave a loaded state
- ARIA busy state correcto
📝 Notes
- Widget system es SOLO infraestructura UI
- Integración completa con arquitectura existente
- Cero duplicación de funcionalidad
- MVP enfocado en funcionalidad core
- Extensibilidad para features futuras