App 6.0.35 — botão do DANFE
O botão da nota na coleta passa à opção 1 escolhida em 02/10.
- "Bipar código de barras do DANFE" numa linha, com o desenho do código de barras embaixo.
- Sem a palavra QR, também na tela da câmera.
- Suíte fechou 527 de 527.
Aplicativo do motorista · Versão 6 · Especificação da API
Este guia é autossuficiente: começa pelo que já roda hoje, segue pelo que muda campo a campo e termina em cada rota, com o motivo de cada regra. Use o sumário ao lado para pular direto para o que interessa.
Ao vivo
O que já foi feito
O aplicativo pronto, a camada que o faz valer no servidor de hoje e o andamento do contrato novo, item a item.
Documentação
A API para o backend
Começa por "só o que muda" — a lista campo a campo para abrir a tarefa — e segue endpoint por endpoint, com o motivo de cada regra.
Diário
Atualizações
Cada versão do aplicativo e cada mudança da entrega, da mais nova para a mais antiga.
6
rotas /mobile/* — a API inteira, nenhuma escondida
100%
do fluxo operável sem sinal — o fato que explica as regras
45 s
o tempo que o aplicativo espera por cada resposta
0
baixas descartadas — recusa fica na fila, com o motivo visível
Esta lista não é um retrato: é o mesmo checklist que a equipe marca no painel interno, filtrado ao que diz respeito ao backend — o Modo 2 (endpoint por endpoint), a observabilidade e a ciência do que já existe.
Por que é seguro
O CPF é inválido de propósito e o modo demonstração nunca manda nada para um servidor: não existe risco de misturar teste com operação real.
Responde a uma pergunta só: o que mudou desde a última vez que eu olhei?
Esta seção não é a especificação completa: é o mapa do que precisa mudar para o backend de hoje falar o contrato da v6. O detalhe endpoint por endpoint vem logo abaixo, e a referência medida contra o servidor real está em /contrato.
08/09/2026 — o caminho B ganhou chão
A equipe do TMS subiu o caminho B em wshomdev.grupoaleff.com.br. Com os romaneios 720/26 (coleta, 5 serviços) e 2303/26 (entrega, 9 serviços), o app 6.0.13 fez 105 chamadas reais; o resultado virou contrato medido em OpenAPI 3.1. Cinco rotas passam: sessão, anexos, posições, baixa com o schema do TMS desde 11/09, e alterações medida na tarde de 11/09. Detalhe completo em /contrato.
| Campo ou comportamento | Caminho A — Adequação | Caminho B — Mundo ideal |
|---|---|---|
| Latitude / longitude do serviço | Adicionar ao retorno existente | Já nasce no modelo do serviço |
| Regras da baixa e do rastreio | Documentar por fora, sem forçar no formato antigo | Regras nativas do endpoint novo |
| Romaneio rebuscável + estado do serviço — o item delicado | Difícil: o formato atual não tem "estado por serviço" | Nativo: GET /mobile/romaneio/{t}/alteracoes |
| Baixa duplicada recusada | Precisa de campo extra e checagem manual | Idempotência nativa do endpoint |
| Posições em lote | Endpoint atual só aceita uma por chamada | POST /mobile/posicoes já nasce em lote |
| Fotos separadas da baixa | Continua base64 dentro do corpo | POST /mobile/anexos, arquivo por fora |
| Coleta com conferência de volumes | Sem campo equivalente hoje | Campos coleta.* nativos na baixa |
| Erro de negócio em 4xx | Impossível sem quebrar o app da Play | Padrão do endpoint, desde o primeiro dia |
Como ler a comparação
A coluna A não é "pior": é o que dá para fazer sem tocar no que já está em produção. A coluna B é o que este guia documenta em detalhe daqui para baixo, porque é o que o aplicativo 6.x já fala.
Latitude e longitude já existem, mas vêm vazias
Medido em 10/08/2026: 0 de 427 serviços vieram com coordenada. O campo existe no contrato; falta o TMS preencher.
Posições em lote é capacidade nova do endpoint
Não é enviar uma posição de cada vez mais rápido: o corpo leva várias de uma vez.
{
"placa": "AAA-1122",
"romaneio": "4471",
"posicoes": [
{ "lat": -23.55, "lon": -46.63, "precisaoM": 12, "em": "2026-09-11T14:02:00.000Z" },
{ "lat": -23.56, "lon": -46.64, "precisaoM": 9, "em": "2026-09-11T14:03:00.000Z" }
]
}| Campo | Onde | Motivo |
|---|---|---|
| latitude / longitude | serviço | Sem coordenada não há mapa nem rota no aplicativo. |
| parametros.{fotosObrigatorias, exigeNome, exigeDocumento, exigeAssinatura, intervaloPosicaoSeg, intervaloEnvioSeg} | sessão | Regras de captura variam por transportadora; o app não pode ter isso fixo no código. |
| parametros.rastrear | sessão | Liga o rastreamento por romaneio, não por documento — evita pedir permissão de GPS sem necessidade. |
| romaneio.numero estável | romaneio | Um mesmo romaneio não pode trocar de número no meio do dia — foi o que picou 734/26 em 735/26 e 736/26 num incidente real. |
| estado do serviço | serviço | O app precisa saber se um serviço já foi baixado por outra via, sem inferir isso sozinho. |
| tipo do serviço + volumesPrevistos / pesoPrevisto | serviço | Sem isso a conferência de volumes na coleta não tem contra o que comparar. |
| motorista.nome | sessão | Usado na tela e na assinatura; hoje falta em alguns retornos. |
| janelaTexto | serviço | Texto pronto da janela de entrega — evita o app calcular formatação de horário sozinho. |
| Comportamento atual | O que precisa virar |
|---|---|
| Reenvio pode duplicar a baixa | Idempotência por chave única, deduplicada no servidor |
| Erro de negócio some dentro de um 200 | Erro de negócio sempre em 4xx, com código e campo |
| Romaneio rebaixado inteiro a cada consulta | GET /alteracoes devolve só o que mudou desde a última vez |
| Foto e assinatura em base64 dentro da baixa | Anexo sobe à parte, a baixa só cita o anexoId |
| Campo | Formato | Motivo |
|---|---|---|
| idempotencia | UUID gerado no aparelho | Evita duplicar a baixa em reenvio |
| fotos / assinatura | fotos: [{seq, anexoId}]; assinatura: {anexoId} | O arquivo já subiu por /mobile/anexos; a baixa só referencia |
| posicao.precisaoM | metros | Permite ao TMS descartar leitura de GPS ruim |
| coleta.* | volumesConferidos, motivoDivergencia, documentos[] | Suporta a conferência de volumes no fluxo de coleta |
O único endpoint inteiramente novo: POST /mobile/anexos
Todos os outros traduzem algo que já existe hoje. Este não tem equivalente no backend atual — cada foto e cada assinatura sobem por ele, uma de cada vez, antes da baixa fechar.
As perguntas ainda em aberto estão reunidas em Perguntas em aberto. O ditado por voz — já embarcado no aplicativo — está descrito em Ditado por voz.
O que "offline" significa aqui
"Offline" não é um modo à parte que alguém liga: é o estado normal. O motorista roda o dia inteiro numa área sem sinal e só percebe a diferença quando a fila esvazia mais rápido. Por isso toda regra de API abaixo assume que a chamada pode chegar minutos, horas ou (num caso raro) dias depois do que aconteceu no chão.
POST /mobile/sessao abre o dia; devolve o romaneio inteiro
GET /mobile/romaneio/{t}/alteracoes o que mudou desde a última consulta
POST /mobile/servicos/{servicoId}/baixa o resultado do serviço
POST /mobile/anexos fotos e assinatura, uma a uma
POST /mobile/posicoes rastreamento, em lote
evoluções — exigem versão nova do aplicativo; nada depende delas:
POST /mobile/dispositivos registra o aparelho para push
→ push (FCM), do TMS para o aparelho avisa que o romaneio mudou
→ anexos com tipo "audio" + origem na baixa ditado por voz — já no app 6.0.10, falta o TMSSucesso vem em 200 ou 201 com "sucesso": true e os campos do endpoint. Erro de negócio vem em 4xx, nunca em 200 com "sucesso": false.
200 / 201 { "sucesso": true, …campos do endpoint }
4xx {
"sucesso": false,
"codigo": "RECEBEDOR_OBRIGATORIO",
"mensagem": "Informe quem recebeu",
"campo": "recebedor.nome"
}A ambiguidade já custou um dia inteiro
09/08/2026: 82 das 86 chamadas foram rejeitadas porque a data ia com o fuso -03:00, documentado como aceito. Só UTC era aceito de fato. Envelope e formato ambíguos custam campo — daí cada regra abaixo vir com o motivo, não só a forma.
Formato único: AAAA-MM-DDTHH:mm:ss.sssZ. Nenhum endpoint aceita o deslocamento -03:00, mesmo onde a documentação antiga sugeria aceitar.
Baixa e anexo levam uma chave gerada no aparelho. Reenviar a mesma chave nunca duplica: o servidor responde como se fosse a primeira vez.
Cada chamada tem 45 s de tempo-limite antes de voltar para a fila local e tentar de novo mais tarde.
Recusa vem com código estável, mensagem legível e o campo específico — nunca um 4xx genérico sem contexto.
Romaneio, alterações e catálogo de ocorrências vêm inteiros. O aparelho não implementa "próxima página" em nenhum fluxo do motorista.
O aplicativo nunca decide sozinho se um serviço já foi entregue; ele reflete o que o servidor mandou na última sincronização.
Cada rota abaixo abre com a mesma sequência: o que o app manda, o que precisa voltar e as regras que o campo já ensinou. A versão medida contra o servidor de homologação fica em /contrato.
A quinta informação: o alarme que presta
Um farol de três cores, derivado das quatro informações acima: tudo certo quando a última posição é recente; sem posição há 30 minutos devendo rastrear vira aviso; sem posição há 60 minutos, ou aparelho mudo, vira alerta.
O que falta confirmar com o time do TMS antes de fechar o contrato definitivo.
O botão da nota na coleta passa à opção 1 escolhida em 02/10.
Os dois ajustes combinados em 01/10.
Os sete itens do teste no Android: textos do login e da bipagem, código de transportadora com 2 dígitos, tipo do documento de viagem e o teclado que cobria os campos.
O relatório de 29/09. O app mandava parar o GPS no fim do romaneio e no desconectar, mas conferia o estado numa leitura antiga e não parava. Agora para de verdade.
O relatório de 22/09. O clique da foto tocava em uma e pulava a seguinte: o vídeo enviado mostra 8 capturas e o som saiu em 5. O app mandava rebobinar e disparar no mesmo instante, e quando o disparo chegava primeiro tocava o fim do arquivo, que é silêncio. Agora espera o rebobinar e toca em todas. O alerta de coleta nova passou a tocar onde o serviço é detectado, o que cobre os dois relatos do dia: romaneio com uma coleta só e coleta inserida pela central. E a obrigatoriedade de nome, RG e assinatura passa a seguir o TMS: o servidor confirmou que parâmetro inativo não gera a linha no JSON, e o app lia esse silêncio como "exige".
Os quatro itens do relatório de ajustes de 21/09. A câmera passou a tocar um clique a cada foto, em coleta, entrega e ocorrência, e o som sai mesmo com o aparelho no silencioso, igual nas duas plataformas. Coleta ou romaneio novo agora avisa com som, além do aviso visual. A tela de foto ganhou a seta de voltar: quem bipou uma nota e percebeu que faltavam outras volta para a leitura de NF-e, remove a errada e segue, sem perder a baixa. E nome e documento do recebedor deixam de ser exigidos quando o TMS diz que não são — o app lia a obrigatoriedade do documento de um lugar só e, na falta, exigia. Homologação: TestFlight no iPhone, APK do Expo no Android.
RG não tem regra nacional: cada estado emite do seu jeito, vários não têm dígito e o campo é um só, "RG OU CPF", sem a UF. O RG de São Paulo tem 8 números mais o dígito, e quem digitava só os 8 — que é o comum — recebia "Confira o RG: o dígito não bateu" num documento correto. Agora o app recusa só o que não pode ser documento nenhum: vazio, menos de 5 números, número repetido ou sequência. Onze números com dígito de CPF errado viram aviso, não erro. Nas 176 baixas de 11 a 21/09 o TMS nunca recusou uma baixa por causa do documento. Homologação: TestFlight no iPhone, APK do Expo no Android.
O campo RG ou CPF passa a decidir pelo tamanho: CPF confere os dígitos verificadores e RG de 8 ou 9 posições tem o dígito conferido pela conta de SP, como aviso, sem travar quem tem RG de outro estado. Obrigatório errado trava dizendo o motivo; opcional errado não trava e fica de fora da baixa. Tocar no microfone fecha o teclado. O card mostra o prazo da coleta, a auditoria conta esse campo e o tamanho dos anexos, e romaneio encerrado deixa de ser consultado em segundo plano. Homologação: TestFlight no iPhone, APK do Expo no Android.
Testando a v6 e achou algo que este guia não explica? Veja as respostas prontas em Dúvidas.
Ver o contrato medidoBaixar o YAML