---
description: "Task list for feature 004-chat-conversations"
---

# Tasks: Conversaciones múltiples del asistente con contexto

**Input**: Design documents from `/specs/004-chat-conversations/`

**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/chat-conversations-api.md, contracts/chat-stream-sse.md, quickstart.md

**Tests**: Incluidos en fase Polish; spec no exige TDD estricto.

**Organization**: Tareas agrupadas por user story para implementación y prueba incremental independiente.

## Format: `[ID] [P?] [Story] Description`

- **[P]**: Paralelizable (archivos distintos, sin dependencias entre sí)
- **[Story]**: User story de spec.md (US1–US5)
- Rutas concretas en cada descripción

## Phase 1: Setup (Shared Infrastructure)

**Purpose**: Configuración compartida y verificación de feature

- [x] T001 Añadir `max_history_messages` y `conversation.title_max` en `config/agent.php` según plan.md (FR-006, FR-012)
- [x] T002 [P] Documentar `AGENT_MAX_HISTORY_MESSAGES` y `AGENT_CONVERSATION_TITLE_MAX` en `specs/004-chat-conversations/quickstart.md`
- [x] T003 [P] Verificar feature pointer en `.specify/feature.json` apunta a `specs/004-chat-conversations`

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Modelo de datos, servicios base y migración — **bloquea todas las user stories**

**⚠️ CRITICAL**: Ninguna user story puede completarse hasta terminar esta fase

- [x] T004 Crear migración `database/migrations/*_create_chat_conversations_table.php` (`user_id`, `title`, timestamps, índice `user_id+updated_at`)
- [x] T005 Crear migración `database/migrations/*_add_conversation_id_to_chat_messages.php` (columna nullable + FK, sin drop `session_id` aún)
- [x] T006 Crear modelo `app/Models/ChatConversation.php` con relación `messages()` y `user()`
- [x] T007 Actualizar `app/Models/ChatMessage.php`: `conversation_id` fillable, `scopeForConversation()`, relación `conversation()`; deprecar `scopeForSession`
- [x] T008 Implementar `app/Services/Chat/ConversationQueryService.php` (`listForUser`, `create`, `findOwnedOrFail`, `deleteOwned`, `touchUpdatedAt`)
- [x] T009 Implementar `app/Services/Chat/ConversationHistoryService.php` (`recentMessages`, `toLlmMessageArray`, ventana 24 mensajes)
- [x] T010 Crear comando `app/Console/Commands/MigrateLegacyChatSessionsCommand.php` (`chat:migrate-legacy-sessions`, idempotente, FR-007)
- [x] T011 Migración final: `conversation_id` NOT NULL, DROP `session_id`, CASCADE delete mensajes al borrar conversación
- [x] T012 [P] Añadir tipos `ConversationSummary`, `ConversationsListResponse`, `ConversationMessagesResponse`, `CreateConversationResponse` en `ChatFront/src/app/core/models/api.types.ts`

**Checkpoint**: Esquema BD + servicios de consulta/historial listos

---

## Phase 3: User Story 1 — Varias conversaciones por usuario (Priority: P1) 🎯 MVP

**Goal**: Operador crea, lista y cambia entre hilos independientes; mensajes persistidos por `conversation_id`

**Independent Test**: Crear 2 conversaciones, enviar mensajes distintos, alternar en UI y ver historial correcto en cada una (SC-001)

### Implementation for User Story 1

- [x] T013 [US1] Añadir `index()` y `store()` en `app/Http/Controllers/Api/V1/ChatController.php` delegando en `ConversationQueryService` (FR-003, FR-004)
- [x] T014 [US1] Añadir `messages(int $conversationId)` en `ChatController` → mensajes ordenados de conversación owned (FR-002)
- [x] T015 [US1] Registrar `GET/POST /chat/conversations` y `GET /chat/conversations/{id}/messages` en `routes/api.php` con `auth:api`
- [x] T016 [US1] Refactorizar `app/Services/ChatConversationService.php`: reemplazar `sessionIdForUser()` por `conversation_id`; `listMessages(ChatConversation $conv)`
- [x] T017 [US1] Auto-crear conversación en `sendMessage` si el cliente envía a id inexistente o primer mensaje sin hilo (edge case spec US1 escenario 1)
- [x] T018 [US1] Actualizar título automático en primer mensaje user vía `ConversationQueryService` + `Str::limit` (FR-012)
- [x] T019 [P] [US1] Implementar `listConversations()`, `createConversation()`, `getConversationMessages()` en `ChatFront/src/app/core/services/chat-api.service.ts`
- [x] T020 [US1] Crear `ChatFront/src/app/features/conversation/conversation-sidebar.component.ts` (+ template/scss): lista títulos, fecha, conversación activa
- [x] T021 [US1] Integrar sidebar y `activeConversationId` signal en `ChatFront/src/app/features/conversation/conversation.component.ts` y `.html`
- [x] T022 [US1] Botón «Nueva conversación» → `POST /chat/conversations` (no borrar hilos previos) en `conversation.component.ts` (FR-003)

**Checkpoint**: MVP multi-hilo — usuario alterna conversaciones con historiales separados

---

## Phase 4: User Story 2 — Preservar contexto en seguimientos (Priority: P1)

**Goal**: Clasificador, chat general y consultas BD reciben historial de la conversación activa

**Independent Test**: Misma conversación: pregunta de datos + seguimiento «¿y cuántos contratos?» coherente; otra conversación no hereda contexto (SC-002, FR-005)

### Implementation for User Story 2

- [x] T023 [US2] Refactorizar `app/Services/OpenAiChatService.php` para usar `ConversationHistoryService` por `conversation_id` (eliminar `forSession`)
- [x] T024 [US2] Ampliar `app/Services/Agent/IntentClassifierService.php` con historial reciente antes del mensaje actual (FR-006)
- [x] T025 [US2] Renombrar parámetro `sessionId` → `conversationId` en `app/Services/Agent/AgentOrchestratorService.php` (`handle` + `handleStreaming`)
- [x] T026 [US2] Actualizar `app/Services/Agent/Handlers/GeneralChatCapabilityHandler.php` para pasar `conversationId` a `OpenAiChatService`
- [x] T027 [US2] Incluir historial en turno 1 y turno 2 de `app/Services/Agent/Handlers/AgentDatabaseQueryCapabilityHandler.php` (`handle`, `interpretResultsAndRespond`)
- [x] T028 [US2] Persistir `meta` con `capability` + `query` en mensaje assistant post-consulta BD en `AgentDatabaseQueryCapabilityHandler` / `ChatConversationService` (FR-013)

**Checkpoint**: Seguimientos dentro del mismo hilo usan contexto LLM

---

## Phase 5: User Story 3 — Retomar conversaciones al volver (Priority: P2)

**Goal**: Recarga de `/assistant` restaura conversación activa y listado completo

**Independent Test**: Tras mensajes en un hilo, recargar página → mismo historial visible (SC-003)

### Implementation for User Story 3

- [x] T029 [US3] Persistir `assistant_active_conversation_id` en `sessionStorage` al cambiar conversación en `conversation.component.ts` (FR-010)
- [x] T030 [US3] En `ngOnInit`: restaurar id de `sessionStorage` o fallback a conversación más reciente por `updated_at` en `conversation.component.ts`
- [x] T031 [US3] Tras envío exitoso, refrescar listado sidebar (`updated_at`, título) sin perder conversación activa en `conversation.component.ts`

**Checkpoint**: Sesión UI sobrevive recarga

---

## Phase 6: User Story 4 — Eliminar una conversación concreta (Priority: P2)

**Goal**: Borrado granular sin afectar otros hilos; 404 para conversaciones ajenas

**Independent Test**: 3 conversaciones → eliminar 1 → las otras 2 intactas (FR-008, SC-004)

### Implementation for User Story 4

- [x] T032 [US4] Añadir `destroy(int $conversationId)` en `ChatController` → `ConversationQueryService::deleteOwned()` (FR-008, FR-009)
- [x] T033 [US4] Registrar `DELETE /chat/conversations/{id}` en `routes/api.php`
- [x] T034 [P] [US4] Implementar `deleteConversation(id)` en `ChatFront/src/app/core/services/chat-api.service.ts`
- [x] T035 [US4] UI eliminar conversación con confirmación (PrimeNG ConfirmDialog o equivalente) en sidebar/`conversation.component.ts`
- [x] T036 [US4] Tras borrar conversación activa: seleccionar siguiente disponible o estado vacío + `POST` nueva en `conversation.component.ts`

**Checkpoint**: Gestión de hilos completa (crear, listar, cambiar, borrar)

---

## Phase 7: User Story 5 — Compatibilidad streaming y adjuntos (Priority: P2)

**Goal**: Mensajes texto/adjunto scoped a `conversation_id`; sin regresión streaming 003

**Independent Test**: Stream + adjunto en misma conversación; bloqueo cambio de hilo durante stream (SC-005, FR-011)

### Implementation for User Story 5

- [x] T037 [US5] Añadir `message(int $conversationId, ChatConversationRequest)` en `ChatController` (sync multipart) en `app/Http/Controllers/Api/V1/ChatController.php`
- [x] T038 [US5] Añadir `messageStream(int $conversationId, ChatStreamMessageRequest)` scoped a conversación owned
- [x] T039 [US5] Refactorizar `app/Services/ChatConversationStreamService.php`: `conversation_id`, persistir user **después** de `handleStreaming` (fix duplicado historial plan.md)
- [x] T040 [US5] Registrar `POST /chat/conversations/{id}/message` y `.../message/stream` en `routes/api.php`; marcar rutas legacy deprecadas
- [x] T041 [US5] Proxy legacy `GET/DELETE /chat/conversation` → conversación más reciente en `ChatController` (research R7)
- [x] T042 [P] [US5] Actualizar `sendConversationMessage()` y `streamConversationMessage(conversationId, ...)` en `ChatFront/src/app/core/services/chat-api.service.ts`
- [x] T043 [US5] Pasar `activeConversationId` en `send()` / `sendSyncMessage()` en `conversation.component.ts`
- [x] T044 [US5] Deshabilitar cambio de conversación y sidebar durante `streaming()` o `sending()` en `conversation.component.ts` (US5 escenario 3)

**Checkpoint**: Flujos 003 integrados con multi-conversación

---

## Phase 8: Polish & Cross-Cutting Concerns

**Purpose**: Tests, migración, calidad, validación quickstart

- [x] T045 [P] Feature test `tests/Feature/Chat/ChatConversationsTest.php`: CRUD, ownership 404, listado ordenado
- [x] T046 [P] Unit test `tests/Unit/Services/Chat/ConversationHistoryServiceTest.php`: límite 24, formato LLM, exclusión duplicado
- [x] T047 [P] Feature test `tests/Feature/Chat/ConversationMigrationTest.php`: backfill `api-user-{id}` → conversación
- [x] T048 Actualizar `tests/Feature/Chat/ChatConversationStreamTest.php` para usar `conversation_id`
- [x] T049 Ejecutar `vendor/bin/pint --dirty` en archivos PHP tocados
- [x] T050 Ejecutar `php artisan test --filter=ChatConversation` y `php artisan test --filter=ConversationHistory` y corregir fallos
- [x] T051 Ejecutar `ng build` en `ChatFront/` sin errores
- [x] T052 Validar escenarios manuales de `specs/004-chat-conversations/quickstart.md` (SC-001 a SC-006)

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: Sin dependencias
- **Foundational (Phase 2)**: Depende de Setup — **BLOQUEA** US1–US5
- **US1 (Phase 3)**: Depende de Phase 2 — MVP multi-hilo
- **US2 (Phase 4)**: Depende de US1 (endpoints + `conversation_id` en mensajes)
- **US3 (Phase 5)**: Depende de US1 (sidebar + listado); puede paralelizarse con US2 tras US1
- **US4 (Phase 6)**: Depende de US1 (listado/conversaciones existentes)
- **US5 (Phase 7)**: Depende de US1 + US2 (orquestador con conversationId); integra stream/adjuntos
- **Polish (Phase 8)**: Depende de US1–US5 deseados

### User Story Dependencies

| Story | Depende de | Notas |
|-------|------------|-------|
| US1 | Phase 2 | Independiente de US2–US5 para probar multi-hilo |
| US2 | US1 | Contexto requiere mensajes por conversación |
| US3 | US1 | Solo frontend persistencia activa |
| US4 | US1 | DELETE sobre recursos US1 |
| US5 | US1, US2 | Stream usa conversationId + historial |

### Parallel Opportunities

**Phase 2** (tras T008–T009 secuenciales):

```text
T012 api.types.ts ∥ T010 MigrateLegacyChatSessionsCommand (tras T005)
```

**Phase 3** (tras T015 backend):

```text
T019 chat-api.service.ts ∥ T020 conversation-sidebar.component
```

**Phase 8**:

```text
T045 ChatConversationsTest.php ∥ T046 ConversationHistoryServiceTest.php ∥ T047 ConversationMigrationTest.php
```

---

## Parallel Example: User Story 1

```bash
# Tras T015 (rutas registradas):
# T019 — ChatFront/src/app/core/services/chat-api.service.ts
# T020 — conversation-sidebar.component.ts

# Secuencial backend US1 recomendado:
# T013 → T014 → T015 → T016 → T017 → T018 → T021 → T022
```

---

## Implementation Strategy

### MVP First (User Story 1)

1. Phase 1 + Phase 2 (fundación + migración)
2. Phase 3 (US1): listar, crear, cambiar conversaciones
3. **STOP and VALIDATE**: quickstart «multiple conversations» (SC-001)
4. Demo: dos hilos con historiales distintos

### Incremental Delivery

1. US1 → multi-hilo (MVP)
2. US2 → contexto en seguimientos (valor principal del feature)
3. US3 + US4 → persistencia UI + borrado granular
4. US5 → stream/adjuntos con `conversation_id`
5. Polish → tests + migración + UAT

### Suggested MVP Scope

**Phase 1 + 2 + 3 (T001–T022)** entrega SC-001 sin contexto LLM completo. Completar **Phase 4 (US2)** para SC-002 y requisito principal del usuario.

---

## Notes

- Total tasks: **52**
- US1: **10** tasks (T013–T022)
- US2: **6** tasks (T023–T028)
- US3: **3** tasks (T029–T031)
- US4: **5** tasks (T032–T036)
- US5: **8** tasks (T037–T044)
- Setup: **3** | Foundational: **9** | Polish: **8**
- Contratos: `specs/004-chat-conversations/contracts/chat-conversations-api.md`, `chat-stream-sse.md`
- Ejecutar `php artisan chat:migrate-legacy-sessions` tras T010 en entornos con datos existentes
