← todos os projetos
/03Data Engineering · Applied AI

Ponto Inteligente

Gestão de jornada com geolocalização e visão computacional

Problema

Construído para uma indústria de alimentos com vendedores e trabalhadores externos, atuando em múltiplos locais e turnos. Prova de presença por digital falha com trabalho manual, crachá pode ser emprestado, e papel não resiste a uma disputa trabalhista. O sistema confirma, na mesma batida, que a pessoa está fisicamente no local certo e que é ela mesma — com cada tentativa, aprovada ou não, registrada e armazenada de forma segura.

Stack

  • React
  • TanStack Start
  • Supabase
  • PostgreSQL
  • Row Level Security
  • face-api.js
  • Python

Planejamento de produto

Da descoberta em chão de fábrica ao MVP

O trabalho começou antes de qualquer linha de código, acompanhando um turno completo numa planta para entender onde o processo de ponto até então falhava — digitais desgastadas por trabalho manual, filas na catraca no início do turno, e colegas batendo ponto uns pelos outros.

Escopo do MVP

Geofencing + reconhecimento facial (não NFC ou digital) foi decisão direta da descoberta: digital tem alta rejeição em mãos de trabalho manual, e um crachá pode ser emprestado.

Onboarding com consentimento

Cadastro pelo admin → magic link → troca de senha (bloqueante) → aceite explícito do termo de geolocalização (bloqueante, sem ele o app não libera) → vínculo do dispositivo ao usuário.

Alinhamento jurídico

O formato do dossiê de auditoria foi desenhado com o time jurídico do cliente, pensando em como esse histórico serviria de evidência numa disputa trabalhista.

Rollout faseado

Implantado numa planta-piloto por 30 dias, com coleta ativa de feedback dos supervisores sobre falsos negativos, antes de expandir para as demais plantas.

Visão computacional

Reconhecimento facial embarcado, em 3 estágios

Todo o pipeline roda no navegador do funcionário — nenhuma imagem biométrica sai do dispositivo até a decisão já estar tomada.

EstágioModeloTamanho
1TinyFaceDetector~190 KB
2FaceLandmark68Net~350 KB
3FaceRecognitionNet~6,2 MB

Custo — cenário de referência (~20 colaboradores, ~80 batidas/dia)

ServiçoCusto mensal
AWS Rekognition CompareFaces~R$ 132/mês
Azure Face API~R$ 132/mês
Google Cloud Vision~R$ 198/mês
face-api local (este projeto)R$ 0,00/mês

Demo

Experimente o pipeline acima, ao vivo

Envie uma foto de referência e tire outra pela câmera — os mesmos 3 modelos da tabela acima rodam de verdade no seu navegador. O limiar de decisão usado aqui não é o número simulado da seção de validação estatística abaixo — é o padrão real de mercado para este modelo (distância euclidiana ≤ 0.6). Explico o porquê logo ali embaixo. Código em src/lib/face-match-live.ts.

Demo ao vivo

Reconhecimento facial rodando no seu navegador, agora

Envie uma foto de referência e tire outra pela câmera — o mesmo pipeline de 3 estágios (detecção → landmarks → descritor) documentado no showcase roda aqui de verdade, 100% no seu navegador. Nenhuma imagem é enviada a um servidor. Isso baixa ~6,7 MB de modelos na primeira vez.

Validação estatística

Como os limiares de decisão foram calibrados

A parte mais fácil de fazer errado num sistema biométrico é escolher um número redondo para o limiar de decisão sem justificar por quê. Os dois limiares centrais deste projeto foram calibrados com metodologia estatística, sobre dados simulados (nenhum dado biométrico ou de localização real de funcionário é usado).

FaceMatch: FAR, FRR e Equal Error Rate

Para cada limiar candidato: FAR (fração de impostores aprovados) e FRR (fração de genuínos reprovados). O EER é onde as duas se cruzam — métrica padrão de sistemas biométricos.

Geofence: percentil empírico de erro de GPS

Mesma técnica usada para SLOs de latência em SRE, aplicada a erro de posicionamento: o raio recomendado é um percentil da distribuição de distâncias observadas, não uma regra de desvio-padrão.

saída real de threshold_calibration.py
EER: threshold=0.680 far=0.014 frr=0.012
Limiar recomendado (FAR <= 2%): threshold=0.655 far=0.020 frr=0.004
saída real de geofence_calibration.py
Raio para aceitar 50% das leituras legítimas: 28.8 m
Raio para aceitar 90% das leituras legítimas: 55.8 m
Raio para aceitar 95% das leituras legítimas: 61.3 m
Raio para aceitar 99% das leituras legítimas: 74.3 m

Correção registrada em produção

A calibração acima roda sobre uma distribuição simulada, criada só para ensinar o método FAR/FRR/EER de forma abstrata — nunca foi uma medição real do @vladmandic/face-api. A demo ao vivo inicialmente reaproveitou o número que saiu dali (0.65), e isso causou falsos negativos reais: a mesma pessoa sendo reprovada com similaridade ~0.50. O limiar em produção foi corrigido para 0.4 (distância euclidiana ≤ 0.6), a referência real adotada pela comunidade dlib/face-api.js para descritores de 128 dimensões — bem mais permissiva que a calibração simulada. Para contexto de mercado: sistemas bancários miram FAR de 0,001%–0,1% com modelos proprietários multi-modais (infravermelho, prova de vida); um descritor de 128 números rodando no navegador é classe controle-de-acesso/ponto, não classe bancária — e isso é documentado aqui, não escondido.

Biometria

Checagem de qualidade e segurança em camadas

Checagem de qualidade

Rejeitado antes de extrair o descritor, com mensagem específica:

  • Nenhum rosto detectado
  • Mais de um rosto no quadro
  • Confiança de detecção baixa
  • Rosto pequeno demais no enquadramento

Otimização de UX

Os modelos e shaders WebGL são pré-aquecidos antes da primeira captura, reduzindo a latência percebida no momento da batida de ponto.

Segurança em camadas

Defesa em profundidade, não só uma checagem:

  • RLS com função SECURITY DEFINER anti-recursão
  • Middleware server-side validando JWT em toda escrita administrativa
  • Checagem de papel repetida na aplicação

Vínculo de dispositivo

Um fingerprint do dispositivo é salvo e associado ao usuário no onboarding — dificulta um funcionário bater ponto de um aparelho que não é o seu.

Arquitetura

Da selfie ao registro auditado

Selfie + GPS (com checagem de precisão)
Detecção + checagem de qualidade
face-api.js (descritor, client-side)
Validação de geofence
Supabase (RLS)
Registro auditado
Os dois limiares (raio e similaridade) vêm de calibração estatística, não de um valor arbitrário — e ficam numa tabela de configuração, ajustáveis sem novo deploy.

Tecnologias

  • React
  • TanStack Start
  • Supabase
  • PostgreSQL
  • Row Level Security
  • face-api.js
  • Python