Aquisição e ingestão — alta volumetria do dispositivo ao banco
Dispositivos publicam métricas, coordenadas e dados binários por MQTT. A bridge Go os separa em Redis Streams; workers decodificam Protobuf e as amostras DAQ, agrupam lotes e persistem antes de confirmar o consumo. Chaves de ingestão deduplicam métricas e posições reentregues. Recuperação de mensagens pendentes e quarentena isolam falhas sem confundir o caminho durável com a distribuição ao vivo.
Séries temporais — histórico com contexto
TimescaleDB armazena nome da métrica, valor, timestamp e sessão em hypertables; PostGIS mantém posições geográficas. O histórico do gráfico filtra as variáveis e o intervalo na sessão mais recente do dispositivo, calcula médias por segundo e envia arrays de tempos e valores. Assim, a tela parte de dados persistidos e depois acrescenta novas amostras, preservando a referência temporal do experimento.
Gráficos ao vivo — WebSocket e Protobuf
Depois da persistência e do ACK, os workers publicam dados binários em Redis Pub/Sub. Um relay encaminha os frames a grupos por dispositivo no Django Channels; o consumidor WebSocket aplica os filtros selecionados e distingue histórico de dados novos. No Vue, ArrayBuffer é decodificado em séries: o histórico substitui o conjunto e amostras ao vivo são anexadas. Atualizações são agrupadas a cada 500 ms e a série incremental mantém até 2.500 pontos por variável. Eventos de alarme atualizam a lista em paralelo.
Frotas e geografia — SSE e mapas
Um fluxo separado fornece o estado das unidades e suas posições por Server-Sent Events. O store Pinia recebe um snapshot inicial, atualiza as unidades a partir do stream e tenta reconectar após interrupções. Leaflet apresenta posições e trajetos, enquanto Chart.js apresenta sinais temporais. SSE do mapa e WebSocket dos experimentos têm contratos distintos; a interface não precisa refazer toda a página para receber cada atualização.
Saúde da ingestão — métricas derivadas das fontes
HealthSnapshots coleta Redis Streams, filas Celery, estatísticas Redis e psutil. Backlog soma mensagens pendentes e lag dos grupos; a taxa de entrada é estimada pela diferença dos contadores cumulativos entre dois snapshots, não pela contagem de inserts no banco. Dead letters, clientes MQTT publicados a partir dos tópicos $SYS, tamanho das filas e recursos visíveis ao processo compõem o painel. Fontes lentas são consultadas em paralelo com timeouts; métricas indisponíveis ficam desconhecidas em vez de virar zero.
Observabilidade — traces, logs e histórico operacional
OpenTelemetry instrumenta Django, Celery, Redis, requests e psycopg2; spans seguem por OTLP em lotes. Logs JSON do backend incluem trace/span IDs, e os serviços Go usam slog estruturado com limitação de erros repetidos. O agregador consulta Prometheus para spans/s, proporção de erros, p99 de duração e histórico de 24 horas. A integração usa um collector OTLP e séries Prometheus compatíveis com as consultas do agregador.
Painel do sistema — snapshots SSE com estado de conexão
A API envia snapshots de saúde por SSE com cadência-alvo de 2 segundos, ajustada ao tempo da coleta. SystemHealth, em Vue, apresenta indicadores atuais e gráficos históricos; o consumidor trata frames SSE fragmentados, reconecta quando perde o fluxo e sinaliza dados possivelmente desatualizados. O painel de enriquecimento complementa essa visão com uso de API, cache e erros, consultados periodicamente. A telemetria de dispositivos fica no TimescaleDB; o histórico operacional deste painel vem do Prometheus.
Demais serviços — gestão, configuração e relatórios
Django/DRF mantém dispositivos, firmware, certificados, experimentos e frotas. O parser A2L prepara configuração de aquisição; plugins de relatórios consultam TimescaleDB e geram PDFs Matplotlib. O logger C++/MDF é um caminho de arquivo separado. Docker Compose e GitLab CI apoiam execução e entrega.