Pular para conteúdo

0006 — Painel colaborador: dashboard e detalhe abertos para o usuário Maxsul

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-08 · Decidido em: 2026-07-14

Contexto

A home (/) era um painel de cards de contagem por tabela — útil para diagnóstico, impróprio para o usuário final da Maxsul, que precisa acompanhar seus pedidos e onde cada um está rumo ao X-Adm, sem jargão de integração e sem login. Além disso, o alerta de erro terminal (decisão 0005) já linka o e-mail para o detalhe do pedido, que não existia.

Decisão

Duas telas abertas (sem auth, atrás da rede — postura atual do app) num chrome limpo da marca XADM (layout-painel, sem os menus de operador), no pacote painel/:

  • GET / — dashboard: tiles de resumo por status + lista de pedidos (nº, cliente via join pied_cliente, data, badge), linha clicável → /pedidos/{code}, filtro ?status=<slug>.
  • GET /pedidos/{code} — detalhe: timeline do status + dados (nº, cliente, documento, datas) + itens (payload.products[]). code inexistente → 404 amigável. Pedido Falhou → mensagem amigável, sem codRetorno/de-para.

Vocabulário de status (4 buckets) — tradução única (painel/StatusBucket) do status técnico: Recebido (CAPTURADO,NA_FILA) · Em processamento (ENVIANDO,ENVIADO) · Importado (CONFIRMADO) · Falhou (ERRO,ERRO_XADM); desconhecido→Recebido. Nenhum segundo campo de estado — a fonte segue sendo pied_pedido.status.

Revisão (spec .ia/003, 2026-08-07). O vocabulário dos 4 buckets foi reescrito para refletir a esteira real: Pedidos em aberto (CAPTURADO) · Enviando ao X-Adm (NA_FILA, ENVIANDO, ENVIADO, ERRO) · Importado no X-Adm (CONFIRMADO) · Erro (ERRO_XADM); desconhecido→Pedidos em aberto. ERRO (transporte, transitório) passou de "Falhou" para Enviando ao X-Adm; só ERRO_XADM (rejeição final do X-Adm) fica em Erro. A decisão estrutural (duas telas abertas, chrome limpo, fonte única StatusBucket) permanece — mudou só o rótulo/agrupamento. Título da home: "Importação de Pedidos PIED → X-Adm"; lista paginada por last_update.

Revisão (prontidão, 2026-09-04). NA_FILA deixou de ser traduzido só pelo nome: sem o invoice no payload o PushService segura o pedido na fila (pode ser horas, até o poll REST passar), então ele volta para Pedidos em aberto — anunciar "Enviando ao X-Adm" enquanto nada sai era mentira visível ao cliente. Com invoice, segue Enviando ao X-Adm. A fonte única continua o StatusBucket, que agora recebe a prontidão como 2º insumo (de(status, pronto) + sqlFiltro() para tiles/lista/filtro lerem a mesma regra). A outra metade do mesmo incidente — encurtar a espera — está na decisão 0017, que também guarda o diagnóstico.

Revisão (2026-09-04) — dois eixos de status na lista (integração × PIED). A coluna única "Status" confundia dois conceitos: "Pedidos em aberto" é o nosso estado de integração, mas na PIED o mesmo pedido já pode constar pago. A lista do dashboard passa a ter duas colunas ortogonais: Status Integração (o bucket do StatusBucket, nosso lado) e Pagamento PIED (pagamento traduzido pelo novo painel/PagamentoPied + deal_status cru). Segue "nenhum segundo campo de estado" no sentido de fonte — PagamentoPied só traduz pied_pedido.payment_status, não é estado novo. Vocabulário dos dois eixos no glossário.

Reorganização: a home de diagnóstico (cards) migra de / para /homedev (o navbar de operador aponta para lá). As demais telas internas (/console, /dados, /captura, /health, /destinatarios) ficam inalteradas.

Reconciliação: o link do e-mail de alerta (0005) passou de /pedido/{code} para /pedidos/{code}.

Consequências

  • Duas superfícies de UI: painel do usuário (chrome limpo) × telas de operador (navbar cheio) — separadas por layout, sem misturar menus.
  • Read-only: o painel não tem ações de escrita; reenviar/enfileirar seguem só no /console.
  • Aberto, sem auth: mantém a postura atual (dívida de login deferida, como /console e /dados).
  • Vocabulário amigável durável: registrado no glossário; o StatusBucket é a fonte única (tiles, lista e timeline consomem dele).
  • Dependência do link: /pedidos/{code} agora resolve — fecha a promessa do e-mail da 0005.

Revisão (2026-08-14) — painel expõe o motivo do erro terminal e deixa de ser read-only. Duas afirmações acima estão superadas: (a) "detalhe … sem codRetorno/de-para" — o detalhe agora mostra o msgRetorno do X-Adm no erro terminal (1XX), limpo do traço de prefixo, com orientação de corrigir e reimportar; 9XX/transporte mantêm o aviso genérico. (b) "read-only … sem ações de escrita; reenviar/enfileirar seguem só no /console" — o painel já ganhara Importar/Dispensar (pedido em aberto pago) e agora Re-Importar no detalhe de qualquer pedido em Erro (reenfileira + envia na hora, espelhando o /console). A distinção 1XX×9XX e a regra de não re-tentar o 1XX automaticamente vivem na 0005.

Revisão (2026-09-08) — o Re-Importar re-arma o espelho, e o flash conta a verdade. "Reenfileira + envia na hora" era insuficiente: sem re-armar o cod_retorno da linha no espelho o X-Adm nunca reprocessava, e o painel dizia "ENFILEIRADO" mesmo assim. O botão agora chama POST /api/v1/xadm/retorno/pedido/reenfileirar depois do push (ver api-integrador §6) e o flash reporta o desfecho real — N linhas reabertas · nada a reabrir · falha explícita. Nunca dizer "reenviado" quando a chamada falhou é requisito de produto, não detalhe: foi o que fez o operador clicar três vezes no mesmo pedido.

Revisão (2026-09-10) — a Falha diz o que falta e pode ser fechada à mão. Incidente dos 15 kits: o contrato gravava no X-Adm e o produto-kit, a composição ou o item não — e o detalhe só dizia "Remessa travada". Duas mudanças: (a) o detalhe em Falha ganha um diagnóstico ao vivo (tipo do pedido, Gravado no X-Adm × NÃO gravado — lance manualmente com os dados do envio, avisos "Possível" tirados do texto do X-Adm), consultando o Integrador na abertura — decidido ao vivo, sem persistir (sem migração, sempre fresco; Integrador fora → aviso no lugar); (b) botão Importado manualmente ao lado do Re-Importar (e na home, nas linhas em Falha), que leva ERRO_XADM → IMPORTADO_MANUAL — o mesmo status do Dispensar, em vez de um novo — com observação obrigatória (importacao_manual_obs, V12), porque o painel não tem login e ela é o único rastro de o que foi lançado e por quem. A reconciliação passa a ignorar IMPORTADO_MANUAL (senão a remessa, que segue TRAVADA no Integrador, devolvia o pedido à Falha a cada minuto). Rotas e texto em configuração.

Revisão (2026-09-10, mesma data) — o botão fecha também a remessa no Integrador. O dono ganhou o resolver-manual (TRAVADA → RESOLVIDA_MANUAL, decisão 0025 dele), e o clique passa a chamá-lo antes de marcar o pedido aqui: só o 200 fecha o pedido; 409 (parte do pedido ainda pendente de entrega — remessa ABERTA, ou TRAVADA com filho 000 bloqueado, que fechar soltaria para o ERP) e falha de transporte o deixam em Falha, com o motivo. Decidido Integrador primeiro — na ordem inversa, uma falha do comando deixaria a remessa travada lá para sempre, sem reconciliação que a revisite; e sem retry em fila (M2M), porque o operador está na tela e pode clicar de novo. Ganha também um campo operador, opcional (o dono o aceita no corpo; o painel segue sem login), gravado localmente no fim da observação — sem migração nova. Detalhe em API do Integrador §5.

Revisão (2026-09-10, terceira) — a Falha tem um caminho só: lançar à mão. O X-Adm é caminho só de ida: o que ele gravou (006) é definitivo e a integração nunca reenvia, e o re-arme só reabre 1XX — reimportar serve, no máximo, para a parte que falhou, e nos 16 pedidos-kit do incidente nem isso resolvia (defeitos do lado ZIM, integrador-client docs/dev/contrato-pabast.md §8). Decidido: (a) o caminho padrão de toda Falha é conferir no X-Adm → lançar à mão o que falta → Importado manualmente, num "O que fazer" único, com o aviso de não excluir no X-Adm o que está em Gravado; (b) o Re-Importar só aparece com parte do pedido pendente (linha no espelho que não é 006 nem 1XX — o filho que espera um pai rejeitado, ex. cliente não cadastrado): aí o resolver-manual responde 409 por desenho e o caminho é corrigir e reimportar. O 409 também o põe à mostra (?pendente=1), cobrindo formulas, que o diagnóstico não consulta; (c) o reenvio automático por dado novo da PIED deixa de tocar ERRO_XADM (ver 0005) — reenviar sozinho re-armaria o 1XX enquanto o operador lança o mesmo à mão; (d) o diagnóstico completa os dados de lançamento: nome de cada componente, produto do item do kit, venda a prazo e, na duplicidade de contrato, os dois códigos e a ordem de escolher qual fica antes de lançar. Rejeitado: excluir no X-Adm e reimportar — esbarra na mão única e exigiria no Integrador um re-arme de 006, com risco de duplicar pedido no ERP.

Alternativas consideradas

  • Reusar o layout/navbar de operador nas telas do usuário: rejeitada — vaza ferramenta interna e foge do "limpo e elegante".
  • Mostrar o estado técnico cru (CAPTURADO/ENVIADO/…): rejeitada — jargão de integração para o usuário final; os 4 buckets comunicam "onde meu pedido está".
  • Manter a home de cards em / e pôr o painel em outra rota: rejeitada — o usuário final é o público primário da raiz; o diagnóstico é secundário (vai para /homedev).
  • Valor monetário e busca no dashboard, ações no detalhe: fora de escopo do MVP (mantém enxuto).