Ir para o conteúdo
← Projetos Projeto Profissional

Inventário Sentric

Sistema interno de asset tracking para o parque de câmeras da Sentric, empresa de monitoramento. Substitui caderno físico por trilha de auditoria append-only, identidade própria do ativo e PWA com scanner DataMatrix para operação em campo. Monorepo NestJS + Next.js com domínio puro e testes property-based. Em desenvolvimento.

01

Contexto

A Sentric opera um parque de ~150 câmeras de monitoramento distribuídas entre clientes. O controle era feito em caderno físico — sem rastreabilidade, sem trilha de auditoria, sem forma de saber em tempo real onde cada câmera estava. O resultado: câmeras perdidas, patrimônio pausado e logística reativa que custava tempo e dinheiro. O sistema resolve isso com identidade própria por câmera (código DataMatrix único, impresso em etiqueta física), trilha de auditoria append-only e PWA para que técnicos em campo deem entrada e saída de equipamentos com o celular — sem app nativo.

02

Papel & Equipe

Papel Desenvolvedor Full-stack (solo)
Duração em desenvolvimento
Equipe Individual
03

Opções consideradas

Updates destrutivos no banco de dados Rejeitado

Simples de implementar, mas destrói o histórico — impossível auditar movimentações passadas

Trilha append-only com eventos imutáveis Escolhido

Cada movimentação é um evento permanente; o estado atual é projetado a partir da sequência histórica — auditoria completa sem custo adicional

Identidade do ativo atrelada ao cliente Rejeitado

Modelagem comum, mas quebra quando a câmera muda de cliente — o ativo perderia seu histórico

Identidade própria do ativo (desacoplada do cliente) Escolhido

A câmera tem uma identidade única permanente; vínculos com clientes são relacionamentos separados — histórico preservado em qualquer movimentação

App nativo (React Native) Rejeitado

UX mais fluida, mas exige distribuição via app store e build separado — atrito desnecessário para ~3 técnicos internos

PWA instalável Escolhido

Zero instalação de app store, funciona offline com service worker, suporte a scanner via câmera do celular — deploy imediato

04

Solução

Arquitetura

Monorepo pnpm — apps/api (NestJS 10) + apps/web (Next.js 15 + PWA). packages/domain é PURO (zero I/O): state machine da câmera, invariantes e commands. PostgreSQL 16 + Drizzle ORM para persistência append-only.

Destaques técnicos

  • Geração de DataMatrix via bwip-js e leitura via @undecaf/zbar-wasm no PWA do técnico
  • Trilha de auditoria append-only — cada evento é imutável, estado atual projetado por fold sobre o histórico
  • packages/domain sem I/O: testável com property-based tests (fast-check) sem nenhum mock
  • OpenTelemetry exportando para obs.timelapseobras.com.br — observabilidade de série
  • Check digit Luhn no código do ativo — detecção de erro de digitação no campo

API / Backend: NestJS 10 (REST) — Node 22 · PostgreSQL 16 · Drizzle ORM

05

Resultados

Métrica Valor
Parque-alvo rastreado ~150 câmeras / 3 operadores
Audit trail Append-only — zero destruição de dados
Deploy para técnicos em campo PWA — zero instalação via app store
Domain layer testável 100% sem I/O — property-based com fast-check
Status Em desenvolvimento (F0 — monorepo)
06

Aprendizados

O problema que o caderno físico não conseguia resolver

Na Sentric, quando uma câmera saía para instalação, o técnico anotava em um caderno. Quando voltava, outra anotação. Quando ia para manutenção, mais uma anotação — se lembrava. O resultado era previsível: câmeras sem paradeiro conhecido, técnicos ligando uns para os outros para saber “onde está a câmera X”, patrimônio parado porque ninguém sabia se o equipamento estava disponível ou em campo.

O problema fundamental não era falta de disciplina — era a ausência de um sistema que tornasse o registro da movimentação inevitável e instantâneo.

A decisão de design mais importante: append-only

A maioria dos sistemas de inventário funciona com um registro central que é atualizado destrutivamente: “câmera X agora está no cliente Y”. Isso resolve a consulta atual, mas destrói o histórico. Se a câmera sumiu, você não tem como saber quem a pegou por último.

O Inventário Sentric funciona de forma diferente: cada movimentação é um evento imutável. Quando a câmera sai para instalação, cria-se um evento SAIDA_CAMPO. Quando volta, um evento RETORNO_BASE. O estado atual da câmera é calculado a partir da sequência de eventos — não armazenado diretamente. Isso significa trilha de auditoria completa sem nenhum esforço adicional: ela é uma consequência estrutural do design, não uma feature separada.

DataMatrix em campo

A etiqueta física é o que ancora a identidade digital ao objeto físico. Optamos por DataMatrix em vez de QR Code por três razões:

  1. Densidade: armazena mais dados no mesmo espaço físico
  2. Robustez: leitura confiável mesmo com até 30% da etiqueta danificada
  3. Leitura oblíqua: funciona em ângulos que fariam um QR Code falhar

O código impresso na etiqueta inclui check digit Luhn — o mesmo algoritmo de cartões de crédito — para detectar erro de digitação antes de chegar ao banco.

packages/domain — o coração sem batimento

A decisão de isolar completamente o domínio em um package sem nenhuma dependência de I/O tem um efeito prático imediato: a state machine da câmera pode ser testada com fast-check gerando milhares de sequências de eventos aleatórias, verificando invariantes como “uma câmera nunca pode estar em dois lugares ao mesmo tempo” ou “não é possível dar baixa em uma câmera que não está na base”.

Esses testes não precisam de banco, não precisam de mock, não precisam de servidor. São funções puras — e fast-check encontra edge cases que nenhum teste escrito à mão encontraria.