2026-07-16 — Twenty CRM para concesionario VW Camiones
Entregable: ~/nef/twenty-vw-crm/ — proyecto completo, tests pasando (7/7).
Decisiones clave
- Alcance = CRM de unidades, no DMS. Refacciones/taller/facturación quedan
en el DMS externo. Frontera:
DmsAdapter(leer inventario, empujar venta). - Dinero en centavos enteros; Twenty CURRENCY usa micros (×10 000 conversión).
- IVA fijo 16% en
precio-buildup.ts(IVA_TASA). - M2M Modelo↔Aplicación requiere objeto puente (Twenty no tiene M2M nativo).
- Adapter intercambiable vía env
DMS_ADAPTER; mock incluido, idempotente por folio de cotización. - Web-to-lead: token compartido
X-Lead-Token+ honeypot, no OAuth. - Recordatorios = objeto custom + cron 5 min que crea Tarea nativa de Twenty (aprovecha notificaciones nativas en vez de reinventarlas).
- Manifiesto de App (
app/package.json→ clavetwenty) marcado como “verificar contra versión instalada”: el framework de Apps aún cambia.
Runner externo (para PikaPods)
PikaPods no permite habilitar el framework de Apps → los handlers corren
FUERA del pod: app/src/server.ts (Express + node-cron). Rutas:
/salud, /web-to-lead (token + CORS), /funciones/* (X-Api-Token
opcional via RUNNER_TOKEN), /tablero (dashboard estático en
app/public/index.html). Crons: recordatorios 5 min, sync DMS 15 min,
sync inicial al arrancar. Config en .env (ver .env.example).
Correr: npm run server (o server:dev). El pod queda 100% vanilla;
solo se usa npm run metadata contra él una vez.
Pendiente al desplegar
- Twenty self-host arriba (docs/self-host-docker.md).
npm run metadatacon API key real.- Crear vistas en UI (docs/vistas.md — receta exacta).
- Adapter real cuando se sepa qué DMS usa el concesionario.