# Research: Agent DB — Clientes y contratos (PropuestaComercial)

**Feature**: `002-agent-db-clients-contracts` | **Date**: 2026-05-24

## R1 — Fuente de verdad para joins

**Decision**: Portar modelos Eloquent desde `desarrolloeneon/app/Models/` a `ia_agent/app/Models/Commercial/` y usar **Eloquent Query Builder** como fuente de verdad para consultas del agente.

**Rationale**: La spec (FR-013) y clarificaciones exigen relaciones de modelos, no SQL ad hoc. Los modelos en `desarrolloeneon` ya definen `PropuestaComercial`, titulares (`Cliente`/`Contacto`) y CUPs.

**Alternatives considered**:
- Mantener SQL crudo en `config/agent.php` — rechazado (desalineado con spec).
- Text-to-SQL libre del LLM — rechazado (FR-002).

## R2 — Entidad «contrato»

**Decision**: **`PropuestaComercial` (`T_PropuestaComercial`)** es el contrato en dominio de negocio. `T_Contrato` es formalización opcional (`Contrato` model).

**Rationale**: Aclaración de producto 2026-05-24. Campos contractuales principales: `TipProCom`, `EstProCom`, `RefProCom`, `FecProCom`, `IdOferta`.

**Alternatives considered**:
- Centrar en `T_Contrato` — rechazado por el usuario.

## R3 — Resolución de titular según TipProCom

**Decision**:
- `TipProCom = 2` → titular vía `PropuestaComercialCliente.cliente()` (`CodCli` → `T_Cliente`).
- `TipProCom = 3` → titular vía `PropuestaComercialCliente.contacto()` (`CodCli` en puente = `CodConCli` en `T_ContactoCliente`).

**Rationale**: Comportamiento existente en `desarrolloeneon/app/Models/PropuestaComercialCliente.php`.

**Alternatives considered**:
- Join universal solo por `T_Cliente` — incorrecto para tipo 3.

## R4 — Ejecución de herramientas (handler)

**Decision**: Refactorizar `AgentDatabaseQueryCapabilityHandler` para delegar en **`AgentCommercialQueryService`** con métodos nombrados (uno por herramienta). El catálogo en config conserva **metadatos** (nombre, descripción, parámetros); la ejecución usa Eloquent, no SQL del LLM.

**Rationale**: Cumple FR-002 (solo herramientas permitidas) y FR-013 (relaciones Eloquent). Compatible con flujo actual (LLM elige `query_name` + `parameters`).

**Alternatives considered**:
- Generar SQL estático en config desde artisan — más frágil y duplica lógica.

## R5 — Multi-tenant (BelongsToTenant)

**Decision**: Al portar modelos, **omitir** trait `BelongsToTenant` y global scopes de tenant. Consultas del agente operan sobre BD operativa completa (operadores internos).

**Rationale**: `ia_agent` no tiene contexto de tenant en el chat. El trait en `desarrolloeneon` requiere `Tenant`/`TenantScope` inexistentes aquí.

**Alternatives considered**:
- Portar stack multi-tenant completo — fuera de alcance.

## R6 — Conexión BD

**Decision**: Modelos comerciales usan conexión **`agent_db_secondary`** (`config/database.php`, variables `AGENT_DB_*`).

**Rationale**: Ya usada por `AgentDatabaseQueryCapabilityHandler` y `config/agent.php`.

## R7 — Límite de resultados

**Decision**: Máximo **50 filas** por herramienta (configurable `agent.agent_database.max_results`, default 50). Listados truncados con indicación al LLM en segunda pasada.

**Rationale**: FR-012, SC-003 (legibilidad y latencia).

## R8 — Alcance frontend

**Decision**: **Sin cambios en Angular** — la feature extiende solo el chat backend existente (`POST /api/v1/chat/message`).

**Rationale**: Misma UX; respuestas en lenguaje natural. Constitution V N/A para esta feature.

## R9 — Modelos mínimos a portar

**Decision**: Portar en fase implementación:

| Modelo | Tabla |
|--------|-------|
| `Cliente` | `T_Cliente` |
| `Contacto` | `T_ContactoCliente` |
| `ContactoDetalleCliente` | `T_ContactoDetalleCliente` |
| `PropuestaComercial` | `T_PropuestaComercial` |
| `PropuestaComercialCliente` | `T_Propuesta_Comercial_Clientes` |
| `PropuestaComercialCups` | `T_Propuesta_Comercial_CUPs` |
| `Contrato` | `T_Contrato` |

Opcional fase 2: `DocumentoPropuesta`, `Comercializadora` (solo si herramienta de documentos se implementa).

**Rationale**: FR-005, FR-014 con alcance P1/P2 de la spec.
