# ENG-1262 - Auditoria de leituras da separação

## Status

- Data: 2026-07-23.
- Estado: aprovado.
- Iniciativa: ENG-1244.
- Repositórios afetados na implementação: `rex-back` e `rex-front`.
- O `Rex-Estoque` manterá o payload atual e precisará apenas de validação de
  compatibilidade.
- Este documento adiciona a ENG-1262 ao escopo posterior ao design geral da
  ENG-1244, que originalmente a registrava como fora do escopo.

## Contexto

O aplicativo de estoque já coleta `reading_logs` durante a separação e os envia
junto da confirmação do item. Hoje o backend armazena esses dados na tabela
polimórfica genérica `reading_logs`, vinculados somente à origem da movimentação.
Esse formato não oferece o contexto necessário para auditar uma tarefa: produto
da pré-fatura, tarefa, usuário e endereço precisam ser inferidos posteriormente.

O volume esperado é de 10 mil a 100 mil leituras por dia. A retenção deve ser
indefinida, mas apenas os 12 meses mais recentes precisam permanecer
imediatamente consultáveis. O ambiente possui um único servidor de aplicação e
não usará S3 ou outro armazenamento de objetos nesta entrega.

Apesar do título original do card mencionar o histórico da pré-fatura, a decisão
de produto é exibir as leituras somente no dashboard **Tempo de Execução**, no
histórico da tarefa.

## Objetivos

- Auditar leituras válidas e inválidas usadas em separações confirmadas.
- Relacionar cada leitura à tarefa, produto da tarefa/pré-fatura, usuário e
  endereço.
- Preservar conteúdo bruto, tipo, formato, horário do aparelho e horário de
  recebimento pelo servidor.
- Gravar separação e leituras de forma atômica.
- Manter 12 meses no PostgreSQL e arquivar períodos anteriores em arquivos no
  servidor.
- Migrar, quando a associação for determinística, até 60 dias dos logs legados
  ainda disponíveis.

## Fora do escopo

- Exibir leituras no histórico da pré-fatura.
- Registrar tentativas abandonadas antes da confirmação de um item.
- Criar fila durável de leituras no aplicativo.
- Deduplicar requisições ou leituras repetidas.
- Ocultar duplicidades existentes.
- Adicionar filtros avançados, pesquisa ou exportação pela interface.
- Usar S3 ou fazer consulta transparente dos arquivos arquivados pela aplicação.
- Usar os logs para medir produtividade individual.

## Abordagem recomendada

Criar uma tabela exclusiva e particionada para as leituras de picking. O fluxo
de separação deixa de enviar seus logs ao armazenamento polimórfico genérico e
os grava diretamente na nova estrutura, dentro da transação principal.

Essa opção mantém o domínio de auditoria separado dos demais fluxos, oferece os
vínculos necessários para consultas e permite uma política de retenção própria.
A gravação assíncrona foi rejeitada porque quebraria a atomicidade. Expandir a
tabela genérica foi rejeitado porque misturaria contextos e dificultaria
particionamento, arquivamento e consultas.

## Modelo de dados

A tabela pai `picking_read_logs` será particionada mensalmente por
`received_at`, o horário confiável do servidor. `read_at` continuará preservando
o horário enviado pelo aparelho, mas não controlará retenção ou partições.

Cada registro conterá, no mínimo:

- `id` e `received_at`, compondo a identidade compatível com particionamento;
- `picking_order_id`;
- `picking_order_product_id`;
- `stock_io_product_id`;
- `user_id`;
- `address_id`;
- `type` e `format`;
- `is_valid`;
- `read_at`;
- `data`, mantendo o limite atual de 255 caracteres;
- `source_reading_log_id`, nullable e usado somente pela migração legada.

Serão guardados somente IDs, sem fotografias de nomes e descrições. A tela
resolverá os dados atuais dos cadastros. Os arquivos de arquivo morto incluirão
os dados descritivos disponíveis no momento da exportação. Exclusões de entidades
relacionadas não podem excluir em cascata os registros de auditoria.

Cada partição terá índice para a consulta principal por
`picking_order_id, received_at desc, id desc` e índice de apoio para
`source_reading_log_id`.

## Fluxo de gravação

O aplicativo mantém o comportamento atual: acumula leituras em memória e envia
`reading_logs` somente ao confirmar a separação do item. Fechar, limpar ou
pausar sem confirmar descarta as tentativas locais.

No backend, o fluxo será:

1. validar a requisição e os enums existentes;
2. bloquear e validar a tarefa e o item;
3. registrar a movimentação, o item separado e a embalagem;
4. resolver o `picking_order_product` correspondente;
5. inserir os logs em lote na partição corrente;
6. confirmar a transação.

O serviço de picking não repassará esses logs ao
`TransferableTransferItemService`; os demais fluxos continuam usando
`reading_logs`. Uma separação sem logs permanece válida.

Se a requisição for repetida, as movimentações e leituras poderão aparecer
duplicadas conforme o comportamento atual. Não haverá UUID, chave idempotente ou
heurística de deduplicação nesta entrega.

## Consulta e interface

Adicionar uma consulta paginada por tarefa, seguindo a visibilidade e a
autorização já aplicadas ao dashboard **Tempo de Execução**. O contrato deve
retornar registros do mais recente para o mais antigo e nunca aceitar uma tarefa
fora do escopo visível do usuário.

Ao clicar em uma tarefa, **Histórico da tarefa** terá as abas **Pausas** e
**Leituras**. A aba Leituras mostrará:

- data e hora da leitura;
- usuário;
- endereço relacionado à separação;
- produto da pré-fatura;
- conteúdo bruto;
- formato: endereço ou produto;
- tipo: manual, EAN-13, código de 16 caracteres ou QR Code;
- resultado: válida ou inválida.

A interface terá carregamento, estado vazio, erro com nova tentativa e paginação
no servidor. Nenhuma tela ou endpoint de histórico por pré-fatura será criado.

Quando o período da tarefa estiver fora da janela consultável, a aba informará:

> Registros de leitura anteriores a 12 meses ficam arquivados. Para consultá-los,
> entre em contato com o suporte do sistema.

## Particionamento e arquivo morto

Uma rotina agendada criará antecipadamente as partições mensais futuras. As
partições dos 12 meses mais recentes permanecerão anexadas à tabela pai.
Partições completas que ultrapassarem a retenção serão processadas por uma
rotina mensal.

O caminho raiz será configurável por ambiente, persistente, fora dos diretórios
de release, incluído no backup e monitorado quanto a espaço em disco. Cada mês
gerará um `JSONL.gz` e um manifesto com:

- versão do esquema do arquivo;
- início e fim do período;
- quantidade de registros;
- SHA-256;
- data da exportação.

A exportação será feita por streaming para um arquivo temporário. O nome
definitivo somente será publicado por rename atômico depois da validação do
arquivo, da contagem e do checksum. A partição do banco somente será removida
após todas as validações. Em qualquer falha, ela permanece consultável e a
rotina pode ser repetida.

## Restauração pelo suporte

Um comando administrativo receberá o mês e um motivo obrigatório. Ele validará
manifesto e checksum, recriará a partição, importará o arquivo e a manterá
consultável durante sete dias.

Cada ação de restauração registrará operador, motivo, período, horário e
resultado. A rotina de arquivamento ignorará partições restauradas dentro do
prazo. Após sete dias, outra rotina removerá somente a partição restaurada; o
arquivo e seu manifesto permanecerão intactos.

## Migração legada

A migração será um comando administrativo separado do deploy, com `--dry-run`,
processamento em lotes, proteção contra execução concorrente e relatório final.
Ela considerará no máximo os últimos 60 dias, embora a limpeza atual possa ter
preservado somente cerca de 30 dias.

Um log será migrado somente quando:

1. sua origem for um endereço;
2. houver uma única movimentação de saída por pré-fatura compatível com o
   endereço e o intervalo curto entre os `created_at`;
3. a movimentação identificar inequivocamente usuário, produto e pré-fatura;
4. esses dados identificarem um único produto de uma única tarefa.

Registros ausentes ou ambíguos serão ignorados, nunca inferidos por aproximação
adicional. `reading_logs.created_at` será usado como `received_at`, e os demais
dados originais serão preservados.

O comando consultará `source_reading_log_id` antes de inserir e usará um lock
administrativo para permitir reexecução sem nova migração dos mesmos registros.
O relatório separará analisados, aptos, migrados, já migrados e ignorados por
motivo, incluindo amostras das ambiguidades. Os logs legados não serão excluídos
até a validação funcional e a conferência das contagens.

## Tratamento de erros

- Dados inválidos serão recusados antes da movimentação.
- Falha ao gravar qualquer leitura reverterá movimentação, item separado,
  embalagem e logs.
- A API orientará o usuário a tentar novamente sem expor detalhes do banco.
- A causa técnica será registrada no log do servidor.
- Falha de arquivamento nunca removerá a partição de origem.
- Falha de checksum impedirá a restauração.
- Ausência de uma partição gravável falhará de forma visível e reverterá a
  separação, exigindo correção operacional antes da nova tentativa.

## Testes

### Backend

- grava todos os tipos, formatos e resultados;
- aceita separação sem logs;
- associa tarefa, produto da tarefa/pré-fatura, usuário e endereço corretos;
- insere em lote na partição esperada;
- reverte toda a separação quando a auditoria falha;
- mantém os outros fluxos na tabela genérica;
- autoriza, isola, ordena e pagina a consulta por tarefa;
- usa o índice esperado com volume representativo;
- cria partições e trata a virada do mês;
- exporta, valida, repete e restaura arquivos sem perda;
- audita a restauração e remove sua partição após sete dias;
- executa a migração em `dry-run` sem escrita;
- migra somente relações determinísticas, ignora ambiguidades e não duplica
  em uma reexecução.

### Frontend

- abre o histórico correto a partir do dashboard;
- preserva a aba Pausas;
- apresenta tipos, formatos e resultados corretamente;
- cobre carregamento, vazio, erro, nova tentativa e paginação;
- exibe o aviso para registros anteriores a 12 meses;
- não permite consultar tarefa fora da visibilidade do usuário.

### Aplicativo

- continua enviando os logs somente com uma confirmação;
- mantém o payload atual compatível;
- descarta tentativas sem confirmação;
- propaga a falha do backend sem indicar sucesso local.

## Implantação e rollback

1. configurar, validar, incluir no backup e monitorar o diretório persistente;
2. publicar tabela, partições, índices, comandos e rotinas agendadas;
3. publicar a nova gravação no backend;
4. publicar a aba Leituras no dashboard;
5. executar e revisar o `dry-run` da migração;
6. migrar somente os registros considerados seguros;
7. acompanhar erros, tamanho das partições e espaço em disco.

Um rollback da aplicação não removerá a nova tabela, partições, logs ou
arquivos. O fluxo antigo poderá voltar a gravar na tabela genérica, mas os dados
já auditados continuarão preservados.

## Pontos operacionais antes da produção

- Definir o caminho absoluto do diretório de arquivo morto no servidor.
- Confirmar que o caminho faz parte do backup e do monitoramento de disco.
- Definir quem recebe os alertas de falha de partição ou arquivamento.
- Registrar o procedimento de restauração no runbook do suporte.
