Aplicacao web em Dash para visualizacao operacional de onibus, com atualizacao em tempo real de posicoes GPS, sobreposicao de dados estaticos GTFS e planejamento de rotas intermodais.
- Execucao oficial em desenvolvimento e producao: Docker.
- Deploy oficial em producao: Render com runtime Docker (
render.yaml). - Endpoint tecnico para monitoramento:
GET /health. - Pagina amigavel para suporte operacional:
GET /status. - Aba Veiculos aceita busca manual de ID fora da listagem atual do dropdown.
- Selecao de linhas persiste entre sessoes do navegador (localStorage).
- Tema claro/escuro com alternancia no topo da interface.
- Preferencia de tema persiste entre sessoes no navegador.
- Camada base do mapa sincroniza automaticamente com o tema ativo.
- Versionamento unificado por build: runtime, cache PWA e chaves de sessao.
- Build atual exibido no topo da interface, ao lado do titulo.
- Reorganizacao estrutural consolidada em
src/, sem camada legada na raiz. - Interface lateral (sidebar): painel de controle fixo ao lado esquerdo do mapa.
- Aba Trajetos: planejamento de rotas intermodais com visualizacao no mapa.
- Aviso de GTFS: banner de alerta automático se os dados estáticos (itinerários/cores) falharem no carregamento.
Principais capacidades:
- Consulta de veiculos em tempo real.
- Filtro por linhas e por veiculos especificos.
- Renderizacao de itinerarios e pontos de parada a partir de GTFS local.
- Basemaps: OSM, Carto Claro e Carto Escuro.
- Exclusao de pontos fora do municipio e filtragem de veiculos em garagem.
- Cache de camadas estaticas e dinamicas para reduzir custo de processamento.
- Health check tecnico e status amigavel para operacao.
- Suporte opcional a Redis e Sentry.
- Planejamento de rotas intermodais com zoom automatico e visualizacao no mapa.
- Cores GTFS: linhas de onibus exibidas com as cores oficiais do GTFS (
route_color). - Paradas intermediarias: marcadores e lista das paradas percorridas por cada trecho.
A aba Trajetos permite planejar rotas de transporte publico entre dois enderecos do Rio de Janeiro.
- Acesse a aba Trajetos no painel lateral.
- Informe o endereco de Origem e Destino.
- Clique em Buscar.
- Selecione uma das opcoes de itinerario exibidas.
- O mapa exibe automaticamente o percurso com zoom ajustado.
- Clipping geométrico: as polylines de roteamento são cortadas exatamente nos pontos de embarque e desembarque. O sistema utiliza uma varredura sequencial com penalidade de comprimento e alinhamento automático com trechos de caminhada adjacentes para garantir conexões sem emendas (seamless) e sem loops.
- Paradas no mapa: círculos coloridos marcam cada parada intermediária, renderizados acima das linhas para melhor visibilidade.
- Paradas no card: a timeline detalhada lista todas as paradas do trecho; o layout foi otimizado para evitar sobreposição de texto em trajetos longos.
- Marcadores de origem/destino: ícones de destaque no mapa para facilitar a orientação.
- Trechos a pé: exibidos com linha pontilhada escura de alto contraste.
- Hierarquia de camadas (Z-Index): o mapa prioriza a visualização exibindo paradas no topo, seguidas por trechos a pé e, por fim, as linhas de ônibus.
As rotas sao calculadas pela API do Transitous — projeto de codigo aberto que agrega dados de transporte publico de diversas cidades e oferece planejamento de rotas via MOTIS 2.
Recurso experimental: o roteamento depende de servico externo e pode apresentar variacao de disponibilidade.
- Python 3.12.x
- Dash + Flask
- Dash Leaflet
- Pandas + GeoPandas
- Gunicorn
- Redis (opcional)
- Docker / Docker Compose
Estrutura atual do projeto:
src/core/app_runtime.py: entrypoint oficial Flask/Dash usado por Gunicorn.src/: pacote Python oficial (config,core,logic,state,ui,utils).src/logic/transitous_logic.py: integracao com a API Transitous (geocoding e roteamento).src/logic/gtfs_static_logic.py: carregamento e cache do GTFS estatico, incluindo cores das linhas.tests/: suite de testes automatizados.assets/: CSS e arquivos estaticos web.
- Docker Desktop (Windows/macOS) ou Docker Engine + Compose plugin (Linux)
- Acesso aos dados locais:
gtfs/gtfs.zipgtfs/dicionario_lecd.csv- shapefile de garagens em
garagens/
docker compose up --buildEsse comando usa o perfil base (producao-like), sem hot reload.
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --buildNesse modo, o codigo local e montado no container e o Gunicorn roda com
--reload, entao alteracoes em arquivos Python sao aplicadas automaticamente.
Servicos esperados:
- App:
http://localhost:8080 - Redis:
localhost:6379
- Health tecnico:
http://localhost:8080/health - Status amigavel:
http://localhost:8080/status - Robots:
http://localhost:8080/robots.txt - Sitemap:
http://localhost:8080/sitemap.xml
Melhorias aplicadas para aumentar indexacao e CTR em buscadores:
- Metadados de SEO no HTML base (
description,robots,canonical). - Metadados sociais (
Open GrapheTwitter Cards) com imagem de preview. - JSON-LD (
WebApplication) para dados estruturados. - Canonicalizacao de URL de linha:
/?linha=LECD137-> redireciona para/linhas/LECD137(301)./linhas/<token>e a URL canonica./veiculose/trajetosabrem as abas correspondentes.- Prefixos de idioma na URL (
/en/,/es/) foram removidos para simplificacao. - O idioma e resolvido automaticamente por
Accept-Languagedo navegador com fallback parapt-BR.
- Endpoints dedicados para crawler:
/robots.txt/sitemap.xml
- Protecao de indexacao de endpoints tecnicos via
X-Robots-Tag: noindexpara/_dash*,/healthe/status.
Execute localmente (ou em CI) para validar respostas esperadas:
curl.exe -sS https://riob.us/robots.txt
curl.exe -sS https://riob.us/sitemap.xml
curl.exe -I "https://riob.us/?linha=LECD137"
curl.exe -I "https://riob.us/?linha=LECD137&lang=en"
curl.exe -sS https://riob.us/linhas/LECD137 | findstr /I "canonical og:url"Resultado esperado:
/robots.txtretorna regras de crawler eSitemap:./sitemap.xmlretorna XML valido com<urlset>./?linha=LECD137responde301para/linhas/LECD137.- HTML de
/linhas/LECD137contem canonical eog:urlda propria linha.
Atalho: script de smoke test SEO
./scripts/seo_smoke.ps1 -BaseUrl http://localhost:8080 -CanonicalBaseUrl https://riob.us -LineToken LECD137
./scripts/seo_smoke.ps1 -BaseUrl https://www.riob.us -CanonicalBaseUrl https://riob.us -LineToken LECD137- Abrir a propriedade
https://riob.usno Search Console. - Ir em
Sitemaps. - Informar
sitemap.xmle enviar. - Confirmar status
Successe ausencia de erro de fetch.
Observacao: a submissao exige autenticacao da conta proprietaria do dominio.
URLs recomendadas para inspecao:
https://riob.us/https://riob.us/linhas/LECD137https://riob.us/veiculoshttps://riob.us/trajetos
Checklist:
- URL canônica reconhecida pelo Google corresponde a URL publicada.
- Pagina esta
Indexable. - Metadados (
title,description,og:*,twitter:*) presentes. - JSON-LD (
WebApplication) detectado no Rich Results Test.
O deploy e feito pelo render.yaml com runtime: docker e dockerfilePath: ./Dockerfile.
Passos recomendados:
- Fazer push para o repositorio remoto.
- Criar/atualizar o servico no Render por Blueprint.
- Confirmar uso do Docker runtime e variaveis de ambiente.
- Validar
/healthe/statusapos deploy.
| Variavel | Obrigatoria | Padrao | Finalidade |
|---|---|---|---|
PORT |
Nao | 8080 |
Porta HTTP usada pelo Gunicorn |
IN_DOCKER |
Sim (runtime oficial) | 1 |
Garante execucao em ambiente containerizado |
REDIS_URL |
Nao | vazio | Habilita cache Redis quando configurado |
SENTRY_DSN |
Nao | vazio | Habilita envio de erros para Sentry |
PERF_LOG_ENABLED |
Nao | 1 local / 0 sugerido em prod |
Liga/desliga logs de performance |
WEB_CONCURRENCY |
Nao | 2 |
Workers do Gunicorn |
GUNICORN_THREADS |
Nao | 2 |
Threads por worker |
GUNICORN_TIMEOUT |
Nao | 180 |
Timeout por request |
MAP_STATIC_CACHE_TTL_SECONDS |
Nao | 900 |
TTL cache camadas estaticas |
VEHICLE_LAYERS_CACHE_TTL_SECONDS |
Nao | 120 |
TTL cache camadas de veiculos |
POLL_INTERVAL_IDLE_MS |
Nao | 90000 |
Poll sem selecao ativa |
POLL_INTERVAL_LINES_ACTIVE_MS |
Nao | 30000 |
Poll com linhas selecionadas |
POLL_INTERVAL_VEHICLES_ACTIVE_MS |
Nao | 20000 |
Poll com veiculos selecionados |
APP_BUILD_ID |
Nao | vazio | ID de build da aplicacao (usa RENDER_GIT_COMMIT como fallback) |
RENDER_GIT_COMMIT |
Injetada pelo Render | hash de commit | Fallback automatico de versao quando APP_BUILD_ID nao e definido |
Comportamento atual da UI para reduzir friccao no retorno do usuario:
- O filtro de
Linhase persistido nolocalStoragedo navegador. - Ao abrir o app novamente, o filtro e restaurado automaticamente.
- Ao alternar entre as abas
LinhaseVeiculos, a selecao anterior de linhas e preservada. - Se alguma linha salva nao existir mais nas opcoes atuais, ela e removida de forma segura.
- Nesses casos, o app mostra um aviso curto no banner superior.
Versionamento unificado no frontend:
APP_BUILD_ID(ou fallbackRENDER_GIT_COMMIT) e a fonte de verdade da versao.- Esse build_id controla:
- invalidacao de estado persistido por build;
- registro/cache do Service Worker (PWA) por build;
- refresh automatico quando backend e frontend estao em builds diferentes.
- O build atual fica visivel no topo da interface (badge ao lado de
RioB.us).
Persistencia de tema no frontend:
- O alternador de tema (claro/escuro) fica no topo da interface.
- A preferencia de tema e salva no
localStorage. - Na primeira abertura sem preferencia salva, o app segue
prefers-color-schemedo navegador/sistema.
Sincronizacao de tema com mapa base:
- Tema claro seleciona automaticamente
Carto Claro. - Tema escuro seleciona automaticamente
Carto Escuro. - O usuario pode trocar manualmente para outra camada base (ex.:
OSM) a qualquer momento.
Na aba Veiculos:
- O dropdown continua priorizando veiculos recentes do snapshot.
- Ao digitar um ID nao presente na lista, aparece uma opcao de busca manual.
- Essa opcao pode ser selecionada para filtrar o mapa sem depender da opcao pre-carregada.
Regras de busca manual:
- Busca por valor completo:
A50001. - Busca por sufixo numerico:
50001tambem encontraA50001.
Você pode abrir abas ou aplicar filtros diretamente pela URL:
- Aba Linhas com filtro único:
https://riob.us/linhas/LECD137 - Aba Linhas com filtro múltiplo (CSV):
https://riob.us/linhas/LECD137,LECD138 - Aba Linhas com filtro via query:
https://riob.us/?linhas=LECD137,LECD138ouhttps://riob.us/?linha=LECD137&linha=LECD138 - Aba Veículos:
https://riob.us/veiculos - Aba Trajeto:
https://riob.us/trajetos
Comportamento:
- O componente correspondente (Linhas, Veículos ou Trajeto) é ativado automaticamente.
- Para linhas, o filtro correspondente é aplicado no carregamento da página.
- Não há deep link para veículos específicos;
/veiculosabre a aba genérica.
Idioma nos deep links:
- Não utilize prefixos de idioma na URL (
/en/,/es/). - O app resolve o idioma automaticamente pelo header
Accept-Language, preferência do navegador ou fallbackpt-BR.
Fluxo recomendado para ambiente Python local (fora de Docker):
pip install -r requirements.txt
pip install -e ".[test]"Esse fluxo garante importacao formal do pacote src sem manipulacao manual de sys.path.
Execute os testes no ambiente local (ou dentro do container de app):
pytestPara mudancas no fluxo de UI/filtros, o conjunto minimo recomendado inclui:
tests/test_callbacks_ui.pytests/test_pipeline_smoke.py
Cobertura estrutural recente de layout:
- Presenca do botao de tema no cabecalho.
- Presenca dos basemaps
Carto ClaroeCarto Escuro. - Ausencia das opcoes antigas
ESRI PadrãoeESRI P&B.
Smoke recomendado apos alteracoes de runtime:
curl http://localhost:8080/health
curl http://localhost:8080/statusGET /health retorna JSON com:
- status geral
- GTFS carregado
- timestamp do ultimo update GPS
- indicador de fetch com dados
- estatisticas de cache
- build_id
- uso de memoria (quando
psutilestiver disponivel)
GET /status expoe painel HTML amigavel para suporte e troubleshooting operacional.
Quando as APIs publicas de GPS estiverem fora do ar (timeouts/503):
- No modo
Veiculos, a camada dinamica depende de snapshot recente e pode ficar sem pontos durante a indisponibilidade.
Caso o app nao consiga baixar ou processar o GTFS oficial na inicializacao:
- Um aviso persistente e exibido no topo da interface.
- O roteamento (Aba Trajetos) continua funcional, mas os trechos de onibus usarao a cor padrao vermelha.
- As camadas de shape/itinerario no modo
Linhasnao serao renderizadas.
- Validar operacao em producao/staging apos migracao para
src. - Manter cobertura de testes e smoke checks (
/healthe/status) a cada lote.
Antes de publicar:
- Revisar alteracoes:
git statusegit diff --name-only. - Revisar historico recente:
git log --oneline -5. - Validar testes impactados.
Para publicar commits locais ja criados:
git push origin mainEste projeto e licenciado sob os termos da GNU General Public License v3 (GPL v3).
Veja o arquivo LICENSE para detalhes completos.
- Este software e fornecido "como esta", sem garantias de qualquer tipo.
- Você pode copiar, distribuir e modificar este software livremente.
- Works derivados devem ser licenciados sob GPL v3.
- O codigo fonte esta disponivel neste repositorio.
| Servico / Projeto | Uso | Licenca / Tipo |
|---|---|---|
| Transitous | Motor de roteamento intermodal (MOTIS 2) | Codigo aberto, dados abertos |
| Data.Rio | Dados GPS e GTFS do sistema de onibus do Rio | API publica |
| IBGE | Geometria do municipio do Rio de Janeiro | API publica |
| Dash Leaflet | Renderizacao do mapa interativo | MIT |
| OpenStreetMap | Camada base de mapa | ODbL |
| Carto | Camadas base Carto Claro e Carto Escuro | Gratuito para uso publico |