🚀 NutriNen Baby — Guía de Despliegue
Última revisión: Marzo 2026
📐 Arquitectura General
┌─────────────────────────────────────────────────────────────────┐
│ CÓDIGO FUENTE (dev, debug, sin minificar) │
│ public/internal/tools/heartbeat-studio/games/baby-nutrinen/ │
│ │
│ index.html (~887 KB) │
│ scenes/ (7 escenas: home, chat, agenda, recetas, etc.) │
│ js/modules/ (8 módulos JS + 4 CSS) │
│ doc/ (documentación técnica) │
│ audio/ (archivos de audio) │
│ config.json (config de desarrollo) │
└──────────────┬──────────────────────────┬───────────────────────┘
│ │
┌───────▼────────┐ ┌────────▼────────┐
│ BUILD WEB │ │ SYNC CAP │
│ (minificado) │ │ (sin minificar) │
└───────┬────────┘ └────────┬────────┘
│ │
┌────────────▼──────────┐ ┌───────────▼──────────────────┐
│ nutrinen-baby/app/ │ │ baby-nutrinen-cap/www/ │
│ Minificado+obfuscado │ │ Código debug, API patcheada │
│ APIs → cadences.app │ │ APIs → cadences.app │
└────────────┬──────────┘ └───────────┬──────────────────┘
│ │
┌────────────▼──────────┐ ┌───────────▼──────────────────┐
│ nutrinen.com/app/ │ │ Android APK / AAB │
│ Cloudflare Pages │ │ Android Studio build │
└───────────────────────┘ └──────────────────────────────┘
El landing page (nutrinen.com/) es un proyecto independiente del app:
public/nutrinen-baby/
├── index.html ← Landing page (SEO, marketing)
├── styles.css ← Estilos del landing
├── app.js ← JS del landing (scroll, animaciones)
├── tools/ ← Herramientas SEO (alimentos-por-edad, percentiles, etc.)
├── privacidad/ ← Política de privacidad
├── terminos/ ← Términos de uso
└── app/ ← 🔒 App web MINIFICADA (generada por build script)
1️⃣ Desplegar el Landing Page (nutrinen.com)
¿Cuándo?
Cuando se modifica el landing (index.html, styles.css, app.js), las herramientas SEO (tools/), el blog (blog/), o las páginas legales.
Pasos
# 1. Build (minifica HTML/CSS/JS → dist/nutrinen/)
cd c:\Users\gonzalo\Documents\GitHub\ProjectOS
node scripts/build-nutrinen-site.cjs
# 2. Deploy
cd dist/nutrinen
npx wrangler pages deploy . --project-name=nutrinen --commit-dirty=true
- Proyecto Cloudflare Pages:
nutrinen - Dominio:
nutrinen.com - ⚠️ NO desplegar directamente desde
public/nutrinen-baby/— el build script minifica y optimiza - Esto sube TODO lo que hay en
dist/nutrinen/(landing + app/ + tools/ + blog/ + legal)
Archivos del landing
| Archivo | Función |
|---|---|
index.html |
Página principal SEO |
styles.css |
Estilos del landing |
app.js |
Scroll reveal, nav, botones CTA |
_headers |
Cache headers de Cloudflare |
robots.txt |
SEO crawl config |
sitemap.xml |
Mapa del sitio para Google |
sw.js |
Service Worker (mínimo) |
404.html |
Página de error personalizada |
img/ |
Imágenes del landing (og-cover, screenshots) |
tools/ |
29 herramientas SEO (calculadoras, quiz, generadores, etc.) |
privacidad/ |
Política de privacidad |
terminos/ |
Términos y condiciones |
2️⃣ Desplegar la App Web (nutrinen.com/app/)
¿Cuándo?
Cuando se modifica el código fuente de la app en baby-nutrinen/.
Pre-requisitos (una sola vez)
npm i -D terser html-minifier-terser
Proceso
Paso 1: Build (minificar + parchear APIs)
node scripts/build-nutrinen-web.cjs
Esto ejecuta el script scripts/build-nutrinen-web.cjs que:
- Limpia
nutrinen-baby/app/(borra todo y recrea) - Copia todos los archivos desde el fuente
baby-nutrinen/ - Parchea URLs de API: convierte rutas relativas → absolutas
/api/heartbeat→https://cadences.app/api/heartbeat/api/nutrinen→https://cadences.app/api/nutrinen
- Minifica JS con Terser:
- Mangle de variables locales (ofuscación)
- Compress en 2 pasadas (dead code, conditionals, evaluate)
- Elimina comentarios
- Mantiene
console.log(para debugging en producción) - NO mangle top-level (preserva
window.Xexports)
- Minifica HTML con html-minifier-terser:
- Whitespace colapsado
- Comentarios eliminados
- Inline
<script>y<style>también minificados
- Copia assets (CSS, imágenes, sonidos) tal cual
Reducciones típicas: JS -60 a -69%, HTML -36 a -48%, ~900 KB ahorrados total.
Archivos/dirs excluidos del build:
sw.js,manifest.json(conflicto con el SW del landing)doc/(documentación técnica — solo dev)audio/(archivos de audio raw)dist/(build Vite experimental — no se usa)config.json,ROADMAP.md(configs de dev)
Paso 2: Deploy
cd public/nutrinen-baby
npx wrangler pages deploy . --project-name=nutrinen --commit-dirty=true
⚡ Ambos pasos (landing + app) se despliegan juntos porque están en el mismo directorio. Si solo cambió la app, el landing se re-sube pero Cloudflare detecta que no cambió (hash idéntico) y no ocupa cuota.
¿Por qué funciona cross-origin?
La app en nutrinen.com/app/ llama a APIs de cadences.app/api/*.
Esto funciona porque:
- Todos los endpoints heartbeat tienen
Access-Control-Allow-Origin: * - La autenticación es por header
Authorization: Bearer <jwt>(no cookies) - Las URLs hardcoded (
https://cadences.app/api/auth/google/login,https://cadences.app/api/contact-sales) ya eran absolutas en el código fuente
⚠️ Requisito: Google OAuth
Para que el login con Google funcione en nutrinen.com, hay que configurar
en la Google Cloud Console:
- Abrir el Client ID:
71544957807-37qleb8hjqnbtu3blf5bvk1unv7shng7 - En Authorized JavaScript origins añadir:
https://nutrinen.com
- En Authorized redirect URIs añadir:
https://nutrinen.com/app/
3️⃣ Desplegar la App Android (Capacitor / APK)
¿Cuándo?
Cuando se modifica el código fuente de la app en baby-nutrinen/.
Proceso
Paso 1: Sync web → Capacitor
cd public/internal/tools/heartbeat-studio/games/baby-nutrinen-cap
npm run sync:web
Esto ejecuta sync-from-web.ps1 que:
- Copia
index.html,config.json,js/,scenes/,audio/,_shared/→www/ - Copia 16+ imágenes compartidas de
heartbeat-studio/img/→www/img/ - Transforma paths de imágenes:
/internal/tools/heartbeat-studio/img/→img/../_shared/→_shared/
- Inyecta
window.__API_BASE = 'https://cadences.app'en index.html - Parchea fetch calls para que usen
__API_BASE - Parchea constantes API_URL en
cloud-sync.js,deep-pulse-engine.js,scene.html - Ejecuta
npx cap sync androidpara copiar www/ → proyecto Android
ℹ️ No se minifica el código en la versión Cap porque:
- El código va empaquetado dentro del APK (no expuesto en un servidor público)
- Facilita el debugging en desarrollo
- Android Studio tiene ProGuard para el código nativo
Paso 2: Compilar en Android Studio
# Abrir en Android Studio
npm run open
# O ejecutar directamente en dispositivo conectado
npm run run:android
Para generar APK/AAB de release:
- Abrir Android Studio
- Build → Generate Signed Bundle / APK
- Seleccionar AAB (para Play Store) o APK (para test)
- Firmar con keystore (en posesión del desarrollador)
Configuración del proyecto Cap
| Campo | Valor |
|---|---|
appId |
app.cadences.nutrinenbaby |
appName |
NutriNen Baby |
webDir |
www |
androidScheme |
https |
| Capacitor | v8 |
| Google Auth Client ID | 71544957807-... (mismo que web) |
Scripts npm disponibles (baby-nutrinen-cap/)
| Script | Comando | Función |
|---|---|---|
sync:web |
powershell sync-from-web.ps1 |
Copia web → cap + parchea APIs |
sync |
npx cap sync android |
Solo sync cap → Android |
open |
npx cap open android |
Abrir en Android Studio |
run:android |
npx cap run android |
Build + run en dispositivo |
build |
npm run sync:web |
Alias de sync:web |
4️⃣ Desplegar cadences.app (APIs + plataforma principal)
¿Cuándo?
Cuando se modifican las funciones serverless (functions/api/heartbeat/*,
functions/api/nutrinen/*, functions/api/auth/*) o cualquier otra parte
de cadences.app.
Comando
# Desde la raíz del proyecto
npx wrangler pages deploy public/ --project-name=projectos
- Proyecto Cloudflare Pages:
projectos - Dominio:
cadences.app - Las Functions de
functions/se despliegan automáticamente
Bindings necesarios (configurados en Cloudflare Dashboard)
| Binding | Tipo | Recurso |
|---|---|---|
DB |
D1 | projectos-db |
NUTRINEN_STORAGE |
R2 | nutrinen-storage (backups usuarios) |
AI |
Workers AI | Free tier (10K neurons/día) |
Secrets (en Dashboard → Settings → Environment Variables)
| Variable | Servicio |
|---|---|
GROQ_API_KEY |
Groq (LLM principal) |
DEEPSEEK_API_KEY |
DeepSeek (LLM económico) |
GEMINI_API_KEY |
Google Gemini (LLM alternativo) |
ELEVENLABS_API_KEY |
ElevenLabs (música AI) |
JWT_SECRET |
Firma de tokens JWT |
GOOGLE_CLIENT_ID |
OAuth (en wrangler.toml, no secret) |
🔄 Flujo Completo: "He modificado la app"
Cuando se cambia código en baby-nutrinen/, hay que actualizar 3 destinos:
1. Web (nutrinen.com/app/) → build + deploy
2. Cap (Android APK) → sync + compile
3. cadences.app (debugging) → deploy (si procede)
Comandos rápidos (desde la raíz del proyecto)
# ── 1. Versión web (nutrinen.com/app/) ──
node scripts/build-nutrinen-web.cjs
cd public/nutrinen-baby
npx wrangler pages deploy . --project-name=nutrinen --commit-dirty=true
cd ../..
# ── 2. Versión Android (Capacitor) ──
cd public/internal/tools/heartbeat-studio/games/baby-nutrinen-cap
npm run sync:web
# Luego compilar en Android Studio
# ── 3. cadences.app (incluye código fuente sin minificar + APIs) ──
cd <raíz del proyecto>
npx wrangler pages deploy public/ --project-name=projectos
📁 Mapa de Archivos Clave
ProjectOS/
├── scripts/
│ ├── build-nutrinen-web.cjs ← Script de build app web (minify + API patch)
│ └── build-nutrinen-site.cjs ← Script de build site estático (minify → dist/nutrinen/)
│
├── functions/api/
│ ├── heartbeat/ ← APIs del servidor (LLM, música, weather...)
│ │ ├── beat.js ← Chat LLM multi-provider
│ │ ├── deep-pulse.js ← Análisis profundo con IA
│ │ ├── music-generate.js ← Generación música (ElevenLabs)
│ │ ├── weather.js ← Proxy clima (wttr.in → Open-Meteo → OWM)
│ │ ├── geocode.js ← Geocodificación inversa
│ │ └── _middleware.js ← Auth middleware (JWT)
│ ├── nutrinen/
│ │ ├── names.js ← Análisis de nombres con IA
│ │ ├── alimentos.js ← Buscador de alimentos por zona/edad
│ │ ├── blw.js ← Generador menús BLW con IA
│ │ ├── bliss.js ← Generador menús BLISS con IA
│ │ └── sync.js ← Cloud sync (R2 storage)
│ └── auth/google/
│ └── login.js ← Google OAuth → JWT
│
├── public/
│ ├── nutrinen-baby/ ← → nutrinen.com (Cloudflare Pages "nutrinen")
│ │ ├── index.html ← Landing page
│ │ ├── styles.css / app.js ← Assets del landing
│ │ ├── tools/ ← 29 herramientas SEO
│ │ ├── blog/ ← 33 artículos SEO (+ index.html)
│ │ ├── privacidad/ terminos/ ← Páginas legales
│ │ ├── _headers ← Cache config Cloudflare
│ │ └── app/ ← ⚡ APP WEB (generada por build script)
│ │ ├── index.html ← App minificada (~460 KB)
│ │ ├── js/modules/ ← JS minificado + ofuscado
│ │ └── scenes/ ← Escenas HTML minificadas
│ │
│ └── internal/tools/heartbeat-studio/games/
│ ├── baby-nutrinen/ ← 🔧 CÓDIGO FUENTE (dev, debug)
│ │ ├── index.html ← App completa (~887 KB)
│ │ ├── js/modules/ ← 8 módulos JS legibles
│ │ ├── scenes/ ← 7 escenas HTML
│ │ └── doc/ ← Documentación técnica
│ │
│ └── baby-nutrinen-cap/ ← 📱 VERSIÓN ANDROID (Capacitor)
│ ├── sync-from-web.ps1 ← Script de sync web → cap
│ ├── capacitor.config.json ← Config Capacitor
│ ├── www/ ← Assets web (synced)
│ ├── android/ ← Proyecto Android Studio
│ └── package.json ← npm scripts (sync:web, open, etc.)
│
└── wrangler.toml ← Config Cloudflare (D1, R2, AI bindings)
⚠️ Cosas a Recordar
Google OAuth: Si
nutrinen.comno está en los "Authorized JavaScript Origins" del Client ID de Google Cloud, el login no funcionará.Cache de Cloudflare: Si actualizas una imagen y no se ve, añade
?v=2alsrcdel<img>en el landing, o purga la caché desde el Dashboard de Cloudflare.El
app/se regenera entero: Cada vez que ejecutasbuild-nutrinen-web.cjs, se borranutrinen-baby/app/y se recrea desde cero. No edites archivos ahí directamente — se perderán.CORS ya configurado: Todos los endpoints de
cadences.app/api/heartbeat/*tienenAccess-Control-Allow-Origin: *. No hay que tocar el servidor para que la versión web funcione cross-origin.La versión Cap NO se minifica: El código va dentro del APK (no expuesto), y mantenerlo legible facilita el debug. ProGuard se encarga del código nativo.
Tres deploys distintos para un cambio de app:
nutrinen.com/app/— build + wrangler deploy nutrinen- Android APK — sync:web + Android Studio build
cadences.app— wrangler deploy projectos (para la version de debug accesible por URL)