You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.9 KiB
6.9 KiB
Arquitectura Reactiva - Documentación
🏗️ Estructura Híbrida
La arquitectura separa estado agnóstico del framework de los adapters específicos:
src/
├── state/ # ← Estado puro (sin framework)
│ ├── SelectionState.ts
│ ├── ValidationState.ts
│ └── ConfigurationState.ts
│
└── adapters/ # ← Adapters por framework
└── svelte/
├── stores/ # Wrappers Svelte
└── components/ # Componentes UI
📦 Capa 1: Estado Agnóstico (/state)
SelectionState.ts
Gestiona qué opciones están seleccionadas.
Responsabilidades:
- Almacenar selecciones:
Record<AttrID, OptionID> - Notificar cambios via listeners
- Historial de cambios (undo/redo)
- Persistencia (toJSON/fromJSON)
API:
const selection = new SelectionState();
// Establecer valor
selection.set('at:suelo', 'op:parquet');
// Obtener valor
selection.get('at:suelo'); // → 'op:parquet'
// Limpiar
selection.clear('at:suelo');
// Suscribirse a cambios
const unsubscribe = selection.subscribe((event) => {
console.log(`${event.attrId} cambió a ${event.newValue}`);
});
// Deshacer
selection.undo();
ValidationState.ts
Gestiona validaciones y violaciones usando el RuleEngine.
Responsabilidades:
- Validar selecciones contra reglas
- Detectar violaciones (errores/warnings)
- Verificar valores permitidos/prohibidos
- Determinar atributos requeridos
API:
const validation = new ValidationState();
// Configurar reglas
validation.setRules(catalog.rules);
// Validar estado
const result = validation.validate(selectionState);
console.log(result.isValid); // → boolean
console.log(result.violations); // → Violation[]
// Helpers
validation.isValueAllowed('at:suelo', 'op:marmol', state);
validation.getAllowedValues('at:suelo', state);
validation.isRequired('at:material', state);
ConfigurationState.ts
Orquestador principal que coordina todo.
Responsabilidades:
- Gestionar catálogo y objeto
- Coordinar SelectionState + ValidationState
- Navegación (sección/vista actual)
- Auto-validación en cambios
- Persistencia completa
API:
const config = new ConfigurationState({
catalog: CATALOGO_VIVIENDAS,
objectId: 'ob:apartamento',
autoValidate: true
});
// Selección
config.selectOption('at:suelo', 'op:parquet');
config.getSelection('at:suelo');
// Navegación
config.setCurrentSection('sc:salon');
config.setCurrentView('vw:front');
// Validación
config.validate();
config.isValid();
config.getViolationsForAttribute('at:suelo');
// Helpers
config.getAllowedValues('at:suelo');
config.isRequired('at:material');
// Persistencia
const saved = config.toJSON();
config.fromJSON(saved);
// Utils
config.reset();
config.undo();
🔌 Capa 2: Adapters Svelte (/adapters/svelte)
stores/configuration.ts
Wrapper que convierte ConfigurationState en Svelte store.
Características:
- ✅ Reactivo automático (subscribe)
- ✅ API idéntica a ConfigurationState
- ✅ Derived stores para valores específicos
- ✅ Type-safe
Uso:
import { createConfigurationStore } from '@/adapters/svelte/stores';
const config = createConfigurationStore({
catalog: CATALOGO_VIVIENDAS,
objectId: 'ob:apartamento'
});
// En componentes Svelte
$: selection = $config.selection;
$: isValid = $config.isValid;
$: currentSection = $config.currentSection;
// Acciones
config.selectOption('at:suelo', 'op:parquet');
config.setCurrentSection('sc:salon');
Derived stores:
const currentSection = deriveCurrentSection(config);
const validation = deriveValidation(config);
const isValid = deriveIsValid(config);
🎨 Capa 3: Componentes UI (/adapters/svelte/components)
Configurator.svelte
Componente principal de ejemplo.
Features:
- ✅ Navegación de secciones
- ✅ Selector de vistas
- ✅ Panel de atributos
- ✅ Preview visual
- ✅ Validación en tiempo real
- ✅ Undo/Reset
Uso:
<script>
import Configurator from '@/adapters/svelte/components/Configurator.svelte';
import { CATALOGO_VIVIENDAS } from './fixtures';
</script>
<Configurator
catalog={CATALOGO_VIVIENDAS}
objectId="ob:apartamento"
/>
🔄 Flujo de Datos
User Action (click)
↓
Component Handler
↓
Store Action (config.selectOption)
↓
ConfigurationState
↓
SelectionState.set()
↓
Notifica listeners
↓
ValidationState.validate() (si autoValidate)
↓
Notifica cambio
↓
Svelte Store actualiza
↓
UI re-renderiza (reactive $config)
✅ Ventajas de esta arquitectura
1. Separación de concerns
- Estado = Lógica de negocio (testeable sin UI)
- Adapter = Integración con framework
- Components = Solo presentación
2. Framework agnostic
El 90% del código está en /state y no depende de Svelte.
Añadir React es fácil:
/adapters/react/
└── hooks/
└── useConfiguration.ts ← Wrapper con useState/useEffect
3. Testing simple
// Test estado SIN montar componentes
const config = new ConfigurationState({...});
config.selectOption('at:suelo', 'op:parquet');
expect(config.getSelection('at:suelo')).toBe('op:parquet');
4. Type-safety completo
Todo tipado con TypeScript. El editor te ayuda en cada paso.
5. Reactivo por defecto
Cambias el estado → UI se actualiza automáticamente.
📝 Ejemplo completo
<script lang="ts">
import { createConfigurationStore } from '@/adapters/svelte/stores';
const config = createConfigurationStore({
catalog: MY_CATALOG,
objectId: 'ob:producto'
});
// Reactivo automático
$: selection = $config.selection;
$: isValid = $config.isValid;
$: violations = $config.validation?.violations || [];
</script>
<!-- UI reactiva -->
<div>
<h1>{$config.object.name.es}</h1>
<select on:change={(e) => config.selectOption('at:color', e.target.value)}>
<option value="">Seleccionar color</option>
<option value="op:rojo">Rojo</option>
<option value="op:azul">Azul</option>
</select>
{#if !isValid}
<div class="errors">
{#each violations as v}
<p>{v.rule.message.es}</p>
{/each}
</div>
{/if}
<button disabled={!isValid}>
Confirmar
</button>
</div>
🚀 Próximos pasos
- ✅ Estado agnóstico implementado
- ✅ Adapter Svelte implementado
- ✅ Componente de ejemplo creado
- ⏳ Implementar renderizado de imágenes
- ⏳ Añadir precio dinámico
- ⏳ Implementar más componentes (AttributePanel, ValidationPanel, etc.)
- ⏳ Testing de stores
- ⏳ Documentación de componentes
📚 Archivos clave
/state/ConfigurationState.ts- Orquestador principal/adapters/svelte/stores/configuration.ts- Svelte store/adapters/svelte/components/Configurator.svelte- Componente ejemplo/docs/ARCHITECTURE.md- Este archivo