Contexto
Super Channel 12 es una plataforma SaaS multimedia que da soporte a varios medios de Grupo Zócalo: el portal de noticias y televisión superchannel12.com, la emisora radiozocalo.com.mx y el sitio hola.mx. El reto no era construir un sitio de noticias más, sino una base común capaz de servir noticias escritas, televisión en directo y radio en vivo, gobernada desde un solo backend y un solo panel editorial.
El sistema se reparte en seis repositorios con responsabilidades claras: una API/CMS en Express, un frontend público en Astro, un panel de administración, un servidor de streaming, una app móvil y un servicio de analítica. Todo corre en contenedores Docker orquestados con Dokploy.
El reto
Un medio regional combina formatos muy distintos —texto, vídeo en directo y audio en directo— y, además, varias marcas que comparten infraestructura pero necesitan su propia identidad, dominio y contenido. Los retos centrales fueron:
- Soportar múltiples sitios (dominios, marca, menús, redes y notificaciones por sitio) sin duplicar la base de código.
- Entregar TV en vivo con baja latencia y radio en vivo con metadatos de “ahora suena”, tanto en web como en móvil.
- Dar al equipo editorial un CMS completo (artículos, multimedia, destacados, categorías, usuarios y roles) cómodo y rápido.
- Hacerlo sostenible: cacheo, backups, analítica propia y despliegue reproducible.
Arquitectura
La pieza central es superchannel12-new-api, una API REST en Express 4 sobre Node.js que también actúa como CMS. Usa MySQL mediante mysql2 con pool de conexiones y SQL escrito a mano (sin ORM), y Redis como capa de caché (configuración de sitios, logos, favicons y stations con TTLs ajustables). La autenticación es por JWT con cookies y Authorization: Bearer, refresh tokens persistidos en base de datos con fingerprint de dispositivo y revocación de sesión, además de roles editoriales (Administrador, Editor web, Editor editorial, Reportero). Un guard de origen valida Origin/Referer contra dominios permitidos, con un secreto dedicado para el renderizado SSR. Los medios (imágenes, adjuntos) y los backups de base de datos viven en Cloudflare R2 (S3-compatible) con URLs prefirmadas y procesamiento de imagen con sharp.
El frontend público (superch12-v2-frontend) es Astro 6 en modo SSR con el adaptador Node standalone, React 19 como islas interactivas hidratadas selectivamente y Tailwind CSS v4. Consume la API por fetch y cachea la información del sitio en memoria durante unos minutos para aliviar carga. El multi-sitio aquí se resuelve por despliegue: cada marca es una instancia con sus propias variables de entorno (PUBLIC_SITE_ID, dominio, nombre, tema). El backend devuelve el contenido y la marca correspondientes a ese SITE_ID; el tema visual (rojo por defecto, púrpura para hola.mx) se decide por variable de entorno.
El panel de administración (superchannel12-newpanel) comparte stack (Astro 6 SSR + React 19 + Tailwind v4) pero es, en la práctica, una aplicación React montada sobre Astro. La interfaz usa shadcn/ui sobre primitivas Radix (más MUI en algunas zonas), el editor de artículos es TipTap v3, el reordenamiento de destacados usa dnd-kit y los gráficos del dashboard, recharts. Es el plano de control multi-tenant: ofrece CRUD de sitios y configuración por sitio (dominio, menú/cabecera con opción de clonar configuración entre sitios, redes sociales, notificaciones).
El streaming en vivo se separa por medio. La televisión se ingiere y empaqueta en vps-streaming, un MediaMTX que recibe la señal por RTMP (:1935) autenticada y la republica como HLS de baja latencia (LL-HLS) con segmentos de 1s y partes de 200ms, sin transcodificación (relay puro). El reproductor del frontend y de la app cargan hls.js para consumir ese .m3u8, con modo low-latency, reintentos con backoff exponencial, recuperación de errores de red/media, PiP y Media Session API. La radio, en cambio, no usa HLS: es un <audio> que reproduce streams Icecast / Triton (StreamTheWorld), con detección automática de proveedor, metadatos de “ahora suena” desde Triton e Icecast, carátulas vía iTunes y letras sincronizadas vía LRCLIB.
La app móvil (apps) es Expo / React Native (SDK 54) con expo-router y NativeWind. Consume la misma API /public/* y reproduce TV (hls.js dentro de un WebView) y radio (expo-audio), con mini-reproductor persistente entre pestañas, además de cámaras de puentes fronterizos, clima/radar, tipo de cambio y edición impresa. Es prácticamente white-label: cambiando las variables de entorno puede re-marcarse para otro medio.
La analítica (vince-analytics) es Vince, un servicio auto-hospedado compatible con la API de Plausible. Los frontends embeben su script por dominio y el backend consume su Stats API en servidor (la API key nunca llega al navegador), exponiéndola al panel mediante rutas autenticadas.
Funcionalidades clave
- Multi-sitio desde un único backend y panel: cada marca con su dominio, identidad, menús, redes y notificaciones.
- TV en vivo con pipeline propio RTMP → LL-HLS y reproductor robusto basado en hls.js.
- Radio en vivo con metadatos en tiempo real, carátulas y letras sincronizadas.
- CMS editorial completo: artículos con TipTap y versionado, multimedia, destacados, categorías/etiquetas, usuarios y roles.
- IA editorial sobre DeepSeek (vía SSE): asistente analista con herramientas, generación de guiones de noticias y creación de borradores.
- Voz / TTS con RunPod serverless (modelo Qwen3-TTS) para narrar guiones, con seguimiento de coste y tiempos por job.
- Notificaciones push (OneSignal), edición digital del periódico, clima, tipo de cambio y cámaras de puentes.
- App móvil iOS/Android que reaprovecha toda la plataforma.
Decisiones técnicas y retos
- MySQL con SQL a mano en lugar de ORM: control fino sobre las consultas y el esquema, a cambio de disciplina en el código. El esquema se inicializa desde archivos
.sqlversionados. - Astro SSR + islas React: páginas server-rendered para SEO (OpenGraph, JSON-LD, sitemap) e hidratación solo donde hay interactividad, manteniendo el frontend público muy ligero.
- Multi-sitio por entorno, no por hostname en runtime: una instancia por marca seleccionada con
PUBLIC_SITE_ID, mientras el panel gobierna la configuración por sitio. Es un modelo pragmático que separa marca y dominio sin reescribir la app. - Streaming desacoplado: TV mediante MediaMTX como relay (RTMP→LL-HLS) y radio mediante proveedores Icecast/Triton, eligiendo en cada caso la tecnología adecuada en vez de forzar un único protocolo.
- Seguridad de sesión: refresh tokens en base de datos con fingerprint de dispositivo, guard de origen y secreto SSR para distinguir peticiones del servidor.
- Operación: caché en Redis, backups de MySQL a R2 con retención GFS y compresión, y analítica auto-hospedada para no depender de terceros.
Resultado
Una plataforma multimedia en producción que alimenta varios medios desde una sola base de código y un solo panel: noticias, televisión en directo y radio en vivo, en web y en aplicación móvil. La arquitectura multi-repo deja cada responsabilidad aislada —API/CMS, frontend, panel, streaming, analítica y móvil— lo que facilita evolucionar cada parte de forma independiente, añadir nuevas marcas con un despliegue parametrizado y mantener un sistema completo y autónomo, desde la ingesta de la señal de TV hasta la analítica de audiencia.