O desafio logístico fora dos grandes centros: Construindo uma aplicação de rotas do zero
Você já teve aquele amigo que soltava: "Eu moro na esquina do bar do seu José, aqui perto da parada de carro..."?
Em regiões fora das grandes capitais e áreas metropolitanas, essa falta de padronização é uma realidade constante. E quando falamos de logística, entregas de pacotes e otimização de rotas, essa informalidade nos endereços transforma-se num problema complexo de engenharia.
Tive a ideia deste projeto ao conversar com um colega que faz entregas na nossa região. Ele comentou comigo que o processo de organizar os pacotes, agrupar as áreas e definir por onde começar a rota era uma verdadeira bagunça, feita muitas vezes com base na memória e na intuição. Pensei comigo: "E se eu montar uma aplicação para, ao menos, separar, roteirizar e setorizar estes pacotes?".
Após realizar um levantamento de requisitos operacionais (briefing) sobre o processo atual dele, percebi que o desenvolvimento de um sistema não precisaria ser algo puramente abstrato. Havia um problema real e tangível a ser resolvido.
Sou estudante de Engenharia de Software e, através da minha jornada acadêmica em ensino à distância e das minhas experiências no suporte técnico de sistemas, tenho procurado aplicar os conceitos teóricos na resolução de atritos do dia a dia. A vida de um programador é dar a cara a tapa, tentar, errar e iterar. Por isso, decidi abraçar este desafio logístico.
Montei a arquitetura base para o sistema. Grande parte das tecnologias que planeio utilizar envolve conceitos com os quais ainda não tive um contacto tão profundo, mas estou a utilizar este projeto para adquirir horas de extensão universitária e como uma fundação robusta para um possível Trabalho de Conclusão de Curso (TCC). Sem esquecer, claro, a perspetiva de monetizar a ferramenta no futuro, visto que o meu colega será o beta tester e o primeiro utilizador real da plataforma.
Boas práticas: Planeamento antes da primeira linha de código
No ecossistema de desenvolvimento, existe uma pressa enorme para começar a escrever código. No entanto, se estudamos boas práticas de engenharia, como os princípios SOLID e padrões de arquitetura, por que não aplicá-los antes de sujar as mãos? Até ao momento, planejei toda a estrutura "no papel".
Primeiro, desenhei o Diagrama de Atividades, mapeando detalhadamente o fluxo do entregador — desde a autenticação na tela inicial até à verificação em loop de pacotes pendentes e à ação contínua de fotografar a etiqueta. Quando o entregador inicia a jornada, ele passa pela extração de dados através de inteligência artificial (Gemini), pelo cálculo do setor e pela gravação do pacote nas rotas pendentes. Este fluxo garante que o utilizador não precise de interagir dezenas de vezes com a tela do celular enquanto está na rua; o ciclo pergunta sistematicamente se existe "Cadastro de mais Pacotes?" antes de prosseguir.

Mas o verdadeiro cérebro da aplicação reside em como os dados são estruturados e como as entidades interagem entre si no backend. Para isso, construí um Diagrama de Classes e Entidade-Relacionamento detalhado.
Dissecando a Arquitetura: O Diagrama de Classes
Para que a aplicação seja resiliente a endereços ambíguos, a modelagem de dados precisa de ser extremamente flexível e, ao mesmo tempo, tipada. O diagrama que estruturei isola a lógica de negócio das integrações externas, utilizando conceitos avançados de Programação Orientada a Objetos.

1. O Domínio de Utilizador e Pacote
A base de controle do sistema passa por garantir que cada utilizador tenha um acesso seguro e um registo de atividade claro. No diagrama, a classe Usuario é responsável pela autenticação, contendo propriedades essenciais como id, login, senha_hash (garantindo que a palavra-passe nunca seja armazenada em texto limpo) e um identificador booleano ativo. Os métodos AutenticarSenhaDigitada(String) e DesativarAcesso() geram o ciclo de vida deste utilizador.
A relação de cardinalidade estipula que um Usuario pode ter de zero a muitos objetos da classe Pacote associados (1 para 0..*). A classe Pacote atua como o núcleo operacional da entrega, registrando o RuaLida, NumeroLido, o status (se está pendente ou entregue) e um campo fundamental para métricas de desempenho: o TempoProcessamentoMS. Este último permitirá medir quanto tempo a inteligência artificial demora a extrair os dados, ajudando a otimizar a experiência do utilizador. As ações do pacote são controladas pelos métodos GravarComoPendente() e RegistrarBaixa().
2. Modelagem Geográfica: Cidades e Setores
A abstração geográfica foi desenhada para escalar. A classe Cidade contém o Nome, o CepGeral e uma propriedade chamada ModuloEstrategia, gerindo o comportamento através do método BuscarSetores(). Uma cidade possui múltiplos Setores (1 para 1..*).
A classe Setor é aquilo que o entregador vai realmente ver na sua tela. Para otimizar o interface visual e a usabilidade (UX), inclui atributos como CodigoCurto (ex: "ZN" para Zona Norte), CorHex (para pintar o pacote visualmente na aplicação com cores específicas, facilitando a identificação rápida) e NomeExibicao. O método GerarPacoteVisual() retorna um dicionário para montar o interface no lado cliente. Múltiplos pacotes (0..*) são alocados num único Setor (1).
3. O Motor de Regras: Resolvendo os Endereços Caóticos
Aqui entra a solução de engenharia para o problema do "bar do seu José". Um setor é composto por várias instâncias da classe RegraRua (1 para 1..*).
Em vez de depender estritamente de nomes oficiais, a classe RegraRua possui o campo NomeRuaLimpo e, de forma muito inteligente, uma lista estendida chamada Apelidos (List<String>). Isto significa que o sistema pode validar se o endereço extraído é a "Avenida Principal", a "Rua da Igreja" ou o "Largo do Mercado". Além disso, possui NumeroInicio e NumeroFim, permitindo que ruas muito longas sejam divididas em setores diferentes, dependendo do bloco de numeração. O atributo LadoVia ajuda a evitar que o entregador precise de atravessar rodovias movimentadas de forma ineficiente. Estes dados são validados internamente pelos métodos ContemNumero(Numero: int) e ValidarLado(Numero: int).
4. Integração com Inteligência Artificial e Padrões de Projeto
Para efetuar a leitura das etiquetas de transporte, que muitas vezes vêm com formatação danificada ou caligrafia difícil, criei o ExtratorGeminiService. Este serviço guarda a apiKey e a ModeloVersao, contendo o método central ProcessarImagem(foto: Base64). A imagem capturada pelo celular é convertida em base64 e enviada para a API.
Para proteger a minha camada de domínio de possíveis alterações na resposta da inteligência artificial, implementei o padrão DTO (Data Transfer Object). O serviço do Gemini não devolve uma entidade complexa, mas sim um objeto simples: EnderecoDTO, que contém atributos básicos como rua, numero, bairro e cep.
5. Inversão de Dependências e Cálculo
Por fim, o DTO transita para o motor de lógica através da interface ICalculadoraSetor, que expõe o contrato DefinirSetor(Endereco: EnderecoDTO, RegrasCidade: List<RegraRua>) retornando um Setor definitivo. Este contrato é implementado concretamente pela classe CalculadoraRuaNumero, que também detém o método HigienizarNomeRua(Texto: String) para limpar ruídos e padronizar o texto antes de comparar com a nossa base de regras. Esta injeção de dependência torna o código facilmente testável (através de mocks) e sustentável a longo prazo.
Os grandes desafios do projeto a longo prazo
Com toda esta arquitetura delineada, tenho clareza sobre os próximos obstáculos:
Mapeamento Prévio: Alimentar a base de dados do PostgreSQL com as entidades RegraRua da cidade. É um trabalho manual considerável no início, mas como a cidade é pequena, o esforço compensa amplamente ao eliminar a dependência e os custos de APIs de geolocalização pagas.
Segurança e Privacidade (LGPD): Garantir a anonimização e segurança dos dados pessoais extraídos das etiquetas, assegurando que o EnderecoDTO transite de forma segura.
A Stack Tecnológica Central: Planeio codificar o backend inteiramente em Python, aproveitando o ecossistema robusto desta linguagem para o manuseamento de dados e consumo da API do Gemini. O armazenamento será relacional através do PostgreSQL, ideal para manter a integridade destas associações complexas.
O Salto para o Mobile: Como mencionei anteriormente, a vida é dar a cara a tapa. Desenvolver a aplicação móvel (o cliente que irá gerar os pacotes visuais a partir da CorHex do setor) será a minha maior curva de aprendizagem, exigindo aprofundamento em frameworks de interface de utilizador móvel.
Criar soluções locais para cenários onde o padrão das grandes infraestruturas tecnológicas falha é o que torna o desenvolvimento de software uma disciplina verdadeiramente intrigante. Transformar caos logístico em entidades estruturadas num diagrama de classes é o primeiro passo para uma verdadeira transformação digital.
E você, também costuma planejar extensivamente as suas classes e diagramas de atividades antes de abrir o editor de código? Está a planear algo novo ou partindo para cima de algum projeto desafiante?


