Diagrama UML de despliegue — ExpressMX
Wave 1.4 del campaign
thesis-diagrams-suite. Vista estricta UML 2.5 de nodos, dispositivos, ambientes de ejecución, artefactos y conectores con protocolo. Complementa al narrativodeployment.mdcon notación formal.Última actualización: 2026-05-05.
Resumen
ExpressMX se despliega como un sistema distribuido sobre cuatro ambientes
funcionales: (1) desarrollo local en máquinas de developer, (2) preview por
PR en Vercel + branch Neon copy-on-write, (3) producción servida desde
expressmx.com con branch Neon production, y (4) distribución móvil vía
Apple App Store y Google Play, alimentada por Expo EAS. Este documento usa
notación UML de despliegue: nodos clasificados con estereotipos
(<<device>>, <<execution environment>>, <<external service>>,
<<distribution>>), artefactos físicos (.ipa, .aab, bundles Next.js,
imágenes Docker locales) y conectores etiquetados con su protocolo de
transporte y mecanismo de autenticación.
La topología sigue el principio de Zero Trust: ningún componente cliente confía en el otro hasta presentar JWT firmado, ningún despliegue de Vercel puede escribir en una base que no sea la que su scope permite, y todos los canales encriptan en tránsito (TLS 1.3 sobre HTTP/2 para tráfico web, Postgres wire protocol con SSL para datos).
Diagrama (PlantUML)
Fuente: uml-deployment-diagram.puml
Renderizar con: plantuml -tpng uml-deployment-diagram.puml
Convención de líneas:
- Línea continua: tráfico síncrono crítico de producción (request/response usuario → API → DB).
- Línea punteada: side-effect asíncrono (email, OTA, distribución móvil, persistencia interna en Neon).
Cuatro ambientes
| Ambiente | Trigger | URL pattern | Branch DB | Audiencia | Lifecycle |
|---|---|---|---|---|---|
| dev local | pnpm dev en máquina del developer |
http://localhost:3000 (web), exp://<lan-ip>:8081 (Expo) |
dev (Neon) o Postgres local opcional |
developers internos | permanente; reset semanal de dev cada domingo 23:00 UTC |
| preview | apertura de PR contra main |
https://<branch>-<hash>.vercel.app |
preview/pr-<NUM> (Neon copy-on-write) |
reviewers, QA, stakeholders del PR | ≤ 7 días; autodelete al cerrar/mergear PR |
| production | merge a main |
https://expressmx.com y https://www.expressmx.com |
production = br-floral-field-amerzuwa |
clientes, prestadores, agentes operativos | permanente; cutover sin downtime; rollback < 60 s vía Vercel + Neon time-travel |
| mobile distribution | tag de release + eas submit |
App Store y Google Play | n/a (apps consumen production API) | público general | permanente por versión publicada; OTA empuja JS bundles entre releases nativos |
Artefactos por nodo
| Nodo | Artefactos desplegados | Runtime | Estrategia de version pinning |
|---|---|---|---|
| iPhone iOS | expressmx-cliente.ipa, expressmx-prestador.ipa |
Hermes + React Native 0.83.6 | app.json:version (semver) + build number incrementado por EAS |
| Android | expressmx-cliente.aab, expressmx-prestador.aab |
Hermes + React Native 0.83.6 | app.json:version + versionCode autoincremento EAS |
| Browser | bundle Next.js 16.2 (RSC chunks + Turbopack) | V8 / SpiderMonkey / JSC del browser | Hash de contenido en _next/static/*; cache-immutable |
| Middleware Edge | apps/web/middleware.ts compilado |
V8 isolate (Edge runtime) | atado al deploy ID de Vercel |
| Next.js Server | apps/web build con transpilePackages (@expressmx/database, @expressmx/types, @expressmx/utils, @expressmx/validations) |
Node.js 20 Function | deploy inmutable por commit SHA; alias expressmx.com apunta al SHA elegido |
API Routes /api/* y /api/v1/* |
route handlers compilados; redirect /api/mobile/:path* → /api/v1/mobile/:path* (apps/web/next.config.ts) |
Node.js 20 Function | mismo SHA que Next.js Server; OpenAPI generado vía pnpm openapi:gen |
| Vercel Cron | scripts/cron/cron-sla-breach-notify.ts, cron-sla-pause-resume.ts, cron-csat-trigger.ts, cron-auto-resolve-inactive.ts, cron-detect-recurring-orden.ts |
Node.js 20 scheduled | atados al deploy de production; firma vía secret en header |
| Static Assets | _next/static, public/, openapi.json |
Vercel CDN | hash de contenido inmutable |
| Neon Compute | Postgres 16 con autoscaling 0.25–4 CU | scale-to-zero 5 min idle | versión Postgres pinneada en proyecto Neon aged-flower-24986215 |
| Neon Storage | pages + WAL (retención 7 días, plan Launch) | object store + page server | gestionado por Neon; backups automáticos |
| Branch production | schema 00.sql + migraciones migrations/00N_*.sql |
n/a | numeración estricta 007_* siguiente; idempotencia obligatoria |
| Branch dev | seed sintético (pnpm db:seed) |
n/a | reset semanal desde production |
| Branch preview/pr-N | copia-en-escritura desde production + migración del PR | n/a | TTL 7 días, autodelete al cerrar PR |
| Resend SMTP relay | cuenta noreply@expressmx.com |
Resend API v6.12.2 | API key rotada por scope (sandbox preview, producción rotada trimestralmente) |
| Resend Templates | HTML inline en apps/web/src/lib/email.ts |
renderer Resend | bundleado en deploy de Next.js |
| EAS Build iOS | runners macOS con Xcode | gestionado por Expo | profile EAS production/preview/development con perfiles de firma Apple |
| EAS Build Android | runners Linux con Gradle | gestionado por Expo | mismo profile EAS; keystore upload-only en EAS |
| EAS OTA | bundles JS firmados | expo-updates |
runtimeVersion atado a la versión nativa instalada |
| App Store Apple | apps ExpressMX Cliente (com.expressmx.client) y ExpressMX Prestador (com.expressmx.provider) |
iOS 16+ | App Store Connect controla phased rollout |
| Google Play | apps ExpressMX Cliente (com.expressmx.client) y ExpressMX Prestador (com.expressmx.provider) |
Android 11+ | Play Console controla staged rollout |
Protocolos en uso
| Protocolo | Dónde aplica | Notas |
|---|---|---|
| HTTPS / TLS 1.3 sobre HTTP/2 | Browser → Vercel; iPhone/Android → Vercel API; Vercel → Resend; EAS → App Store / Play Console | Certificado gestionado por Vercel; HSTS habilitado en expressmx.com. |
| JWT Bearer | Apps móviles y panel admin → /api/v1/* y /api/* |
Token firmado HS256 con JWT_SECRET; refresh token con REFRESH_TOKEN_SECRET; expiración JWT_EXPIRES_IN=7d. |
| Postgres wire protocol /5432 con SSL | Funciones serverless Vercel + crons → Neon Compute | Driver pg (packages/database/src/client.ts) con Pool max=10, idleTimeoutMillis=30000, ssl.rejectUnauthorized=false (CA gestionado por Neon). |
| SMTP outbound (TLS) | Resend → buzones de usuarios finales | Resend gestiona SPF/DKIM/DMARC para expressmx.com. |
| Resend HTTPS API v6.12 | API Routes Vercel → Resend | Header Authorization: Bearer ${RESEND_API_KEY}; key segregada por ambiente. |
| OTA expo-updates (HTTPS firmado) | EAS OTA → apps móviles | Manifest firmado con clave gestionada por Expo; respeta runtimeVersion para no romper compatibilidad nativa. |
| TestFlight / App Store Connect API | EAS → Apple | Submit con perfil distribución; review humano antes de release. |
| Google Play Developer API | EAS → Google | Tracks Internal → Closed → Production con porcentaje de rollout. |
Servicios externos configurados pero no en uso
Listado siguiendo la convención de mantener visibilidad de dependencias provisionadas aunque hoy no se ejecuten en producción:
- Stripe (
STRIPE_SECRET_KEY,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYen.env.example): variables presentes en plantilla pero ningún módulo del monorepo (apps/web/src/**) importa el SDK de Stripe en este snapshot. Estado: configurado pero no en uso — preparado para wave 2 de facturación. - Expo Push (
EXPO_ACCESS_TOKEN): variable definida; las apps importanexpo-notifications(apps/mobile-client/package.json,apps/mobile-provider/package.json) pero el envío push aún no está cableado al backend. Estado: configurado pero no en uso. - Google Maps (
NEXT_PUBLIC_GOOGLE_MAPS_KEY,EXPO_PUBLIC_GOOGLE_MAPS_KEY): keys provisionadas con restricciones de origen; el mapa interactivo se cablea en wave posterior. Estado: configurado pero no en uso. - Sentry / DataDog: ningún paquete en
package.jsonraíz ni enapps/web/package.jsonlos referencia. Estado: no presente — no forman parte de la topología actual.
Estos servicios no se dibujan como nodos en el diagrama principal porque
no participan en flujos de tráfico actuales; cuando se activen en una wave
posterior, este documento debe actualizarse con sus nodos <<external
service>> y conectores con protocolo.
Diferencia con deployment.md
El documento expressmx/docs/architecture/deployment.md
es un texto narrativo orientado a la operación: explica el deploy flow paso
a paso, los SLAs por proveedor, las variables de entorno por tier y los
procedimientos de rollback. Su diagrama Mermaid es informal — usa
agrupaciones por proveedor y conectores con etiquetas cortas pero sin
distinguir devices, execution environments y external services. Este
documento (uml-deployment-diagram.md) en cambio adopta notación estricta
UML 2.5 de despliegue: cada nodo lleva estereotipo (<<device>>,
<<execution environment>>, <<external service>>, <<distribution>>),
los artefactos físicos están explícitos (.ipa, .aab, bundles, route
handlers) y los conectores incluyen el protocolo de transporte y el
mecanismo de autenticación. Los dos textos son complementarios: el
narrativo se lee para operar el sistema, el UML se lee para certificar la
arquitectura ante el caso práctico SOFTWARE 6.
Trazabilidad
| Elemento | Origen |
|---|---|
| Stack web (Next.js 16.2, React 19, Resend 6.12) | expressmx/apps/web/package.json:30-49 |
| Mobile-client (Expo 55, RN 0.83.6, expo-secure-store) | expressmx/apps/mobile-client/package.json:13-46 |
| Mobile-provider (Expo 55, RN 0.83.6) | expressmx/apps/mobile-provider/package.json:13-46 |
| Bundle ID y package iOS/Android cliente | expressmx/apps/mobile-client/app.json:9-15 |
| Bundle ID y package iOS/Android prestador | expressmx/apps/mobile-provider/app.json:8-15 |
Redirect /api/mobile/* → /api/v1/mobile/* y transpilePackages |
expressmx/apps/web/next.config.ts:4-19 |
Pool de conexiones pg (max=10, idleTimeoutMillis=30000, ssl) |
expressmx/packages/database/src/client.ts:1-13 |
Cliente Resend y EMAIL_FROM |
expressmx/apps/web/src/lib/email.ts:1-7 |
| Vercel Cron scripts (5 jobs) | expressmx/apps/web/package.json:16-20 |
Branch production br-floral-field-amerzuwa y proyecto Neon aged-flower-24986215 |
expressmx/docs/architecture/neon-branching.md:8,16 |
| SLA por componente (Vercel 99.99 %, Neon 99.95 %, Resend 99.9 %) | expressmx/docs/architecture/deployment.md:72-80 |
| Variables de entorno por tier (dev/preview/production) | expressmx/docs/architecture/deployment.md:84-106 |
Plantilla pública .env.example |
expressmx/.env.example:1-32 |
| Deploy flow GitHub → Vercel → Neon (6 pasos) | expressmx/docs/architecture/deployment.md:114-132 |
| Política de migraciones idempotentes | expressmx/docs/architecture/neon-branching.md:152-181 |
Referencias UML
- ISO/IEC 19505-2:2012 (UML 2.5) — Deployment Diagrams (cláusula 19).
- Estereotipos usados:
<<device>>,<<execution environment>>,<<external service>>(extensión común para SaaS),<<distribution>>(extensión específica de este proyecto para marketplaces de apps). - Artefactos representados como instancias físicas desplegadas; las
dependencias de manifest (manifestation) se expresan dentro de la
etiqueta del nodo (
artefacto: ...).
Cubre Problema 2 (Arquitectura) y Problema 6 (Seguridad/infraestructura) del Caso Práctico SOFTWARE 6.