Actualizado el 18-oct-2026. Primera versión de la arquitectura de esta épica.
Qué responde. Cómo funciona por dentro FT-ARQ-02: 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-ARQ-02.json, generada con generar.py; la ficha de la épica es trazabilidad/features/FT-ARQ-02-bitacora-inmutable-y-versionado.md.
En 30 segundos
Hoy P360 guarda 52 millones de renglones de bitácora sin el valor anterior ni el nuevo, y un repoblamiento sólo se pudo revertir de tres días. Esta épica hace de Auditoría (MS-05) la bitácora única: recibe los eventos de todos los módulos y guarda, por objeto y campo, el antes y el después, quién, cuándo, desde dónde y en qué ejecución, sin que nada se pueda cambiar ni borrar. Las versiones completas del producto las guarda Producto, para compararlas y restaurarlas.
- Módulo dueño: MS-05 Auditoría. También participan: MS-01 Catálogo, MS-02 Producto, MS-13 Identidad y acceso, MS-07 Ingesta de archivos, MS-03 Migración y convivencia.
- Etapa T · Transversal. Recibe de otras épicas y entrega «PE-T · Usuario con permisos y bitácora».
- APIs: construye 10 y usa 6 que construyen otras épicas.
- Eventos: publica 1 y consume 17.
1. Dónde encaja
Recibe
| De | Qué |
|---|---|
| FT-USR-01 · Identidad y autenticación de usuarios internos… | El actor de cada evento (ID, rol y área) tomado del token y del directorio. |
| FT-FLU-01 · Motor de estados configurable con dos carreteras y reglas… | Las transiciones y tareas del motor, que llegan como STATUS_CHANGED y TASK_CHANGED para guardarse. |
| FT-MIG-03 · Migración inicial de productos desde P360 | La versión 1 de cada producto migrado, con su corrida, y la historia de estado de P360 y Omega (API-05-006). |
Entrega
| A | Qué |
|---|---|
| PE-T · Usuario con permisos y bitácora | Cada cambio de cualquier módulo queda en la bitácora con antes, después, actor, origen, solicitud y ejecución, sin poder cambiarse. |
| FT-PLT-01 · Fundamentos de gobierno de plantillas | La historia por campo de plantillas, atributos y listas, y la comparación de sus versiones. |
| FT-CAT-01 · Administración del árbol de categorías web | La auditoría de categorías: cada cambio y publicación con usuario, y la comparación de dos versiones. |
| FT-RAC-06 · Métricas de tiempos por paso y clasificación de errores | La historia de estado, incluida la migrada, para medir los pasos anteriores a la salida. |
| FT-RAC-04 · Consistencia entre sistemas y gobierno de datos proactivo | El origen de cada valor, para explicar una diferencia entre sistemas. |
| FT-INT-07 · Repoblamiento masivo de productos hacia la tienda | Qué productos y campos cambió cada corrida de repoblamiento, para revisarla y revertirla como otra ejecución. |
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 | Administración del catálogo | Entrada Única · Vendor Center | Cambia la guía de nombre de la plantilla EU4-0412 | — |
| 2 | Entrada Única · Vendor Center | MS-01 Catálogo (por el BFF) | Confirma el plan del cambio | API-01-004 |
| 3 | MS-01 Catálogo | Eventos | Avisa el cambio con antes y después | catalog.governance.changed/TEMPLATE_CHANGED |
| 4 | Eventos | MS-05 Auditoría | Entrega el cambio a la bitácora | catalog.governance.changed/TEMPLATE_CHANGED |
| 5 | MS-05 Auditoría | Base pim | Guarda una entrada por objeto y campo, sin borrar | — |
| 6 | MS-02 Producto | Eventos | Avisa un cambio de producto con su origen | catalog.product.changed/PRODUCT_UPDATED |
| 7 | Eventos | MS-05 Auditoría | Entrega el cambio; descarta repetidos y versiones viejas | catalog.product.changed/PRODUCT_UPDATED |
| 8 | Gobierno de Datos | Entrada Única · Vendor Center | Abre la historia del producto | — |
| 9 | Entrada Única · Vendor Center | BFF del portal | Pide la historia compuesta | API-BFF-507 |
| 10 | BFF del portal | MS-05 Auditoría | Trae los cambios por campo | API-05-001 |
| 11 | BFF del portal | MS-13 Identidad y acceso | Pone el nombre visible de cada actor | API-13-018 |
| 12 | BFF del portal | MS-02 Producto | Trae la lista de versiones del producto | API-02-115 |
3.1 Comparar y restaurar una versión
3.2 Revertir una ejecución masiva
3.3 Revisar una incidencia de días anteriores
4. Si algo sale mal
- Alguien intenta cambiar o borrar una entrada de la bitácora. No existe ninguna ruta para hacerlo: la API responde 405 y el intento queda como evento de seguridad; en la base, ninguna cuenta puede actualizar ni borrar en audit_events.
- Llega un evento repetido o fuera de orden. MS-05 lo descarta por su eventId y por su versión; lo que no puede leer va a la cola de mensajes muertos y Operación lo reprocesa.
- MS-05 se atrasa o se cae. Ningún módulo espera a la bitácora: sus eventos se quedan en el bus de eventos y MS-05 se pone al día al volver. La historia muestra «al día hasta» con la hora del último evento guardado.
- Se revierte una corrida y algún producto cambió después. La vista previa marca ese producto como conflicto y no lo toca; se revierte lo demás y quien revierte decide el resto a mano.
- Se pide restaurar la versión vigente. MS-02 responde 422 BUSINESS_ERROR: no hay nada que restaurar y no se crea versión.
5. APIs
Las que construye esta épica (10)
GET /api/v2/audit/entities/{entityType}/{entityId}/events · Historia de un objeto
| Campo | Valor |
|---|---|
| API | API-05-001 · MS-05 Auditoría |
| Para qué | La historia de un producto, variante, plantilla, atributo, lista, categoría, usuario o tercero, campo por campo: valor anterior y nuevo, quién (ID, rol y área), cuándo, desde dónde, en qué solicitud y en qué ejecución. Los estados salen como «Etiqueta (código)». |
| En esta épica | La historia por campo de cualquier objeto |
| Quién la llama | BFF del portal |
| Permiso | ENT-L para productos (proveedores y sellers, sólo los suyos), CAT-L para catálogo, ACCESS-ADMIN para usuarios y terceros |
| Cabeceras | Authorization, X-Request-Id |
| Parámetros | entityType = PRODUCT, entityId = PRD-0004812, field = attributes.MATERIAL, from = 2026-09-01, to = 2026-10-18, page = 1, size = 50 |
| También la usan | FT-CAT-01, FT-INT-07, FT-PLT-01, FT-PRD-05 |
Request
null
Response · 200
{
"success": true,
"data": {
"items": [
{
"eventId": "7f1c2a9e-0b44-4c55-9a51-2f7d1b8e6c10",
"occurredAt": "2026-10-16T18:02:11Z",
"version": 14,
"field": "attributes.MATERIAL",
"before": "Plástico",
"after": "Acero inoxidable",
"actor": {
"userId": "USR-004410",
"role": "PROVEEDOR",
"area": null,
"type": "SUPPLIER"
},
"origin": "PORTAL",
"requestId": "req-55e0c2",
"jobId": null,
"sourceModule": "MS-02",
"eventType": "PRODUCT_UPDATED"
}
],
"page": 1,
"size": 50,
"total": 1,
"upToDateUntil": "2026-10-18T15:03:59Z"
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | No hay historia de ese objeto o no es visible para quien llama |
| 403 | AUTHORIZATION_ERROR | Quien llama no puede ver ese tipo de objeto |
GET /api/v2/audit/entities/{entityType}/{entityId}/status-history · Historia de estado
| Campo | Valor |
|---|---|
| API | API-05-002 · MS-05 Auditoría |
| Para qué | Todos los cambios de estado de un producto con su transición, quién, cuándo, desde dónde y con qué precisión, incluida la historia que se migró de P360 y Omega. |
| En esta épica | La historia de estado, incluida la migrada |
| Quién la llama | BFF del portal, MS-04 Reportes |
| Permiso | ENT-L (proveedores y sellers, sólo sus productos); la cuenta de servicio de MS-04 |
| Cabeceras | Authorization, X-Request-Id |
| Parámetros | entityType = PRODUCT, entityId = PRD-0004812, page = 1, size = 50 |
| También la usan | FT-PRD-02, FT-RAC-06 |
Request
null
Response · 200
{
"success": true,
"data": {
"items": [
{
"occurredAt": "2027-02-14T00:00:00Z",
"from": null,
"to": "En revisión (EN_REVISION)",
"legacyCode": 1001,
"origin": "MIGRATION",
"runId": "run-status-0007",
"precision": "DAY",
"actor": null
},
{
"occurredAt": "2027-02-20T16:30:02Z",
"from": "En revisión (EN_REVISION)",
"to": "Creación de SKU (CREACION_SKU)",
"transition": "T05",
"origin": "PORTAL",
"precision": "EXACT",
"actor": {
"userId": "USR-000231",
"role": "COMPRAS",
"area": "COMPRAS-HOGAR"
}
}
],
"page": 1,
"size": 50,
"total": 2
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | El producto no existe o no es visible para quien llama |
GET /api/v2/audit/search · Buscar en la bitácora
| Campo | Valor |
|---|---|
| API | API-05-003 · MS-05 Auditoría |
| Para qué | Busca cambios por actor, fechas, tipo de objeto, origen, solicitud o ejecución. Con jobId lista qué objetos y campos cambió un proceso masivo, para revisarlo o revertirlo. |
| En esta épica | Buscar por actor, fechas, origen, solicitud o ejecución |
| Quién la llama | BFF del portal |
| Permiso | AUDIT-L (Gobierno de Datos y de Producto); el dueño de una ejecución ve la suya y cada usuario ve sus propias operaciones |
| Cabeceras | Authorization, X-Request-Id |
| Parámetros | actor = `, from = 2026-09-23, to = 2026-09-24, entityType = PRODUCT, origin = BULK, requestId = , jobId = job-rep-0923, page = 1, size = 200` |
Request
null
Response · 200
{
"success": true,
"data": {
"summary": {
"jobId": "job-rep-0923",
"objects": 861,
"fields": 1722,
"startedAt": "2026-09-23T03:00:05Z",
"finishedAt": "2026-09-23T04:12:40Z"
},
"items": [
{
"entityType": "PRODUCT",
"entityId": "PRD-0007710",
"version": 9,
"field": "classification.webCategoryIds",
"before": [
"catst-000812"
],
"after": [],
"occurredAt": "2026-09-23T03:00:09Z",
"origin": "BULK",
"requestId": "req-0923a1",
"jobId": "job-rep-0923"
}
],
"page": 1,
"size": 200,
"total": 1722
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | VALIDATION_ERROR | No trae ningún filtro o el periodo pasa de 400 días sin jobId ni objeto |
| 403 | AUTHORIZATION_ERROR | Busca operaciones de otros sin AUDIT-L |
POST /internal/audit/bulk-load/status-history · Carga de historia migrada
| Campo | Valor |
|---|---|
| API | API-05-006 · MS-05 Auditoría |
| Para qué | MS-03 carga, por lotes, la entrada inicial de cada objeto migrado (versión 1, origen MIGRATION y su corrida) y la historia de estado de P360 y Omega con su precisión. |
| En esta épica | Cargar la versión 1 migrada y la historia de estado |
| Quién la llama | MS-03 Migración y convivencia |
| Permiso | Sólo la cuenta de servicio de MS-03 (MIG-ADMIN) |
| Cabeceras | Authorization, X-Request-Id, Idempotency-Key |
| Escribe en | audit_events |
| También la usan | FT-MIG-03, FT-MIG-04 |
Request
{
"runId": "run-status-0007",
"records": [
{
"entityType": "PRODUCT",
"entityId": "PRD-0004812",
"baseline": {
"version": 1,
"origin": "MIGRATION",
"at": "2027-02-14T05:00:00Z"
},
"statusHistory": [
{
"at": "2026-08-30T00:00:00Z",
"from": null,
"legacyCode": 1001,
"to": "EN_REVISION",
"precision": "DAY",
"source": "P360"
}
]
}
]
}
Response · 200
{
"success": true,
"data": {
"runId": "run-status-0007",
"stored": 2,
"duplicates": 0,
"rejected": []
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 409 | IDEMPOTENCY_MISMATCH | El mismo lote llega otra vez con contenido distinto |
| 422 | VALIDATION_ERROR | Un registro trae un estado o un código de P360 sin equivalencia |
GET /api/v2/audit/entities/{entityType}/{entityId}/versions/compare · Comparar dos versiones desde la bitácora
| Campo | Valor |
|---|---|
| API | API-05-008 · MS-05 Auditoría |
| Para qué | Compara dos versiones de una plantilla, atributo, lista o categoría con su cadena de cambios: qué campos cambiaron entre las dos, el valor en cada una y la fecha y el usuario de cada versión. Los productos se comparan con sus fotos en MS-02. |
| En esta épica | Comparar dos versiones de una plantilla o categoría desde la bitácora |
| Quién la llama | BFF del portal |
| Permiso | CAT-L |
| Cabeceras | Authorization, X-Request-Id |
| Parámetros | entityType = CATEGORY, entityId = catst-000812, from = 3, to = 7, fields = name.es,parent,status |
Request
null
Response · 200
{
"success": true,
"data": {
"entityType": "CATEGORY",
"entityId": "catst-000812",
"from": {
"version": 3,
"at": "2027-03-02T17:00:00Z",
"actor": {
"userId": "USR-000502",
"role": "CATEGORY"
}
},
"to": {
"version": 7,
"at": "2027-05-11T14:20:00Z",
"actor": {
"userId": "USR-000503",
"role": "CATEGORY"
}
},
"fields": [
{
"field": "name.es",
"atFrom": "Licuadoras",
"atTo": "Licuadoras y batidoras",
"changed": true
},
{
"field": "parent",
"atFrom": "catst-000800",
"atTo": "catst-000800",
"changed": false
},
{
"field": "status",
"atFrom": null,
"atTo": null,
"changed": false,
"note": "Sin dato: no cambió desde la migración y la migración no lo trajo"
}
]
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | El objeto o alguna de las versiones no existe |
| 422 | BUSINESS_ERROR | Se pide comparar un producto: sus versiones son de MS-02 |
GET /bff/v1/history/{entityType}/{entityId} · Historia de un objeto
| Campo | Valor |
|---|---|
| API | API-BFF-507 · BFF del portal |
| Para qué | La pantalla de historia: los cambios por campo de la bitácora (MS-05), con el nombre visible de cada actor (MS-13) y, si es producto, sus versiones (MS-02). A proveedores y sellers les muestra el área, no el nombre. |
| En esta épica | La pantalla de historia: bitácora, nombres y versiones |
| Quién la llama | Entrada Única · Vendor Center (por el BFF) |
| Permiso | El mismo que da cada módulo para ver el objeto (ENT-L, CAT-L o el dueño del producto) |
| Cabeceras | X-Request-Id |
| Parámetros | entityType = PRODUCT, entityId = PRD-0004812, field = `, page = 1` |
Request
null
Response · 200
{
"success": true,
"data": {
"entity": {
"type": "PRODUCT",
"id": "PRD-0004812",
"currentVersion": 14
},
"events": [
{
"at": "2026-10-16T18:02:11Z",
"version": 14,
"field": "attributes.MATERIAL",
"before": "Plástico",
"after": "Acero inoxidable",
"actor": {
"displayName": "Proveedor Demo 01",
"area": null,
"type": "SUPPLIER"
},
"origin": "PORTAL",
"requestId": "req-55e0c2",
"jobId": null
},
{
"at": "2026-10-15T09:40:00Z",
"version": 13,
"field": "attributes.TITULO",
"before": "Licuadora 10 vel",
"after": "Licuadora de 10 velocidades",
"actor": {
"displayName": null,
"area": "IA",
"type": "SYSTEM"
},
"origin": "IA",
"requestId": "req-1b77a0",
"jobId": "job-ia-3301"
}
],
"versions": [
{
"version": 14,
"at": "2026-10-16T18:02:11Z"
},
{
"version": 13,
"at": "2026-10-15T09:40:00Z"
}
],
"upToDateUntil": "2026-10-18T15:03:59Z"
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | El objeto no existe o no es visible para quien llama |
GET /bff/v1/receipts · Mis comprobantes
| Campo | Valor |
|---|---|
| API | API-BFF-508 · BFF del portal |
| Para qué | La pantalla de comprobantes: las operaciones que hizo el usuario en un periodo, de cualquier módulo, tomadas de la bitácora (MS-05), y el recibo de cada una pedido a su módulo dueño, aunque se haya perdido la respuesta. |
| En esta épica | La pantalla de comprobantes de todos los módulos |
| Quién la llama | Entrada Única · Vendor Center (por el BFF) |
| Permiso | El propio usuario; AUDIT-L para ver las de otro |
| Cabeceras | X-Request-Id |
| Parámetros | from = 2026-10-16, to = 2026-10-18, requestId = `` |
Request
null
Response · 200
{
"success": true,
"data": {
"items": [
{
"requestId": "req-55e0c2",
"module": "MS-02",
"at": "2026-10-18T15:04:05Z",
"objects": 1,
"status": "DONE",
"receiptPath": "/api/v2/product-receipts/req-55e0c2"
},
{
"requestId": "req-3f90d1",
"module": "MS-13",
"at": "2026-10-18T15:04:07Z",
"objects": 1,
"status": "DONE",
"receiptPath": "/api/v2/identity-receipts/req-3f90d1"
}
],
"page": 1,
"size": 50,
"total": 2
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | VALIDATION_ERROR | El periodo pasa de 90 días |
GET /api/v2/products/{id}/versions · Lista las versiones completas de un producto (product_versio
| Campo | Valor |
|---|---|
| API | API-02-115 · MS-02 Producto |
| Para qué | Lista las versiones completas de un producto (product_versions) con su número, fecha, usuario, origen, motivo (edición, aprobación, restauración o migración) y la solicitud o ejecución que la creó. |
| En esta épica | Lista de versiones de un producto |
Request
null
Response · 200
{
"success": true,
"data": {
"productId": "PRD-0004812",
"current": 14,
"items": [
{
"version": 14,
"at": "2026-10-16T18:02:11Z",
"actor": {
"userId": "USR-004410",
"role": "PROVEEDOR"
},
"origin": "PORTAL",
"reason": "EDIT",
"requestId": "req-55e0c2",
"jobId": null
},
{
"version": 1,
"at": "2027-02-14T05:00:00Z",
"actor": null,
"origin": "MIGRATION",
"reason": "MIGRATION",
"runId": "run-prd-0003"
}
],
"page": 1,
"size": 50,
"total": 14
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 403 | AUTHORIZATION_ERROR | Quien llama no tiene el permiso o no es el módulo autorizado |
| 404 | NOT_FOUND | No existe lo que se pide o no es visible para quien llama |
GET /api/v2/products/{id}/versions/compare?from=&to=&attributes= · Compara dos versiones cualesquiera de un producto con sus fo
| Campo | Valor |
|---|---|
| API | API-02-116 · MS-02 Producto |
| Para qué | Compara dos versiones cualesquiera de un producto con sus fotos completas y sólo con los atributos elegidos: el valor en cada una, si cambió, y la fecha y el usuario de cada versión. Debe responder en el mismo tiempo con 14 o con 1 versión. |
| En esta épica | Comparar dos versiones de un producto por atributos elegidos |
Request
null
Response · 200
{
"success": true,
"data": {
"productId": "PRD-0004812",
"from": {
"version": 1,
"at": "2027-02-14T05:00:00Z",
"origin": "MIGRATION"
},
"to": {
"version": 12,
"at": "2027-04-02T17:15:00Z",
"actor": {
"userId": "USR-004410",
"role": "PROVEEDOR"
}
},
"attributes": [
{
"attribute": "NOMBRE",
"atFrom": "Licuadora 10 vel",
"atTo": "Licuadora de 10 velocidades",
"changed": true
},
{
"attribute": "MATERIAL",
"atFrom": "Acero inoxidable",
"atTo": "Acero inoxidable",
"changed": false
}
]
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 403 | AUTHORIZATION_ERROR | Quien llama no tiene el permiso o no es el módulo autorizado |
| 404 | NOT_FOUND | No existe lo que se pide o no es visible para quien llama |
POST /api/v2/products/{id}/versions/restore/plans · Prepara la restauración de una versión anterior: dice qué va
| Campo | Valor |
|---|---|
| API | API-02-117 · MS-02 Producto |
| Para qué | Prepara la restauración de una versión anterior: dice qué valores y relaciones vuelven y crea, al confirmar con API-02-057, una versión nueva con esos valores; nunca borra historia ni restaura la vigente. |
| En esta épica | Restaurar una versión anterior del producto |
Request
{
"version": 3,
"currentVersion": 14,
"reason": "El proveedor cambió el material por error"
}
Response · 200
{
"success": true,
"data": {
"planId": "pln-rs1402",
"expiresAt": "2026-10-18T15:14:05Z",
"productId": "PRD-0004812",
"restores": 3,
"createsVersion": 15,
"changes": [
{
"path": "attributes.MATERIAL",
"before": "Acero inoxidable",
"after": "Plástico"
}
],
"applyUrl": "/api/v2/product-plans/pln-rs1402/apply"
}
}
Errores
| HTTP | Código | Cuándo |
|---|---|---|
| 403 | AUTHORIZATION_ERROR | Quien llama no tiene el permiso o no es el módulo autorizado |
| 422 | VALIDATION_ERROR | Falta un dato o viene con un formato inválido; el detalle dice qué campo |
| 409 | IDEMPOTENCY_MISMATCH | Se repite la llave de idempotencia con otro cuerpo |
Las que usa y construye otra épica (6)
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-05-007 | POST /internal/audit/security-events | Registrar los intentos de cambiar o borrar la bitácora | FT-USR-02 · Matriz de roles y permisos por módulo, acción, negocio y… |
| API-13-018 | GET /api/v2/directory/display-names | El nombre visible de cada actor | FT-USR-01 · Identidad y autenticación de usuarios internos… |
| API-01-004 | POST /api/v2/catalog-plans/{planId}/apply | Ejemplo de cambio confirmado en el catálogo | FT-PLT-01 · Fundamentos de gobierno de plantillas |
| API-02-057 | POST /api/v2/product-plans/{planId}/apply | Confirmar la restauración o la reversa | FT-FLU-01 · Motor de estados configurable con dos carreteras y reglas… |
| API-02-403 | POST /api/v2/publications/{jobId}/revert/plans | Preparar la reversa de una corrida, que salta lo que cambió después | FT-INT-07 · Repoblamiento masivo de productos hacia la tienda |
| API-07-001 | GET /api/v2/sap-ingest/files?interface=&state= | Los archivos de SAP de días anteriores | FT-INT-03 · Entrada de SKUs creados en SAP |
6. Eventos
Publica
| Evento | Cuándo | Quién lo consume |
|---|---|---|
catalog.product.changed/PRODUCT_UPDATED | Al restaurar una versión o revertir una corrida, MS-02 publica el cambio con su origen y su ejecución | FT-ACT-05, FT-IA-01, FT-PLT-07, FT-PRD-05, FT-RAC-06 |
Consume
| Evento | Para qué | Quién lo publica |
|---|---|---|
catalog.governance.changed/TEMPLATE_CHANGED | Guardar por campo los cambios de plantillas | FT-IA-04, FT-PLT-01, FT-PLT-05, FT-PLT-06, FT-PLT-09 |
catalog.governance.changed/ATTRIBUTE_CHANGED | Guardar por campo los cambios de atributos | FT-PLT-02, FT-PLT-04, FT-PLT-09 |
catalog.governance.changed/LOV_VALUE_CHANGED | Guardar los cambios de valores de lista | FT-INT-04, FT-PLT-03, FT-PLT-09, FT-REF-01 |
catalog.governance.changed/CATEGORY_UPSERTED | Guardar los cambios de categorías | FT-CAT-01 |
catalog.governance.changed/CATEGORY_MOVED | Guardar los movimientos de rama | FT-CAT-01 |
catalog.product.changed/PRODUCT_UPDATED | Guardar por campo los cambios de producto, con su origen | esta misma épica |
catalog.product.changed/STATUS_CHANGED | Guardar cada transición de estado | FT-CAT-03, FT-CAT-05, FT-FLU-01, FT-FLU-02, FT-FLU-04, FT-FLU-06, FT-FLU-07, FT-INT-03, FT-INT-05, FT-INT-06, FT-INT-07, FT-PRD-02, FT-PRD-03, FT-PRD-04, FT-PRD-05, FT-PRD-06, FT-PRD-07, FT-PRD-09, FT-PRD-10, FT-RAC-01, FT-RAC-02, FT-RAC-03, FT-RAC-05, FT-REF-02 |
catalog.product.changed/TASK_CHANGED | Guardar quién abrió, tomó y cerró cada tarea | FT-ACT-02, FT-ACT-05, FT-ACT-06, FT-CAT-03, FT-CAT-04, FT-CAT-06, FT-FLU-01, FT-FLU-02, FT-FLU-04, FT-FLU-07, FT-IA-04, FT-IA-06, FT-INT-03, FT-INT-07, FT-PRD-02, FT-PRD-03, FT-PRD-04, FT-PRD-05, FT-PRD-06, FT-PRD-07, FT-PRD-08, FT-RAC-01, FT-RAC-02, FT-RAC-03, FT-RAC-04, FT-RAC-05, FT-REF-03 |
catalog.product.changed/EAN_CHANGED | Guardar cada alta y liberación de EAN | FT-FLU-01, FT-INT-04, FT-INT-06, FT-MIG-04, FT-PRD-03, FT-PRD-04, FT-PRD-06, FT-PRD-09 |
catalog.product.changed/SKU_ASSIGNED | Guardar el SKU que asignó SAP con el 122 | FT-INT-03, FT-PRD-02 |
catalog.product.changed/CONFIG_CHANGED | Guardar quién cambió una tabla del motor, incluida la de permisos (ROLE_MATRIX) | FT-FLU-01, FT-FLU-07 |
catalog.delivery.result/DELIVERY_RESULT | Guardar el acuse de cada destino | FT-CAT-02, FT-CAT-05, FT-INT-01, FT-INT-02, FT-INT-05, FT-INT-07, FT-PRD-02 |
catalog.sap.inbound/SAP_MASTER_DATA_CHANGED | Guardar los datos maestros que llegaron de SAP, con SAP como origen | FT-INT-04 |
catalog.governance.changed/ATTRIBUTE_GROUP_CHANGED | Guardar los cambios de grupos de atributos, incluidos los de permiso | FT-PLT-04 |
catalog.asset.changed/ASSET_FROZEN | Guardar el congelado de cada imagen | FT-ACT-02, FT-ACT-03, FT-ACT-04, FT-ACT-06 |
catalog.identity.changed/ROLE_CHANGED | Guardar los cambios de roles | FT-USR-02 |
catalog.ai.result/AI_SUGGESTION_READY | Guardar qué propuso la IA, como origen distinto del de quien corrigió después | FT-IA-01, FT-IA-04 |
7. Datos
Cada colección tiene un solo dueño, el único que escribe en ella.
| Colección | Dueño | Qué guarda | Esta épica |
|---|---|---|---|
audit_events | MS-05 | Quién cambió qué, cuándo, desde dónde, con el antes y el después. | escribe |
product_versions | MS-02 | Foto numerada del producto en cada versión. | escribe |
audit_events | MS-05 | Quién cambió qué, cuándo, desde dónde, con el antes y el después. | lee |
8. Historias que cubre
| Historia | Prioridad | Cómo la cubre |
|---|---|---|
| FT-ARQ-02·H1 · Ver por cada campo cambiado el valor anterior y el nuevo, quién, cuándo y… | P1 | pasos 1, 2, 3, 4, 5, 8, 9, 10, 11; API-05-001, API-05-007 |
| FT-ARQ-02·H2 · Versiones completas del producto y regresar a una anterior | P1 | pasos 12; flujo «Comparar y restaurar una versión»; API-02-115, API-02-117 |
| FT-ARQ-02·H3 · Saber qué productos cambió cada ejecución y revertirla | P1 | flujo «Revertir una ejecución masiva»; API-05-003, API-02-403 |
| FT-ARQ-02·H4 · Revisar propuestas, logs y archivos de integración de días anteriores | P2 | flujo «Revisar una incidencia de días anteriores»; API-07-001, API-BFF-508 |
| FT-ARQ-02·H5 · Saber qué sistema originó cada valor y si lo enriqueció la IA | P2 | pasos 6, 7; flujo «Revisar una incidencia de días anteriores»; API-05-006, API-05-002 |
| FT-ARQ-02·H6 · Comparar dos versiones por atributos elegidos | P2 | flujo «Comparar y restaurar una versión»; API-02-116, API-05-008 |
9. Decisiones de esta épica
Las tomó el TL como arquitecto; quedan como [Propuesta] hasta que el equipo de la épica las revise.
- D-ARQ-02-1. Una sola bitácora: MS-05 consume todos los tópicos catalog. y guarda una entrada por objeto y campo con antes, después, actor, origen, fecha, versión, solicitud y ejecución. Las bitácoras sueltas que se diseñaron por separado (audit_events de plantillas, category_audit_events con vencimiento, audit-log-service) no se construyen aparte. Por qué:* Había tres diseños de bitácora; un solo dueño evita historias que no cuadran entre sí. Se apoya en PD-05, ADR-12, RF-CAL-12.
- D-ARQ-02-2. Inmutable de verdad: no existe ninguna ruta para cambiar ni borrar; la cuenta de MS-05 en la base sólo inserta y lee audit_events y ninguna otra cuenta la toca; un intento por la API responde 405 y queda como evento de seguridad. Sin vencimiento automático. Por qué: La ERF pide bitácora inmutable y la traza de categorías de hoy vence a los 90 días. Se apoya en DUD-27, RF-CAL-12.
- D-ARQ-02-3. La foto completa de cada versión la guarda su dueño, MS-02, en product_versions. Nace versión nueva cuando cambia el usuario, cuando el mismo usuario edita más de 30 minutos después de la última versión, al aprobar y al restaurar. Restaurar crea la versión N+1 con los valores elegidos; no se restaura la vigente y no se borra historia. Por qué: Producto es dueño del producto y de sus versiones; MS-05 guarda la cadena de cambios. El umbral de 30 minutos agrupa una sesión de captura sin perder trabajo de días distintos. Se apoya en DUD-27, RF-CAL-12.
- D-ARQ-02-4. Plantillas, atributos, listas y categorías no tienen fotos: se comparan con la cadena de cambios de MS-05 (API-05-008), con la fecha y el usuario de cada versión; lo que no cambió desde la migración sale «sin dato» si la migración no lo trajo. Los productos se comparan con las fotos de MS-02. Por qué: No se duplica el catálogo en otra colección y la comparación sale de lo que ya se guarda. Se apoya en RF-CAL-12, PD-05.
- D-ARQ-02-5. Todo evento lleva en su cuerpo la solicitud (requestId) y, si vino de un proceso masivo, la ejecución (jobId); MS-05 los indexa para listar qué cambió cada ejecución. Revertir es otra ejecución de MS-02 con su propia vista previa (API-02-403 para las corridas), que salta lo que cambió después. Por qué: Hoy sólo se pudieron revertir 3 días de repoblamiento; sin el jobId en el evento no se sabe qué tocó cada corrida. Se apoya en RF-CAL-13, DEC-90, FT-INT-07.
- D-ARQ-02-6. La bitácora no vence: a los 24 meses se archiva por mes en el almacén con su huella y se consulta en segundo plano, pero nunca se borra. Los archivos de integración (SAP, respuestas de destinos y cargas) se conservan 13 meses, para poder revisar una incidencia de cualquier temporada. Por qué: Las propuestas de días anteriores no se pudieron analizar porque se borraron los archivos; 13 meses cubren una temporada completa más un mes. Se apoya en DUD-27, RF-CAL-13.
- D-ARQ-02-7. La versión 1 de un producto migrado es la foto de la migración, con origen MIGRATION y su corrida; MS-03 carga en MS-05 esa entrada inicial y la historia de estado con su precisión (API-05-006). La historia de valores arranca en cero; se recomienda no migrar las 52 M filas de P360, que no traen antes ni después. Por qué: Así el primer registro de cada producto dice de dónde vino, y la historia migrada sirve para medir tiempos sin inventar valores. Se apoya en PD-18, DEC-ARQ-09, DEC-PRD-06.
- D-ARQ-02-8. MS-05 guarda el ID del actor, su rol y su área, no su nombre; el BFF pone el nombre visible al mostrar la historia (API-13-018), y a proveedores y sellers les muestra el área. El origen de cada valor (portal, carga masiva, API de terceros, SAP, IA, migración) va en cada entrada, así se ve cuando la IA propuso y una persona corrigió. Por qué: El nombre es un dato de MS-13 y puede cambiar; copiarlo en la bitácora lo duplicaría. Se apoya en ADR-12, DEC-65.
Qué falta decidir
| ID | Qué falta |
|---|---|
| PD-18 | Gobierno de Producto con Arquitectura confirma que la versión 1 es la migración y si se migra algo de las bitácoras de P360 (FT-MIG-03). |
| DUD-27 | Arquitectura con Gobierno de Producto ratifica el umbral de versión (30 minutos) y la retención de archivos de integración (13 meses). |
| PD-01 | Confirmar que el versionado con restauración entra en la Fase 1, porque P360 no lo tiene. |
Fuentes
- [D]
trazabilidad/features/FT-ARQ-02-bitacora-inmutable-y-versionado.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.