# Drill-Down Agent

## Responsabilidad
Proveer datos transaccionales detallados cuando el usuario hace drill-down desde cualquier valor numérico del dashboard. Opera sobre datos cacheados en MySQL para respuesta instantánea sin llamar a QBO en cada clic.

## Trigger
- Usuario hace clic en botón de drill-down en tabla de ventas
- Usuario hace clic en valor numérico de KPI card
- URL directa: `GET /api/transactions?company=solar&account=Sales&from=2025-06-09&to=2025-06-15`

## Endpoint

```
GET /api/transactions
  Query params:
    - company      (string, slug) — 'solar', 'hvac', 'roofing', 'all'
    - account      (string) — nombre de cuenta QBO, e.g. 'Sales', 'Cost of Goods Sold'
    - account_id   (string, opcional) — ID de cuenta QBO para match exacto
    - txn_type     (string, opcional) — 'Invoice', 'Bill', 'Expense', etc.
    - class_name   (string, opcional) — zona/segmento
    - from         (date, YYYY-MM-DD)
    - to           (date, YYYY-MM-DD)
    - limit        (int, default 50, max 200)
    - offset       (int, default 0)
    - sort         (string, default 'txn_date DESC')
```

## Respuesta
```json
{
  "success": true,
  "data": [
    {
      "txn_id": "12345",
      "txn_date": "2025-06-09",
      "txn_type": "Invoice",
      "customer_name": "Familia Rodríguez",
      "account_name": "Sales",
      "amount": 18400.00,
      "class_name": "Zona Sur",
      "memo": "Instalación 8kW residencial",
      "company_name": "Sunbright Solar"
    }
  ],
  "meta": {
    "total": 142,
    "limit": 50,
    "offset": 0,
    "company": "solar",
    "period": "2025-06-09 to 2025-06-15"
  }
}
```

## Flujo frontend (drilldown.js)

```javascript
async function openDrilldown(params) {
  // 1. Mostrar modal con spinner
  showDrilldownModal();
  setDrilldownLoading(true);

  // 2. Fetch transacciones
  const qs = new URLSearchParams(params).toString();
  const res = await fetch(`/api/transactions?${qs}`);
  const json = await res.json();

  // 3. Popular tabla del modal
  const tbody = document.getElementById('drilldownBody');
  tbody.innerHTML = json.data.map(txn => `
    <tr style="border-bottom:1px solid rgba(255,255,255,0.04)">
      <td class="py-2.5 px-3 text-slate-400">${formatDate(txn.txn_date)}</td>
      <td class="py-2.5 px-3 text-white font-medium">${txn.customer_name || txn.vendor_name || '-'}</td>
      <td class="py-2.5 px-3 text-slate-400">${txn.txn_type}</td>
      <td class="py-2.5 px-3 text-right text-white">$${txn.amount.toLocaleString()}</td>
      <td class="py-2.5 px-3 text-slate-400">${txn.memo || ''}</td>
    </tr>
  `).join('');

  // 4. Actualizar header del modal con contexto
  setDrilldownHeader(params);
  setDrilldownLoading(false);
}
```

## Paginación en el modal
- Mostrar primeros 50 resultados
- Botón "Cargar más" al final de la tabla → offset += 50, append filas
- Total de registros mostrado en el header: "Mostrando 50 de 142 transacciones"

## Contexto del drill-down
El modal muestra:
- Header: cuenta o zona + período
- Empresa de origen
- Tabla de transacciones con columnas: Fecha, Cliente/Proveedor, Tipo, Monto, Memo
- Footer con total y count

## Performance
- Query sobre `cached_transactions` con índices en (company_id, txn_date) y (company_id, account_name)
- Para 3 empresas con ~10K transacciones cada una, la query es < 10ms
- No se llama a QBO API — todo desde cache local

## Dependencias
- `TransactionsController.php` — endpoint
- `CachedTransaction` model — query con filtros
- `drilldown.js` — frontend fetch + render
- `modals/drilldown.php` — template del modal (tbody vacío, se llena con JS)
