01Resumen del proyecto
Mapa de Alertasmuestra dónde hay una alerta de bombardeo en este momento: por óblast y por distrito, con objetivos en movimiento en el mapa, la línea del frente, puntos térmicos de satélites y un feed de canales de monitoreo debajo. Es leído por personas que necesitan la respuesta en segundos, y se lee en un teléfono, de noche, con mala conexión móvil.
La página, sin embargo, es solo una parte del producto. Los mismos datos salen a través de una API JSON abierta con claves y límites de tasa, y a través de un widget que otros sitios web incrustan en un marco propio. Diseñamos y construimos todo: los recolectores, el almacenamiento, la API, el mapa y el widget.
02Contexto y el problema
Los datos que responden «¿hay una alerta aquí?» no existen en un solo lugar. Las alertas oficiales vienen por óblast. Las alertas locales para comunidades provienen de un servicio diferente. Dónde están los objetivos está escrito, en palabras, por canales de monitoreo. La línea del frente es publicada por un proyecto de mapeo. Los incendios son vistos por satélites. Cinco fuentes, cinco formatos, cinco ideas diferentes de lo que significa «ahora».
El segundo problema es el silencio. Cualquiera de esas fuentes puede detenerse: un canal se queda en silencio, una API comienza a agotar el tiempo, y el modo de fallo honesto es decirlo, no seguir dibujando la imagen de ayer. Un mapa que parece tranquilo porque su fuente murió es peor que ningún mapa.
03Objetivos del proyecto
- una imagen ensamblada de cinco fuentes independientes, cada una en su propio reloj de actualización;
- una respuesta en segundos en un teléfono, con una conexión débil, de noche;
- datos que pueden salir del sitio: una API abierta con claves, límites y tarifas, y un widget embebible;
- tres idiomas, porque la audiencia no es solo local;
- una fuente que cayó en silencio debe ser visible como silenciosa, no como tranquila;
- la dirección del servidor nunca debe alcanzar las fuentes que lee.
04Cinco fuentes, una imagen
- Alertas oficiales por óblast — la columna vertebral del mapa;
- alertas locales para comunidades y distritos, de un servicio separado;
- canales de monitoreo en Telegram — leer tanto de vistas previas públicas como, para canales cerrados, a través del protocolo de mensajería en sí;
- la línea del frente, de un proyecto de mapeo que lo publica;
- puntos térmicos de satélites de NASA — incendios vistos desde la órbita.
Los recolectores funcionan como dos trabajadores de larga duración bajo el supervisor del sistema, cada uno reiniciado por su cuenta, y escriben en el almacenamiento local. El sitio web nunca se comunica directamente con una fuente: lee lo que los recolectores ya han escrito, por lo que una fuente lenta hace que el mapa esté más desactualizado en lugar de no disponible.
05Cuatro archivos en lugar de una base de datos
Los datos viven en cuatro archivos SQLite separados: el registro de alertas, suscripciones push y su estado por región, eventos del mapa con el feed, y claves API con sus contadores de tasa. No hay una base de datos compartida a propósito — la falla de un archivo no debe afectar a los otros. Si las suscripciones push no están disponibles, el mapa aún se dibuja; si el almacén de claves está ocupado, la página aún responde.
Los mismos archivos son escritos por el panel de control de todo el grupo — emitiendo una clave, restableciendo un estado de alerta — por lo que cada conexión se abre con un tiempo de espera. SQLite se rinde instantáneamente en una base de datos ocupada por defecto, y «instantáneamente» aquí significaría una página de error mientras un trabajador simplemente estaba escribiendo una fila.
06Tres relojes en una página
Diferentes datos envejecen a diferentes velocidades, por lo que se actualizan a diferentes velocidades: alertas cada 15 segundos, objetivos en movimiento cada 10, el feed cada 20. Un intervalo común sería incorrecto en ambas direcciones a la vez — demasiado lento para los objetivos, derrochador para el feed, y una solicitud innecesaria cada pocos segundos para miles de pestañas abiertas.
Cada bloque también lleva su propio «última actualización». Una página que se redibuja en silencio te enseña a confiar en ella exactamente cuando no debería ser confiable; una marca de tiempo que deja de moverse es la forma más rápida de decir «esta parte está desactualizada».
07Una API abierta con claves y tarifas
El mapa publica lo que sabe: alertas actuales, eventos, un punto final de análisis con un mapa de calor de «oblast × intervalo de tiempo», el ritmo del día, tipos de objetivos y direcciones. Los llamadores anónimos tienen un límite modesto por minuto; una clave lo aumenta, y las tarifas suben en escalones para aquellos que construyen sobre ello.
Las claves se emiten desde el panel de control compartido, nunca se escriben a mano, y el uso se cuenta por clave por día. Un punto final está deliberadamente cerrado para todos menos para el propietario de la clave — el que le dice a una clave su propia tarifa, límite y consumo. Todo lo demás está abierto, porque un mapa de servicio público que oculta sus datos es solo medio servicio público.
08Un widget que vive en los sitios de otras personas
El widget es la parte del producto que sale de casa. Dos tamaños fijos — una franja de estado y un panel cuadrado — tres idiomas, dos temas, y una política de marco escrita específicamente para que se permita la inserción aquí y en ningún otro lugar del sitio: el mapa y el widget pueden ser enmarcados, la cuenta y las páginas de soporte no pueden.
Debido a que vive en un marco, el widget no tiene cookies propias y no elige una generación de interfaz: se ve igual para todos. Esa es una decisión, no una limitación — un widget que se renderiza de manera diferente dependiendo de las elecciones previas de un visitante sería imposible de soportar en la página de otra persona.
09Notificación que conoce tu región
Una suscripción está vinculada a una región, y el estado de cada región se mantiene junto a las suscripciones. Eso es lo que hace que una notificación llegue al borde — cuando la alerta en tu oblast comienza o termina — en lugar de en cada actualización de la fuente. La diferencia es todo el producto: uno es una señal, el otro es ruido que la gente apaga en un día.
Hay una aplicación nativa sobre los mismos datos, y se comunica con una API de la aplicación en lugar de con las páginas web. Un endpoint de salud propio responde al registro de flota, porque una verificación de disponibilidad no debe ser más costosa que el trabajo que verifica.
10Tres idiomas, incluido el widget
El mapa habla ucraniano, inglés y ruso, al igual que la referencia de la API, las páginas de la cuenta y el widget. Se añade una nueva cadena de interfaz a los tres a la vez y un chequeo cuenta los que faltan: el conteo tiene que ser cero. Las interfaces medio traducidas no se anuncian a sí mismas: muestran silenciosamente un idioma dentro de otro y lucen bien para quien las escribió.
Los nombres de las regiones son una historia aparte: provienen de las fuentes en su propia ortografía, por lo que el mapa mantiene un diccionario propio en lugar de confiar en lo que llegó en el feed.
11Lectura de fuentes sin mostrar tu dirección
Todo lo que los recolectores obtienen sale a través de un proxy SOCKS5, incluido el protocolo de mensajería utilizado para canales cerrados: el proxy allí se realiza en código, sin una dependencia adicional. La dirección del servidor nunca llega a una fuente, y una fuente que decide bloquear a alguien bloquea el proxy, no la máquina que sirve el mapa.
El limitador de tasa se sitúa frente a la API por la misma razón al revés: un punto final público con datos en vivo atrae a los raspadores, y un límite por clave por minuto es lo que mantiene un servicio público utilizable para las personas para las que fue escrito.
12Pila tecnológica
- PHP 8.3 sin un marco: un pequeño enrutador, puntos finales y renderizadores;
- Trabajadores de Python bajo el supervisor del sistema: uno en la biblioteca estándar sola, uno que habla el protocolo de mensajería;
- SQLite, cuatro archivos separados, cada uno con su propia razón de existir;
- Leafletpara el mapa, activos encriptados, un widget con tamaños fijos;
- notificaciones web con estado por región, una aplicación nativa con los mismos datos;
- salida SOCKS5 para cada solicitud saliente, límites de tasa por clave frente a la API.
13El resultado
Un mapa que responde en segundos y sigue respondiendo cuando una de sus cinco fuentes se detiene. Datos que otros sitios pueden utilizar: una API abierta con claves y tarifas, y un widget en tres idiomas y dos temas. Notificaciones que se activan en el borde de un evento en lugar de en cada sondeo. Una aplicación nativa con los mismos datos, y un panel de control donde se emiten claves y se restablecen estados.
14Conclusiones
Tres cosas que llevaríamos a cualquier proyecto con datos en vivo.Separa el recolector de la página: un sitio web que obtiene una fuente mientras un visitante espera es un sitio web que se cae cada vez que la fuente falla.Dale a cada bloque su propio reloj y su propia marca de tiempo: un solo intervalo está mal en ambas direcciones, y un redibujo silencioso oculta la obsolescencia.Di cuando no sabes: un bloque vacío que lo admite vale más que un mapa que parece tranquilo con los datos de ayer.
Y una lección de producto: en el momento en que los datos pueden ser incrustados en otros lugares, el widget se convierte en el producto. Necesita tamaños fijos, su propia política de marco y traducciones: el mismo cuidado que la página principal, no un sobrante de ella.
Si tienes datos en vivo y necesitas un mapa, una API y un widget que otros sitios puedan tomar, este es el tipo de trabajo que hacemos de principio a fin.



