Revo Mobile v6
Aplicativo do motorista · Versão 6 · Especificação da API

A entrega da versão 6, em três partes: o que já foi feito, as atualizações e a API para o backend.

Esta página foi escrita para valer sozinha. As duas primeiras partes mostram o estado da entrega — ao vivo, sem depender de perguntar a ninguém. A terceira é a especificação: cada rota, a requisição exata que o aplicativo manda, a resposta que ele espera e o porquê de cada regra — o suficiente para a equipe de backend implementar sem a nossa presença. O botão no topo gera o PDF; cada seção tem um endereço fixo (o # ao lado do título) para citar em e-mail ou tarefa.

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
Parte 1 · Ao vivo

O que já foi feito #

O aplicativo não ficou esperando a API nova: ele está pronto e operando hoje. Três coisas já estão entregues — e a quarta, o contrato desta página, é acompanhada item a item logo abaixo.

O aplicativo inteiro, reescrito
Login, romaneio, baixa com foto e assinatura, coleta com conferência de volumes, ocorrências, fila offline, rastreamento e atualização remota — tudo novo, do zero, no mesmo fluxo que o motorista já conhece.
A camada que faz tudo valer no servidor de hoje
Um adaptador traduz o contrato novo para o servidor atual, e as correções descobertas em campo já estão dentro dele: o formato de data que derrubava as baixas, o romaneio que o servidor só entrega uma vez, a lista que apagava serviços. O motorista opera agora, sem esperar a API nova ficar pronta.
O acesso de demonstração
Transportadora 0000: qualquer pessoa instala e percorre o fluxo inteiro sem servidor, sem cadastro e sem VPN — como testar.

O contrato novo, item a item #

Andamento ao vivo

carregando…

Esta lista não é um retrato: é o mesmo checklist que a equipe marca no painel interno — uma tela praticamente igual a esta, com senha, onde os itens são marcáveis e as manutenções são acompanhadas. O que for concluído lá aparece aqui na próxima abertura da página, e o PDF que você baixar sai com o andamento do momento em que baixou.

Parte 1 · Experimente

Ver o aplicativo funcionando #

Nada acima é promessa: dá para instalar e percorrer o fluxo inteiro agora, sem servidor, sem cadastro e sem VPN — o acesso de demonstração roda com dados locais no próprio aparelho.

Acesso de demonstração

Digite 0000 na transportadora

Ao digitar 0000 no primeiro campo, o aplicativo preenche o resto sozinho e abre um romaneio completo de exemplo — entregas, coletas, todos os tipos de documento, baixa com foto e assinatura, modo avião.

Transportadora
0000
CPF
000.000.000-01
Placa
AAA-1122

Por que é seguro: esse CPF é inválido de propósito — não passa no dígito verificador, então nenhum motorista real cai nesse acesso por engano, e nesse modo o aplicativo nunca envia nada para servidor nenhum.

Parte 2 · Diário da entrega

Atualizações #

Toda vez que sobe uma versão do aplicativo, a anotação entra aqui — da mais nova para a mais antiga. Serve para responder, sem perguntar a ninguém, “o que mudou desde a última vez que eu olhei?”.

carregando…

Parte 3 · A documentação

Só o que muda — a lista para abrir a tarefa #

A pedido da equipe do TMS: a comparação entre a API de hoje (o Swagger do ApiMobile) e o contrato novo, listando apenas o que não existe hoje — campo por campo, com o bloco onde entra e a finalidade de cada um. O que a API já manda não aparece aqui e continua valendo igual. Cada linha aponta para a seção desta página que traz o contrato completo daquele item. E, como a decisão entre adequar a API atual ou subir as rotas novas é da equipe, a comparação entre os dois caminhos está logo abaixo — os campos são os mesmos nos dois, muda o endereço onde entram e o risco de cada um.

Os dois caminhos, lado a lado #

AAdequação — o Swagger de hoje absorve a lista
Nenhuma rota nova além do anexo: cada item vira um campo ou uma regra a mais nos endpoints que já existem (GetDocumentos, AtualizaDocumento, CadastraLocalizacaoMotorista). O limite a vigiar: esses endpoints são os mesmos que o aplicativo da Play consome hoje — tudo precisa ser adição compatível, e dois itens da lista mexem em comportamento que ele pressupõe.
BMundo ideal — as rotas novas, e o Swagger atual intocado
As seis rotas /mobile/* desta página sobem ao lado das atuais: o Swagger de hoje fica limpo, sem remendo, e o aplicativo da Play continua funcionando sem tomar risco nenhum. As regras novas (idempotência, lote, anexo separado, erro em 4xx) nascem dentro das rotas novas, em vez de serem encaixadas em endpoints que já têm outro contrato.
O itemNo caminho da adequação (Swagger de hoje)No mundo ideal (rotas /mobile/*)
latitude / longitude preencher os dois campos que já existem vazios no GetDocumentos já nascem preenchidos em cada serviço da sessão
regras da baixa e do rastreio (parametros, rastrear) campos a mais na resposta do GetDocumentos — adição compatível, o aplicativo da Play ignora campo que não conhece bloco parametros da resposta da sessão
romaneio rebuscável + estado do serviço mudar o “entrega uma vez só” do GetDocumentoso item delicado: o aplicativo da Play pressupõe o comportamento de hoje, então a mudança precisa ser combinada com cuidado dobrado a regra nasce dentro do POST /mobile/sessao, sem tocar no endpoint que o aplicativo da Play usa
baixa duplicada recusada conferir “este documento já está baixado” no AtualizaDocumento — dá para fazer já, e protege inclusive o aplicativo da Play chave idempotencia que toda baixa manda
posições em lote o CadastraLocalizacaoMotorista passar a aceitar uma lista POST /mobile/posicoes já é lote por definição
fotos separadas da baixa endpoint novo de qualquer jeito — não existe onde pendurar isso no Swagger atual POST /mobile/anexos — o mesmo endpoint, nos dois caminhos
coleta campo tipo (mais volumes e peso previstos) a mais no GetDocumentos já definida no formato do serviço (tipo: "coleta")
erro de negócio em 4xx não dá sem quebrar o aplicativo da Play — ficaria como está (200 com o motivo no corpo) nasce certo nas rotas novas
Como ler a comparação

Na adequação, quase tudo é adição compatível e barata — preencher campo, aceitar campo a mais — mas os dois itens que mais importam (o romaneio rebuscável e o erro de verdade) mexem em comportamento que o aplicativo da Play pressupõe, e é aí que o caminho fica caro. No mundo ideal, o Swagger atual fica intocado e cada regra nova nasce no lugar certo. Os dois caminhos terminam no mesmo aplicativo: ele já fala os dois servidores hoje, e a troca é um seletor — nada precisa ser reinstalado.

As duas dúvidas levantadas, respondidas primeiro #

latitude / longitude — já existem, com estes mesmos nomes. Só vêm vazias.

Não é campo novo nem renomeado: o GetDocumentos de hoje já devolve latitude e longitude em cada documento — mas vazias em 100% dos casos (medido em 10/08/2026: 0 de 427 serviços com coordenada). A adequação é preenchê-las com a coordenada do destino. No contrato novo elas continuam com os mesmos nomes, dentro de cada serviço do romaneio (sessão). Enquanto vêm vazias, o aplicativo descobre a coordenada pelo endereço, no próprio aparelho — paliativo que erra número e complemento em endereço brasileiro e depende de rede.

Envio de posições em lote — é capacidade nova do endpoint, não campo renomeado.

Hoje o CadastraLocalizacaoMotorista aceita uma posição por chamada. O contrato novo (POST /mobile/posicoes) manda um lote: { placa, romaneio, posicoes[…] }, cada ponto com lat, lon, precisaoM e em (o horário em que o GPS mediu — o dataLocalizacao de hoje). O motivo é o modo de operar sem rede: as posições se acumulam no aparelho e sobem juntas quando o sinal volta. O único campo realmente novo por ponto é precisaoM — a precisão do GPS em metros, para a central saber o quanto confiar em cada ponto.

Campos a criar (ou preencher) no retorno do login #

Hoje o retorno é o do GetDocumentos; no contrato novo é a resposta da sessão. A coluna “onde entra” usa os nomes do contrato novo.

CampoOnde entraHojePara quê
latitude, longitude em cada serviço do romaneio os campos existem e vêm vazios (0 de 427) distância real no cartão (“a 3,2 km”), ordenação por proximidade — sem adivinhar pelo endereço
parametros (bloco novo): fotosObrigatorias, exigeNome, exigeDocumento, exigeAssinatura, intervaloPosicaoSeg, intervaloEnvioSeg na resposta do login, uma vez por romaneio não existe — o aplicativo repete as regras fixas do 5.x o TMS passa a mandar as regras da baixa e o ritmo do rastreio; mudar uma regra deixa de exigir versão nova do aplicativo
parametros.rastrear dentro do bloco parametros o parâmetro existe no TMS e não chega ao aplicativo com false o GPS nem liga e a permissão “Sempre” nem é pedida — hoje ela é pedida a todo motorista, inclusive de carga não rastreada
romaneio.numero estável no envelope do romaneio o número muda a cada lote do mesmo dia (734/26735/26736/26, em 10/08/2026) o aplicativo precisa reconhecer que é o mesmo romaneio — o número instável já causou perda de serviços na tela
estado do serviço (concluído / cancelado) em cada serviço serviço entregue ou cancelado apenas some da resposta — os dois casos são indistinguíveis é a única forma de o aplicativo saber que a central cancelou um serviço; hoje o cancelado fica na tela até alguém baixar
tipo do serviço (entrega | coleta) + volumesPrevistos, pesoPrevisto em cada serviço não existe — tudo é entrega habilita a coleta com conferência de volumes, que o aplicativo já tem pronta
motorista.nome no bloco motorista não vem em campo nenhum — o aplicativo mostra a placa no lugar o nome do motorista no perfil e no cabeçalho; quando vier, aparece sozinho
janelaTexto (opcional) em cada serviço não vem nos campos janela de horário no cartão da entrega; sem o campo, o bloco simplesmente não aparece

Comportamentos que precisam mudar (não são campos) #

O que mudaHojePara quê
Buscar o romaneio de novo devolve o mesmo romaneio — a mudança mais importante da lista (as três garantias) cada serviço é entregue uma vez só; da segunda busca em diante, erro pelo resto do dia sair e entrar do aplicativo, reiniciar ou trocar de aparelho sem perder o dia — hoje o romaneio não volta nem pelo suporte
Motorista sem romaneio recebe 200 com lista vazia erro 400 com mensagem “sem trabalho no momento” é situação normal do dia, não falha
Segunda baixa do mesmo serviço é reconhecida como repetição o AtualizaDocumento aceita e gera movimento novo — aconteceu em produção em 10/08/2026, duas baixas do mesmo CT-e aceitas a fila offline reenvia por projeto; a chave idempotencia que o aplicativo manda em toda baixa é o que permite ao servidor responder sucesso sem duplicar
Recusa de negócio responde 4xx com mensagem o servidor responde 200 mesmo recusando (o motivo vem em logDaRequisicao) o aplicativo distingue recusa (mostra o motivo ao motorista) de falha de rede (tenta de novo sozinho)

Campos novos que o aplicativo passa a mandar na baixa #

O sentido inverso: o que o servidor precisa passar a aceitar (contrato completo da baixa).

CampoHojePara quê
idempotencia (UUID gerado no aparelho) não existe a mesma baixa reenviada pela fila é reconhecida e não duplica
fotos [{seq, anexoId}] e assinatura {anexoId} no lugar das fotos dentro da baixa foto e assinatura vão em base64 dentro do AtualizaDocumento — corpo de 2 a 3 MB, e uma foto pesada derruba a baixa inteira a baixa vira um JSON pequeno que só cita as provas; cada foto sobe separada no endpoint de anexos e uma foto que falha nunca trava a baixa
posicao.precisaoM latitudeEntrega/longitudeEntrega já existem; a precisão não a central sabe o quanto confiar na coordenada da baixa
coleta (volumes e peso conferidos) não existe — coleta não existe hoje o resultado da conferência da coleta, junto da baixa
O único endpoint inteiramente novo: POST /mobile/anexos

Todo o resto desta lista é campo ou regra em cima do que já existe. O endpoint de anexos é a exceção: recebe uma foto (ou a assinatura) por chamada, em multipart/form-data — o arquivo como parte binária e os metadados (anexoId, servicoId, baixaIdempotencia, tipo, seq, formato, capturadoEm) como campos de texto. O anexoId nasce no aparelho — o servidor não o devolve, só o aceita; reenvio do mesmo anexoId é substituição, nunca duplicata. O anexo pode chegar antes ou depois da baixa; a amarração é pela baixaIdempotencia. As regras de dimensionamento (e o alerta sobre o campo seq, que é ordem, não contagem) estão na seção do endpoint. Esse formato é o que o documento do cliente de 12/08 definiu.

É esta a lista inteira — o suficiente para abrir a tarefa de adequação. O contrato completo de cada item está nas seções seguintes, o que ainda depende de decisão da equipe está em as onze perguntas — e há um recurso à parte, o ditado por voz, que não entra nesta tarefa: o aplicativo já o faz desde a 6.0.10 sem exigir nada do servidor de hoje, e o lado do TMS, quando for feito, reaproveita o endpoint de anexos em vez de criar rota.

Os fundamentos

Três fatos moldam tudo o que vem abaixo #

Quase toda regra deste documento é consequência de um destes três fatos. Quando uma exigência parecer arbitrária, o motivo dela está aqui.

1O aplicativo é offline primeiro
Toda ação grava no aparelho e envia depois. O motorista nunca espera a rede: um dia inteiro de romaneio pode ser feito em modo avião e subir de uma vez à noite. Por isso datas antigas são normais, e por isso nada pode ter prazo de validade.
2A fila reenvia até conseguir
O que não subiu volta a ser tentado — na volta do sinal, ao abrir o aplicativo, em espera crescente. Consequência direta: a mesma requisição vai chegar mais de uma vez, e o servidor precisa reconhecer a repetição e responder sucesso.
3Só existe um momento de rede garantido
O login, na garagem, de manhã. Depois disso a rede é loteria. Tudo o que o motorista precisa para o dia tem que vir na sessão — endereços, documentos, regras da baixa e motivos de ocorrência.
O que “offline” significa aqui

Não é um modo separado que se liga. A baixa gravada no aparelho já está concluída para o motorista; enviar é problema do aplicativo. Fechar o aplicativo no meio de uma baixa e reabrir não perde nada. Para o servidor, isso quer dizer: o que chega pode ter sido feito há minutos ou há dias — e as duas coisas estão certas.

O mapa

A API inteira em uma tela #

Seis rotas — e não há nenhuma escondida. As duas últimas são evoluções: exigem uma versão nova do aplicativo e nada depende delas; a API funciona completa sem as duas.

POST  /mobile/sessao                        abre o dia; devolve o romaneio inteiro
GET   /mobile/romaneio/{numero}/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 TMS

Ir direto a um endpoint: sessão · alterações · baixa · anexos · posições · dispositivo e push · ditado por voz (já no app 6.0.10).

O dia de um motorista, visto pela API #

  1. De manhã: uma chamada

    O motorista faz o login e POST /mobile/sessao devolve o dia inteiro numa resposta só. A partir daqui o aparelho consegue operar até a noite sem rede nenhuma.

  2. Durante o dia: quatro conversas curtas

    O aplicativo consulta as alterações do romaneio a cada minuto e ao concluir cada serviço; cada conclusão vira uma baixa, com as fotos e a assinatura subindo como anexos, uma a uma; e as posições do GPS sobem em lotes, no ritmo que a própria sessão configurou.

  3. O tempo todo: a fila insiste

    O que a rede engoliu volta a ser enviado — com a mesma idempotência, até receber sucesso. É por isso que a repetição não é um caso raro a tolerar: é o comportamento normal do sistema, e o contrato inteiro foi desenhado em volta dela.

Regras gerais

As sete regras que valem para a API inteira #

Fechar isto antes evita a situação clássica de cada endpoint inventar o próprio formato. Cada regra vem com o motivo — e, quando existe, com o caso real que a justificou.

  1. Sucesso e recusa usam o código HTTP
    // sucesso
    200 / 201  { "sucesso": true, …campos do endpoint }
    
    // recusa — com CÓDIGO estável, para o app decidir sem ler a frase
    4xx {
      "sucesso":  false,
      "codigo":   "RECEBEDOR_OBRIGATORIO",   // ESTÁVEL e versionado
      "mensagem": "Informe quem recebeu",    // em português: vai para a tela do motorista
      "campo":    "recebedor.nome"           // opcional: o app foca o campo
    }

    Recusar com 200 e "sucesso": false é o pior dos mundos — o aplicativo tem de olhar o corpo para descobrir que falhou, e é assim que baixa some sem ninguém ver. O contrário também: responder erro carregando uma resposta boa no corpo obriga o cliente a adivinhar. Código 4xx para pedido que não serve, 5xx para falha do servidor, 2xx para o resto.

  2. Recusa nunca descarta — e reenvio de algo já gravado responde 2xx

    Um item recusado permanece na fila do aparelho, com o motivo visível para o motorista, e volta a ser tentado em espera crescente: 30 s, 1 min, 2 min… até o teto de 15 minutos. Mas 15 minutos é o teto, não o ritmo — a volta do sinal e o botão tentar agora zeram a espera, então o mesmo pacote pode reaparecer em segundos.

    Daí a regra que não se negocia: reenvio de algo que já foi gravado responde 2xx, jamais 409 de duplicado — o 409 prenderia para sempre, na fila do motorista, uma baixa que já está no TMS.

  3. Idempotência com a resposta guardada

    Toda gravação carrega um identificador de idempotência gerado no aparelho — o mesmo em todas as tentativas. Quando ele repetir, o servidor devolve a mesma resposta da primeira vez (o mesmo baixaId), não um “já existe” — e nos anexos, cujo anexoId também nasce no aparelho, reenvio do mesmo anexoId é substituição, nunca duplicata. E o identificador precisa de índice único no banco: a duplicidade acontece em corrida, não em sequência.

  4. Nada tem prazo de validade

    Uma baixa feita offline há dias sobe com o horário original de execução e precisa ser aceita — inclusive se o romaneio já fechou. Recusar por antiguidade apaga trabalho que foi feito de verdade e que o motorista não tem como refazer. O horário que vale é o do momento da entrega, não o da chegada do pacote.

  5. Datas em ISO 8601, sempre com o fuso escrito

    2026-08-10T14:32:10-03:00 — em todo campo de data, nos dois sentidos. E são sempre duas datas que não se misturam: a do aparelho (quando o motorista fez) e a do servidor (quando o TMS gravou). Cada uma tem seu campo.

    A ambiguidade já custou um dia inteiro

    Em 09/08/2026, o servidor atual recusou 82 das 86 chamadas do dia por não aceitar exatamente o formato de data que a documentação define — só passava em UTC. Nenhuma baixa se perdeu (a fila segurou tudo), mas o rastreamento ficou mudo o dia inteiro. A escolha do formato precisa estar escrita no contrato — é a pergunta 4.

  6. Identidade em toda requisição — sem token, por enquanto

    Seguindo a convenção atual, não há cabeçalho de autorização: a identidade (transportadora, CPF, placa) viaja no corpo. Se a equipe preferir adotar token, a sessão passa a devolvê-lo e o aplicativo o envia em toda chamada — com uma exigência: validade que cubra o turno inteiro com folga. Token que vence às 14h joga o motorista para a tela de login no meio da rua, com baixas ainda no aparelho. É a pergunta 3.

  7. Respostas comprimidas, corpos enxutos, formatos exatos

    Compressão (gzip) nas respostas é configuração de servidor e derruba um romaneio grande de ~900 KB para ~90 KB — e o aplicativo espera no máximo 45 segundos por resposta, então um romaneio de 400 serviços precisa caber nesse tempo. Duas lições de campo que valem para todo endpoint: no contrato novo o arquivo viaja em multipart, fora do JSON (onde ainda houver base64 — como no Swagger atual —, vai sem o prefixo data: e sem quebras de linha), e código de ocorrência é numérico — as duas coisas já derrubaram baixas em produção com um erro genérico que não dizia qual era o problema.

O modelo

Nove entidades e três regras de banco #

É o único ponto em que este documento fala de dentro do TMS, e vem antes dos endpoints porque as chaves daqui reaparecem em todas as requisições: motorista, dispositivo, romaneio, serviço, documento, baixa, anexo, posição e o catálogo de ocorrências.

1servico.id único e estável
Ele vai na URL da baixa e é a chave que o aparelho guarda no banco local. Uma baixa feita offline pode subir dias depois: se o id daquele serviço tiver mudado entre sessões, a baixa não acha o serviço e vira trabalho perdido.
2Idempotência é chave única, não log
O aparelho gera um identificador por baixa e repete o mesmo valor em toda tentativa. É isso que impede uma entrega de ser gravada duas vezes quando a rede confirma tarde demais — e exige índice único no banco, porque a duplicidade acontece em corrida.
3Anexo órfão é estado normal
A foto sobe separada da baixa e a rede decide a ordem. A amarração é pela idempotência da baixa — não por uma chave estrangeira que exigiria a baixa existir primeiro. O modelo precisa aceitar anexo sem baixa e amarrar quando ela chegar.
Endpoint 1 de 6 · vale hoje

Sessão — o login abre o dia #

POST/mobile/sessao
Para explicar em uma frase

O login do motorista devolve, numa resposta só, tudo o que o aparelho precisa para trabalhar o dia inteiro sem rede: quem ele é, as regras da baixa, os motivos de ocorrência e o romaneio completo.

O que o aplicativo manda #

{
  "transportadora": "0001",       // 3 ou 4 dígitos
  "cpf":            "12345678901", // 11 dígitos, sem máscara
  "placa":          "ABC1D23",     // maiúscula, sem hífen — placa antiga e Mercosul
  "dispositivo": {
    "so":        "android",        // "android" | "ios"
    "versaoApp": "6.0.9",       // a versão instalada — o app manda a dele
    "id":        "…"              // identificador estável do aparelho
  }
}

O bloco dispositivo não participa da autenticação: ele existe para o suporte saber, olhando o registro do servidor, qual versão do aplicativo e qual aparelho estavam por trás de cada chamada — sem depender de perguntar ao motorista.

O que o aplicativo espera de volta #

→ 200
{
  "sucesso": true,
  "motorista": {
    "nome": "…", "cpf": "…",
    "transportadora": "…",         // nome de exibição, não o código
    "telefoneCentral": "…"         // opcional: vira o botão "ligar para a central"
  },
  "parametros": {
    "fotosObrigatorias": 2,        // 0 a 10 — monta os passos da baixa
    "exigeNome": true,
    "exigeDocumento": false,
    "exigeAssinatura": true,
    "intervaloPosicaoSeg": 5,      // ritmo da medição de GPS
    "intervaloEnvioSeg": 120,      // ritmo da subida dos lotes (120–300)
    "rastrear": true                // false = o GPS nem liga e a permissão nem é pedida
  },
  "ocorrencias": [                 // o catálogo INTEIRO — sem rede não dá para buscar depois
    { "codigo": 4,                 // numérico e estável
      "texto": "Destinatário ausente",
      "tipo": "entrega",           // "entrega" | "coleta" | "ambos"
      "exigeFoto": true }
  ],
  "romaneio": {
    "numero": "4471",
    "servicos": [ … ]              // todos — o formato está logo abaixo
  }
}
// cada item de "servicos":
{
  "id": "S-88213",                 // ESTÁVEL entre sessões — vai na URL da baixa
  "tipo": "entrega",               // "entrega" | "coleta"
  "ordem": 3,                      // sugestão de sequência — o app não trava por ela
  "cliente": "…", "remetente": "…",
  "logradouro": "…", "bairro": "…", "cidade": "…", "uf": "SP", "cep": "…",
  "latitude": -23.55, "longitude": -46.63,  // mandem sempre — sem elas o app adivinha a distância pelo endereço
  "janelaTexto": "08:00–12:00",    // texto livre, mostrado como veio
  "documentos": [
    { "tipo": "NFE",               // NFE | CTE | CTP | MDE | COLETA
      "numero": "…",
      "chave": "4425…",             // 44 dígitos — é o que a bipagem lê
      "parceiro": "…" }
  ],
  "volumesPrevistos": 12, "pesoPrevisto": 340.5   // coleta: base da conferência
}

A forma de entrega do romaneio — as três garantias #

É a parte mais importante do documento

1 — Abrir a sessão de novo devolve o mesmo romaneio. A segunda, a quinta e a vigésima abertura do dia devolvem o romaneio inteiro, quantas vezes for preciso. Motorista sai e entra no aplicativo o tempo todo: bateria acabou, aparelho reiniciou, trocou de veículo.

2 — Serviço já baixado continua vindo na lista, com o estado marcado (concluído), em vez de sumir. Sumir da lista é indistinguível de “a central removeu este documento” — e o aplicativo agiria de acordo.

3 — Motorista sem romaneio recebe lista vazia com 200, não erro. “Não ter trabalho no momento” é uma situação normal do dia, não uma falha.

Por que virou a parte mais importante: o servidor atual trata a busca do romaneio como uma retirada — cada serviço é entregue uma vez só, e buscar de novo responde erro. Os registros de 10/08/2026 mostram os dois estragos. O primeiro: uma placa recebeu 427 serviços às 14:17 e ouviu a mesma recusa onze vezes seguidas às 14:19 — motorista que saiu e entrou do aplicativo ficou com a tela vazia, sem ter dado nenhuma baixa; e o aplicativo que está na loja mostra o mesmo padrão em 170 placas (ele só nunca reclamou porque nunca busca a lista duas vezes). O segundo, pior: no mesmo dia, o mesmo romaneio saiu picado em pedaços com números diferentes — 427 serviços como 734/26, depois 7 como 735/26, depois 123, 12 e 285 como 736/26 (7 + 123 + 12 + 285 = 427) — e, como sumir da lista significa “removido pela central”, 135 serviços desapareceram da tela do motorista com o dia em andamento.

O aplicativo ganhou remendos locais (guarda o romaneio no aparelho e trata a lista do servidor atual como aditiva), mas remendo tem custo: o aplicativo fica cego para cancelamento da central, e troca ou perda do aparelho não tem salvação — essa informação só existe do lado do servidor. No contrato novo, as três garantias acima resolvem as duas coisas de uma vez, e a regra nasce dentro do endpoint.

As demais regras — e o motivo de cada uma #

RegraMotivo
O romaneio vem inteiro, sem paginação O aplicativo é offline por projeto. Paginar aqui equivale a entregar meio dia de trabalho — o motorista não tem como pedir a página seguinte no meio da estrada. Com compressão, até um romaneio de 400 serviços chega em segundos.
Sessão nova não invalida a fila Baixas feitas antes do relogin continuam válidas quando subirem. Amarrar a gravação à “sessão aberta agora” transforma cada relogin em perda de trabalho.
Recusa de negócio explica o motivo CPF não cadastrado, placa de outra transportadora, romaneio de outro motorista: 4xx com a mensagem em português. Ela vai direto para a tela do login.
Endpoint 2 de 6 · vale hoje

Alterações — o que mudou no romaneio #

GET/mobile/romaneio/{numero}/alteracoes?desde={data}
Para explicar em uma frase

De minuto em minuto o aplicativo pergunta “mudou alguma coisa?” — e a resposta quase sempre é “não”. Este endpoint devolve só a diferença, para que a pergunta mais frequente da API seja também a mais barata.

O que o aplicativo manda #

Nada no corpo. O número do romaneio vai na URL, e desde é o sincronizadoEm que veio na resposta anterior — devolvido exatamente como chegou. Na primeira consulta do dia, desde é o momento da sessão.

O que o aplicativo espera de volta #

→ 200
{
  "sucesso": true,
  "incluidos": [ … ],   // serviços NOVOS — objeto completo, formato da sessão
  "alterados": [ … ],   // objeto INTEIRO, mesmo id — nunca parcial
  "removidos": [ "S-88213" ],              // só os ids
  "sincronizadoEm": "2026-08-10T14:40:11-03:00"  // relógio DO SERVIDOR
}
// nada mudou (o caso comum): 200 com as três listas vazias

As regras — e o motivo de cada uma #

RegraMotivo
sincronizadoEm vem do relógio do servidor É a âncora da conversa: o aplicativo guarda o valor e o devolve na consulta seguinte. O relógio do aparelho não participa — ele pode estar errado, e aí a conversa perderia ou repetiria mudanças para sempre.
alterados traz o serviço inteiro O aplicativo substitui o que tem pelo que recebe. Mandar só os campos que mudaram criaria um estado híbrido — metade de uma versão, metade de outra.
removidos importa tanto quanto incluidos Serviço cancelado que continua na tela é motorista dirigindo até um endereço que não existe mais.
Baixa de serviço removido ainda chega — e deve ser aceita Uma baixa que já estava na fila não é apagada quando o serviço some da lista. O que o TMS faz com ela é decisão de negócio — é a pergunta 7.
Serviço entregue não entra em removidos Conclusão não é remoção. Foi um dos defeitos do servidor atual: o documento sumia da lista assim que era entregue, e o aplicativo entendia que a central o havia cancelado.

Evolução: marcador de versão exige versão nova do app #

Com ETag na resposta e If-None-Match na consulta, o caso comum vira 304 sem corpo — e sem consulta ao banco. O marcador é a versão do romaneio, não da resposta: se mudar a cada requisição, o 304 nunca acontece. A economia não é de banda, é de banco — multiplicada pelo número de motoristas em rua vezes uma consulta por minuto. O aplicativo em campo hoje manda só o desde; implementar o ETag desde já não atrapalha em nada.

Endpoint 3 de 6 · vale hoje

Baixa — o resultado do serviço #

POST/mobile/servicos/{servicoId}/baixa
Para explicar em uma frase

Cada serviço concluído vira um pacote pequeno com quem recebeu, quando, onde e as provas — e reenviar o mesmo pacote nunca pode duplicar o registro nem travar a fila.

O que o aplicativo manda #

{
  "idempotencia": "9f1c2b7e-…",   // gerado no aparelho; o MESMO em toda tentativa
  "servicoId":    "S-88213",      // repete o da URL — se divergirem, recuse
  "resultado":    "executado",    // "executado" | "ocorrencia"
  "executadoEm":  "2026-08-10T14:32:10-03:00",  // quando o MOTORISTA confirmou

  "posicao":   { "lat": -23.55, "lon": -46.63, "precisaoM": 8 },  // pode faltar
  "recebedor": { "nome": "…", "documento": "…", "setor": "…" },   // conforme os parâmetros
  "fotos":      [ { "seq": 1, "anexoId": "a7f3c9…" } ],          // pode vir vazio
  "assinatura": { "anexoId": "…" },                              // quando exigida

  // só quando resultado = "ocorrencia":
  "ocorrencia": { "codigo": 4, "observacao": "…", "retornaHoje": true },

  // só quando o serviço é coleta:
  "coleta": {
    "volumesConferidos": 11,
    "motivoDivergencia": "…",     // obrigatório quando divergiu do previsto
    "documentos": [ { "tipo": "NFE", "numero": "…", "chave": "…" } ]
  }
}

O que o aplicativo espera de volta #

→ 200 { "sucesso": true, "baixaId": "B-88213", "registradoEm": "2026-08-10T14:35:02-03:00",
        "situacao": "registrada" }  // "registrada" | "duplicada" | "ignorada"

situacao conta o que aconteceu: registrada — baixa nova; duplicada — a mesma idempotência voltou, o servidor devolve a resposta guardada e não gera movimento novo; ignorada — a central já tinha baixado o documento por dentro do TMS, e a versão do motorista fica só como histórico. Nos três casos o HTTP é 200: responder 409 ou 422 faria a fila do aparelho tratar como falha e reenviar a mesma baixa para sempre.

As regras — e o motivo de cada uma #

RegraMotivo
Idempotência repetida devolve a resposta guardada O caso real: a gravação funciona, a confirmação se perde na volta, o aplicativo reenvia dias depois. Se o reenvio devolver só “já existe”, o aparelho fica sem o baixaId e sem saber se o que valeu foi o dele.
Baixa antiga não tem prazo Recusar por antiguidade — ou por “romaneio já fechado” — apaga trabalho feito de verdade, que o motorista não tem como refazer. executadoEm é o relógio do motorista; registradoEm, o do servidor. As duas datas convivem.
fotos pode vir vazia — e citar arquivo que ainda não subiu O anexoId nasce no aparelho (ver anexos), então a baixa já sai citando cada foto — mesmo as que ainda estão na fila para subir. Prender a entrega por causa de um arquivo que já está garantido no aparelho inverte a prioridade — a baixa nunca espera anexo.
posicao pode nem vir O carimbo é tentado no “Cheguei”, com oito segundos de paciência. GPS desligado, subsolo ou permissão negada deixam a baixa sair sem coordenada, de propósito — exigir o campo prende para sempre a entrega feita num galpão sem sinal.
Ocorrência não é fracasso — é resultado “Destinatário ausente” fecha o serviço do mesmo jeito que “executado”. O código é numérico e vem do catálogo que a própria sessão entregou.
Coleta valida a conferência, não a foto volumesConferidos pode divergir do previsto — aí o motivoDivergencia vem preenchido, e é obrigatório. Os documentos vinculados na coleta chegam na própria baixa.
Endpoint 4 de 6 · vale hoje

Anexos — fotos e assinatura #

POST/mobile/anexos
Para explicar em uma frase

Cada foto e a assinatura sobem sozinhas, uma por chamada, antes ou depois da baixa — e uma foto que falha nunca segura a entrega.

O que o aplicativo manda #

A chamada é multipart/form-data — o arquivo vai como parte binária, sem base64, e os metadados vão como campos de texto (formato definido pelo documento do cliente de 12/08):

anexoId            "a7f3c9…"     // GERADO NO APARELHO — é o mesmo que a baixa cita
servicoId          "S-88213"
baixaIdempotencia  "9f1c2b7e-…"  // amarra à baixa — que pode AINDA NÃO ter chegado
tipo               "foto"        // "foto" | "assinatura"
seq                1             // ordem da foto; assinatura = 0
formato            "jpeg"        // foto = jpeg · assinatura = png
capturadoEm        "2026-08-10T14:31:58-03:00"  // relógio do aparelho, no clique
arquivo            (binário)     // a parte de arquivo do multipart

O que o aplicativo espera de volta #

→ 200 { "sucesso": true }

O anexoId não vem na resposta — ele nasce no celular e chega no próprio envio. É isso que permite à baixa citar a foto antes de o arquivo terminar de subir. Receber de novo o mesmo anexoId nunca duplica: o TMS trata como substituição (ou confirmação) do mesmo anexo.

As regras — e o motivo de cada uma #

RegraMotivo
O anexo pode chegar antes da baixa A rede decide a ordem. Se a baixa daquela idempotência já existe, amarre o anexo a ela; se ainda não existe, guarde e amarre quando chegar. Anexo órfão é estado normal do sistema, não inconsistência.
Foto que falha nunca trava a baixa É a razão de o anexo ser um endpoint separado. A baixa é o que a operação espera; a foto é prova complementar e sobe no seu próprio ritmo.
seq é ordem, não contagem O número da próxima foto é o último + 1, e apagar uma foto não devolve o número: uma baixa com 4 fotos pode chegar com seq 1, 2, 5 e 9 — e o seq pode passar de 10. A identidade do anexo é o anexoId; o seq só diz a posição na baixa. Não validem faixa nem exijam sequência sem buracos — isso recusaria baixa boa.
O tamanho é conhecido — dimensionem o limite por ele A foto sai do aparelho comprimida, entre ~360 e ~525 KB — e em multipart o corpo da chamada fica nesse tamanho mesmo, sem o inchaço de ~33% que o base64 teria. Cinco fotos são cinco chamadas (2–3 MB no total) — nunca uma requisição só. O limite de corpo aceito precisa comportar isso com folga (pergunta 5).

Evolução: três passos, direto ao armazenamento exige versão nova do app #

1. POST /mobile/anexos/autorizacao      // só metadados + sha256 (com o anexoId do aparelho)
   → { "url": "https://storage…", "expiraEm": "…" }
2. PUT  https://storage…                // os bytes — SEM passar pelo TMS
3. POST /mobile/anexos/a7f3c9…/confirmacao
   → { "sucesso": true }  // o TMS confere tamanho e hash

Tira o arquivo de dentro do corpo da chamada: o TMS deixa de ser o caminho dos bytes e passa a ser só quem autoriza e registra. Três decisões fazem o desenho funcionar: o anexoId continua nascendo no celular — o passo 1 apenas o registra —, então a baixa segue podendo citá-lo antes de os bytes subirem; a URL assinada vale bastante tempo (sugestão: 30 minutos — o motorista pode entrar numa sombra de cobertura logo depois da foto); e o passo 3 pode não chegar — o aparelho pode descarregar no meio — então o melhor é o TMS ouvir o evento do próprio armazenamento. Do lado do aplicativo isso é um método só: custa uma versão nova, não uma reescrita.

Evolução · o aplicativo já faz; falta o lado do TMS

Ditado por voz — o que a API precisaria receber no app desde a 6.0.10 #

POST/mobile/anexos (o mesmo endpoint — nenhuma rota nova)
Status: o lado do aplicativo está pronto; o do TMS, não

O recurso vem do documento do cliente de 12/08 (Sitra Mobile 1C — Demandas Consolidadas) e foi entregue no aplicativo na versão 6.0.10 (13/08): o motorista já dita nome, documento e observação, e o reconhecimento acontece dentro do próprio aparelho. Nada disso muda o servidor de hoje — o que chega ao TMS continua sendo o texto, no campo normal da baixa; o áudio fica guardado no aparelho.

O que está descrito abaixo é o que falta do lado de vocês para o áudio também viajar: não exige rota nova, mas cria um tipo novo de anexo e seis campos novos na baixa — mais o player, sem o qual o recurso não se paga (última linha da tabela de regras).

Para explicar em uma frase

O motorista fala em vez de digitar — nome do recebedor, documento e observação da ocorrência —, o texto reconhecido entra no campo (e pode ser corrigido), e o áudio original sobe como anexo: a prova de voz que vale numa contestação.

O áudio sobe como anexo — mesmo multipart, tipo novo #

anexoId            "b41d07…"     // gerado no aparelho, como qualquer anexo
servicoId          "S-88213"
baixaIdempotencia  "9f1c2b7e-…"
tipo               "audio"       // o tipo novo
campo              "nome"        // "nome" | "documento" | "observacao"
transcricao        "João da Silva"  // texto reconhecido ANTES da correção — PODE VIR VAZIA
duracaoSeg         4             // teto: 20 s (nome/documento) · 60 s (observação)
formato            "m4a"         // AAC mono 16 kHz — ~25 a 180 KB, menor que uma foto
capturadoEm        "2026-08-10T14:31:40-03:00"
arquivo            (binário)

seq não se aplica ao áudio: por campo existe no máximo um áudio, e regravar substitui o anterior — a baixa cita sempre o último anexoId.

E a baixa ganha a origem de cada campo ditado #

  "recebedor": {
    "nome":               "João da Silva",  // o texto FINAL, já corrigido pelo motorista
    "nomeOrigem":         "voz_corrigida",  // "teclado" | "voz" | "voz_corrigida"
    "nomeAudioAnexoId":   "b41d07…",        // presente quando a origem foi voz
    "documento":          "12345678-9",
    "documentoOrigem":    "voz",
    "documentoAudioAnexoId": "c02e91…"
  },
  "ocorrencia": {
    "codigo": 4, "observacao": "…",
    "observacaoOrigem": "teclado"          // sem áudio quando veio do teclado
  }

As regras — e o motivo de cada uma #

RegraMotivo
transcricao pode divergir do texto final — nunca validar igualdade A transcrição é o que o reconhecimento entendeu antes da correção; o campo da baixa é o que o motorista confirmou. Divergirem é o caminho feliz — é exatamente o caso voz_corrigida. Recusar por diferença mataria o recurso.
Áudio sem transcrição é aceito Em Android anterior ao 13, ou sem o pacote de português baixado, o aparelho grava mas não reconhece — a transcricao chega vazia e o áudio continua valendo como prova. O motorista digita o texto nesses casos. Medido em campo na 6.0.10.
Os campos de origem são opcionais Baixa sem nomeOrigem/documentoOrigem/observacaoOrigem (aplicativo atual, ou motorista que digitou tudo) continua válida. Origem ausente significa teclado.
Sem player no TMS, o recurso não se paga O valor do ditado não é digitar menos — é a prova em contestação. Isso só existe se a tela do TMS tocar o áudio ao lado da baixa. Guardar arquivo que ninguém consegue ouvir é custo sem retorno.
O que precisamos ouvir do TMS antes de fechar

1. Confirmam que anexo de áudio sem transcrição é aceito (Android antigo)?  2. A retenção do áudio segue a regra das fotos ou tem prazo próprio — voz é dado pessoal (LGPD)?  3. O formato AAC/M4A serve para o player de vocês, ou só WAV?

Endpoint 5 de 6 · vale hoje

Posições — o rastreamento #

POST/mobile/posicoes
Para explicar em uma frase

O caminhão aparece no mapa porque o aparelho junta as posições e as sobe em lotes — inclusive as das horas em que ele estava sem sinal.

O que o aplicativo manda #

{
  "placa":    "ABC1D23",
  "romaneio": "4471",
  "posicoes": [
    { "lat": -23.55, "lon": -46.63,
      "precisaoM": 8,                       // raio de erro do GPS, em metros
      "em": "2026-08-10T14:31:55-03:00" },  // quando o GPS MEDIU// já houve lote real com 316 posições
  ]
}
→ 200 { "sucesso": true }

O ritmo vem dos parâmetros da sessão: mede a cada intervaloPosicaoSeg, sobe a cada intervaloEnvioSeg. O rastreamento roda apenas enquanto houver serviço pendente — romaneio concluído, o GPS desliga e a notificação some.

Ligar e desligar é pelo parâmetro rastrear da sessão, e ele é por romaneio, não por documento: é um caminhão, um GPS, uma trilha — de cinco cargas no mesmo romaneio, não há como seguir três e não seguir duas. O ganho de mandar esse campo é concreto: com rastrear: false o aplicativo não liga o GPS e não pede a permissão de localização “Sempre” — que no Android 11 em diante é uma ida manual aos ajustes, o passo onde mais se perde motorista na instalação. Hoje o TMS tem esse parâmetro e ele não chega ao aplicativo — carga marcada como “não rastrear” está sendo rastreada assim mesmo.

As regras — e o motivo de cada uma #

RegraMotivo
Guardem as duas datas Quando o GPS mediu (vem no pacote) e quando o servidor gravou. A diferença entre elas é a métrica mais barata de saúde de rede em campo — e é a base da seção de observabilidade.
Posição com data antiga é comportamento correto Um lote que chega às 17h com posições das 14h significa três horas sem sinal, não atraso de fila. Descartar por antiguidade apaga justamente o trecho de estrada que ninguém viu.
Lote parcialmente inválido: aceitem o que der Recusar o lote inteiro por uma coordenada ruim faz o aplicativo reenviar o mesmo lote para sempre.
A recusa aqui é silenciosa — desduplicação é de vocês É o único recurso em que o erro não aparece para o motorista nem entra na espera crescente: o lote fica pendente e sobe de novo no próximo ciclo. Se vocês gravaram e ainda assim responderam erro, as mesmas coordenadas chegam repetidas — e o pacote não tem identificador próprio. A chave prática é placa + romaneio + horário da medição.
Caminhão parado não manda posição — e está certo O envio é por movimento, não por relógio: é o que faz a bateria durar o turno. Parado no almoço ou numa descarga de uma hora, o GPS dorme e volta quando o veículo se mexe. Alarme de “sem posição há X minutos”, sozinho, dispara todo dia à toa.
Endpoint 6 de 6 · evolução

Dispositivo e push — o TMS avisa exige versão nova do app #

POST/mobile/dispositivos
Para explicar em uma frase

Em vez de o aplicativo perguntar a cada minuto se o romaneio mudou, o TMS avisa o aparelho na hora — e a consulta periódica continua existindo como rede de segurança.

Como funciona #

// na abertura da sessão, o aplicativo registra o aparelho:
POST /mobile/dispositivos
{ "so": "android", "versaoApp": "6.1.0", "id": "…", "tokenPush": "…" }
→ 200 { "sucesso": true }

// quando o romaneio muda, o TMS dispara pelo FCM (Firebase Cloud Messaging):
{ "tipo": "romaneio-alterado", "romaneio": "4471" }
// o aplicativo acorda e consulta /alteracoes — o mesmo endpoint de sempre

As duas regras #

Mensagem de dados, não de notificação. Com notificação, o sistema mostra um balão a cada mudança de romaneio; em uma semana o motorista desliga as notificações do aplicativo inteiro — e junto vai o aviso que importa. Mensagem de dados não aparece na tela: ela acorda o aplicativo.

O push é otimização, nunca garantia. O aparelho pode estar sem rede ou com economia de bateria agressiva. A consulta periódica continua existindo, e o pior caso é exatamente o comportamento sem push — por isso este é o último endpoint da lista: com as alterações baratas, perguntar já custa quase nada.

Operação

O que a central precisa enxergar #

O aplicativo entrega a posição; quem sabe se o rastreamento está saudável é o TMS. São cinco informações de tela — e quatro delas saem de dados que já chegam nos endpoints acima, sem campo novo no aplicativo.

1Última posição recebida
Por motorista e placa. São duas datas, e não são a mesma coisa: quando o GPS mediu e quando o servidor recebeu. A diferença entre elas é o tamanho da represa que acabou de esvaziar — a métrica mais barata de saúde de rede em campo.
2Último contato do aplicativo
Qualquer requisição, de qualquer tipo. Responde “o aparelho ainda fala comigo?”, que é diferente de “onde ele estava?”. Alarme de aparelho mudo se apoia nesta, nunca na primeira.
3Deveria estar rastreando?
O aplicativo só rastreia enquanto houver serviço pendente. O TMS já tem tudo para derivar isso: romaneio aberto e serviço sem baixa. Sem essa informação, todo alarme dispara à toa.
4Início do romaneio
O primeiro evento recebido. Responde uma pergunta que hoje não tem resposta: romaneio despachado às 6h sem nenhum evento às 9h não é motorista atrasado, é aplicativo que não subiu — e é o único jeito de descobrir antes de o cliente ligar.
A quinta informação: o alarme que presta

“Não chega posição há X minutos”, sozinho, é um alarme quebrado — dispara todo almoço e toda descarga, e em duas semanas ninguém mais olha. O alarme confiável cruza as três primeiras informações desta seção: deveria estar rastreando? · há quanto tempo não vem posição? · há quanto tempo o aparelho não fala? Em degraus: ⚪ tudo certo · 🟡 sem posição há 30 minutos devendo rastrear · 🔴 sem posição há 60 minutos, ou aparelho mudo.

Para a reunião

As onze perguntas que precisam de resposta #

Tudo o que este documento assume e precisa de confirmação — ou que só a equipe do TMS pode decidir. Cada pergunta vem com o porquê, e a linha em branco é para anotar a resposta na própria reunião, no papel ou por cima do PDF. Respondidas as onze, não sobra decisão em aberto.

  1. Em que endereço os /mobile/* vão responder?

    A documentação define os caminhos, não a base. O aplicativo assumiu a convenção atual — produção em ws.aleff.com.br, homologação em wshomdev.grupoaleff.com.br (por exemplo: …/ApiMobileNew/mobile/sessao). No aplicativo é um único ponto de configuração; sem essa resposta, nada é testável.

    Resposta
  2. Como se entra em homologação?

    Hoje a transportadora 999 cai no servidor de homologação — essa regra continua? E quais credenciais de teste (transportadora, CPF, placa, romaneio de exemplo) a equipe do aplicativo pode usar para validar os endpoints novos de ponta a ponta?

    Resposta
  3. Vai ter token de autenticação?

    Hoje a identidade viaja no corpo, sem token — o aplicativo seguiu isso. Se a equipe preferir token: em qual cabeçalho, e com qual validade? A exigência inegociável é que a validade cubra o turno inteiro com folga — token que vence no meio do dia joga o motorista para a tela de login no meio da rua.

    Resposta
  4. Data com fuso ou em UTC?

    A documentação define ISO 8601 com o fuso escrito (…T14:32:10-03:00); o servidor atual só aceita UTC (…T17:32:10Z) — e essa diferença já recusou 82 das 86 chamadas de um dia. As duas opções servem ao aplicativo; o que não serve é ficar sem resposta por escrito.

    Resposta
  5. O anexo fica como está — ou nasce em três passos?

    O documento de 12/08 já definiu o formato: multipart/form-data, com o anexoId gerado no aparelho, como especificado acima. Restam duas pontas: qual o limite de corpo aceito por requisição (o aplicativo manda até ~525 KB por foto)? E se o desenho em três passos interessar — qual armazenamento (S3, Azure Blob, outro)?

    Resposta
  6. As três garantias da sessão estão aceitas?

    Reabrir devolve o mesmo romaneio; serviço baixado continua na lista com o estado marcado; sem romaneio é lista vazia, não erro (a forma de entrega do romaneio). É o único item desta lista que já custou o dia de um motorista em campo — precisa de um “sim” explícito.

    Resposta
  7. A central cancela, o motorista já tinha baixado: qual lado vale?

    Um serviço removido pela central pode ter uma baixa já feita offline, que chega minutos depois da remoção. O contrato manda o TMS aceitar e registrar essa baixa — mas o que ela vale no processo (reativa o serviço? vira pendência para a central resolver?) é decisão de negócio de vocês.

    Resposta
  8. Quem cadastra os parâmetros do romaneio?

    fotosObrigatorias (0 a 10), exigeNome, exigeDocumento, exigeAssinatura e os dois ritmos do rastreamento montam os passos da baixa sem nova versão do aplicativo. Onde isso vai ser cadastrado no TMS — por romaneio, por transportadora, por cliente? E quem mantém?

    Resposta
  9. O “rastrear ou não” vem por romaneio, na sessão?

    O TMS já tem o parâmetro que diz se a carga é rastreada — e hoje ele não chega ao aplicativo, que rastreia todo mundo. A proposta é mandá-lo na resposta da sessão, junto dos outros parâmetros (o porquê de ser por romaneio). Se preferirem mandar por documento, funciona — mas fica combinado que um documento marcado liga o rastreamento do romaneio inteiro.

    Resposta
  10. De onde vem o catálogo de ocorrências?

    A sessão entrega o catálogo inteiro: código numérico e estável, texto, tipo (entrega, coleta ou ambos) e se o motivo exige foto. Esse cadastro já existe no TMS? Quem o mantém — e o código de cada motivo está garantido como imutável?

    Resposta
  11. Para o push: existe projeto Firebase da empresa?

    Só interessa se a evolução do push entrar no plano: o disparo é feito pelo FCM (Firebase Cloud Messaging), do lado do TMS. Existe conta ou projeto Firebase da empresa? Quem dispararia o aviso quando o romaneio muda?

    Resposta