# 🖥️ Frontend — klaUS-aicalc-roi
## 🤔 ¿Qué hago? ¿Cómo lo hago? ¿Y para qué lo hago?
**¿Qué hago?**
Soy la interfaz gráfica del TCO Calculator. Permito que cualquier stakeholder — sin tocar código ni curl — configure un análisis de coste de infraestructura AI, lo lance contra la API REST y visualice los resultados con recomendación y gráfico comparativo.
**¿Cómo lo hago?**
Next.js 15 con App Router, TypeScript strict y TailwindCSS. El frontend es completamente stateless — no tiene base de datos propia. Carga el catálogo de modelos y hardware desde la API en el arranque, gestiona todo el estado en React con `useState`, y lanza `POST /v1/analyze` al pulsar el botón. Los resultados se muestran con un gráfico de barras Recharts y una tarjeta de recomendación.
**¿Y para qué lo hago?**
Para cerrar la Fase 1 MVP: convertir el engine Python y la API REST en una herramienta accesible. Sin esta capa, el sistema solo puede ser usado por desarrolladores que escriban curl o código Python. Con ella, un CTO o un responsable de infraestructura puede comparar estrategias de despliegue AI en 30 segundos.
---
## 🗺️ Flujo de usuario
```mermaid
flowchart TD
A[Usuario abre la app] --> B[Carga catálogo GET /v1/models + /v1/hardware]
B --> C{Catálogo OK?}
C -- Error --> D[Pantalla de error con instrucciones]
C -- OK --> E[Formulario con pre-selección Claude Sonnet + Llama 8B + RTX 4090]
E --> F[Usuario selecciona modelos]
F --> G{¿Hay modelos local?}
G -- Sí --> H[GET /v1/hardware/recommend?min_vram_gb=X]
H --> I[Auto-selección del hardware óptimo con unidades correctas]
I --> J[Badge 🤖 en la GPU recomendada]
G -- No --> K[HardwareSelector oculto]
J --> L[Usuario ajusta hardware si quiere]
K --> M[Usuario configura caso de uso y horizonte]
L --> M
M --> N[Botón Analizar TCO]
N --> O[POST /v1/analyze]
O --> P{Análisis OK?}
P -- Error --> Q[Mensaje de error inline]
P -- OK --> R[SizingCard + RecommendationCard + StrategyChart]
R --> S[Usuario lee métricas de sizing, recomendación, riesgos y tabla comparativa]
```
---
## 📁 Estructura de ficheros
```text
frontend/
├── src/
│ ├── app/
│ │ ├── layout.tsx # Layout global — metadata, fuentes, body
│ │ ├── globals.css # Estilos base Tailwind
│ │ └── page.tsx # Página principal — toda la lógica de estado
│ ├── components/
│ │ ├── ModelSelector.tsx # Selector de modelos AI agrupado por deployment_type
│ │ ├── HardwareSelector.tsx # Selector de hardware GPU (aparece solo si hay modelos local)
│ │ ├── UseCaseForm.tsx # Nombre, tokens/mes y horizonte de análisis
│ │ ├── SizingCard.tsx # Tarjeta de métricas de dimensionamiento LLM
│ │ ├── StrategyChart.tsx # Gráfico de barras Recharts + tabla comparativa
│ │ └── RecommendationCard.tsx # Tarjeta de recomendación óptima + excluidos
│ ├── lib/
│ │ └── api.ts # Cliente fetch tipado — fetchModels, fetchHardware, analyze
│ └── types/
│ └── tco.ts # Tipos TS que espejan los modelos Pydantic del backend
├── next.config.ts
├── tsconfig.json
└── package.json
```
---
## 🚀 Arrancar en desarrollo
```bash
# Prerrequisito: la API debe estar corriendo
cd ../
uv run uvicorn backend.api.app:app --reload
# En otra terminal:
cd frontend
npm install
npm run dev
# → http://localhost:3000
```
La URL de la API se configura con `NEXT_PUBLIC_API_URL` (default: `http://localhost:8000`):
```bash
NEXT_PUBLIC_API_URL=http://api.ejemplo.com npm run dev
```
---
## 🧩 Componentes
### `ModelSelector`
Agrupa los modelos del catálogo por `deployment_type` y permite selección múltiple con toggle. Muestra el precio de entrada para modelos cloud API.
### `HardwareSelector`
Solo aparece cuando hay al menos un modelo local seleccionado. Muestra cards con VRAM y precio de compra de cada GPU.
Cuando la página detecta modelos locales, llama a `GET /v1/hardware/recommend` y pasa el resultado como `topRecommendation`. El componente:
- Marca con 🤖 la GPU recomendada (borde azul, badge en el header)
- Si la selección actual tiene VRAM insuficiente, la auto-selección se aplica automáticamente con la cantidad de unidades correcta
- El usuario puede cambiar o desmarcar el hardware libremente — la recomendación es informativa, no bloqueante
### `SizingCard`
Tarjeta de métricas de dimensionamiento de capacidad LLM (capacity planning). Aparece en la sección de resultados una vez ejecutado el análisis. No requiere inputs adicionales — todo se calcula desde los modelos, hardware y caso de uso seleccionados.
**Secciones:**
- **📊 Distribución de tokens**: tokens/año, % input, % output, % cache (Fase 2), validación Σ=100%
- **⚙️ Capacidad operativa**: horas/día, días/año, horas pico, usuarios concurrentes, tok/s objetivo/usuario
- **🖥️ On-prem & Agentes**: cuantización inferida (FP16/INT8/INT4/INT2), contexto promedio de sesión, streams/usuario agentic, tok/s para agentes
**Fórmulas clave:**
| Campo | Fórmula |
| --- | --- |
| Tokens/año | `(input + output) × 12 / 1M` |
| % Input/Output | `tokens_tipo / total × 100` |
| Usuarios concurrentes | `hw_throughput_tok_s / 20 tok/s` |
| Cuantización | `FP16 si VRAM≥params×2, INT8 si ≥params, INT4 si ≥params×0.5` |
| Contexto sesión | `context_window × 0.25` (uso típico producción) |
| Tok/s agentes | `20 tok/s × 3 streams` |
Valores con asterisco (*) usan defaults ISO 20000 / MLPerf enterprise (8h/día, 220 días/año, 4h pico, 20 tok/s, 3 streams agentic).
### `UseCaseForm`
Nombre del caso de uso, tokens de entrada/mes, tokens de salida/mes y selector de horizonte temporal (1, 6, 12, 24, 36, 60 meses).
### `StrategyChart`
Gráfico de barras ordenado por coste ascendente. Color por estado:
- 🔵 Azul: estrategia normal
- 🟢 Verde: Pareto-óptima
- 🟡 Ámbar: Recomendada
Incluye tabla comparativa con CAPEX, OPEX y flag de Pareto.
### `RecommendationCard`
Muestra la recomendación óptima con rationale, riesgos y payback. Si no hay estrategias válidas, muestra los modelos excluidos y sus razones (compliance).
---
## 🔌 Cliente API (`src/lib/api.ts`)
| Función | Método | Endpoint |
| --- | --- | --- |
| `fetchModels(params?)` | GET | `/v1/models?deployment_type=&data_residency=` |
| `fetchHardware()` | GET | `/v1/hardware` |
| `fetchHardwareRecommendation(min_vram_gb)` | GET | `/v1/hardware/recommend?min_vram_gb=` |
| `analyze(input)` | POST | `/v1/analyze` |
Todos devuelven promesas tipadas. Los errores HTTP lanzan `Error` con el status y body — se capturan en el `catch` de la página.
---
## ⚡ Decisiones de diseño
| Decisión | Razón |
| --- | --- |
| Single-page, sin routing | MVP Fase 1 — una sola pantalla es suficiente para el flujo completo |
| Estado en `useState`, sin Zustand/Redux | La complejidad no justifica un store externo en esta fase |
| Pre-selección al arrancar | Reduce la fricción — el usuario puede lanzar un análisis en 1 clic |
| `"use client"` en toda la página | El formulario y el gráfico son interactivos — no hay beneficio de RSC aquí |
| Recharts (no Chart.js/D3) | Componentes React nativos, sin manipulación de DOM, tipado completo |
| Auto-recomendación en cliente (no SSR) | La llamada a `/v1/hardware/recommend` se hace desde `useEffect` — evita bloquear el render inicial y permite que el usuario vea el formulario antes de que llegue la recomendación |
| `useRef` para `lastAutoSelectKey` | Evita re-selección de hardware en cada re-render; solo se re-aplica cuando el conjunto de modelos locales cambia realmente |
| `SizingCard` como cálculo puro en cliente | Los datos ya están disponibles en el estado de la página — no requiere endpoint de backend ni llamada de red adicional |
---
## 🔒 Seguridad
- Sin auth en Fase 1 MVP — la API es local.
- `NEXT_PUBLIC_API_URL` es la única variable de entorno — no expone secretos.
- No hay llamadas a APIs de terceros desde el frontend.
- El frontend no guarda datos del usuario — todo el estado es efímero (en memoria del navegador, limpiado al recargar).
---
## 🔗 Documentos relacionados
- [API REST](api.md) — endpoints que consume este frontend
- [TCO Engine](tco-engine.md) — motor de cálculo detrás de la API
- [Data Catalog](data-catalog.md) — catálogo de modelos y hardware