Primera fase del plugin de propuesta consultiva (docs/superpowers/specs/
2026-07-28-propuesta-consultiva-ia-fase0-fase1-design.md). Recupera el contexto
humano que hoy se captura y se descarta, y cierra los bloqueadores que el
analisis previo destapo.
Seguridad (lo mas urgente):
- POST /mcp no tenia NINGUNA autenticacion: cero Depends() en main.py, mientras
el servicio recibe dominio publico en produccion (SERVICE_FQDN_API_8000).
Cualquiera en internet podia leer y escribir cotizaciones. Ahora exige
require_auth, que ya existia en app/auth.py y no se estaba usando ahi.
- _obtener_cotizacion hacia SELECT c.* y devolvia dict(cot) al agente, asi que
cualquier columna nueva se publicaba sola. Ahora usa lista blanca espejo de
CotizacionResponse, excluyendo observacionesInternas.
Totales:
- Nueva calcularTotalesCotizacion() en calculators.ts como fuente de verdad
unica. El calculo estaba duplicado a mano en siete consumidores.
- conIva() sustituye a los `* 1.16` hardcodeados de pdf-generator y
excel-builder, que ignoraban IVA_RATE y el flag incluirIva.
Contexto humano:
- Campo nuevo Cotizacion.observacionesInternas. La migracion es PURAMENTE
ADITIVA: no mueve ni una fila. El movimiento de datos no hace falta porque la
unica fila de produccion con observaciones ya contiene texto dirigido al
cliente, y separarlo en dos despliegues mantiene el rollback limpio.
- Dos textareas visualmente inconfundibles en el formulario.
- observaciones se imprime por primera vez en el PDF y el Excel; el dato ya
viajaba hasta las rutas de borrador y se tiraba.
- observacionesInternas solo se ve en la app. La garantia es estructural: el
campo no existe en CotizacionPDFData ni en ExcelData, asi que el generador no
puede filtrarlo aunque alguien lo intente.
Bugs vecinos:
- orderBy explicito en las cuatro rutas de export: el PDF asume las partidas
agrupadas por fase y sin orderBy podia diferir del Excel del mismo envio.
- El PDF de borrador leia solo el branding, no los datos bancarios, e imprimia
los hardcodeados del generador.
- detalleModelo local en PDF y Excel omitia la rama "demanda": esa partida
salia en $0 y sin explicacion. Ahora delegan en la version canonica.
- Los bonos salen de la tabla Bono; la lista hardcodeada queda de respaldo y su
texto ya no coincidia con el seed.
- La palomita de los bonos mide 0pt en las fuentes base de PDFKit (verificado),
o sea que salia como dos espacios. Sustituida por una vineta.
Ademas: zod pasa a ser dependencia declarada. Se importaba en schemas.ts y
resolvia transitivamente, asi que un npm ci --omit=dev reventaba.
Verificado con build, lint y 22 comprobaciones funcionales sobre PDF y Excel
reales (texto del cliente presente, texto interno ausente incluso inyectandolo
a la fuerza, texto largo multipagina, y totales con y sin IVA).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
- Recupera el trabajo revertido (doble propuesta, retainer, niveles, API Python) desde el stash de GitHub Desktop
- Dockerfile multi-stage para Next.js (migraciones automáticas al arrancar, seed opcional via RUN_SEED)
- docker-compose.coolify.yml: postgres + web + api con healthchecks y SERVICE_FQDN_*
- Endpoint público /api/health (verifica BD) para healthchecks
- seed.ts parametrizado: conexión DB_* y credenciales SEED_* por entorno (sin passwords hardcodeadas)
- .env.example, .dockerignore, uvicorn con --proxy-headers
- Limpieza: .xlsx y __pycache__ fuera del repo
Co-Authored-By: Claude Fable 5 <[email protected]>