Especificaciones
K · Eventos y notificaciones
Épica K — Eventos y notificaciones
Estado: Borrador · Última actualización: 2026-08-24 · Índice: README
Cubre la emisión de eventos de dominio como efecto de otros casos de uso, su publicación garantizada hacia notifications.flagare y la notificación en vivo al frontend por SSE. Es un bloque transversal: no deriva de un caso de uso de actor, sino que sirve a todos. Reglas de negocio del bloque: RN-069 a RN-072, más RN-061 en lo que toca al Client.
HU-025 — Emitir eventos de dominio y notificar
Épica: K · Eventos y notificaciones · Deriva de: Transversal · Cubre: RF-117–RF-123 · Reglas: RN-069, RN-070, RN-071, RN-072 · Decisiones: DEC-012, DEC-043, DEC-050 · Estado: Borrador
Historia
Como plataforma, quiero emitir cada hito del proceso como un evento de dominio, publicarlo sin pérdida y reflejarlo en vivo en el frontend, para que el equipo se entere de lo que pasa en el momento en que pasa, sin que la notificación ponga en riesgo la operación que la originó.
Objetivo / valor. Que los cambios relevantes —un caso congelado, un escenario fallido, un bug abierto— se propaguen de forma confiable a notifications.flagare y a la vista del usuario, con entrega garantizada e idempotente, y sin que el Client vea en vivo lo que no le corresponde.
Alcance
- Dentro: el catálogo de eventos de dominio, la emisión como efecto de otras HU, la cola
de salida persistente con reintento, la publicación por API hacia notifications.flagare, la entrega en vivo por SSE con reconexión y recuperación, la autorización del canal y la idempotencia por identificador único.
- Fuera: qué dispara cada evento en particular (eso vive en la HU que lo emite), el
contrato fino del payload y del transporte SSE (documentado, no diseñado; PA-009), y la lógica interna de notifications.flagare.
Actores y permisos (comportamiento del sistema)
- Los eventos los emite el sistema, no un rol; ninguna acción de usuario publica un
evento directamente.
- La suscripción al canal en vivo se autoriza por rol de proyecto: un usuario recibe
solo eventos de proyectos donde tiene rol asignado.
- El rol
Clientnunca se suscribe al canal de eventos, en ninguna circunstancia; su
vista se refresca por consulta (RN-071, DEC-043).
Precondiciones
- Ocurre una operación de negocio que, según su HU, emite un evento del catálogo.
- Para la entrega en vivo: el usuario tiene una sesión autenticada con el JWT de Flagare y
rol asignado en el proyecto del evento.
Comportamiento funcional
- Principal. La operación de negocio que origina el hito **persiste su evento antes de
publicarlo**: el evento entra en una cola de salida persistente con un identificador único. Un despachador lo publica mediante la API de notifications.flagare y, en paralelo, lo entrega por SSE a los suscriptores autorizados del proyecto. El commit de la operación de negocio no depende de que la publicación tenga éxito.
- Alternativo A1 — entrega en vivo. Un usuario con rol en el proyecto abre el canal SSE y
recibe los eventos del proyecto en tiempo real, sin recargar la vista.
- Alternativo A2 — reconexión. Si el canal SSE se cae, el cliente reconecta de forma
automática y el sistema le reentrega los eventos ocurridos durante la desconexión, sin huecos (RN-070).
- Error E1 —
notifications.flagareno responde. El evento permanece en la cola y se
reintenta; la operación de negocio no falla ni se revierte, y ningún evento se pierde (RN-069).
- Error E2 — reintento y duplicados. Un reintento puede reentregar un evento ya recibido;
el identificador único permite al consumidor descartar el duplicado (RN-072). La emisión es idempotente por diseño.
- Error E3 — suscripción de un
Client. El sistema **rechaza el establecimiento de la
suscripción** de un usuario cuyo único rol en el proyecto es Client. La exclusión se aplica al abrir el canal, no filtrando el payload (RN-071, DEC-043).
Datos y campos (funcional, no esquema)
- Del evento: identificador único, tipo de evento (del catálogo de RF-117), proyecto,
artefacto afectado, autor u origen de la operación, timestamp.
- De la cola de salida: estado de publicación (pendiente, publicado, en reintento),
número de reintentos.
- Del canal: usuario suscriptor, proyectos autorizados, punto de recuperación tras
desconexión.
Catálogo de eventos (RF-117, DEC-050)
requirement.ingested,use_case.generated,use_case.frozen,use_case.obsoleted,test_plan.generated,test_plan.approved,test_case.failed,test_case.blocked,bug.created,bug.assigned,bug.ready_for_retest,bug.reopened,blocker.created,blocker.resolved,cycle.completed,quality_report.generated.
El congelamiento —no la validación— es el hito con consecuencias externas: el catálogo usa use_case.frozen en lugar de use_case.approved, y el paso a Validado no emite evento (RN-069, DEC-050). use_case.obsoleted se incluye porque la obsolescencia invalida artefactos derivados.
Reglas de negocio aplicables
- RN-069 — el evento se persiste antes de publicarse; su emisión nunca hace fallar la
operación de negocio ni se pierde por indisponibilidad del consumidor.
- RN-070 — el canal en vivo reconecta solo y recupera los eventos perdidos durante la
desconexión.
se rechaza para el Client, que se refresca por consulta.
- RN-072 — cada evento lleva un identificador único para descartar duplicados de
reintento.
Estados y transiciones. No aplica una máquina de estados de dominio; el único ciclo relevante es el interno del elemento en la cola de salida: Pendiente → Publicado, con En reintento ante fallo del consumidor.
Integraciones (documentado, el dev implementa)
notifications.flagare— recibe los eventos publicados por su API. Qué se toca:
publicación de cada evento del catálogo. El contrato fino (forma del payload, quién expone el SSE, autenticación del canal, comportamiento ante desconexión) se cierra con PA-009; el comportamiento local —cola persistente, reintento, no pérdida— no depende de ella.
- SSE (canal en vivo del frontend) — entrega los eventos en tiempo real a los
suscriptores autorizados, con reconexión y recuperación. Documentado a nivel funcional; el dev lo implementa.
Eventos que emite. Los del catálogo de RF-117; cada uno lo dispara la HU dueña del hito (por ejemplo, bug.created en HU-020, use_case.frozen en HU-010, cycle.completed en HU-022). Esta HU no origina eventos propios: define cómo se emiten, publican y entregan.
Criterios de aceptación
- CA-340
> Dado una operación de negocio que emite un evento de dominio > Cuando la operación se confirma > Entonces el evento se persiste con un identificador único en la cola de salida antes de publicarse, y el commit de la operación no depende de la publicación.
- CA-341
> Dado un evento persistido en la cola y notifications.flagare disponible > Cuando el despachador lo publica > Entonces el evento se entrega por la API de notifications.flagare y queda marcado como publicado.
- CA-342
> Dado un evento persistido y notifications.flagare sin responder > Cuando falla la publicación > Entonces el evento permanece en la cola con reintento, la operación de negocio no se revierte y ningún evento se pierde.
- CA-343
> Dado un reintento que reentrega un evento ya recibido > Cuando el consumidor lo procesa > Entonces el identificador único le permite descartarlo como duplicado.
- CA-344
> Dado un usuario con rol asignado en un proyecto > Cuando abre el canal SSE > Entonces recibe en vivo únicamente los eventos de los proyectos donde tiene rol.
- CA-345
> Dado un canal SSE que se cae durante una sesión activa > Cuando el cliente reconecta > Entonces el sistema reentrega los eventos ocurridos durante la desconexión, sin huecos.
- CA-346
> Dado un usuario cuyo único rol en el proyecto es Client > Cuando intenta establecer la suscripción al canal de eventos en vivo > Entonces el sistema rechaza el establecimiento de la suscripción y su vista se refresca por consulta.
Dependencias y bloqueos
- PA-009 (contrato de
notifications.flagarey del SSE) — condiciona el payload, el
transporte y la autenticación del canal; el comportamiento local —catálogo, cola persistente, reintento, idempotencia, no pérdida— no depende de ella.
común que todas invocan.
Casos borde / notas. La exclusión del Client se aplica al abrir la suscripción, no filtrando el payload de un canal ya abierto: el canal en vivo revelaría por sí mismo que un escenario falló o que se abrió un bug, así que el Client nunca lo abre (RN-071). El paso de un caso de uso a Validado es un trámite interno del equipo y no emite evento; el hito que se propaga es el congelamiento.