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

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

  1. ✅ Estado agnóstico implementado
  2. ✅ Adapter Svelte implementado
  3. ✅ Componente de ejemplo creado
  4. ⏳ Implementar renderizado de imágenes
  5. ⏳ Añadir precio dinámico
  6. ⏳ Implementar más componentes (AttributePanel, ValidationPanel, etc.)
  7. ⏳ Testing de stores
  8. ⏳ 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

Powered by TurnKey Linux.