Actualizado el 18-oct-2026. Primera versión de la arquitectura de esta épica.
Qué responde. Cómo funciona por dentro FT-CAT-06: qué piezas participan, en qué orden hablan, qué APIs hay que construir con su request y su response, y qué le entrega a la épica siguiente.
Para quién. Los equipos que van a construir la épica, QA y arquitectura.
Estado. [Propuesta] del TL del Nuevo PIM, 18-oct-2026, construida sobre ADR-12. La spec de cada épica dice el qué; estas páginas, el cómo.
Fuente. docs/arquitectura/por-epica/epicas/FT-CAT-06.json, generada con generar.py; la ficha de la épica es trazabilidad/features/FT-CAT-06-agrupadores-y-correccion-masiva.md.
En 30 segundos
Cuando miles de productos se quedan sin categoría, o con un agrupador distinto al de la tienda, dejan de verse. Esta épica corrige en masa sólo la categoría, sobre el universo completo y sin tocar otros campos; republica lo corregido para que la tienda lo vuelva a indexar; deja el rastro de cada corrida para revertirla, y avisa cuando la tienda descarta una actualización en lugar de perderla en silencio.
- Módulo dueño: MS-02 Producto. También participan: MS-01 Catálogo, MS-04 Reportes, MS-08 Adaptadores de salida, MS-14 Avisos y ayuda.
- Etapa C · Configura el catálogo. Recibe «PE-9 · Publicado por canal», «PE-C · Catálogo vigente» y entrega «PE-10 · Cambio aprobado».
- APIs: construye 3 y usa 8 que construyen otras épicas.
- Eventos: publica 3 y consume 4.
1. Dónde encaja
Recibe
| De | Qué |
|---|---|
| PE-9 · Publicado por canal | Productos publicados que dejaron de verse por no tener categoría o por un agrupador distinto en la tienda. |
| PE-C · Catálogo vigente | El árbol de categorías y el mapeo plantilla ↔ categoría vigentes en Catálogo. |
| FT-CAT-02 · Publicación de categorías a la tienda | Las categorías publicadas en la tienda: sólo esas se pueden usar al corregir. |
| FT-INT-01 · Publicación a e-commerce | La publicación a la tienda y su acuse por producto. |
| FT-INT-07 · Repoblamiento masivo de productos hacia la tienda | El mecanismo de corrida con vista previa, resultado por producto y reversa, y la publicación de sólo categorías. |
| FT-CAT-01 · Administración del árbol de categorías web | Los productos que perdieron una categoría desligada, para corregirlos y republicarlos. |
| FT-RAC-04 · Consistencia entre sistemas y gobierno de datos proactivo | Los productos sin categoría en la tienda, listos para la corrección masiva con republicación e indexación. |
| FT-RAC-07 · Reportes, exportes, importes y búsquedas por atributos | El exporte de las categorías de los productos por ID, listo para editarse e importarse en la corrección masiva. |
| FT-RAC-08 · Monitoreo de visibilidad y alertas de caída de SKUs… | La comprobación de que, después de corregir, republicar e indexar, el seller volvió a su línea base. |
Entrega
| A | Qué |
|---|---|
| PE-10 · Cambio aprobado | Los productos corregidos siguen Aprobados y su canal de tienda pasa de Publicado a Enviado, con la publicación pedida sólo con la categoría. |
| FT-INT-01 · Publicación a e-commerce | La petición de republicar sólo la categoría de cada producto corregido. |
| FT-RAC-08 · Monitoreo de visibilidad y alertas de caída de SKUs… | La lista de productos corregidos por corrida, para verificar que vuelven a verse. |
Cambios de estado que hace
| Transición | De → a | Cuándo |
|---|---|---|
| C06 | Publicado → Enviado (por canal) | Se aprueba un cambio. |
| C03 | Enviado → Publicado (por canal) | Llega el acuse del destino. |
| C04 | Enviado → Error (por canal) | No llega el acuse o el destino rechaza. |
| C05 | Error → Enviado (por canal) | Se republica. |
Tareas que abre o cierra: Category, Gobierno de Datos.
2. Diagrama de contexto
Quién participa y cómo se conecta. Las pantallas llegan por el BFF del portal, que valida el token y compone; cada módulo vuelve a validar el token y decide sus permisos con los roles de MS-13.
🟩 Verde: nuevo, se construye · 🟦 Azul: ya existe y se queda, se reutiliza su código · 🟧 Naranja: temporal o se retira (se apaga en R3) · ⬜ Gris: sistema externo · ★ módulo dueño
3. Diagrama de flujo
El camino principal, paso por paso. Cuando una pantalla llama a un módulo se ven dos flechas: la pantalla al BFF y el BFF al módulo. Los eventos salen del outbox del módulo después de guardar; quien los consume ignora los repetidos.
Los pasos en texto
| Paso | De | A | Qué hace | API o evento |
|---|---|---|---|---|
| 1 | Gobierno de Datos | Entrada Única · Vendor Center | Pide corregir todos los productos sin categoría | — |
| 2 | Entrada Única · Vendor Center | MS-02 Producto (por el BFF) | Pide el plan sobre el universo completo, sin fechas | API-02-111 |
| 3 | MS-02 Producto | MS-01 Catálogo | Lee el árbol publicado para validar cada categoría | API-01-039 |
| 4 | Entrada Única · Vendor Center | MS-02 Producto (por el BFF) | Confirma la corrida | API-02-057 |
| 5 | MS-02 Producto | Base pim | Cambia sólo la categoría y guarda el antes de cada producto | — |
| 6 | MS-02 Producto | Base pim | Abre Category con su motivo para lo que no se resolvió | — |
| 7 | MS-02 Producto | Eventos | Avisa la categoría nueva de cada producto | catalog.product.changed/CLASSIFICATION_CHANGED |
| 8 | MS-02 Producto | Eventos | Pide republicar sólo la categoría | catalog.product.publication/PUBLICATION_REQUESTED |
| 9 | Eventos | MS-08 Adaptadores de salida | Entrega la petición al adaptador de la tienda | catalog.product.publication/PUBLICATION_REQUESTED |
| 10 | MS-08 Adaptadores de salida | Tienda en línea | Manda las categorías para que la tienda reindexe | — |
| 11 | MS-08 Adaptadores de salida | Eventos | Devuelve el acuse de cada producto | catalog.delivery.result/DELIVERY_RESULT |
| 12 | Eventos | MS-02 Producto | Entrega el acuse; el canal tienda queda Publicado | catalog.delivery.result/DELIVERY_RESULT |
| 13 | Gobierno de Datos | Entrada Única · Vendor Center | Revisa el resultado de la corrida | — |
| 14 | Entrada Única · Vendor Center | MS-02 Producto (por el BFF) | Consulta universo, corregidos, publicados y pendientes | API-02-112 |
3.1 Repoblar o reimportar categorías por archivo
3.2 Revertir una corrida
3.3 La tienda descarta por agrupador distinto
4. Si algo sale mal
- El filtro de la corrida trae fechas. El plan avisa que un filtro de fechas deja casos fuera, como pasó en la primera corrección, y muestra junto el universo sin fecha para comparar; Gobierno de Datos decide antes de confirmar.
- Un producto no se puede resolver. Queda sin cambio y se abre Category con el motivo (sin mapeo o categoría no publicada); la corrida termina con los demás y el resultado lo cuenta aparte.
- Alguien cambió un producto entre la vista previa y la ejecución. Ese producto queda bloqueado en la corrida, porque su versión ya no es la fijada; no se toca y aparece en el resultado para corregirlo a mano.
- La tienda no confirma o rechaza la publicación. El canal queda Enviado y, si no llega señal de la tienda o llega un rechazo, pasa a Error con el motivo; se republica desde el resultado de la corrida y FT-RAC-08 vigila que los visibles regresen.
- La corrida bajó los productos visibles. Se revierte con la reversa común de corridas: regresa la categoría anterior de cada producto, deja como conflicto lo que cambió después y republica.
5. APIs
Las que construye esta épica (3)
POST /api/v2/products/category-corrections/plans · Corrección masiva de categorías
| Campo | Valor |
|---|---|
| API | API-02-111 · MS-02 Producto |
| Para qué | Prepara una corrida que corrige sólo la categoría web de muchos productos sobre un universo que sale de un filtro sin fechas (por ejemplo, todos los que no tienen categoría); dice cuántos se resuelven, con qué fuente, cuántos no y por qué, sin escribir nada. Al confirmar, la corrida es un trabajo asíncrono que guarda el antes y el después de cada producto, para revertirlo con la reversa común de corridas (API-02-403). Repoblar categorías desde un archivo va por la carga masiva y la corrida de publicación (FT-INT-07). |
| En esta épica | Preparar la corrección masiva de categorías sobre un universo sin fechas |
| Quién la llama | BFF del portal |
| Permiso | Gobierno de Datos o Category |
| Cabeceras | Authorization, X-Request-Id, Idempotency-Key |
| Publica | catalog.product.changed/CLASSIFICATION_CHANGED, catalog.product.changed/TASK_CHANGED, catalog.product.publication/PUBLICATION_REQUESTED |
Request
{
"universe": {
"filters": [
{
"field": "classification.webCategoryIds",
"op": "IS_EMPTY"
},
{
"field": "status",
"op": "IN",
"values": [
"APROBADO"
]
}
]
},
"sources": [
"LAST_PUBLISHED",
"MAPPING"
],
"republish": true,
"comment": "Productos sin categoría tras la caída de visibles"
}
Response · 200
{
"success": true,
"data": {
"planId": "pln-4f0d27",
"expiresAt": "2026-10-18T17:35:00Z",
"universe": {
"total": 23104,
"dateFilters": false
},
"summary": {
"resolved": 21876,
"bySource": {
"LAST_PUBLISHED": 19410,
"MAPPING": 2466
},
"unresolved": 1228,
"unresolvedReasons": {
"NO_MAPPING": 1011,
"CATEGORY_NOT_PUBLISHED": 217
}
},
"onlyField": "classification.webCategoryIds",
"republish": {
"channel": "TIENDA",
"scope": "CATEGORIES"
},
"applyUrl": "/api/v2/product-plans/pln-4f0d27/apply",
"warnings": []
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | VALIDATION_ERROR | Un filtro usa un campo u operador que no existe |
| 422 | VALIDATION_ERROR | El universo pasa de 2,000,000 de productos; se rechaza completo, nunca se trunca |
| 403 | AUTHORIZATION_ERROR | Quien llama no es Gobierno de Datos ni Category |
GET /api/v2/products/category-corrections/{jobId} · Avance y resultado de una corrida
| Campo | Valor |
|---|---|
| API | API-02-112 · MS-02 Producto |
| Para qué | Dice cómo va una corrida de corrección: quién la lanzó, su universo, cuántos productos se corrigieron, cuántos quedaron para Category, cuántos ya llegaron a la tienda y si se puede revertir con la reversa común de corridas (API-02-403); con view=items da el antes y el después de cada producto. |
| En esta épica | Ver el avance y el resultado de la corrida, con el antes y el después |
| Quién la llama | BFF del portal |
| Permiso | Gobierno de Datos o Category |
| Cabeceras | Authorization, X-Request-Id |
| Parámetros | jobId = job-8d21 |
Request
null
Response · 200
{
"success": true,
"data": {
"jobId": "job-8d21",
"status": "DONE",
"launchedBy": {
"area": "GOBIERNO-DATOS"
},
"launchedAt": "2026-10-18T17:02:00Z",
"finishedAt": "2026-10-18T17:21:00Z",
"universe": 23104,
"corrected": 21876,
"unresolved": 1228,
"categoryTasksOpened": 1228,
"publication": {
"sent": 21876,
"published": 21490,
"error": 386
},
"revertible": true,
"links": {
"items": "/api/v2/products/category-corrections/job-8d21?view=items",
"revert": "/api/v2/publications/job-8d21/revert/plans"
}
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | La corrida no existe |
POST /internal/product/classifications/impact · Impacto de quitar categorías
| Campo | Valor |
|---|---|
| API | API-02-114 · MS-02 Producto |
| Para qué | Antes de desligar o mover categorías, Catálogo pregunta qué productos las tienen y cuáles se quedarían sin ninguna categoría web activa; no cambia nada. Responde a la pedida PEDIDA-CAT-01-1 de FT-CAT-01. |
| En esta épica | Que Catálogo sepa, antes de desligar o mover categorías, qué productos se quedarían sin categoría web |
| Quién la llama | MS-01 Catálogo |
| Permiso | Sólo MS-01 (cuenta de servicio) |
| Cabeceras | Authorization, X-Request-Id |
| También la usan | FT-CAT-01 |
Request
{
"structure": "WEB_CATEGORIES",
"removeCategoryIds": [
"catst10045",
"catst10046",
"catst10047"
],
"page": 1,
"size": 50
}
Response · 200
{
"success": true,
"data": {
"productsInCategories": 128,
"wouldLoseAllWebCategories": 2,
"items": [
{
"productId": "PRD-0004812",
"name": "Camisa de lino manga larga",
"business": "MER",
"status": "APROBADO",
"activeWebCategories": [
"catst10045"
]
},
{
"productId": "PRD-0004813",
"name": "Camisa de lino manga corta",
"business": "MER",
"status": "APROBADO",
"activeWebCategories": [
"catst10046"
]
}
],
"page": 1,
"size": 50,
"total": 2
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | VALIDATION_ERROR | Más de 1,000 categorías en una consulta o una estructura que no es de categorías web |
Las que usa y construye otra épica (8)
Su request y su response están en la página de la épica que la construye.
| API | Método y ruta | Para qué, aquí | La construye |
|---|---|---|---|
| API-01-039 | GET /api/v2/categories/tree | Validar que cada categoría exista y esté publicada en el árbol | FT-CAT-01 · Administración del árbol de categorías web |
| API-02-057 | POST /api/v2/product-plans/{planId}/apply | Confirmar la corrida, la carga, la reversa o la republicación | FT-FLU-01 · Motor de estados configurable con dos carreteras y reglas… |
| API-02-042 | GET /api/v2/delivery-status?productId=&sku= | Que el seller verifique en qué quedó cada canal de su producto corregido | FT-CAT-05 · Sitios, enrutamiento y visibilidad por negocio |
| API-04-001 | POST /api/v2/exports | Exportar SKU, título y categoría para editarlos | FT-RAC-07 · Reportes, exportes, importes y búsquedas por atributos |
| API-02-046 | POST /api/v2/product-imports | Validar el archivo de categorías renglón por renglón | FT-FLU-04 · Carga masiva de productos por archivo |
| API-02-047 | POST /api/v2/product-imports/{id}/apply | Aplicar el archivo de categorías | FT-FLU-04 · Carga masiva de productos por archivo |
| API-02-039 | POST /api/v2/publications/plans | Mandar sólo las categorías o republicar la familia completa | FT-INT-07 · Repoblamiento masivo de productos hacia la tienda |
| API-02-403 | POST /api/v2/publications/{jobId}/revert/plans | Revertir una corrida con la reversa común | FT-INT-07 · Repoblamiento masivo de productos hacia la tienda |
6. Eventos
Publica
| Evento | Cuándo | Quién lo consume |
|---|---|---|
catalog.product.changed/CLASSIFICATION_CHANGED | La corrida corrige o revierte la categoría de un producto | FT-ACT-05, FT-ACT-06, FT-CAT-05, FT-IA-02, FT-IA-04 |
catalog.product.changed/TASK_CHANGED | Se abre Category para lo no resuelto o Gobierno de Datos por un agrupador distinto | FT-ACT-05, FT-ACT-06, FT-ARQ-02, FT-FLU-01, FT-IA-06, FT-PRD-02, FT-PRD-05, FT-PRD-06, FT-PRD-07, FT-PRD-08, FT-RAC-02, FT-RAC-03, FT-RAC-04, FT-RAC-05, FT-RAC-06 |
catalog.product.publication/PUBLICATION_REQUESTED | Un producto corregido o revertido se republica con sólo su categoría | FT-CAT-05, FT-INT-01, FT-INT-02, FT-INT-05, FT-INT-07, FT-PLT-08, FT-PRD-05, FT-RAC-03 |
Consume
| Evento | Para qué | Quién lo publica |
|---|---|---|
catalog.delivery.result/DELIVERY_RESULT | MS-02 marca el canal tienda Publicado o en Error y detecta el agrupador distinto | FT-CAT-02, FT-CAT-05, FT-INT-01, FT-INT-02, FT-INT-05, FT-INT-07, FT-PRD-02 |
catalog.product.publication/PUBLICATION_REQUESTED | MS-08 manda a la tienda sólo las categorías del producto | esta misma épica |
catalog.governance.changed/CATEGORY_UNLINKED | MS-02 deja lista, como plan para Gobierno de Datos, la corrección de los productos que tenían esa categoría | FT-CAT-01 |
catalog.product.changed/TASK_CHANGED | MS-14 avisa a Gobierno de Datos o a Category que tienen casos por resolver | esta misma épica |
7. Datos
Cada colección tiene un solo dueño, el único que escribe en ella.
| Colección | Dueño | Qué guarda | Esta épica |
|---|---|---|---|
products | MS-02 | La familia del producto con sus variantes, valores, imágenes (URL), clasificaciones, estado, tareas abiertas y rechazos. | escribe |
product_jobs | MS-02 | Trabajos asíncronos: cargas masivas de productos, edición masiva y publicación. | escribe |
tasks | MS-02 | Todo el trabajo asignado: visto bueno, corrección, Gobierno de Datos, foto, secciones, QA, revisión del cambio y repoblamiento. | escribe |
product_delivery_status | MS-02 | El estado de publicación por producto y canal: Pendiente, Enviado, Publicado, Error o Retirado. | escribe |
product_receipts | MS-02 | El recibo de cada escritura confirmada en el producto (antes operation_receipts). | escribe |
product_outbox | MS-02 | Los cambios del producto que esperan salir como evento (antes outbox). | escribe |
categories | MS-01 | Cada categoría web con su lugar en el árbol y su estado. | lee |
governance_rules | MS-01 | Reglas de captura y clasificación: marcas por plantilla, grupo de artículo a plantilla, alcance del proveedor y lista negra de Marketplace. | lee |
product_versions | MS-02 | Foto numerada del producto en cada versión. | lee |
8. Historias que cubre
| Historia | Prioridad | Cómo la cubre |
|---|---|---|
| FT-CAT-06·H1 · Corregir en masa la categoría de todos los productos con categoría nula o vacía | P1 | pasos 1, 2, 3, 4, 5, 6; API-02-111 |
| FT-CAT-06·H2 · Que mi producto corregido se republique e indexe solo | P1 | pasos 8, 9, 10, 11, 12; API-02-112, API-02-042 |
| FT-CAT-06·H3 · Repoblar categorías por archivo con SKU, título y clasificación web | P1 | flujo «Repoblar o reimportar categorías por archivo»; API-02-046, API-02-039 |
| FT-CAT-06·H4 · Exportar, editar e importar por ID las categorías de productos | P2 | flujo «Repoblar o reimportar categorías por archivo»; API-04-001, API-02-047 |
| FT-CAT-06·H5 · Que el agrupador del PIM y el de e-commerce coincidan y que ningún producto… | P2 | flujo «La tienda descarta por agrupador distinto» |
| FT-CAT-06·H6 · Rastrear y revertir cada corrección masiva | P2 | flujo «Revertir una corrida»; API-02-403, API-02-112 |
9. Decisiones de esta épica
Las tomó el TL como arquitecto; quedan como [Propuesta] hasta que el equipo de la épica las revise.
- D-CAT-06-1. La corrección masiva es una corrida de MS-02 con plan: el plan cuenta el universo con un filtro sin fechas y dice cuántos se resuelven, con qué fuente y cuántos no; al confirmar corre como trabajo asíncrono y responde con el recibo. Por qué: La primera corrección falló por un filtro de fechas y dejó casos fuera; quitarlo devolvió a un seller a sus 1,355 visibles. Se apoya en DEC-93, RF-CAT-15.
- D-CAT-06-2. Actualización parcial: la corrida sólo toca las categorías web del producto, con la versión fijada al confirmar; guarda el antes y el después de cada producto, y a la tienda sólo viaja la categoría. Por qué: Se pidió revisar que una corrección no sobrescriba otro campo; un trabajo que sólo puede escribir un campo lo garantiza. Se apoya en RF-CAT-15, DEC-92.
- D-CAT-06-3. Fuentes de la categoría, en orden: la última categoría que la tienda tenía publicada y, si no hay, el mapeo de la plantilla (el mismo de FT-CAT-03). Lo que no se resuelve abre Category con su motivo. La corrida masiva no usa IA. Por qué: Lo no resuelto pasa a la category manager, y la masiva categoriza sin IA, como se acordó. Se apoya en DEC-92, DEC-61.
- D-CAT-06-4. Cada producto corregido se republica solo, con una publicación de sólo categorías (como SEND_CATIDS de FT-INT-07) que manda la lista completa de categorías y retira las que ya no tiene. Enviado es cuando el adaptador confirma la entrega; Publicado, cuando hay señal del lado de la tienda. FT-RAC-08 vigila que los visibles regresen. Por qué: Insertar la categoría en la base dejó productos apagados hasta republicar; además la tienda conserva el valor anterior si sólo se vacía un campo. Se apoya en RF-PUB-07, RN-PUB-02, DUD-20.
- D-CAT-06-5. La corrección la lanza el dueño del dato (Gobierno de Datos o Category): no pasa por Revisión del cambio ni por En modificación. El producto sigue Aprobado y sólo su canal de tienda pasa de Publicado a Enviado. Por qué: La revisión del cambio existe para cambios de otros sobre datos ajenos; aquí el cambio es del dueño y sólo de la categoría. Se apoya en FT-PRD-05, RF-PUB-07.
- D-CAT-06-6. Una sola mecánica de corridas en MS-02, la de FT-INT-07: la corrección se revierte con la reversa común (API-02-403), que regresa el antes guardado, deja como conflicto lo que cambió después y republica. Por qué: Dos reversas para dos tipos de corrida duplicarían la misma capacidad; en el Remaster se revirtieron 3 días de repoblamiento. Se apoya en FT-INT-07, RF-CAL-13.
- D-CAT-06-7. Repoblar categorías por archivo (SKU, título y categoría web) y exportar, editar e importar por SKU van por la carga masiva con su perfil y la publicación de sólo categorías, como el archivo de repoblamiento de FT-INT-07. Un renglón con una categoría no publicada o vacía se rechaza solo, sin depender de la completitud. Por qué: Un solo camino de archivo para el producto; un segundo importador sólo para categorías duplicaría reglas. Se apoya en FT-INT-07, DEC-93.
- D-CAT-06-8. Agrupador es la familia (el genérico con sus variantes) con la que la tienda agrupa. Si el acuse dice que la tienda descartó la actualización por agrupador distinto, el canal queda en Error con el motivo y se abre Gobierno de Datos con el tipo de caso; la acción por omisión es republicar la familia completa. Nunca se descarta en silencio. Por qué: Hoy unos 700 mil productos de Marketplace conservan el agrupador antiguo sin aviso, y nadie ha definido qué es el agrupador. Se apoya en PEN-112, RN-CAT-03, DEC-74, RF-CAT-14.
Qué falta decidir
| ID | Qué falta |
|---|---|
| DUD-20 | Confirmar cómo retira la tienda una categoría que el producto ya no tiene, para no dejar el valor anterior. |
| DUD-24 | Fijar las reglas del repoblamiento con el área de Repoblamiento. |
También siguen abiertos: PEN-112, Gobierno de Datos define qué es el agrupador y la acción por tipo de caso (aquí arranca como la familia y republicarla completa); PEN-123, Confirmar si el universo de los 23 mil sin categoría es el mismo que el de los no indexados.
Fuentes
- [D]
trazabilidad/features/FT-CAT-06-agrupadores-y-correccion-masiva.md: la ficha de la épica, con sus historias, reglas y bloqueos. - [D] ADR-12 · Un solo sistema: backend compartido y una sola base (sección 3.4).
- [D]
docs/arquitectura/por-epica/base/: piezas, colecciones, eventos y el hilo de punta a punta. - [D]
docs/arquitectura/omega-a-pim-headless/contratos-api.md: convenciones y endpoints de partida. - [D]
docs/arquitectura/maquina-de-estados-to-be/propuesta-maquina-de-estados.md§7: estados, tareas y canales. - [I] Las decisiones de la sección 9 son del TL sobre esas fuentes.