Documentação Completa — BI Transporte¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-10
O sistema como ele é hoje, em ordem de raciocínio: o problema, o que entra, como os dados são guardados, como o processamento funciona e, no fim, os contratos que outros sistemas consomem. Quem só integra pode pular direto para o cap. 7. O histórico ("como chegamos aqui") está no apêndice; o passo a passo de cada feature, nas Etapas do Projeto.
1. Contexto e problema¶
A Vantroba extrai do X-Adm, periodicamente, planilhas Excel com o faturamento e o movimento de frota do seu transporte. Antes, transformar esses arquivos exportados em dados consultáveis dependia de alguém rodar um script Python à mão — frágil, sem histórico, sem rastreabilidade de "qual arquivo gerou qual dado".
O BI Transporte substitui esse processo por um serviço contínuo (Java/Micronaut):
recebe as planilhas por uma API autenticada — um .zip com 1..N .xlsx do ciclo —,
valida, processa de forma assíncrona e persiste os fatos no PostgreSQL, de onde os
clientes móveis leem (via PowerSync) e a equipe consulta (telas web e API). Cada
planilha fica registrada com checksum, status e métricas — auditável.
Fora do escopo: editar os dados pela web (a origem é sempre a planilha) e enviar a planilha por tela (o envio é só por API). Relatórios e dashboards são de quem consome os dados, não deste serviço.
2. Dados de entrada¶
A entrada é um .zip com 1..N arquivos .xlsx exportados do X-Adm — o zip
é o lote (decisão 0032). Cada .xlsx tem
três abas de nome fixo — "10", "20" e "30" — e traz o próprio período de
referência, na aba 10 (decisão
0016); o cliente não informa
período no envio. Cada arquivo é validado por magic bytes ZIP antes de qualquer
leitura; abas com outro nome são ignoradas. A leitura é FastExcel (StAX,
streaming) — arquivos grandes não estouram a memória; escolhida no lugar do POI
para compilar em native-image (decisão 0026). O layout coluna-a-coluna é contrato com o
X-Adm (decisão 0003), fixado
no parser e em fixtures golden.
📎 Arquivo de referência:
RESULTADO_TRANSPORTE_0100_072025.xlsx— um arquivo real, com as 3 abas no formato abaixo, emdocs/anexos/privado/no Forgejo (docs/anexos/privado/RESULTADO_TRANSPORTE_0100_072025.xlsx). Arquivo confidencial — acesso restrito à equipe (só com login no Forgejo).
Aba 10 — período de referência¶
Só a primeira linha importa: célula E1 (data inicial) e F1 (data
final), formato dd/MM/yyyy. É o período que delimita o diff-aware (decisão
0016).
| Célula | Conteúdo | Formato |
|---|---|---|
E1 |
data inicial do período | dd/MM/yyyy |
F1 |
data final do período | dd/MM/yyyy |
Aba 20 — faturamento (uma linha por lançamento)¶
Colunas por letra do Excel (índice 0-based entre parênteses). Linha descartada se
dt_frete ou valor vier vazia.
| Coluna | Campo | Formato / regra |
|---|---|---|
| B (1) | classif_ctb |
texto (3) |
| C (2) | ident_ger |
texto (2) |
| D (3) | nro_frete |
texto (6) |
| E (4) | dt_frete |
data dd/MM/yyyy — obrigatória |
| F (5) | nro_docto |
texto (6) |
| G (6) | serie |
texto (3) |
| H (7) | dt_em |
data dd/MM/yyyy |
| I (8) | db_cr |
texto (1) |
| J (9) | tanque |
texto (1) |
| K (10) | placa |
texto (10) |
| L (11) | placa_comp |
texto (10) |
| M (12) | segmento |
texto (3) |
| N (13) | desc_seg |
texto (30) |
| O (14) | seq_proj |
texto (6) |
| P (15) | cod_proj |
texto (10) |
| Q (16) | filial |
texto (2) |
| R (17) | valor |
decimal — obrigatório |
| S (18) | fator_fat |
decimal |
| T (19) | distancia |
decimal |
| U (20) | espec_veic |
texto (10) |
| V (21) | mun_orig |
texto (30) |
| W (22) | mun_dest |
texto (30) |
| X (23) | cod_mot |
texto (6) |
| Y (24) | nome_mot |
texto (30) |
| Z (25) | cpf_mot |
texto (11) |
| AA (26) | gestor |
texto (6) |
| AB (27) | nome_gestor |
texto (30) |
| AC (28) | desc_classif |
texto (70) |
| AH (33) | tipo_frota |
texto (20) |
| AI (34) | marca_veiculo |
texto (80) |
| AJ (35) | modelo_veiculo |
texto (80) |
| AK (36) | ano AAAA/AAAA |
→ ano_construcao / ano_modelo |
Aba 30 — movimento de frota (uma linha por lançamento)¶
Linha descartada se data_lcto ou valor vier vazia.
| Coluna | Campo | Formato / regra |
|---|---|---|
| B (1) | classif_ctb |
texto (3) |
| C (2) | ident_ger |
texto (2) |
| D (3) | ident_custo |
texto (1) |
| E (4) | atrib_custo |
texto (1) |
| F (5) | ident_rat |
texto (1) |
| G (6) | db_cr |
texto (1) |
| H (7) | tanque |
texto (1) |
| I (8) | placa |
texto (10) |
| J (9) | placa_comp |
texto (10) |
| K (10) | segmento |
texto (3) |
| L (11) | desc_seg |
texto (30) |
| M (12) | seq_proj |
texto (6) |
| N (13) | cod_proj |
texto (10) |
| O (14) | filial |
texto (2) |
| P (15) | valor |
decimal — obrigatório |
| Q (16) | data_lcto |
data dd/MM/yyyy — obrigatória |
| R (17) | espec_veic |
texto (10) |
| S (18) | cod_conta |
texto (5) |
| T (19) | classif_conta |
texto (18) |
| U (20) | desc_conta |
texto (70) |
| V (21) | desc_classif |
texto (70) |
| AA (26) | processo |
texto (6) |
| AB (27) | tipo_frota |
texto (20) |
| AC (28) | marca_veiculo |
texto (80) |
| AD (29) | modelo_veiculo |
texto (80) |
| AE (30) | ano AAAA/AAAA |
→ ano_construcao / ano_modelo |
Entrada veicular malformada (marca/modelo/ano/placa) não derruba o lote — vira métrica de defesa (etapa 04).
3. Modelo de dados¶
O schema abaixo é a fonte da verdade — toda migration que evolui o banco atualiza este modelo no mesmo PR.
O schema vive em PostgreSQL, versionado por Flyway (V1..VN, congeladas por
checksum — nunca editar uma aplicada, sempre uma nova). Duas famílias de tabela,
por prefixo, que é contrato com o PowerSync:
bi_*— fatos e configuração sincronizados para os clientes móveis via PowerSync (exigemGRANT SELECTaopowersync_role, decisão 0013).xls_*— controle e auditoria locais ao backend, nunca sincronizados.
Tabelas e relacionamentos¶
erDiagram
xls_processamento ||--o{ bi_faturamento : "mescla por período"
xls_processamento ||--o{ bi_movimento : "mescla por período"
xls_conjunto_lote ||--o{ xls_processamento : "agrupa o lote .zip"
xls_conjunto_lote {
varchar conjunto_id PK
}
bi_faturamento {
bigint id PK
}
bi_movimento {
bigint id PK
}
xls_processamento {
bigint id PK
varchar checksum_sha256 UK
}
bi_configuracao {
text id PK
}
xls_resetar_powersync {
bigint id PK
}
Sem FK físicas. A relação
xls_processamento → bi_*é por período (periodo_inicial/periodo_final, lidos da aba 10), não por chave estrangeira: um upload mescla os fatos do seu período (UPSERT diff-aware), não os "possui".placaliga fato e dados veiculares de forma desnormalizada — não há tabela mestre de frota. As tabelasxls_*são controle/auditoria;xls_processamento.conjunto_idaponta o lote emxls_conjunto_lote(V16), também sem FK física.
Fluxo de dados¶
flowchart TD
xadm[X-Adm] -->|exporta .xlsx → .zip| up["POST /api/xls/processar (.zip)"]
up -->|binário| store[("Garage / arquivo_bytes")]
up -->|registra upload| ctrl[("xls_processamento")]
up --> sax["ExcelProcessor (FastExcel/StAX)"]
sax -->|aba 20| fat[/faturamento/]
sax -->|aba 30| mov[/movimento/]
fat --> upsert["UPSERT diff-aware + DELETE seletivo"]
mov --> upsert
upsert --> bif[("bi_faturamento")]
upsert --> bim[("bi_movimento")]
upsert -->|métricas| ctrl
bif -->|PowerSync| cli[Clientes móveis]
bim -->|PowerSync| cli
cfg[("bi_configuracao")] -->|PowerSync| cli
Detalhe de cada tabela¶
Dicionário por tabela (coluna, tipo, chave, nulo?, desde, nota). A chave natural
composta, os índices e os CHECK vêm em bullets abaixo de cada tabela — é onde a
chave de várias colunas fica legível (o ER acima só dá a topologia). Desde vazio =
coluna original da tabela.
bi_faturamento — fatos de faturamento (aba 20) · sincronizada¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
id |
bigint | PK | NOT NULL | ||
classif_ctb |
varchar | ||||
ident_ger |
varchar | ||||
nro_frete |
varchar | parte da chave natural | |||
dt_frete |
date | parte da chave natural | |||
nro_docto |
varchar | parte da chave natural | |||
serie |
varchar | ||||
dt_em |
date | parte da chave natural | |||
db_cr |
varchar | ||||
tanque |
varchar | ||||
placa |
varchar | parte da chave natural | |||
placa_comp |
varchar | ||||
segmento |
varchar | parte da chave natural | |||
desc_seg |
varchar | ||||
seq_proj |
varchar | parte da chave natural | |||
cod_proj |
varchar | parte da chave natural | |||
filial |
varchar | ||||
valor |
decimal | ||||
fator_fat |
decimal | ||||
distancia |
decimal | ||||
espec_veic |
varchar | parte da chave natural | |||
mun_orig |
varchar | ||||
mun_dest |
varchar | ||||
cod_mot |
varchar | parte da chave natural | |||
nome_mot |
varchar | ||||
cpf_mot |
varchar | ||||
gestor |
varchar | ||||
nome_gestor |
varchar | ||||
desc_classif |
varchar | ||||
tipo_frota |
varchar | V3 | veicular | ||
marca_veiculo |
varchar | V3 | veicular | ||
modelo_veiculo |
varchar | V3 | veicular | ||
ano_construcao |
smallint | V3 | veicular | ||
ano_modelo |
smallint | V3 | veicular |
- Chave natural (UK)
uq_bi_faturamento_natural— 10 colunas (NULLS NOT DISTINCT, V6):nro_frete, dt_frete, nro_docto, dt_em, placa, segmento, seq_proj, cod_proj, espec_veic, cod_mot. É a chave do UPSERT diff-aware. - Índices (V2):
dt_frete,dt_em,placa,filial,cod_proj. - Veiculares (
tipo_frota…ano_modelo) adicionadas em V3; demais em V1.
bi_movimento — movimento de frota (aba 30) · sincronizada¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
id |
bigint | PK | NOT NULL | ||
classif_ctb |
varchar | parte da chave natural | |||
ident_ger |
varchar | parte da chave natural | |||
ident_custo |
varchar | parte da chave natural | |||
atrib_custo |
varchar | parte da chave natural | |||
ident_rat |
varchar | parte da chave natural | |||
db_cr |
varchar | parte da chave natural | |||
tanque |
varchar | ||||
placa |
varchar | parte da chave natural | |||
placa_comp |
varchar | ||||
segmento |
varchar | parte da chave natural | |||
desc_seg |
varchar | ||||
seq_proj |
varchar | parte da chave natural | |||
cod_proj |
varchar | parte da chave natural | |||
filial |
varchar | parte da chave natural | |||
valor |
decimal | parte da chave natural | |||
data_lcto |
date | parte da chave natural | |||
espec_veic |
varchar | parte da chave natural | |||
cod_conta |
varchar | parte da chave natural | |||
classif_conta |
varchar | parte da chave natural | |||
desc_conta |
varchar | ||||
desc_classif |
varchar | ||||
processo |
varchar | ||||
tipo_frota |
varchar | V3 | veicular | ||
marca_veiculo |
varchar | V3 | veicular | ||
modelo_veiculo |
varchar | V3 | veicular | ||
ano_construcao |
smallint | V3 | veicular | ||
ano_modelo |
smallint | V3 | veicular | ||
seq_dentro_grupo |
smallint | NOT NULL | V6 | desambiguador da chave natural |
- Chave natural (UK)
uq_bi_movimento_natural— 17 colunas (NULLS NOT DISTINCT, V6): as 16 contábeis (classif_ctb, ident_ger, ident_custo, atrib_custo, ident_rat, db_cr, placa, segmento, seq_proj, cod_proj, filial, data_lcto, espec_veic, cod_conta, classif_conta, valor) +seq_dentro_grupo(desambiguador — colisões nas 16 são lançamentos legítimos, não duplicatas). - Índices (V2/V6):
data_lcto,placa,filial,cod_proj,cod_conta.
bi_configuracao — KV global sincronizada · sincronizada¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
id |
text | PK | NOT NULL | a chave É o id (semântica) | |
valor |
text | NOT NULL | |||
tipo |
varchar | NOT NULL | CHECK (ver abaixo) | ||
descricao |
text | ||||
sistema |
boolean | NOT NULL | default FALSE |
||
atualizado_em |
timestamptz | NOT NULL | default NOW() |
- CHECK
chk_bi_configuracao_tipo:tipo ∈ {STRING, INT, BOOL, TIMESTAMP, JSON}. - Seed (V12):
ultimo_nuke(TIMESTAMP,sistema=TRUE— sinal de reset, contrato com o cliente Flutter) eslow_query_timeout_ms(INT,10000, editável). idé a própria chave semântica (não surrogate; renomear = delete+insert).
xls_processamento — controle do pipeline · local¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
id |
bigint | PK | NOT NULL | ||
checksum_sha256 |
varchar | UK | NOT NULL | SHA-256 do binário (dedup) | |
nome_arquivo |
varchar | ||||
recebido_em |
timestamp | default NOW() |
|||
data_referencia |
date | legado — era o período do upload; nulo desde o lote .zip (decisão 0016) |
|||
hora_referencia |
time | legado — idem data_referencia |
|||
periodo_inicial |
date | período real, lido da aba 10 | |||
periodo_final |
date | período real, lido da aba 10 | |||
status |
varchar | default PENDENTE |
|||
iniciado_em |
timestamp | ||||
concluido_em |
timestamp | ||||
tempo_ms |
bigint | ||||
erro_mensagem |
text | ||||
log_arquivo |
varchar | caminho relativo do histórico que a UI exibe, data/execucoes/processamento-{id}.log (a V17 reescreveu os de logs/execucoes) |
|||
registros_faturamento |
integer | ||||
registros_movimento |
integer | ||||
arquivo_bytes |
bytea | object storage (etapa 03) | |||
objeto_bucket |
varchar | V8 | object storage | ||
objeto_chave |
varchar | V8 | object storage | ||
objeto_tamanho_bytes |
bigint | V8 | object storage | ||
faturamento_* |
integer | V7 | ×4: inseridas/atualizadas/inalteradas/removidas | ||
movimento_* |
integer | V7 | ×4: idem | ||
defesa_*_qtd |
integer | V11 | ×5: defesa veicular (etapa 04) | ||
xls_legado |
boolean | V11 | |||
conjunto_id |
varchar(64) | V16 | lote .zip de origem → xls_conjunto_lote (sem FK); índice ix_xls_processamento_conjunto |
- UNIQUE
uq_xls_processamento_checksum (checksum_sha256)— dedup de upload. - Object storage (V8):
objeto_*+arquivo_bytes(etapa 03). - Métricas de idempotência (V7):
faturamento_*/movimento_*× {inseridas, atualizadas, inalteradas, removidas} (8 colunas, etapa 02). - Defesa veicular (V11): 5 colunas
defesa_*_qtd+xls_legado(etapa 04). - Lote
.zip(V16):conjunto_idagrupa as entradas de um mesmo envio (decisão 0032).
xls_conjunto_lote — lote de envio .zip · local¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
conjunto_id |
varchar(64) | PK | NOT NULL | V16 | gerado no servidor: zip- + 60 primeiros hex do SHA-256 do .zip |
total |
integer | NOT NULL | V16 | nº de entradas do .zip |
|
duplicados |
integer | NOT NULL | V16 | default 0 |
|
nao_processados |
integer | NOT NULL | V16 | default 0; entradas que não viraram processamento nem duplicata-sucesso (tipo inválido, já em andamento) — contam para o lote fechar |
|
criado_em |
timestamp | NOT NULL | V16 | default NOW() |
|
notificado_em |
timestamp | V16 | quando saiu o resumo único no Telegram |
- Um lote fecha quando todas as entradas terminam; aí sai um resumo no Telegram
(decisão 0032). Espelha o modelo do
bi-comercial-xls.
xls_resetar_powersync — auditoria do reset · local¶
| Coluna | Tipo | Chave | Nulo? | Desde | Nota |
|---|---|---|---|---|---|
id |
bigint | PK | NOT NULL | ||
iniciado_em |
timestamp | NOT NULL | default NOW() |
||
concluido_em |
timestamp | ||||
status |
varchar | NOT NULL | default PENDENTE; CHECK (ver abaixo) |
||
motivo |
text | ||||
iniciado_por |
varchar | ||||
tempo_ms |
bigint | ||||
erro_mensagem |
text | ||||
step_atual |
varchar | ||||
steps_completados |
jsonb | NOT NULL | default [] |
||
detalhes |
jsonb | ||||
atividade_atual |
text | V9 | escrita ao vivo p/ polling |
- CHECK
chk_resetar_powersync_status:status ∈ {PENDENTE, EM_ANDAMENTO, SUCESSO, ERRO}. - Unique parcial
uq_xls_resetar_powersync_em_andamentoWHERE status = 'EM_ANDAMENTO': no máximo um reset em andamento (2º disparo → 409). - Índice
iniciado_em DESC. Ex-xls_nuke_replication(renomeada V14).
4. Mapeamento entrada↔dados¶
Cada aba alimenta uma tabela do banco (o ExcelProcessor lê por índice de coluna):
| Aba da planilha | → Tabela do banco | Linha válida exige |
|---|---|---|
10 (E1/F1) |
xls_processamento.periodo_inicial / periodo_final |
— (1ª linha) |
20 faturamento |
bi_faturamento |
dt_frete (E) e valor (R) |
30 movimento |
bi_movimento |
data_lcto (Q) e valor (P) |
Cada coluna grava na coluna homônima da tabela (nomes na seção 2); não é mapeamento posicional no banco, é por nome. Transformações na leitura:
- datas
dd/MM/yyyy→DATE; valores →DECIMAL; texto truncado ao tamanho da coluna (ver Modelo de dados). - ano
AAAA/AAAA(coluna AK/AE) → divide emano_construcao(esquerda) eano_modelo(direita); formato inválido → ambos nulos. - o período da aba 10 não vira coluna de fato — delimita quais linhas o processamento mescla naquele upload (cap. 5).
A identidade de cada fato no banco não é a posição na planilha, e sim a chave natural (cap. 3) — é o que permite reprocessar o mesmo período sem duplicar.
5. Fluxos e processamento¶
Arquitetura interna¶
O código é package-by-feature (decisão
0022): cada funcionalidade —
processamento, powersync, configuracao, seguranca — carrega suas próprias
camadas Controller → Service → Repository. A fundação transversal — erro RFC
7807, health, Sentry, versão, motor de auth (Firebase/sessão/Bearer/CSRF), object
storage Garage, utilitários e infra de teste — vem das libs do xadm-commons
(xadm-seguranca, xadm-comum-web, -storage, -util, -teste; decisões
0023/0024/0025).
O pacote local comum guarda só o resto app-específico (config typed,
StorageIndisponivelException, dto, AnosVeiculoParser, notificação Telegram).
Dentro de uma feature o fluxo é
Controller → Service → Repository: o controller só fala com service, nunca
com repositório direto, e a entidade não cruza o controller (a borda HTTP fala
DTO/view-model). A leitura do Excel está em processamento.processing (parser
FastExcel/StAX); a persistência é Micronaut Data JDBC, sem Hibernate (decisão
0001). O ArchUnit guarda três
invariantes: sem ciclos entre as features de topo, nenhum subpacote de comum
depende de feature e processamento.processing não depende da camada HTTP
(a leitura do Excel não conhece HTTP).
Recepção e processamento assíncrono¶
O envio responde 202 Accepted na hora; o trabalho pesado roda num pool
dedicado (processamento, 4 threads). Cada .xlsx do lote vira um processamento
próprio; o lote (xls_conjunto_lote) fecha quando todos terminam e manda um resumo
único no Telegram (decisão 0032). O
status em xls_processamento é a máquina de estados de cada planilha:
stateDiagram-v2
[*] --> PENDENTE: receber (checksum, grava binário, insere linha)
PENDENTE --> PROCESSANDO: job inicia
PROCESSANDO --> SUCESSO: grava métricas
PROCESSANDO --> ERRO: catch → erro_mensagem
ERRO --> PENDENTE: reprocessar
SUCESSO --> [*]
Reenviar o mesmo arquivo (mesmo checksum) já concluído com sucesso responde
200 sem reprocessar; já em fila, 409. Jobs presos por um restart são retomados
no boot (StartupRecoveryService).
Persistência idempotente (diff-aware)¶
O núcleo é o UPSERT diff-aware (etapa 02,
decisão 0006): por período,
COPY → TEMP TABLE → INSERT ... ON CONFLICT (chave natural) DO UPDATE WHERE ... IS
DISTINCT FROM, seguido de DELETE seletivo do que sumiu no período. Só linhas
realmente alteradas trocam de xmin — as inalteradas não re-propagam pelo
PowerSync (sem churn de bateria/banda nos celulares). Cada upload grava 8 métricas
finas (inseridas/atualizadas/inalteradas/removidas, por fato) em xls_processamento.
Como os arquivos de um lote mesclam em paralelo, a mescla tem duas defesas contra
deadlock: o INSERT … SELECT ordena pela chave natural e a fase de banco é
serializada por um advisory lock (decisão
0031); o parse do Excel
segue paralelo.
O binário do .xlsx vai para object storage (Garage), não para o banco — ver a
configuração de storage no cap. 6.
6. Conceitos transversais e configuração¶
Idempotência por checksum + chave natural (caps. 3 e 5) é o conceito central:
identidade de upload (checksum_sha256) separada da identidade de fato (chave
natural). Preservação de cadastro veicular (decisão
0012): correção feita direto no
banco sobrevive ao reprocessamento (entrada vazia não sobrescreve). Sinal de
reset (ultimo_nuke em bi_configuracao) avisa os clientes a reconectar após um
reset da replicação (etapas 05/06).
Prefixos de tabela são contrato com o PowerSync: bi_* sincroniza (exige
GRANT SELECT ao powersync_role — decisão
0013), xls_* é local.
Configuração (variáveis do projeto):
| Tema | Variáveis principais |
|---|---|
| Banco | DATASOURCES_DEFAULT_URL, DB_USER, DB_PASSWORD |
| API | VANTROBA_XLS_API_TOKEN (Bearer do /api/**; antes API_BEARER_TOKEN) |
| Object storage | S3_FILE_STORAGE (PSQL/PSQL_GARAGE/GARAGE), GARAGE_ENDPOINT, GARAGE_ACCESS_KEY, GARAGE_SECRET_KEY, GARAGE_BUCKET (antigas S3_* via fallback) |
| Auth das views | AUTH_FIREBASE_*, AUTH_SESSION_SECRET (login Google @xadm.com.br) |
| Reset / PowerSync | POWERSYNC_MONGODB_URI, POWERSYNC_NUKE_CONFIRMATION, COOLIFY_API_TOKEN |
| Notificação / erros | TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, SENTRY_DSN |
Defaults, semântica de cada modo de storage e o fluxo de auth/reset estão nas
etapas 03, 05 e
07; o runbook exaustivo de envs em
operacao/deploy. O deploy é procedimento — fica no
runbook, não neste livro.
7. Contratos públicos / API¶
A conclusão de tudo acima: as assinaturas que outros sistemas consomem.
| Método / rota | Auth | Resultado |
|---|---|---|
POST /api/xls/processar |
Bearer (ROLE_API) |
202 lote recebido (conjuntoId/total/itens[], status por arquivo) · 400 zip inválido/vazio/sem .xlsx |
GET /api/transporte/processamentos |
anônimo | lista paginada (page/size/status) |
GET /api/transporte/processamentos/{id} |
anônimo | detalhe (status, métricas) |
GET …/{id}/logs · …/{id}/arquivo |
anônimo | log (text/plain) · XLS original |
POST /api/transporte/admin/resetar-powersync |
Bearer + X-Confirm-Nuke |
202 (reset da replicação) |
GET /api/transporte/admin/resetar-powersync |
Bearer | histórico de resets: o Page do micronaut-data (page/size) |
Auth em duas camadas (decisão 0011):
/api/** por Bearer estático; as telas server-rendered por login Google. O
contrato narrado (exemplos curl, formato do arquivo, respostas) está em
dev/api-rest; a referência interativa gerada do código
(OpenAPI/Swagger) em
docs.xadm.biz/.../public/api/.
8. Apêndice — Histórico (changelog)¶
Como o sistema chegou ao estado atual — as etapas entregues e as decisões que as fundamentaram. Cada etapa descreve o seu delta; este livro é o consolidado.
Etapas:
- Recebimento e processamento automático das planilhas de transporte, com histórico rastreável de cada envio.
- Reprocessar um período sem gerar tráfego nem churn desnecessário para os aplicativos móveis.
- Arquivamento dos arquivos recebidos em storage dedicado, fora do banco de dados.
- Identificação de veículo e frota nos lançamentos, preservando correções manuais de cadastro.
- Reset seguro e auditável da replicação quando o estado replicado precisa ser zerado.
- Configurações compartilhadas entre servidor e aplicativo, ajustáveis sem novo deploy.
- Acesso às telas internas restrito a contas @xadm.com.br.
- Stack uma major atrás modernizada e código alinhado às práticas do framework, sem mudar comportamento observável.
Decisões:
- Micronaut Data JDBC, sem Hibernate
- Processar XLS (POI)
- Contrato canônico JSON para paridade Python↔Java
- Período de referência vem do upload (data/hora multipart)
- BIGSERIAL como PK nas tabelas bi_*
- Chaves naturais + UPSERT diff-aware
- COPY + TEMP TABLE no upsert em lote
- Object storage Garage com 3 modos (PSQL / PSQL_GARAGE / GARAGE)
- Resetar Powersync
- Sinal de reset do Powersync para clientes via bi_configuracao
- Autenticação em duas camadas (API Bearer + views Google)
- Preservação de cadastro de veículo no UPSERT
- GRANT automático ao powersync_role em tabelas novas
- Documentação no portal central (adoção da constituição X-Adm)
- GETs de leitura da API são anônimos (sem Bearer)
- Período do diff-aware vem da aba-10; data/hora do upload são metadado
- Contrato de erro único {code, message} via ErrorResponseProcessor
- Auth das views no micronaut-security nativo (aposenta o AuthFilter)
- Bump major para Java 25 + Micronaut 5 e seus efeitos colaterais
- Serialização via serde (build-time) e HTTP declarativo (@Client)
- Erro de API em RFC 7807 (ProblemDetail), alinhado ao default da casa
- Organização package-by-feature, alinhada ao padrão Micronaut da casa
- Adotar a lib xadm-seguranca (motor de auth compartilhado)
- Adotar a lib xadm-comum-web (infra web compartilhada)
- Adotar as libs xadm-comum-storage / -util / -teste (dedup do commons)
- Migrar leitura de XLSX de POI (SAX) para FastExcel — viabiliza native-image
- Bump das libs xadm-comum + migração do prefixo de storage s3. → garage.
- Views server-render em JTE (gg.jte) no lugar de Thymeleaf — native-safe
- 0029 — Adota o smoke de produção pós-deploy — ponteiro do ADR central 0031
- 0030 — Adota o CI 100% GitHub Actions e o deploy pelo control-plane — ponteiro dos ADRs centrais 0022, 0024, 0026 e 0027
- 0031 — Mescla concorrente: ORDER BY pela chave natural + advisory lock (anti-deadlock 40P01)
- 0032 — Envio em lote: um .zip com 1..N .xlsx por chamada
- 0033 — Adota a tela de login da xadm-seguranca e renomeia o token de API
- Adota a constituição 2.0.0: só native, libs na corrente e mavenLocal filtrado