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, em múltiplos locais e turnos. A exigência era dupla: uma prova de presença que resistisse a uma disputa trabalhista (digital falha com trabalho manual, crachá pode ser emprestado, papel não resiste) e geolocalização confiável para quem trabalha fora da planta, não só dentro dela. O sistema confirma, na mesma batida, que a pessoa está fisicamente no local certo e que é ela mesma, 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
Entendendo a necessidade do cliente
O trabalho começou a partir de um relato simples: funcionários externos saem todo dia com recursos da empresa, veículos, combustível, ferramentas, e não havia como saber se estavam de fato em jornada. Sem um registro de presença vinculado a localização, o controle ficava dependente de declaração, e a empresa não conseguia provar, em uma disputa, onde o colaborador estava no horário da batida. Foi a partir daí que desenhamos o MVP: geolocalização mais reconhecimento facial, sem crachá, senha ou digital, para garantir que a pessoa certa está no lugar certo.
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ágio | Modelo | Tamanho | O que faz |
|---|---|---|---|
| 1 | TinyFaceDetector | ~190 KB | Detecta o rosto e define a bounding box, com score de confiança |
| 2 | FaceLandmark68Net | ~350 KB | Marca 68 pontos anatômicos e alinha o rosto |
| 3 | FaceRecognitionNet | ~6,2 MB | Converte o rosto alinhado num vetor de 128 números (embedding) |
Custo: cenário de referência (~20 colaboradores, ~80 batidas/dia)
| Serviço | Cobrança | Custo mensal |
|---|---|---|
| AWS Rekognition CompareFaces | US$ 1,00 / 1.000 chamadas | ~R$ 132/mês |
| Azure Face API | US$ 1,00 / 1.000 chamadas | ~R$ 132/mês |
| Google Cloud Vision | US$ 1,50 / 1.000 chamadas | ~R$ 198/mês |
| face-api local (este projeto) | sem chamadas de API | 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. Antes de aceitar a captura, o sistema pede uma ação aleatória (sorrir, abrir a boca, virar o rosto) e só segue adiante se a mudança entre o quadro neutro e o quadro do desafio bater com o que foi pedido, uma foto estática não reage sob comando. 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), com a justificativa detalhada na seção seguinte. Código em src/lib/face-match-live.ts e src/lib/liveness-challenge.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. A captura ao vivo passa por um desafio de vivacidade (sorrir, abrir a boca ou virar o rosto, escolhido ao acaso) antes de ser aceita, uma foto estática não reage sob comando. Nenhuma imagem é enviada a um servidor. Isso baixa ~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.
EER: threshold=0.680 far=0.014 frr=0.012
Limiar recomendado (FAR <= 2%): threshold=0.655 far=0.020 frr=0.004Raio 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 mCorreçã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.
Segunda correção: ataque de apresentação
Um segundo teste real expôs outra lacuna: segurar uma foto estática em frente à câmera também era aprovada como "mesma pessoa", o FaceMatch confirma quem está na imagem, mas nunca verificava se a captura vinha de uma pessoa viva. É uma vulnerabilidade conhecida em biometria facial (ataque de apresentação). A contramedida foi um desafio de movimento aleatório: sorrir, abrir a boca ou virar o rosto, escolhido na hora, comparando um quadro neutro com um quadro depois do desafio, uma foto ou um vídeo em loop não reage sob comando aleatório. Não é infalível (um vídeo preparado com todas as reações poderia, em teoria, ser sincronizado), mas eleva o custo do ataque bem além de "segurar uma foto", que é o vetor mais barato e mais comum.
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
Prova de vivacidade
Antes de aceitar a captura, um desafio de movimento aleatório (sorrir, abrir a boca, virar o rosto) confirma que é uma pessoa real ao vivo, contramedida a foto ou vídeo estático, adicionada depois de um teste real expor essa brecha.
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, dificultando um funcionário bater ponto de um aparelho que não é o seu.
Arquitetura
Da selfie ao registro auditado
Tecnologias
- React
- TanStack Start
- Supabase
- PostgreSQL
- Row Level Security
- face-api.js
- Python
Próximo projeto
PitaIA
Inteligência pessoal de saúde com IA