Deploy y entornos
EMA Well se despliega como un único worker de Cloudflare que sirve tanto la API Hono como los assets estáticos del SPA. La operación es deliberadamente simple: un comando empaqueta y publica todo, sin distinción entre “deploy de frontend” y “deploy de backend”. Esa unificación elimina toda una categoría de errores típicos de proyectos con dos pipelines.
Comando de deploy
Sección titulada «Comando de deploy»El despliegue se ejecuta desde la raíz del repo:
cd emawellnpm installnpm run deployEl script npm run deploy encapsula dos pasos secuenciales: primero
vite build compila la SPA en dist/client, y a continuación
wrangler deploy empuja el worker —API Hono más assets estáticos—
a Cloudflare. El binding [assets] del wrangler config permite que
el mismo worker sirva tanto rutas de API (bajo /api/*) como los
archivos estáticos del SPA (todo lo demás), con fallback al
index.html para que React Router maneje las rutas client-side.
Plataformas externas
Sección titulada «Plataformas externas»El producto se apoya en cinco plataformas externas además de Cloudflare. La separación es intencional: cada servicio cumple una función específica y se mantiene aislado del resto, lo que evita acoplamientos innecesarios:
| Componente | Plataforma | Función |
|---|---|---|
| API y assets | Cloudflare Workers (un solo worker con binding [assets]) | Backend y frontend en un solo deploy |
| Base de datos | Supabase (proyecto independiente emawell) | Postgres aislado del resto del ecosistema |
| Loops.so | Transaccional, nurturing y resúmenes | |
| Pagos | Stripe | Suscripción Pro mensual y anual |
| Push notifications | VAPID self-hosted | Web Push estándar |
Secrets requeridos
Sección titulada «Secrets requeridos»El worker depende de nueve secrets que se configuran via
wrangler secret put <NOMBRE> o desde el dashboard de Cloudflare.
Tres categorías agrupan los secrets por función:
Los secrets de Supabase —SUPABASE_URL, SUPABASE_ANON_KEY y
SUPABASE_SERVICE_ROLE_KEY— controlan el acceso al Postgres
aislado. La anon key se usa para queries con RLS aplicado (el flujo
del usuario común); la service role key se usa solo en crons y jobs
de administración que requieren bypass de RLS controlado.
Los secrets de integraciones externas —LOOPS_API_KEY,
ANTHROPIC_API_KEY, STRIPE_SECRET_KEY y STRIPE_WEBHOOK_SECRET—
habilitan los servicios correspondientes. La key de Anthropic solo
se usa cuando el tier del usuario es Pro, lo que mantiene los
costos de IA acotados al ARR generado por suscripciones.
Los secrets de Push notifications —VAPID_PUBLIC_KEY y
VAPID_PRIVATE_KEY— permiten enviar notificaciones push estándar a
los usuarios que las habilitaron explícitamente.
Dominio y crons
Sección titulada «Dominio y crons»El custom domain well.emahealth.io se configura en el dashboard
de Cloudflare apuntando al worker. La PWA se instala desde ese
dominio sin pasar por tiendas de aplicaciones, lo que evita el
costo y la fricción de revisión de Apple Store y Google Play.
Dos crons corren periódicamente, definidos en wrangler.toml:
[triggers]crons = [ "0 0 * * 0", # Domingo 00:00 UTC — weekly summary "0 20 * * *", # Diario 20:00 UTC — streak at risk]El de domingo a la medianoche UTC dispara los resúmenes semanales para usuarios con al menos dos check-ins esa semana. El diario a las 20:00 UTC chequea quiénes no hicieron check-in ese día y, si habilitaron notificaciones, les manda alerta de racha en riesgo.
Convenciones de desarrollo
Sección titulada «Convenciones de desarrollo»El repo sigue conventional commits (feat:, fix:, chore:,
etc.) por consistencia con el resto del ecosistema. Los tests
viven en cinco subcarpetas —unit/, integration/,
regression/, performance/, security/— ejecutables
individualmente o en bloque con Vitest. El deploy es manual o
mediante la integración Git de Cloudflare; deliberadamente no se
mantiene una pipeline de GitHub Actions, porque el workflow del
equipo prefiere que cada deploy sea una decisión consciente y no un
efecto secundario de un merge.