Traducción. Autoritativo:Estado: RECONSTRUCCIÓN PROPUESTA · Convive con../../slices/create-initiative.md. ⚠️ Reconstruido para validar, no recuperado. El slice original no está en este repositorio, pero cada task spec declara un arquetipo y la mitad declara este, así que los agentes necesitan que exista. Etiquetas: [derived] tiene respaldo en los estándares y ADRs que tenemos · [inferred] es deducido · [proposed] es un hueco llenado con criterio. La forma está bien evidenciada —standards/api.md, ADR-017 y el slicetrackEventla describen desde afuera. Lo genuinamente incierto es la disposición de archivos y los nombres, porque todavía no existe código de aplicación al que apuntar.
track-event.md (arquetipo de
pipeline asíncrono). Cada task spec declara cuál sigue (DEC-I5).
Para qué sirve este arquetipo
Un comando síncrono: llega un request, el sistema valida, cambia estado y responde con el resultado. El llamador espera, y la respuesta es autoritativa — a diferencia del pipeline asíncrono, donde la respuesta es “recibido” y el trabajo ocurre detrás de una cola. Se usa cuando el llamador necesita saber el resultado antes de seguir: crear un registro, publicar una regla, canjear puntos en un mostrador. Se usatrackEvent en cambio cuando al llamador solo le basta
saber que el sistema aceptó la entrada.
La mayor parte de la plataforma es este arquetipo. Es el default, y el pipeline es la excepción.
Las seis capas
1. Ruta — backend/api [derived]
- Autenticar — sesión, API key o token de member.
- Autorizar — exactamente un permiso declarado,
{module}.{resource}.{action}(R16). - Validar — un esquema Zod sobre el cuerpo, produciendo un comando tipado.
- Resolver contexto — tenant, programa u organización, según cómo acote el módulo.
- Llamar al command handler, y mapear su resultado o error tipado a la respuesta.
2. Command handler — la capa de aplicación del módulo [derived]
El handler es donde vive la transacción. Es el único lugar del arquetipo que abre una, y abre exactamente una (R12).makeDeps(ctx). Un handler que importa un SDK de vendor es un defecto.
3. Dominio [derived]
Funciones puras y servicios de dominio: invariantes, transiciones de estado, cálculos. Sin I/O, sin conocimiento de Drizzle, sin conocimiento de HTTP. Esta es la capa donde vale la pena ser estricto. Todo lo de arriba es plomería que se puede regenerar; las reglas de acá son el producto. [inferred]4. Persistencia — database/postgres por un repositorio [inferred]
Drizzle dentro de la transacción. Toda escritura lleva tenant_id y cell_id (R6), llega a la base
por getDb(tenantCtx) (R8), y obedece el estándar de datos — códigos paramétricos en vez de enums,
montos con su moneda.
(La indirección por repositorio es [inferred]. R8 exige getDb(tenantCtx), que igual se podría
llamar desde el handler directamente. Propuse un repositorio porque mantiene el handler testeable sin
base de datos, pero es un punto donde el original puede diferir.)
5. Outbox y auditoría — misma transacción [derived]
No negociable y la razón por la que existe la transacción:- Uno o más eventos de dominio escritos en el outbox (R13), nunca publicados directamente.
- Una fila de
core.audit_logcon actor tipado, el diff completo old→new, y elcorrelation_idheredado del request (R15).
6. Respuesta [derived]
El recurso creado o actualizado, o un error tipado como RFC 9457problem+json con un code estable.
El handler devuelve un tipo resultado; la ruta lo mapea. Un handler que formatea HTTP es un handler
que no se puede llamar desde un worker.
Qué copian los agentes de acá
- La ruta de cinco pasos y la disciplina de que no contiene lógica de negocio.
- Una transacción por comando, abierta en el handler y en ningún otro lugar.
- Outbox y auditoría dentro de ella, siempre, con el correlation id atravesándola.
- Puertos por
makeDeps, nunca un import de vendor. - Errores tipados en vez de strings lanzados, para que la ruta los mapee sin inspeccionar mensajes.
- La capa de dominio se mantiene pura, que es lo que hace los tests lo bastante rápidos como para que la gente los escriba.
Tests que exige el arquetipo [inferred]
En qué difiere de trackEvent
Copiar este arquetipo dentro de un pipeline produce una ruta que hace trabajo pesado en línea y revienta
el presupuesto de ingesta. Copiar el pipeline dentro de un comando produce un llamador que nunca se
entera de si su acción tuvo éxito. Ambos son errores que bloquean la revisión, y por eso cada task spec
declara su arquetipo.
Lo que hay que validar
- La disposición de archivos y los nombres. Ruta → handler → dominio → repositorio es la forma que inferí; el original puede nombrarlas o anidarlas distinto. [inferred]
- Si existe una indirección por repositorio o los handlers llaman a
getDbdirectamente. [inferred] - El nombre. “Initiative” sugiere el dominio del módulo Tracker, lo que significa que el slice original probablemente vive en un módulo que este repositorio no contiene. Si es así, esta reconstrucción debería eventualmente reemplazarse por el real y no quedar al lado. [proposed]