Guía técnica

Diseño de Workflows en Pimcore para Empresas: La Arquitectura Detrás de 20 Editores

Cómo diseñar workflows en Pimcore para equipos enterprise. Separación de estado en tres capas, propiedad de campos, control de eventos, gestión de versiones y seguridad en importaciones ERP.

25 de marzo de 202624 min de lecturaEquipo de Ingeniería Oronts

El problema del que nadie habla

Toda instalación de Pimcore empieza igual. Unos pocos productos, un equipo de contenido de tres personas, todo gestionado desde la interfaz de administración. Publicar significa hacer clic en un botón. La vida es sencilla.

Luego el sistema crece. Veinte editores en múltiples departamentos. Un ERP enviando miles de actualizaciones de productos al día. Workers en segundo plano generando thumbnails, PDFs y actualizaciones de índice de búsqueda. Múltiples canales de salida extrayendo productos para diferentes audiencias. Un motor de búsqueda sincronizando cada cambio.

Y de repente todo se rompe de formas que nadie anticipó.

Lo vimos de primera mano en un proyecto PIM enterprise para un fabricante B2B en la región DACH. El sistema tenía múltiples event subscribers, varios async workers, una integración ERP enviando importaciones diarias, y múltiples canales de salida sirviendo diferentes necesidades de negocio. El equipo había crecido a más de 20 editores, y la arquitectura original se desmoronaba bajo su propio peso.

El problema de fondo: el save() de Pimcore está diseñado para editores humanos, no para sistemas enterprise con múltiples procesos automatizados compitiendo por los mismos datos.

Este artículo cubre cómo rediseñamos la arquitectura de workflows desde cero. Los patrones aquí aplican a cualquier instalación de Pimcore que supere lo básico. Para más contexto sobre cómo abordamos la arquitectura de sistemas y las implementaciones PIM, esas guías ofrecen información de fondo útil.

Por qué el modelo por defecto de Pimcore falla a escala

La persistencia de objetos en Pimcore funciona a través de un único punto de entrada:

$product->save();

Esto dispara una cadena de comportamiento implícita:

save()
  -> PRE_UPDATE event fires (all subscribers, synchronous)
  -> update() persists FULL object state to published tables
  -> saveVersion() creates a version snapshot
  -> POST_UPDATE event fires (all subscribers, synchronous)
  -> Each subscriber may dispatch async messages
  -> Each message handler may call save() again
  -> Loop until supervisor or error breaks it

Cada save() persiste el objeto completo. No el campo que cambió. El objeto completo. Este diseño funciona bien para editores humanos haciendo cambios ocasionales. Falla cuando tienes:

ProblemaQué pasaImpacto real
Sin control de concurrenciaDos workers cargan el mismo producto, cada uno modifica un campo, ambos guardan. El segundo save sobrescribe el cambio del primer worker.Assets generados se revierten silenciosamente después de que otro worker se ejecuta
Tormentas de eventosUn save dispara múltiples subscribers, cada uno despachando mensajes, cada uno causando más savesUna importación de producto genera miles de saves innecesarios
Explosión de versionesCada save de worker crea una versión que nadie necesitaMiles de versiones por producto, almacenamiento consumido, historial inútil
Sin propiedad de camposLas ediciones de contenido y las escrituras del sistema pasan por el mismo path de save()La importación ERP sobrescribe campos curados manualmente
Sin control de efectos secundariosVersion::disable() es un flag estático global, no tiene scope ni es componibleDeshabilitar versiones en un worker afecta a todos los workers en el mismo proceso

Antes de corregir estos problemas, una importación de productos tardaba horas y generaba colas de mensajes masivas. Después del rediseño de la arquitectura, la misma importación se procesa en minutos con efectos secundarios controlados y predecibles.

El modelo de estado en tres capas

La decisión arquitectónica central: separar tres responsabilidades que Pimcore fusiona en una sola.

┌─────────────────────────────────────────────────────────┐
│                                                         │
│  Layer 1: OPERATIONAL WORKFLOW (human process)          │
│  ┌─────┐  ┌───────────┐  ┌──────────┐  ┌──────────┐  │
│  │ NEW │─▶│IN_PROGRESS│─▶│IN_REVIEW │─▶│ APPROVED │  │
│  └─────┘  └───────────┘  └──────────┘  └────┬─────┘  │
│                  ▲            │               │        │
│                  └────────────┘               │        │
│                (feedback loop)                ▼        │
│                                        ┌───────────┐  │
│                                        │ PUBLISHED  │  │
│                                        └─────┬─────┘  │
│                                                        │
├────────────────────────────────────────────────────────┤
│                                                        │
│  Layer 2: PUBLICATION STATE (Pimcore built-in)         │
│  published = true  → product is live on website        │
│  published = false → not visible on any channel        │
│  Draft versions → edits saved without publishing       │
│                                                        │
├────────────────────────────────────────────────────────┤
│                                                        │
│  Layer 3: CHANNEL ELIGIBILITY (computed, NOT stored)   │
│  isChannelReady = published=true                       │
│                   AND workflow=PUBLISHED                │
│                   AND ChannelValidator.passes()         │
│                   AND not archived                      │
│                                                        │
└─────────────────────────────────────────────────────────┘

Capa 1: Workflow operacional

Un solo workflow en la clase Product usando la integración Symfony Workflow de Pimcore. Tipo: state_machine (un estado a la vez).

Este workflow responde: ¿Quién es dueño del producto ahora? ¿En qué fase está? ¿Quién actúa a continuación?

pimcore:
    workflows:
        product_lifecycle:
            enabled: true
            label: 'Product Lifecycle'
            type: 'state_machine'
            supports:
                - 'Pimcore\Model\DataObject\Product'
            initial_markings:
                - 'new'
            marking_store:
                type: state_table

            places:
                new:
                    label: 'New'
                    color: '#90CAF9'
                    permissions:
                        - save: true
                          publish: false
                in_progress:
                    label: 'In Progress'
                    color: '#FFE082'
                    permissions:
                        - save: true
                          publish: false
                in_review:
                    label: 'In Review'
                    color: '#FFAB91'
                approved:
                    label: 'Approved'
                    color: '#A5D6A7'
                published:
                    label: 'Published'
                    color: '#4CAF50'
                archived:
                    label: 'Archived'
                    color: '#BDBDBD'

La distinción clave que la mayoría de equipos no ven: no hay estado REJECTED. El rechazo es una transición de vuelta a IN_PROGRESS con un comentario obligatorio almacenado en Notes & Events. Esto mantiene el workflow limpio y el proceso de revisión como un ciclo, no un callejón sin salida.

Capa 2: Estado de publicación

Esto NO es un workflow. Usa los mecanismos existentes de Pimcore:

  • published = true controla la visibilidad en el sitio web
  • El versionado de Pimcore crea snapshots en cada guardado
  • Las versiones borrador permiten a los editores trabajar sin afectar el sitio en vivo
  • Publicar promueve una versión específica a ser la versión en vivo

Esto da un comportamiento similar a Git:

Concepto GitEquivalente Pimcore
Rama mainVersión publicada actualmente
Feature branchVersión borrador (guardada sin publicar)
Merge a mainAcción de publicar (promueve borrador a live)
Historial de commitsHistorial de versiones en la pestaña Versiones

Cuando un editor guarda sin publicar, solo se crea una versión borrador. Las tablas publicadas no cambian. El sitio web en vivo nunca ve trabajo a medio terminar.

Capa 3: Elegibilidad por canal (computada, no almacenada)

Esta es la decisión que eliminó toda una clase de bugs. La elegibilidad por canal (si un producto es apto para un canal de salida específico como un feed de marketplace, un pipeline de exportación, o una API de partner) NO es un campo almacenado en el producto. Se computa a partir de la verdad actual.

class ProductOutputEligibility
{
    public function isChannelReady(Product $product, string $channel): bool
    {
        return $product->isPublished()
            && $this->workflowState->getCurrentState($product) === 'published'
            && !$this->workflowState->isArchived($product)
            && $this->channelValidator->isValid($product, $channel);
    }

    public function getBlockingErrors(Product $product, string $channel): array
    {
        $errors = [];
        if (!$product->isPublished()) {
            $errors[] = 'Product must be published';
        }
        // ... check workflow state, archived
        return array_merge($errors, $this->channelValidator->getErrors($product, $channel));
    }
}

Por qué computar es mejor que un campo de estado almacenado:

Campo almacenadoResultado computado
Puede quedar obsoleto (dice READY pero la imagen requerida fue eliminada)Siempre refleja la verdad actual
Necesita reset manual después de cambiosNo necesita reset, se computa bajo demanda
Debe sincronizarse con el estado del workflowNo requiere sincronización
Crea verdad duplicadaFuente única de verdad: los datos reales
Requiere migración para nuevas reglasSolo actualiza la lógica del validador

El sistema anterior usaba hacks donde los productos tenían que despublicarse para prepararlos para ciertos canales. Esto rompía la visibilidad web cada vez. El enfoque computado elimina ese patrón por completo.

Para más sobre cómo pensamos los pipelines de ingeniería de datos y la salida específica por canal, esa página de servicios cubre nuestro enfoque más amplio.

Propiedad de campos: Quién puede escribir qué

La segunda decisión arquitectónica crítica: no todos los campos son iguales. Algunos pertenecen a editores, algunos a máquinas, algunos a ambos con reglas.

pimtx:
    field_ownership:
        Product:
            editor_owned:
                - name
                - description
                - shortDescription
                - images
            system_owned:
                - thumbnail
                - searchIndex
                - checksum
                - lastSyncTimestamp
            shared:
                - categories
                - price
                - availability
                - status
DominioPropietarioEjemplosRuta de mutación
Editor-ownedUsuarios adminnombre, descripción, imágenesSave nativo de Pimcore
System-ownedWorkers e integracionesthumbnails, índice de búsqueda, checksumsCapa de transacciones
SharedAmbos, con política de conflictoscategorías, precios, disponibilidadCapa de transacciones con estrategia de conflictos

La propiedad de campos determina:

  • Qué campos disparan detección de cambios para qué operaciones
  • Qué estrategias de resolución de conflictos aplican
  • Si la actualización parcial es segura para un campo dado
  • Qué se muestra en la vista de auditoría de negocio vs técnica

Sin propiedad de campos, una importación ERP puede sobrescribir contenido curado manualmente. Con ella, la importación solo toca los campos que le pertenecen, y los campos compartidos usan una estrategia de conflictos configurada (reintentar, omitir, fallar, o merge si es seguro).

Este patrón es central en cómo construimos PimTx, nuestra capa de transacciones y concurrencia open-source para Pimcore. El equipo de consultoría ha ayudado a múltiples clientes enterprise de Pimcore a implementar exactamente este patrón.

Control de event subscribers: Deteniendo la cascada

El patrón más peligroso en sistemas Pimcore enterprise es la cascada de saves. Un save dispara múltiples event subscribers. Cada uno despacha mensajes asíncronos. Cada message handler carga el producto, modifica un campo y guarda. Cada save dispara todos los subscribers de nuevo.

El EventSubscriberSupervisor es un singleton con scope de proceso que controla qué subscribers están activos:

// Deshabilitar todos los event subscribers de la app antes del save del worker
$this->eventSubscriberSupervisor->disableAll();

try {
    $product->setQrCode($generatedAsset);
    $product->save();
} finally {
    $this->eventSubscriberSupervisor->enableAll();
}

El orden de operaciones importa. Hacerlo mal crea exactamente el bucle que intentas prevenir:

// MAL: eventos re-habilitados ANTES del save
$this->eventSubscriberSupervisor->disableAll();
try {
    // hacer trabajo...
} finally {
    $this->eventSubscriberSupervisor->enableAll(); // re-habilitado aquí
}
$product->save(); // save dispara eventos, el bucle empieza

// CORRECTO: save ocurre DENTRO del scope deshabilitado
$this->eventSubscriberSupervisor->disableAll();
try {
    $product->setQrCode($generatedAsset);
    $product->save(); // save aquí, eventos suprimidos
} finally {
    $this->eventSubscriberSupervisor->enableAll();
}

Esto tiene scope de proceso. Solo deshabilita subscribers dentro del mismo proceso PHP. Otros pods de workers tienen sus propias instancias del supervisor. Pero como el save no despacha nuevos mensajes (los subscribers están deshabilitados), ningún mensaje nuevo llega a otros workers.

Gestión de versiones: Previniendo la explosión

En el sistema original, cada save de worker creaba una versión. Con 6 workers procesando cada cambio de producto, una sola edición humana generaba más de 6 versiones que nadie necesitaba. Con el tiempo, los productos acumulaban miles de versiones, consumiendo almacenamiento y haciendo el historial de versiones inútil para auditoría real.

La solución: un version guard con scope que suprime versiones innecesarias durante operaciones del sistema.

// PimTx scoped version guard (reference-counted)
$versionGuard = $this->versionGuardFactory->create();
$versionGuard->suppress();

try {
    // Múltiples operaciones del sistema, no se crean versiones
    $product->setThumbnail($thumbnailAsset);
    $product->save();

    $product->setChecksum($newChecksum);
    $product->save();
} finally {
    $versionGuard->restore();
}

A diferencia del Version::disable() global de Pimcore, este guard usa conteo de referencias y tiene scope. Las operaciones anidadas funcionan correctamente. Un guard que se restaura no re-habilita accidentalmente las versiones para una operación padre que aún las necesita suprimidas.

EnfoqueScopeAnidamientoSeguridad
Version::disable() (Pimcore)Estático globalRoto (cualquier enable() re-habilita para todos)Peligroso en workers concurrentes
Scoped Version Guard (PimTx)Por operación, con conteo de referenciasCorrecto (restaura solo cuando todos los guards se liberan)Seguro para workers concurrentes

El resultado: los saves de editores crean versiones (se preserva el trail de auditoría). Los saves de workers crean entradas de log de operación en su lugar (observabilidad completa sin inflación de versiones). Puedes ver exactamente qué hizo cada worker, cuándo y en qué campos, sin tener que desplazarte por 4,000 entradas de versión inútiles.

Seguridad en importaciones ERP

La parte más políticamente sensible de cualquier arquitectura PIM: qué pasa cuando el ERP envía datos.

En el sistema original, las importaciones ERP sobrescribían todo. Descripciones curadas manualmente, categorías configuradas con cuidado, estado editorial. Todo desaparecía después de una importación nocturna.

La solución arquitectónica combina propiedad de campos con reglas específicas de importación:

# ERP import field mapping
# Campos PROTEGIDOS (no están en el mapping, la importación no puede tocarlos):
#   - description (propiedad del editor)
#   - shortDescription (propiedad del editor)
#   - images (propiedad del editor)
#   - workflow state (controlado por proceso)

# Campos IMPORTADOS (propiedad de ERP):
#   - erpId (clave de resolución)
#   - sku
#   - dimensions
#   - weight
#   - ean

# Campos COMPARTIDOS (la importación actualiza, pero aplica detección de cambios):
#   - categories (estrategia de merge)
#   - price (sobrescritura con notificación)
#   - availability (sobrescritura con verificación de impacto)

Cuando una importación ERP cambia un campo crítico de negocio en un producto publicado, la detección de impacto de cambios lo marca automáticamente para revisión. La importación no necesita saber nada sobre workflows editoriales. El sistema de propiedad de campos se encarga.

Salvaguardas críticas:

  1. La elegibilidad por canal se recalcula automáticamente (computada, no almacenada)
  2. El estado del workflow nunca se resetea por importaciones
  3. Los campos propiedad del editor no están en el mapping de importación
  4. Los campos compartidos usan estrategias de conflictos con notificación
  5. El EventSubscriberSupervisor previene cascadas disparadas por importaciones

Qué pasa cuando se edita un producto en vivo

Este es el flujo más crítico de cara al usuario. Un editor necesita actualizar un producto en vivo sin romper el sitio web ni ningún canal de salida.

1. Product is in PUBLISHED state, published=true, live on website
2. Editor opens product, modifies description
3. Editor clicks "Save" (not "Publish")
4. Pimcore creates a DRAFT VERSION only
5. Published tables stay unchanged
6. Website continues serving the current published version
7. Change-impact detection runs:
   - If business-critical fields changed: relevant teams notified
   - If only internal/SEO fields changed: no notification
8. Editor continues working on the draft
9. When ready: submit for review (IN_REVIEW)
10. Reviewer approves: transition to APPROVED
11. Release manager publishes: draft promoted to live
12. Workflow returns to PUBLISHED
13. Channel eligibility recalculates automatically

El sitio web nunca ve trabajo a medio terminar. Ningún canal de salida se rompe por cambios en progreso. Todo tiene control de versiones, es auditable y reversible.

Este es exactamente el tipo de arquitectura de software a medida que construimos para clientes enterprise. Si necesitas ayuda planificando un rediseño de workflows, solicita un presupuesto o habla con nuestro equipo de consultoría.

Detección de impacto de cambios

No todos los cambios son iguales. Un editor corrigiendo un typo en el texto SEO no debería disparar una revisión de canal. Un editor reemplazando la imagen principal del producto sí.

El sistema de detección de cambios clasifica los cambios por impacto:

class ChangeImpactClassifier
{
    private const BUSINESS_CRITICAL_FIELDS = [
        'description',
        'shortDescription',
        'images',
        'technicalAttributes', // Classification Store
        'price',
        'availability',
        'categories',
    ];

    private const NON_IMPACTFUL_FIELDS = [
        'seoText',
        'searchKeywords',
        'internalTags',
        'lastSyncTimestamp',
    ];

    public function classify(Product $product, array $changedFields): ChangeImpact
    {
        $critical = array_intersect($changedFields, self::BUSINESS_CRITICAL_FIELDS);

        if (count($critical) > 0) {
            return ChangeImpact::BUSINESS_CRITICAL;
        }

        $nonImpactful = array_intersect($changedFields, self::NON_IMPACTFUL_FIELDS);
        if (count($nonImpactful) === count($changedFields)) {
            return ChangeImpact::NON_IMPACTFUL;
        }

        return ChangeImpact::STANDARD;
    }
}

Implementación: un subscriber PRE_UPDATE carga los datos de la versión anterior, compara campo por campo contra el estado actual, clasifica los cambios por impacto de negocio, y almacena el resumen de cambios como una Note en el objeto.

Reglas de validación para elegibilidad por canal

Como la elegibilidad por canal es computada, el validador define qué significa "listo" por canal:

class ChannelValidator
{
    public function isValid(Product $product, string $channel): bool
    {
        return count($this->getErrors($product, $channel)) === 0;
    }

    public function getErrors(Product $product, string $channel): array
    {
        $errors = [];

        // Requisitos comunes para todos los canales
        if (!$product->getMainImage()) {
            $errors[] = 'At least one product image required';
        }

        if (empty($product->getDescription())) {
            $errors[] = 'Description text required in at least one locale';
        }

        // Requisitos específicos del canal
        if ($channel === 'marketplace') {
            if (empty($product->getPrice())) {
                $errors[] = 'Price is required for marketplace export';
            }
            if (empty($product->getCategories())) {
                $errors[] = 'At least one category required for marketplace';
            }
        }

        return $errors;
    }
}

La UI muestra exactamente qué bloquea la elegibilidad por canal. Sin adivinanzas, sin "pregúntale al responsable del canal." El producto pasa la validación o el sistema te dice por qué no.

Para ver cómo manejamos patrones de validación similares en el diseño de workflows de IA y la gobernanza de IA, esas guías cubren los paralelismos.

La capa de transacciones (PimTx)

Todos estos patrones convergen en PimTx, la capa de transacciones y concurrencia que construimos como un bundle de Symfony. Cada escritura del sistema se convierte en una operación explícita:

// En lugar de un $product->save() directo
$result = $this->transactionManager->execute(
    OperationContext::for($product)
        ->name('qr_code_generation')
        ->systemField('qrCode')
        ->lock(LockType::OPERATION)
        ->version(VersionPolicy::SUPPRESS_PIMCORE_VERSION)
        ->events(EventPolicy::SUPPRESS)
        ->conflict(ConflictStrategy::RETRY)
        ->maxRetries(3)
        ->idempotencyKey("qr:{$product->getId()}:{$locale}")
        ->mutate(function (Product $p) use ($qrAsset) {
            $p->setQrCode($qrAsset);
        })
);

if ($result->wasSkipped()) {
    // Idempotente: la misma operación ya se ejecutó
    $this->logger->info('QR generation skipped', [
        'reason' => $result->skipReason,
        'product_id' => $product->getId(),
    ]);
}

Lo que esta declaración hace:

  • Adquiere un lock con scope de operación (previene generación concurrente de QR para el mismo producto)
  • Verifica idempotencia (la misma operación con la misma key no se ejecuta dos veces)
  • Suprime la creación de versiones (la operación se registra en la auditoría de PimTx, no en versiones de Pimcore)
  • Suprime event subscribers (previene saves en cascada)
  • Reintenta en caso de conflicto (si otro worker modificó el producto entre la carga y el guardado)
  • Retorna un resultado estructurado (éxito, omitido, conflicto resuelto, o fallido)

La regla de gobernanza: cualquier mutación no editorial que llegue a Pimcore a través de un save() no gestionado se considera fuera de política. El código del sistema debe pasar por la capa de transacciones. Sin esta regla, los equipos gradualmente evitan la capa y recrean los mismos incidentes.

Para más sobre cómo observamos y monitorizamos sistemas como este en producción, consulta nuestra guía de observabilidad de IA, que cubre patrones similares de logging estructurado y tracing.

Arquitectura de notificaciones

El workflow de Pimcore soporta notificaciones en las transiciones:

EventoQuién recibe la notificaciónCanal
Producto entra en IN_REVIEWRol de revisorNotificación Pimcore + email
Producto aprobadoPropietario del producto / editorNotificación Pimcore
Cambio crítico de negocio detectadoEquipos de canal relevantesEmail con resumen de cambios
Producto publicado editado (borrador creado)Editor responsableNotificación Pimcore
Producto publicadoRelease managerNotificación Pimcore
Importación cambia campos compartidosPropietario del campoEmail con diff

Las notificaciones llevan contexto: qué cambió, quién lo cambió, qué campos fueron afectados y el nivel de impacto de negocio. No simplemente "El producto 12345 fue actualizado."

Errores comunes

  1. Usar múltiples workflows. Un workflow por clase de producto. Múltiples workflows crean conflictos de estado y confusión de permisos. La elegibilidad por canal se maneja con computación, no con workflows separados.

  2. Almacenar el estado de canal como campo. Cualquier campo de estado almacenado se vuelve obsoleto en el momento en que alguien elimina una imagen o cambia un atributo requerido. Computa la elegibilidad a partir de la verdad actual.

  3. Omitir la propiedad de campos. Sin propiedad de campos, cada importación, worker y editor compite por los mismos campos a través del mismo path de save(). Define quién es dueño de qué antes de la primera línea de código.

  4. Usar Version::disable() globalmente. Este flag estático global falla cuando múltiples operaciones se ejecutan concurrentemente. Usa version guards con scope y conteo de referencias.

  5. Dejar que las importaciones toquen el estado del workflow. Las importaciones ERP deben actualizar campos de datos, no estado de proceso. El estado del workflow lo controlan las transiciones humanas y la detección automatizada de cambios.

  6. Disparar revisión en cada cambio. Clasifica los cambios por impacto. Las actualizaciones de texto SEO no deberían disparar revisiones de negocio. Solo los cambios en campos críticos de negocio deberían hacerlo.

  7. No separar el save editorial del save del sistema. La mayor fuente de tormentas de eventos. Los saves de workers y los saves de editores necesitan paths diferentes con políticas de efectos secundarios diferentes.

  8. Ignorar el bucle de saves. Un subscriber sin control puede convertir una importación de productos en un desastre de varias horas. El EventSubscriberSupervisor no es opcional.

Hoja de ruta de implementación

Fase 1: Fundamentos (workflow + elegibilidad por canal)

  • Definir estados y transiciones del workflow en YAML
  • Implementar elegibilidad por canal computada (reemplazar campos de estado almacenados)
  • Configurar permisos del workflow por estado
  • Detección básica de impacto de cambios (crítico de negocio vs sin impacto)

Fase 2: Gobernanza (propiedad de campos + control de eventos)

  • Definir registro de propiedad de campos (editor/system/shared por campo)
  • Implementar EventSubscriberSupervisor
  • Agregar version guards con scope para operaciones de workers
  • Configurar protección de campos en importación ERP

Fase 3: Producción completa (capa de transacciones + notificaciones)

  • Desplegar la capa de transacciones PimTx
  • Agregar idempotencia para todas las operaciones de workers
  • Implementar arquitectura de notificaciones
  • Logging de auditoría completo con vistas de negocio y técnicas
  • Pruebas de regresión en todos los workers e integraciones

Consulta nuestra visión general de confianza y cumplimiento para ver cómo documentamos las garantías del sistema para clientes enterprise.

Conclusiones clave

  • Separa tres responsabilidades en tres capas. El workflow controla el proceso. El flag de publicación controla la visibilidad web. La elegibilidad por canal se computa a partir de la verdad actual. Mezclarlos crea hacks que lo rompen todo.

  • La propiedad de campos no es opcional a escala. Sin ella, cada worker, importación y editor sobrescribe el trabajo del otro a través del mismo path de save(). Define quién es dueño de qué campos antes de escribir la primera transición del workflow.

  • El control de event subscribers previene desastres en cascada. Un save sin control puede disparar miles de mensajes. El EventSubscriberSupervisor es la corrección con mayor impacto para el rendimiento de Pimcore a escala.

  • Computa, no almacenes la elegibilidad por canal. Cualquier campo de estado almacenado se vuelve obsoleto. Computa la elegibilidad a partir del estado publicado actual, el estado del workflow y las reglas de validación. No necesita sincronización, no es posible que los datos queden obsoletos.

  • Los version guards preservan trails de auditoría sin la explosión. Los saves de editores crean versiones. Los saves de workers crean logs de operación. Misma observabilidad, 1/100 del almacenamiento.

  • Envuelve Pimcore, no lo forkees. PimTx gobierna todas las escrituras del sistema a través de un modelo de operaciones explícito. Envuelve $object->save() con guards. No reemplaza ni sobreescribe el core de Pimcore. Las actualizaciones se mantienen limpias.

Construimos PimTx como un bundle de Symfony open-source exactamente para estos patrones. Si tienes una instalación Pimcore enterprise y estás enfrentando estos problemas de escalabilidad, nuestros servicios de IA e ingeniería de datos cubren todo el stack, desde la revisión de arquitectura hasta el despliegue en producción.

¿Listo para rediseñar tu arquitectura de workflows en Pimcore? Habla con nuestro equipo o solicita un presupuesto.

Temas cubiertos

Pimcore workflowPimcore enterpriseSymfony workflow Pimcorediseño de workflows PIMmáquina de estados Pimcoreversionado Pimcorepropiedad de camposPimTx

¿Listo para construir sistemas de IA listos para producción?

Nuestro equipo se especializa en sistemas de IA listos para producción. Hablemos de cómo podemos ayudar.

Iniciar una conversación