Skip to content

Rota Facil

Thauã Gabriel edited this page Jul 17, 2026 · 7 revisions

Introdução:

O Rota Fácil é um sistema de gestão de rotas voltado para o transporte escolar municipal, desenvolvido para apoiar prefeituras na organização e no acompanhamento das rotas realizadas pelos ônibus que transportam estudantes. Seu objetivo é centralizar as informações relacionadas ao transporte escolar e facilitar a comunicação entre os diferentes participantes desse processo, incluindo gestores municipais, motoristas e alunos. Ao estruturar e organizar os dados relacionados às rotas, o sistema contribui para tornar a logística do transporte escolar mais clara, previsível e acompanhada por todos os envolvidos. O Rota Fácil atua como um sistema central de gerenciamento das rotas escolares. Ele organiza as informações relacionadas ao transporte estudantil e permite acompanhar o andamento das rotas realizadas pelos ônibus. Por meio dessa organização, o sistema possibilita que os motoristas tenham acesso às informações necessárias para realizar suas rotas de forma adequada, como as paradas previstas e os alunos associados a cada trajeto. Ao mesmo tempo, os estudantes podem acompanhar o andamento da rota responsável pelo seu transporte. Essa centralização das informações também permite que a equipe de gestão municipal tenha uma visão mais ampla do funcionamento do transporte escolar, podendo acompanhar o status das rotas, verificar se os trajetos foram iniciados e identificar possíveis atrasos ou irregularidades.

O escopo:

  • Autenticação e controle de acesso por perfil (Prefeitura/ADMIN, Motorista/DRIVER, Aluno/STUDENT), com vínculo obrigatório de cada usuário a uma única prefeitura;
  • Gerencia de (CRUD) de rotas, ônibus, motoristas e instituições — restrito ao perfil Prefeitura;
  • Gestão de viagens: início, finalização e cancelamento (motorista, com justificativa obrigatória no cancelamento), inscrição e cancelamento de participação (aluno), telemetria em tempo real, controle de presença/falta de estudantes, feedback entre usuários e relatórios em PDF;
  • Check-in de estudantes exclusivamente via QR Code e válido apenas para a viagem ativa;
  • Notificações de eventos importantes, com destaque para o cancelamento de viagens, que notifica todos os usuários vinculados;
  • Auditoria automática de toda alteração relevante de estado (criação/atualização/exclusão de usuários, ônibus, viagens etc.), com registros imutáveis;
  • Perfil de usuário com visualização de dados como e-mail e foto, para usuários autorizados;
  • Análise inteligente: geração de descrição/interpretação de rotas e mapas de calor de pontos de embarque via IA (OpenAI).

O sistema é concebido desde sua base como uma aplicação distribuída de microsserviços (pré-requisito do Projeto Integrador de Sistemas Distribuídos), com comunicação assíncrona via RabbitMQ, múltiplas linguagens (Java/Spring Boot para os serviços de domínio, Python/FastAPI para o serviço de inteligência) e execução containerizada via Docker/Docker Compose.

Requisitos Funcionais - (RF)

  • Permitir diferentes níveis de acesso para usuário (Prefeitura, Motorista, Aluno possuem permissões distintas)
  • Permitir o cadastro de usuários, informando dados pessoais e selecionando uma prefeitura.
  • Permitir edição e exclusão de usuários, respeitando os níveis de acesso definidos
  • Vincular usuários a uma prefeitura (vínculo obrigatório para acesso ao sistema)
  • O sistema deve permitir o cadastro, consulta, atualização e remoção de prefeituras.
  • Permitir que alunos visualizem viagens disponíveis da sua prefeitura, com horários, rotas e paradas
  • Permitir que alunos se inscrevam em viagens
  • Permitir que alunos cancelem sua participação em viagens
  • Permitir check-in de alunos via QR Code
  • CRUD de viagens (rota, motorista, horários) — motorista e aluno não têm acesso
  • Permitir que motoristas visualizem as viagens do dia atribuídas a eles
  • Permitir que motoristas iniciem viagens, registrando horário de início e gerando QR Code
  • Enviar notificações sobre eventos importantes, incluindo cancelamento de viagens (todos os alunos vinculados notificados)
  • CRUD de rotas
  • CRUD de ônibus
  • CRUD de instituições
  • Registrar automaticamente logs de todas as alterações relevantes (criação/atualização/deleção); nenhum nível de usuário pode alterar ou remover esses registros
  • Exibir perfil de usuário com dados importantes (e-mail, foto) — motorista e aluno sem acesso a perfis de terceiros

Requisitos Não Funcionais / de Qualidade

  • Sistema acessível via navegador web (desktop e mobile)
  • Disponibilidade mínima de 95% em horário de uso (inatividade não deve ultrapassar 5%)
  • Armazenamento em banco relacional, com suporte a PostgreSQL
  • Seguir boas práticas de usabilidade — interface clara e intuitiva, com cores e ícones consistentes
  • Autenticação obrigatória via login e senha
  • Restringir acesso por papéis (admin, motorista, aluno), com diferentes níveis de confiabilidade e autorização
  • Registrar todas as ações sensíveis dos usuários em tabela de auditoria centralizada, melhorando a rastreabilidade
  • Comunicação assíncrona entre serviços via mensageria (RabbitMQ)
  • Execução em ambiente containerizado (Docker)

Diagramas auxiliares

* Diagrama de casos de uso

Captura de tela 2026-05-15 123618

* Diagrama de classes

Captura de tela 2026-07-13 113626

Arquitetura Geral

O Rota-Fácil foi desenvolvido seguindo uma arquitetura de microsserviços, na qual cada domínio do sistema (identidade, transporte, lugares, arquivos, auditoria, notificações e inteligência artificial) é isolado em um serviço independente, com banco de dados próprio, ciclo de deploy próprio e responsabilidade única e bem definida. A comunicação entre esses serviços é híbrida: síncrona via HTTP/REST para operações que exigem resposta imediata ao usuário, e assíncrona orientada a eventos via RabbitMQ para propagação de estado entre domínios e para processos que não bloqueiam a experiência do usuário final (auditoria, notificações, sincronização de réplicas de dados). Essa decisão foi guiada pela natureza do próprio domínio de negócio: o transporte escolar municipal envolve múltiplos atores com necessidades muito diferentes entre si (alunos, motoristas, prefeituras e administradores gerais), múltiplas integrações externas (Google OAuth2, OpenStreetMap, OpenAI, serviço de push notification) e requisitos de escalabilidade desiguais entre módulos — por exemplo, o processamento de telemetria de viagens (/transports/trips/process) é chamado com alta frequência pelos aplicativos dos motoristas, enquanto o cadastro de instituições ou prefeituras é uma operação esporádica. Uma arquitetura monolítica dificultaria escalar apenas os componentes que realmente precisam, além de acoplar times e ciclos de deploy que, na prática, evoluem em ritmos diferentes.

Justificativa da Escolha por Microsserviços.

  • a) Separação de responsabilidades por domínio: Cada serviço tem uma única razão para mudar: o auth-service muda quando as regras de identidade mudam; o transport-service muda quando as regras operacionais de rotas e viagens mudam. Isso reduz o acoplamento entre times e minimiza o "efeito cascata" de bugs — uma falha no notification-service, por exemplo, não derruba o cadastro de motoristas ou o processamento de uma viagem em andamento.

  • b) Escalabilidade independente: Serviços com padrões de carga muito diferentes (como o transport-service, que recebe atualizações de geolocalização em tempo real, versus o audit-service, que processa eventos em segundo plano) podem ser escalados horizontalmente de forma independente, sem desperdiçar recursos replicando o sistema inteiro.

  • c) Resiliência e tolerância a falhas: Como a comunicação entre domínios ocorre majoritariamente por eventos assíncronos (RabbitMQ), a indisponibilidade temporária de um serviço não bloqueia diretamente o funcionamento dos demais. Por exemplo, se o notification-service estiver fora do ar, o cancelamento de uma viagem ainda é processado normalmente pelo transport-service; o e-mail de aviso é apenas entregue quando o consumidor voltar a processar a fila.

  • d) Evolução tecnológica independente por serviço: A arquitetura permite que cada serviço utilize a stack mais adequada ao seu problema — os serviços de domínio de negócio (auth, transport, places, file, audit, notification, gateway, eureka) são construídos em Java/Spring Boot, enquanto o intelligence-service, por lidar com processamento de dados, geração de gráficos e integração com modelos de IA, foi implementado em Python com FastAPI, aproveitando o ecossistema de bibliotecas de ciência de dados (Pandas, Plotly) sem forçar essa dependência sobre o restante do sistema.

  • e) Desacoplamento via eventos: Serviços como transport-service, file-service e audit-service não criam usuários, instituições ou pontos de embarque diretamente — eles mantêm cópias locais desses dados a partir de eventos publicados pelo auth-service e pelo places-service (fontes únicas de verdade). Isso evita chamadas síncronas em cadeia entre serviços para operações de leitura frequentes, reduzindo latência e pontos únicos de falha.

* Modelos C4

Diagrama-contexto

Rota-Fácil_diagrama_contexto

Diagrama-container

Rota-Facil_container drawio

Diagrama-auth_componente

Rota-Fácil_auth_componente drawio

Diagrama-audit_componente

Rota-Fácil_audit_componente drawio

Diagrama-file_componente

Rota-Fácil_file_componente drawio

Diagrama-transport_componente

Rota-Fácil_transport_componente drawio

Diagrama-places_componente

Rota-Fácil_places_componente drawio

Manutenção VACUUM

Esta rotina executa periodicamente VACUUM (ANALYZE) nos bancos PostgreSQL do Rota Facil. Ela complementa o autovacuum nativo do PostgreSQL; não o substitui e não deve ser usada como motivo para desativá-lo. O processo não utiliza VACUUM FULL. O FULL reescreve tabelas e exige bloqueios mais agressivos, por isso não faz parte da manutenção automática.

Bancos atendidos.

O script percorre os containers definidos no compose geral:

  • auth-database
  • places-database
  • transport-database
  • audit-database
  • files-database
  • notification-database

Para cada container, o script usa POSTGRES_USER e POSTGRES_DB já presentes no ambiente do próprio container. Senhas e conteúdo do .env não são copiados para o script ou para as unidades do systemd.

Arquivos

  • scripts/maintenance/rota-facil-vacuum.sh: executa e monitora a manutenção de cada banco.
  • deploy/systemd/rota-facil-vacuum.service: serviço oneshot responsável pela execução.
  • deploy/systemd/rota-facil-vacuum.timer: agenda a execução mensal.

Funcionamento

O timer inicia o serviço no primeiro domingo de cada mês, às 03:30 no fuso America/Fortaleza, com atraso aleatório de até 30 minutos. O fuso é explícito porque o host de produção pode operar em UTC. A opção Persistent=true faz o systemd recuperar uma execução perdida depois que a máquina voltar a funcionar.

O serviço reduz a prioridade de CPU e I/O e permite no máximo seis horas por execução. Os logs são enviados ao journal do systemd.

O script:

  1. Confirma que docker e flock estão instalados.

  2. Obtém um lock em /var/lock/rota-facil-vacuum.lock, impedindo execuções simultâneas.

  3. Confirma que cada container existe e está em execução.

  4. Executa vacuumdb --analyze --jobs=2 --verbose no banco configurado no container.

  5. Continua nos demais bancos caso um deles falhe.

  6. Retorna erro ao systemd se pelo menos um banco não for processado.

O paralelismo pode ser alterado por meio de ROTA_FACIL_VACUUM_JOBS. O valor padrão é 2 para evitar carga excessiva em produção.

Instalação no host de produção

Execute a partir da raiz do projeto, com um usuário que possua sudo:

sudo install -o root -g root -m 0750 \
  scripts/maintenance/rota-facil-vacuum.sh \
  /usr/local/sbin/rota-facil-vacuum.sh
sudo install -o root -g root -m 0644 \
  deploy/systemd/rota-facil-vacuum.service \
  /etc/systemd/system/rota-facil-vacuum.service
sudo install -o root -g root -m 0644 \
  deploy/systemd/rota-facil-vacuum.timer \
  /etc/systemd/system/rota-facil-vacuum.timer
sudo systemctl daemon-reload
sudo systemctl enable --now rota-facil-vacuum.timer

O serviço roda como root por padrão para acessar o socket do Docker e criar o arquivo de lock. Não adicione senhas aos arquivos do systemd.

Validação inicial

Confira quando ocorrerá a próxima execução:

systemctl list-timers rota-facil-vacuum.timer
systemctl status rota-facil-vacuum.timer

Antes de depender do agendamento, faça uma execução manual em horário de baixa utilização:

sudo systemctl start rota-facil-vacuum.service
sudo journalctl -u rota-facil-vacuum.service -f

Ao terminar, confirme o resultado:

sudo systemctl status rota-facil-vacuum.service
sudo journalctl -u rota-facil-vacuum.service --since today

O resultado esperado é status=0/SUCCESS. Se algum container estiver ausente, parado ou não tiver as variáveis necessárias, o serviço terminará como falha e indicará o container afetado no journal.

Operação e ajustes

Para executar com apenas uma conexão por banco, adicione ao bloco [Service] da unidade instalada:

Environment=ROTA_FACIL_VACUUM_JOBS=1

Depois de qualquer alteração em uma unidade:

sudo systemctl daemon-reload
sudo systemctl restart rota-facil-vacuum.timer

Para mudar a periodicidade, altere OnCalendar em rota-facil-vacuum.timer. A expressão atual representa o primeiro domingo de cada mês. A expressão pode ser validada antes da implantação:

systemd-analyze calendar 'Sun *-*-01..07 03:30:00 America/Fortaleza'

Para desativar a rotina sem apagar os arquivos:

sudo systemctl disable --now rota-facil-vacuum.timer

Observações de produção

  • Faça a primeira execução em uma janela de baixa demanda e acompanhe CPU, I/O, espaço em disco e duração.
  • O VACUUM comum permite operações concorrentes, mas ainda consome recursos do banco e do host.
  • Se o nome de um container mudar no compose de produção, atualize a lista DATABASE_CONTAINERS no script e reinstale-o.
  • Se a aplicação deixar de usar containers para PostgreSQL, este script deverá ser adaptado para conectar diretamente aos servidores de banco.
  • Necessidade de VACUUM FULL, REINDEX ou ajustes de autovacuum deve ser avaliada separadamente, com métricas e janela de manutenção.

Eventos RabbitMQ do Rota Fácil

Mapeamento do contrato assíncrono observado em 2026-07-13. Este documento registra exchanges, routing keys, produtores, consumidores e efeitos. O location-service não faz parte do escopo desta atualização.

Visão geral

Exchange Dono Conteúdo
auth.events auth-service Usuários, autenticação e prefeituras.
places.events places-service Instituições e pontos de embarque.
transport.events transport-service Rotas, ônibus, viagens, feedback e contadores.
file.events file-service Ciclo de vida de arquivos.

Os eventos cumprem dois papéis: integração operacional e auditoria. Muitos payloads carregam simultaneamente dados do domínio e campos userId, prefectureId, userEmail/email, role, actor*, actionTitle, actionType, resourceName e resourceId.

Contrato da auditoria

O audit-service consome um DTO genérico, AuditEventReceive.

  • Se actorUserId, actorEmail e actorRole estiverem preenchidos, eles identificam o autor real da ação.
  • Caso contrário, o mapper usa userId, userEmail/email e role.
  • prefectureId determina o isolamento na consulta HTTP.
  • actionTitle, actionType, resourceName e resourceId descrevem a ação e o recurso.

A API de auditoria nunca aceita a prefeitura como filtro externo; usa o x-prefecture-id autenticado.

auth-service

Publica em auth.events

Routing key Quando Consumidores Observações
user.created Cadastro público, motorista por admin e conclusão Google. Transport, audit, notification. Cadastro por admin inclui actor*; cadastro público usa o usuário criado como ator.
user.updated Atualização própria e troca de prefeitura. Transport, audit. Sincroniza a cópia local.
driver.admin.updated Admin edita motorista. Transport, audit. Carrega motorista como recurso e admin como ator.
user.deleted Usuário remove a própria conta. Transport, file, audit, notification, gateway. Limpeza, e-mail e invalidação do token.
user.email.changed Alteração de e-mail. Gateway, audit. Invalida o token anterior.
user.deactivate Desativação própria ou de motorista por admin. Transport, audit. A variante administrativa inclui actor*.
user.logout Logout. Gateway, audit. Invalida o token e registra auditoria.
prefecture.created Criação de prefeitura. Audit. Registra criação.
prefecture.updated Atualização de prefeitura. Audit. Registra atualização.
prefecture.deleted Exclusão de prefeitura. File, audit. Remove arquivos e registra auditoria.

O fluxo atual de registerUserPrefecture cria usuário administrativo, mas não publica user.created.

Consome de transport.events

Routing key Fila padrão Efeito
user.feedback auth.user.updated.queue Atualiza score do avaliado.
trip.completed auth.user.complete.trip.queue Incrementa completedTrips.
user.trips.increased auth.user.trips.increased.queue Incrementa trips.
user.trips.decreased auth.user.trips.decreased.queue Decrementa trips.

places-service

Publica em places.events

Routing key Quando Consumidores
institution.created Criação de instituição. Transport, audit.
institution.updated Atualização de instituição. Transport, audit.
institution.deleted Exclusão de instituição. Transport, file, audit.
boarding.created Criação de ponto de embarque. Transport, audit.
boarding.updated Atualização de ponto de embarque. Transport, audit.
boarding.deleted Exclusão de ponto de embarque. Transport, file, audit.

Não há consumidores RabbitMQ no places-service.

transport-service

Consome de auth.events

Routing key Fila padrão Efeito
user.created transport.user.created.queue Cria cópia local.
user.updated transport.user.updated.queue Atualiza cópia local.
driver.admin.updated transport.user.updated.queue Atualiza motorista na mesma fila.
user.deleted transport.user.deleted.queue Remove ou ajusta cópia local.
user.deactivate transport.user.deactivate.queue Desativa cópia local.

Consome de places.events

Routing key Efeito
institution.created/updated/deleted Mantém a cópia operacional da instituição.
boarding.created/updated/deleted Mantém a cópia operacional do ponto.

As filas padrão são específicas por operação, sob os prefixos transport.institution..queue e transport.board.point..queue.

Publica em transport.events

Routing key Quando Consumidores Observações
trip.created Criação/agendamento de viagem. Nenhum consumidor observado. Payload operacional; não está ligado à auditoria.
trip.running Motorista inicia a ida. Audit, notification. Registra auditoria e notifica passageiros. O início explícito da volta não republica este evento.
trip.cancelled Motorista cancela viagem. Audit, notification. Inclui motivo, passageiros e dados de auditoria.
trip.deleted Exclusão de viagem. Audit. Inclui dados de auditoria.
trip.completed Finalização operacional. Auth. Atualiza viagens concluídas dos usuários.
user.trips.increased Entrada de aluno ou início do motorista. Auth. Incrementa contador.
user.trips.decreased Aluno sai antes do início. Auth. Após o início, a saída marca falta e não publica decremento.
user.feedback Avaliação de usuário. Auth, notification, audit. Atualiza score, envia e-mail e registra auditoria.
route.created Criação de rota. Audit. Dados de auditoria.
route.updated Atualização de rota. Audit. Dados de auditoria.
route.deleted Exclusão/soft delete de rota. Audit. Dados de auditoria.
bus.created Cadastro de ônibus. Audit. Admin como ator.
bus.updated Atualização de ônibus. Audit. Admin como ator.
bus.deleted Soft delete de ônibus. File, audit. Remove arquivos e registra auditoria.

file-service

Publica em file.events

Routing key Quando Consumidor
file.created Upload/criação. Audit.
file.updated Substituição. Audit.
file.deleted Remoção. Audit.

Consome exclusões

Exchange Routing key Fila padrão Efeito
auth.events user.deleted file.user.deleted.queue Remove arquivos de estudante/motorista.
auth.events prefecture.deleted file.prefecture.deleted.queue Remove arquivos da prefeitura.
places.events institution.deleted file.institution.deleted.queue Remove arquivos da instituição.
places.events boarding.deleted file.boarding.deleted.queue Remove arquivos do ponto.
transport.events bus.deleted file.bus.deleted.queue Remove arquivos do ônibus.

audit-service

O audit usa uma fila por exchange:

  • audit.auth.queue: todos os eventos de auth listados acima.
  • audit.places.queue: CRUD de instituição e ponto.
  • audit.transport.queue: CRUD de rota e ônibus, trip.running, trip.cancelled, trip.deleted e user.feedback.
  • audit.file.queue: CRUD de arquivo.

O serviço não publica eventos.

notification-service

Exchange Routing key Fila padrão Efeito
auth.events user.created notification.user.created.queue E-mail de boas-vindas.
auth.events user.deleted notification.user.deleted.queue E-mail de conta removida.
transport.events trip.running notification.trip.running.queue Persiste notificação de início.
transport.events trip.cancelled notification.trip.cancelled.queue E-mail e notificação persistida.
transport.events user.feedback notification.user.feedback.queue E-mail de feedback.

Os handlers de viagem capturam exceções e registram o payload contextual no log. O listener está configurado com defaultRequeueRejected=false; mensagens com falha são descartadas para evitar loop de reprocessamento. Não há DLQ configurada no código atual.

O serviço não publica eventos.

gateway-service

Consome user.deleted, user.email.changed e user.logout de auth.events. Os três bindings compartilham gateway.invalid.user.token.queue e adicionam o token ao Redis.

O gateway não publica eventos.

Matriz resumida

Serviço Publica Consome
Auth Usuários e prefeituras. Score e contadores do transporte.
Places Instituições e pontos. Nenhum.
Transport Rotas, ônibus, viagens, feedback e contadores. Usuários e lugares.
File Ciclo de arquivos. Exclusões de auth, places e transport.
Audit Nenhum. Auth, places, transport e file.
Notification Nenhum. Auth e transport.
Gateway Nenhum. Invalidação de tokens de auth.