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.com y 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
POST a https://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_tracking con 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.com y 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.com y api.medinodo.com hacia los contenedores privados sin publicar directamente sus puertos en Internet.
Entradas
Solicitudes públicas a las rutas trk y api.
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
POST autenticado a api.medinodo.com tras 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
POST autenticado 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/interest ejecutado 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, cloudflared y 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.