# Implementation Plan: Agent DB — Clientes y contratos

**Branch**: `002-agent-db-clients-contracts` | **Date**: 2026-05-24 | **Spec**: [spec.md](./spec.md)

**Input**: Feature specification from `/specs/002-agent-db-clients-contracts/spec.md`

## Summary

Extender la capacidad `agent_database` del asistente para que operadores autenticados consulten **clientes**, **contactos** y **propuestas comerciales (contratos)** en la BD operativa secundaria, usando únicamente herramientas preaprobadas. Las consultas se implementan con **Eloquent y relaciones de modelos** portados desde `desarrolloeneon`, no con SQL ad hoc en config. El LLM elige herramienta + parámetros; un servicio de dominio ejecuta la consulta y el LLM interpreta resultados en español sin inventar datos.

## Technical Context

**Language/Version**: PHP 8.2+, Laravel 12  
**Primary Dependencies**: Eloquent (conexión `agent_db_secondary`), `AgentDatabaseQueryCapabilityHandler`, `LlmChatCompletionContract`  
**Storage**: BD secundaria — tablas `T_Cliente`, `T_ContactoCliente`, `T_ContactoDetalleCliente`, `T_PropuestaComercial`, `T_Propuesta_Comercial_Clientes`, `T_Propuesta_Comercial_CUPs`, `T_Contrato`  
**Testing**: PHPUnit (`php artisan test --filter=AgentCommercial`)  
**Target Platform**: API Laravel existente; sin cambios en Angular  
**Project Type**: Extensión backend del orquestador de agente (brownfield)  
**Performance Goals**: Respuesta end-to-end < 30 s en local (SC-003)  
**Constraints**: Solo lectura (FR-009); máx. 50 filas por herramienta (FR-012); `TipProCom` 2 y 3 únicamente  
**Scale/Scope**: 7 modelos comerciales, 7 herramientas P1, refactor de 3 herramientas legacy  

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

| Principle | Status | Notes |
|-----------|--------|-------|
| **I. Spec-First** | ✅ | Trazado a FR-001–FR-014, US1–US4 |
| **II. Skinny Controllers** | ✅ | Sin cambios en controladores; lógica en `AgentCommercialQueryService` |
| **III. Contratos IA** | ✅ | Handler existente + `LlmChatCompletionContract`; sin acoplar proveedor |
| **IV. API v1** | ✅ | Reutiliza `POST /api/v1/chat/message`; errores runtime documentados en contrato herramientas |
| **V. Contrato API** | ✅ N/A | Feature backend-only; contrato = catálogo herramientas en `contracts/agent-database-tools.md` |
| **VI. Frontend desacoplado** | ✅ N/A | Sin cambios en `ChatFront/` |
| **VII. Fidelidad al dato** | ✅ | FR-007/FR-008: respuestas solo desde resultados de consulta |
| **VIII. Simplicidad** | ✅ | Un servicio de consulta; modelos planos sin tenant stack |

**Post-design re-check**: ✅ Todos los gates pasan. Sin entradas en Complexity Tracking.

## Project Structure

### Documentation (this feature)

```text
specs/002-agent-db-clients-contracts/
├── spec.md
├── plan.md                          # Este archivo
├── research.md                      # Phase 0
├── data-model.md                    # Phase 1
├── quickstart.md                    # Phase 1
├── contracts/
│   └── agent-database-tools.md      # Catálogo herramientas agent_database
├── checklists/
│   └── requirements.md
└── tasks.md                         # (/speckit-tasks — pendiente)
```

### Source Code (cambios previstos)

```text
app/
├── Models/Commercial/
│   ├── Cliente.php
│   ├── Contacto.php
│   ├── ContactoDetalleCliente.php
│   ├── PropuestaComercial.php
│   ├── PropuestaComercialCliente.php
│   ├── PropuestaComercialCups.php
│   └── Contrato.php
├── Services/Agent/
│   ├── AgentCommercialQueryService.php   # NUEVO — ejecución Eloquent por herramienta
│   ├── DatabaseSchemaService.php         # Sin cambio funcional (catálogo desde config)
│   └── Handlers/
│       └── AgentDatabaseQueryCapabilityHandler.php  # Refactor: delegar a servicio
config/
└── agent.php                             # Metadatos herramientas; quitar SQL crudo
tests/
└── Feature/Agent/
    └── AgentCommercialQueryServiceTest.php
```

**Structure Decision**: Feature exclusivamente backend. Los modelos comerciales viven en `app/Models/Commercial/` con `$connection = 'agent_db_secondary'`, sin trait `BelongsToTenant` (R5 en research.md).

## Architecture

```mermaid
sequenceDiagram
    participant U as Operador
    participant C as ChatController
    participant O as AgentOrchestrator
    participant H as AgentDatabaseQueryCapabilityHandler
    participant S as AgentCommercialQueryService
    participant DB as agent_db_secondary
    participant L as LLM

    U->>C: POST /chat/message
    C->>O: handle(message)
    O->>H: capability agent_database
    H->>L: turn 1 — elegir herramienta
    L-->>H: {query_name, parameters}
    H->>S: execute(query_name, params)
    S->>DB: Eloquent (PropuestaComercial, Cliente, ...)
    DB-->>S: rows (max 50)
    S-->>H: JSON rows
    H->>L: turn 2 — interpretar resultados
    L-->>H: respuesta natural ES
    H-->>U: mensaje chat
```

## Implementation Phases (for /speckit-tasks)

### Phase A — Modelos comerciales (prerequisito)

1. Portar 7 modelos desde `desarrolloeneon/app/Models/` a `app/Models/Commercial/`
2. Omitir `BelongsToTenant` y global scopes de tenant
3. Fijar `$connection = 'agent_db_secondary'`, PKs y `$table` según origen
4. Conservar relaciones: `PropuestaComercial` ↔ `PropuestaComercialCliente` ↔ titular/CUPs

**FR**: FR-013, FR-004, FR-005, FR-014

### Phase B — Servicio de consultas

1. Crear `AgentCommercialQueryService` con un método por herramienta (ver contrato)
2. Implementar resolución titular por `TipProCom` (2 → Cliente, 3 → Contacto)
3. Aplicar límite `max_results` y truncado con flag `truncated: true`
4. Validar parámetros (termino max 120 chars, IDs numéricos)

**FR**: FR-002, FR-003, FR-005, FR-006, FR-012

### Phase C — Handler y config

1. Refactorizar `AgentDatabaseQueryCapabilityHandler::executeQuery` → delegar en servicio
2. Actualizar `config/agent.php`: metadatos (description, parameters) sin clave `query` SQL
3. Añadir herramientas nuevas; alias `buscar_representantes_contactos` → `buscar_contactos`
4. Deprecar o redirigir `listar_clientes` (alto volumen; preferir búsqueda acotada)
5. Invalidar cache `agent_database_queries_catalog` al cambiar config

**FR**: FR-002, FR-011

### Phase D — Tests y verificación

1. Tests PHPUnit con SQLite/MySQL fixture o mocks de query builder
2. Casos: TipProCom 2/3, sin resultados, params inválidos, límite filas
3. Manual: escenarios US fence de quickstart.md

**FR**: SC-001, SC-002, SC-004, SC-005

## Tool Catalog (summary)

Detalle completo en [contracts/agent-database-tools.md](./contracts/agent-database-tools.md).

| Tool | Priority | User Story |
|------|----------|------------|
| `buscar_clientes` | P1 | US1 |
| `buscar_contactos` | P1 | US1 |
| `listar_propuestas_por_cliente` | P1 | US1 |
| `listar_propuestas_por_contacto` | P1 | US1 |
| `detalle_propuesta` | P1 | US2 |
| `listar_cups_propuesta` | P2 | US3 |
| `detalle_formalizacion` | P2 | US2 |

## Phase 0 / Research

Ver [research.md](./research.md) — todas las NEEDS CLARIFICATION resueltas.

## Phase 1 / Design

- Entidades y relaciones: [data-model.md](./data-model.md)
- Contrato herramientas: [contracts/agent-database-tools.md](./contracts/agent-database-tools.md)
- Pruebas manuales: [quickstart.md](./quickstart.md)

## Complexity Tracking

> Sin violaciones de constitución que requieran justificación.

## Next Steps

1. `/speckit-tasks` → generar `tasks.md` ordenado por dependencias
2. `/speckit-implement` → portar modelos, servicio, refactor handler, tests
