# Feature Specification: Streaming híbrido en chat de conversación

**Feature Branch**: `003-chat-streaming`

**Created**: 2026-05-24

**Status**: Draft

**Input**: User description: "Implementar streaming para mi chat — streaming híbrido: eventos de estado durante el procesamiento y respuesta del asistente apareciendo progresivamente. Solo mensajes de texto; adjuntos mantienen flujo síncrono actual."

> **Constitution (I. Spec-First)**: Este spec MUST ser agnóstico de stack.
> No mencionar Laravel, Angular ni rutas de código. El CÓMO va en `plan.md`.

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Ver progreso mientras el asistente trabaja (Priority: P1)

Como operador en la pantalla de conversación del asistente, quiero ver indicaciones de qué está haciendo el asistente (por ejemplo, «Analizando tu pregunta…», «Consultando datos…») para saber que el sistema sigue activo y no está colgado.

**Why this priority**: Las preguntas que requieren consulta de datos pueden tardar varios segundos antes de generar texto; sin feedback intermedio el usuario interpreta que la aplicación falló.

**Independent Test**: Enviar una pregunta que requiera consulta de datos comerciales; la interfaz muestra al menos un cambio de estado antes del primer fragmento de respuesta.

**Acceptance Scenarios**:

1. **Given** un mensaje de texto enviado, **When** el sistema procesa la solicitud, **Then** el usuario ve actualizaciones de estado legibles en español antes de recibir contenido de respuesta.
2. **Given** un procesamiento en curso, **When** transcurren más de 3 segundos sin texto final, **Then** el indicador de estado sigue visible (no pantalla en blanco).
3. **Given** un error durante el procesamiento, **When** falla el stream, **Then** el usuario ve un mensaje de error claro y puede reintentar.

---

### User Story 2 - Respuesta apareciendo progresivamente (Priority: P1)

Como operador, quiero que la respuesta del asistente aparezca fragmento a fragmento (como en asistentes conversacionales modernos) para leer mientras se genera y percibir menor latencia.

**Why this priority**: Es el beneficio principal del streaming: reducir la sensación de espera bloqueante respecto al modelo actual de «pensando…» hasta respuesta completa.

**Independent Test**: Enviar un mensaje de chat general; el bubble del asistente se rellena incrementalmente sin esperar al texto completo.

**Acceptance Scenarios**:

1. **Given** una respuesta del asistente en generación, **When** llegan fragmentos de texto, **Then** se muestran en orden en el bubble del asistente.
2. **Given** un stream completado, **When** termina el evento final, **Then** el mensaje queda persistido en el historial de conversación igual que en el flujo actual.
3. **Given** un usuario que recarga la pantalla de conversación, **When** abre el hilo, **Then** ve el mensaje completo ya guardado (no un stream parcial).

---

### User Story 3 - Compatibilidad con adjuntos (Priority: P2)

Como operador que adjunta PDF o JPG, quiero que el envío con archivo siga funcionando como ahora (respuesta al completar) sin romper el flujo existente.

**Why this priority**: El procesamiento de adjuntos implica extracción y análisis de documentos; queda fuera del alcance del streaming en esta versión pero no debe regresionar.

**Independent Test**: Enviar mensaje con adjunto; la respuesta aparece al finalizar usando el flujo no-streaming actual.

**Acceptance Scenarios**:

1. **Given** un mensaje con adjunto, **When** lo envío, **Then** se usa el flujo síncrono existente y la respuesta aparece al finalizar el procesamiento.
2. **Given** un envío con adjunto en curso, **When** intento enviar otro mensaje, **Then** la interfaz impide envíos concurrentes hasta completar el actual.

---

### Edge Cases

- Conexión interrumpida a mitad del stream: el usuario ve error visible; el historial no queda corrupto con mensajes assistant incompletos persistidos.
- Usuario intenta enviar un segundo mensaje mientras hay stream activo: bloqueado hasta completar o cancelar el stream en curso.
- Respuesta vacía del modelo: mensaje de error amigable; no queda un bubble vacío permanente.
- Sesión expirada durante el stream: el usuario es informado o redirigido al login de forma coherente con el comportamiento actual de autenticación.
- Respuestas con tablas o formato enriquecido: contenido legible al completar el mensaje; durante el stream puede mostrarse texto plano si el renderizado progresivo no está disponible en v1.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: El sistema MUST ofrecer un canal de respuesta en streaming para mensajes de texto en la conversación del asistente.
- **FR-002**: El canal MUST emitir eventos de **estado** con mensajes orientados al usuario durante fases de procesamiento (interpretación, consulta de datos, generación de respuesta).
- **FR-003**: El canal MUST emitir **fragmentos de texto** de la respuesta del asistente en orden hasta completar el mensaje.
- **FR-004**: Al finalizar correctamente, el sistema MUST persistir el mensaje completo del asistente en el historial de conversación del usuario autenticado.
- **FR-005**: El sistema MUST requerir autenticación equivalente al endpoint de mensaje actual para el canal streaming.
- **FR-006**: Los envíos con adjunto (PDF/JPG) MUST continuar usando el flujo síncrono existente sin regresiones.
- **FR-007**: La interfaz MUST mostrar el bubble del asistente durante el stream, sustituyendo el indicador estático «El asistente está pensando…» por contenido o estado dinámico.
- **FR-008**: El sistema MUST manejar errores de stream con mensajes comprensibles en español, sin exponer detalles técnicos internos.
- **FR-009**: El historial cargado al abrir la conversación MUST seguir mostrando mensajes completos en orden cronológico.
- **FR-010**: El usuario MUST poder iniciar una nueva conversación (borrar hilo) con el mismo comportamiento que hoy, incluso tras usar streaming.

### Key Entities

- **StreamEvent**: unidad de progreso emitida durante el procesamiento; tipos conceptuales: estado, fragmento de texto, finalización, error. Contiene el payload mínimo necesario para actualizar la interfaz.
- **ConversationMessage**: mensaje persistido (usuario o asistente) con contenido final completo, rol y metadatos de sesión.
- **ChatSession**: hilo de conversación asociado a un usuario autenticado; agrupa mensajes en orden cronológico.

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: En el 90% de mensajes de texto de prueba, el usuario ve el **primer feedback visible** (estado o texto) en **menos de 2 segundos** desde enviar el mensaje.
- **SC-002**: En pruebas con preguntas que requieren consulta de datos, los evaluadores reportan que el chat **no parece colgado** respecto al comportamiento baseline (validación cualitativa en UAT).
- **SC-003**: El 100% de streams completados exitosamente dejan el mensaje del asistente persistido e idéntico al contenido mostrado al cerrar el stream.
- **SC-004**: Cero regresiones en el flujo con adjuntos según los criterios de aceptación de User Story 3.
- **SC-005**: En escenarios de error simulados (timeout o desconexión), el 100% de casos muestran mensaje de error y permiten reintentar sin duplicar mensajes de usuario en el historial.

## Assumptions

- El alcance v1 se limita a la pantalla de conversación del asistente; otras vistas de chat (por ejemplo, extracción de PDF) quedan fuera de alcance.
- El proveedor de IA configurado soporta generación incremental de texto; los detalles de integración se documentan en `plan.md`.
- Se mantiene un endpoint síncrono de mensaje como respaldo y para envíos con adjunto.
- Durante el stream el contenido puede mostrarse como texto plano; el renderizado de formato enriquecido (tablas, listas) puede aplicarse al completar el mensaje en v1.
- Los usuarios tienen conectividad estable; reconexión automática mid-stream queda fuera de alcance v1.
