Arquitectura
Servicios
Cada componente del sistema con su responsabilidad, entradas, salidas, dependencias, errores posibles y observaciones.
Resumen
MediNodo se compone de ocho servicios principales, que participan directamente en la entrega y el registro de eventos, y siete servicios complementarios, que dan soporte operativo, de seguridad o de infraestructura sin transportar cada mensaje.
Servicios principales
listmonk Composición · Envío
- Responsabilidad
- Administra suscriptores, listas, templates y campañas; genera los enlaces individuales, entrega los mensajes por SMTP y procesa bajas, bounces y complaints.
- Entradas
- Datos de suscriptores y campañas desde PostgreSQL; credenciales SMTP de AWS IAM; eventos de feedback vía webhook de SNS.
- Salidas
- Mensajes SMTP hacia Amazon SES; enlaces bajo
trk.medinodo.com; registro de clicks, bajas y bounces en PostgreSQL. - Dependencias
- PostgreSQL, Amazon SES, Cloudflare Tunnel (ruta
trk), AWS IAM. - Errores posibles
- Fallo de autenticación SMTP; rechazo de SES por identidad o cuota; webhook de feedback no accesible.
- Observaciones
- No entrega correo directamente a Internet: decide a quién enviar y conserva el estado de campaña.
Amazon SES Transporte
- Responsabilidad
- Recibe los mensajes de listmonk por SMTP, autentica el envío de
medinodo.comy los entrega a los proveedores de correo de los destinatarios. - Entradas
- Conexión SMTP autenticada de listmonk; registros DKIM, SPF, DMARC y MAIL FROM publicados en Cloudflare DNS.
- Salidas
- Entrega a los proveedores de correo; eventos de hard bounce y complaint hacia Amazon SNS.
- Dependencias
- Cloudflare DNS (autenticación), AWS IAM (credenciales), Amazon SNS (feedback).
- Errores posibles
- Límites de cuota o restricciones de sandbox por región; fallos de alineación DKIM/SPF/DMARC.
- Observaciones
- Transporta el mensaje y genera feedback de entrega, pero no administra listas ni campañas.
Amazon SNS Feedback
- Responsabilidad
- Publica de forma asíncrona los eventos de hard bounce y complaint generados por SES hacia el webhook de listmonk.
- Entradas
- Notificaciones de SES en el tópico
ses-bounces. - Salidas
POSTahttps://trk.medinodo.com/webhooks/service/ses.- Dependencias
- Amazon SES (origen), Cloudflare Tunnel (ruta
trk), listmonk (consumidor). - Errores posibles
- Webhook inaccesible o rechazado; reintentos de entrega del evento.
- Observaciones
- Transporta eventos; es listmonk quien decide cómo registrarlos y cuándo aplicar blocklist.
PostgreSQL Persistencia
- Responsabilidad
- Almacena la configuración y los datos de listmonk, clicks y bounces, además del esquema propio
med_trackingcon los eventos de interés. - Entradas
- Escrituras de listmonk (campañas, clicks, bounces) y de FastAPI (interés).
- Salidas
- Lecturas de campañas y suscriptores para listmonk; validaciones para FastAPI.
- Dependencias
- Docker Compose (ejecución), Restic (backups cifrados).
- Errores posibles
- Pérdida de conectividad; violaciones de restricciones de idempotencia.
- Observaciones
- Los datos de negocio permanecen aquí, con independencia del borde de Cloudflare.
Cloudflare DNS Borde
- Responsabilidad
- Resuelve los dominios de MediNodo y publica los registros DKIM, SPF, DMARC y MAIL FROM requeridos por SES.
- Entradas
- Registros de autenticación provistos por Amazon SES.
- Salidas
- Resolución de
medinodo.comy subdominios; verificación de identidad de envío. - Dependencias
- Amazon SES (valores de autenticación).
- Errores posibles
- Registros mal configurados que rompen la alineación SPF/DKIM/DMARC.
- Observaciones
- Ver Dominios y DNS para el detalle de cada registro.
Cloudflare Tunnel Borde
- Responsabilidad
- Expone
trk.medinodo.comyapi.medinodo.comhacia los contenedores privados sin publicar directamente sus puertos en Internet. - Entradas
- Solicitudes públicas a las rutas
trkyapi. - Salidas
- Tráfico enrutado a listmonk (trk) y FastAPI (api) dentro de la red privada.
- Dependencias
- Docker Compose (
cloudflared), listmonk, FastAPI. - Errores posibles
- Túnel caído o desconectado deja inaccesibles el tracking y la API.
- Observaciones
- En el ambiente local esta función la cumple Caddy.
Vercel Experiencia
- Responsabilidad
- Aloja
landing.medinodo.com, la aplicación Next.js y el Route Handler/api/interest. - Entradas
- Redirección desde listmonk con los UUID opacos de suscriptor y campaña; envíos del formulario.
- Salidas
POSTautenticado aapi.medinodo.comtras validar el envío.- Dependencias
- Upstash Redis (rate limit), Cloudflare Turnstile (anti-abuso), FastAPI (destino).
- Errores posibles
- Rate limit excedido; verificación de Turnstile fallida; backend no disponible.
- Observaciones
- La validación previa a FastAPI se ejecuta aquí. Ver Landing e interés.
FastAPI Aplicación
- Responsabilidad
- Valida la relación entre campaña y suscriptor, aplica idempotencia y registra el interés en PostgreSQL.
- Entradas
POSTautenticado desde el Route Handler de Vercel, vía Cloudflare Tunnel.- Salidas
- Escritura del evento de interés en el esquema
med_tracking. - Dependencias
- PostgreSQL, Cloudflare Tunnel (ruta
api). - Errores posibles
- Campaña o suscriptor inexistentes; intento de registro duplicado (rechazado por idempotencia).
- Observaciones
- Registra el interés confirmado en la landing; no registra el click del email.
Servicios complementarios
Dan soporte a la plataforma sin transportar cada mensaje. Expandí cada tarjeta para ver su ficha completa.
- Responsabilidad
- Comprueba que el envío del formulario de interés no provenga de automatización abusiva. La validación se ejecuta en Vercel.
- Entradas
- Token del widget generado en el navegador.
- Salidas
- Veredicto de validez consumido por el Route Handler.
- Dependencias
- Vercel (Route Handler).
- Errores posibles
- Token inválido o expirado que bloquea el envío.
- Observaciones
- Primera línea anti-abuso del formulario.
- Responsabilidad
- Aplica el rate limit distribuido del endpoint
/api/interestejecutado en Vercel. - Entradas
- Contadores por identificador de cliente.
- Salidas
- Permitir o rechazar el envío según el umbral.
- Dependencias
- Vercel (Route Handler).
- Errores posibles
- Límite alcanzado; indisponibilidad del store distribuido.
- Observaciones
- Complementa a Turnstile controlando la frecuencia de envío.
- Responsabilidad
- Recibe el correo entrante y las respuestas dirigidas a
info@medinodo.com. No transporta las campañas enviadas por SES. - Entradas
- Respuestas de los destinatarios a los mensajes.
- Salidas
- Correo entregado a la bandeja de
info@medinodo.com. - Dependencias
- Cloudflare DNS (registros de correo entrante).
- Errores posibles
- Configuración de correo entrante incorrecta.
- Observaciones
- Las respuestas no regresan a listmonk ni pasan por el flujo de SNS.
- Responsabilidad
- Mantiene el registro del dominio y el sitio principal
www.medinodo.com. No participa directamente en el envío de campañas. - Entradas
- Tráfico institucional del sitio principal.
- Salidas
- Sitio institucional publicado.
- Dependencias
- —
- Errores posibles
- —
- Observaciones
- Ámbito separado del sistema de campañas.
- Responsabilidad
- Ejecuta y conecta listmonk, PostgreSQL, FastAPI,
cloudflaredy los procesos operativos en el host. - Entradas
- Definición de servicios y variables de entorno.
- Salidas
- Contenedores en ejecución e interconectados.
- Dependencias
- Host del despliegue.
- Errores posibles
- Fallo de arranque de un contenedor o de la red interna.
- Observaciones
- Orquestador del despliegue en el host.
- Responsabilidad
- Crea y conserva copias cifradas de PostgreSQL y de los uploads de listmonk. No interviene en una entrega individual.
- Entradas
- Datos de PostgreSQL y uploads de listmonk.
- Salidas
- Copias de respaldo cifradas.
- Dependencias
- PostgreSQL, almacenamiento de destino.
- Errores posibles
- Fallo del respaldo o del cifrado.
- Observaciones
- Recuperación ante desastres, fuera del camino de entrega.
- Responsabilidad
- Publica listmonk y FastAPI solamente en el ambiente local. En producción esa entrada corresponde a Cloudflare Tunnel.
- Entradas
- Solicitudes locales a listmonk y FastAPI.
- Salidas
- Tráfico enrutado a los servicios en desarrollo.
- Dependencias
- Docker Compose (entorno local).
- Errores posibles
- Configuración local incorrecta.
- Observaciones
- Su equivalente productivo es Cloudflare Tunnel.
- Responsabilidad
- Provee a listmonk las credenciales SMTP técnicas para autenticarse ante SES. No transporta mensajes.
- Entradas
- Política de acceso al envío por SMTP.
- Salidas
- Credenciales SMTP para listmonk.
- Dependencias
- Amazon SES.
- Errores posibles
- Credenciales revocadas o mal configuradas que rompen el envío.
- Observaciones
- Provee identidad técnica, no transporte.
Buenas prácticas
- Rotar y custodiar las credenciales SMTP de AWS IAM; tratarlas como secretos de despliegue.
- Verificar la salud del Cloudflare Tunnel: si cae, se pierden tracking y API a la vez.
- Automatizar y verificar periódicamente las copias de Restic para garantizar la recuperación.
Consideraciones
Local vs. producción
Caddy y Cloudflare Tunnel cumplen la misma función de exposición en ambientes distintos. Confundirlos al operar puede exponer puertos que deberían permanecer privados.