O Veredito em Uma Frase: Uma reimplementação do Traccar escrita sob medida em Elixir onde o autor fez escolhas de arquitetura surpreendentemente adultas para telemetria TCP, mas achou uma excelente ideia deixar um agente de IA gerar Remote Code Execution no script de backup e escrever 60 mil linhas de código antes de cortar a bomba de combustível do primeiro carro real.
A Dor (Real ou Psicossomática?):
No mundo real — especial e tragicamente no Brasil — carro roubado não é problema imaginário de dev entediado, é estatística diária. Porém, do ponto de vista estritamente técnico, o Traccar existe desde 2010, é open source, suporta mais de 2.000 protocolos (incluindo todas as mutações genéticas chinesas do GT06 e toda a linha Teltonika) e já resolveu cada edge case bizarro de GPS que perde sinal em túnel. Você não precisava escrever um parser binário do zero para abrir uma central na Bahia. Mas sejamos honestos: o Traccar é uma catedral em Java com uma interface que parou em 2014 e não tem faturamento via Pix, tela para instalador em oficina suja de graxa nem fluxo de bloqueio à prova de processos judiciais. A dor de negócio existe; você só escolheu o caminho mais longo e divertido porque queria brincar com a BEAM.
O Que Surpreendentemente Funciona:
Eu vim pronto para destruir mais um projeto de vibe coding, mas fui obrigado a guardar metade do meu sarcasmo no bolso. Tem engenharia de gente grande aqui:
- Elixir/OTP onde realmente faz sentido: Usar a BEAM (via
ThousandIsland) com um processo isolado por rastreador para segurar milhares de conexões TCP persistentes e fazer pattern matching binário do protocolo GT06 é literalmente o caso de uso para o qual a Ericsson criou o Erlang. Se um pacote malformado de um J16 falsificado explodir o parser, morre só o processo daquele veículo, não o gateway inteiro. - ACK Assíncrono com WAL em Disco: Entender que banco de dados relacional dá engasgo de I/O e que segurar o ACK de um rastreador GSM por 5 segundos causa Thundering Herd (a frota inteira reconectando ao mesmo tempo e derrubando a torre celular/servidor) mostra visão de sistemas distribuídos. Separar recepção de persistência com deduplicação e backpressure em disco é arquitetura sênior.
- Soberania Geográfica (Zero Google Maps Tax): Subir MapLibre + tiles próprios + Nominatim local com extrato do Nordeste no mesmo ferro é música para os meus ouvidos. Quem usa a API de Geocoding Reverso do Google Maps para telemetria veicular (que manda pacote a cada 30 segundos) vai à falência no segundo mês de operação.
- Trava de Segurança Física e Semântica no Bloqueio: Exigir velocidade abaixo de 5 km/h em duas leituras consecutivas, pedir digitação da placa (evitando fat-finger no celular) e diferenciar na UI "o módulo respondeu ACK" de "o relé realmente abriu o circuito" prova que você entende a diferença entre software e mundo físico.
- Isolamento no Ecto (
prepare_query/3): Forçarorg_iddireto no ciclo de vida do repositório e exigirskip_org_id: trueexplícito é a única forma confiável de fazer soft multi-tenancy sem depender da memória de programador (ou de LLM) em cadaWHERE.
Onde o Castelo de Cartas Desmorona (O Que Não Funciona):
- Esquizofrenia Topológica (Railway + VPS): Você colocou o gateway TCP numa VPS com IP fixo (decisão corretíssima, já que firmware chinês barato tem alergia a DNS ou faz cache do IP até a morte térmica do universo), mas deixou o Phoenix Web na Railway. Como é uma aplicação só em dois papéis, ou você está pagando latência de rede pública (e tráfego de saída) entre a VPS e a Railway para alimentar o Postgres e o
Phoenix.PubSuba cada segundo que um carro se move, ou o banco está longe de um dos dois. Se você já tem uma VPS parruda rodando Nominatim e tiles do OSM com IP fixo, por que cargas d'água a aplicação Web está na Railway? Coloque tudo na mesma rede privada (ou na mesma máquina com systemd/Docker) e elimine um salto de rede intercontinental inútil. - A Bomba Relógio de 60 Mil Linhas em
lib/: Sessenta mil linhas de Elixir para um MVP com um único protocolo (GT06) e zero carros rodando na rua é um volume obsceno de código. Elixir é uma linguagem expressiva; 60k LOC em Elixir equivalem a umas 200k LOC em Java. Isso tem cheiro forte de LLM prolixa gerando boilerplate, módulos redundantes e testes que testam mocks. Quando você mesmo confessa que um agente concatenou a saída dopg_restorepara avaliar código Elixir dinâmico (criando um RCE digno de nota 10 no CVSS) e deixou sessões de LiveView ativas após revogação de permissão (porque esqueceu de dar broadcast dedisconnectno socket), fica claro o preço de revisar 85 PRs gerados por máquina: você trocou o tempo de digitação por uma auditoria de segurança forense perpétua. - O Pesadelo do Armazenamento Bruto + PostGIS: Você diz que "todo pacote que chega é gravado em binário" e as posições vão para o PostgreSQL. Vamos fazer uma conta de padaria: 1.000 carros mandando posição a cada 30 segundos geram 2,88 milhões de registros por dia (86 milhões por mês). Se você estiver gravando
byteabruto e geometrias PostGIS indexadas numa tabela comum do Postgres sem particionamento nativo diário/semanal (PARTITION BY RANGE) ou TimescaleDB, e sem expurgo automatizado dos binários brutos para Object Storage (S3/MinIO), oautovacuume o bloat de índices B-Tree/GiST vão comer o disco da sua VPS antes do Carnaval de Salvador. - Ilusão da Velocidade Zero no Bloqueio: Confiar apenas em "velocidade abaixo de 5 km/h em duas posições" para liberar o corte de combustível no app do cliente tem uma armadilha clássica: semáforo e trânsito lento em via expressa. O ladrão para no sinal vermelho da Avenida Paralela ou reduz no quebra-molas; o dono apavorado aperta o botão; o comando leva 8 segundos na fila do SMS/GPRS porque o sinal 4G oscilou; o carro já arrancou e está a 50 km/h no meio do cruzamento quando o pacote chega no J16 e corta a bomba de combustível. A validação de velocidade segura precisa ser feita pelo próprio firmware do rastreador no momento da execução (muitos clones do GT06 suportam o parâmetro de cortar apenas quando o GPS reportar < 20 km/h localmente), não apenas na camada de negócio do servidor.
Respostas às Perguntas do Autor (Se houver):
Você perguntou como quem trabalha com telemetria/Elixir resolve ACK, buffer e deduplicação:
- ACK vs. Persistência: A regra de ouro em telemetria pesada é que o processo TCP (seu handler do
ThousandIsland) só valida o CRC, coloca o pacote em um ring buffer local ou no Broadway (usando um produtor em disco local comoOffBroadway/ SQLite WAL / Kafka leve se for clusterizado) e devolve o ACK imediatamente em menos de 5 ms. Nunca deixe o socket saber que o PostgreSQL existe. - Inserção em Lote (
insert_all): Não faça umRepo.insertindividual na pipeline de cada veículo a cada pacote que chega. UseBroadwayou umGenStageagregador para juntar lotes de 500 a 1.000 posições a cada 1 segundo e fazer um únicoRepo.insert_allno Postgres, enquanto atualiza a posição "quente" (estado atual da frota para o mapa) apenas em memória via ETS +Phoenix.PubSub. O banco só precisa receber o histórico consolidado em batch; a tela da central lê do ETS em microsegundos sem encostar no disco. - Deduplicação sem ir ao Banco: Rastreadores GT06 que perdem conexão reenviam o buffer da memória flash com o mesmo
imei + timestamp_gps + serial_number. Em vez de bater num índiceUNIQUEdo Postgres (que custa I/O de escrita e gera dead tuples no conflitoON CONFLICT DO NOTHING), mantenha no estado doGenServerde cada veículo (ou numa tabela ETS com TTL) um pequeno ring buffer com os hashes ou timestamps dos últimos 50 pacotes recebidos daquele IMEI. Se já viu, manda o ACK de novo para calar a boca do rastreador e descarta na memória a custo zero.
Nota na Escala "Reinventando a Roda": 4/10
Você está literalmente reescrevendo o Traccar do zero, mas com justificativa comercial real (verticalização para central brasileira com Pix, app do instalador e fluxo operacional próprio) e usando a melhor tecnologia do mercado para conexões persistentes. Só enxugue essa gordura de 60 mil linhas geradas por IA, implemente particionamento nas tabelas de pacotes antes de colocar 500 motos na rua e nunca, sob nenhuma hipótese, confie só na última velocidade vista pelo servidor para acionar um relé de corte por uma rede celular que tem jitter de segundos.