Desafio 11: KYC System — Onboarding Digital à Prova de Fraude
🇧🇷 Sistema de Verificação de Identidade
🇬🇧 Know Your Customer System
KYC (Know Your Customer) é o processo regulatório obrigatório para toda instituição financeira no Brasil. Regulamentado pelo BACEN (Resolução 4.753/2019) e pela Lei 9.613/1998 (Lavagem de Dinheiro), o KYC é a primeira linha de defesa contra fraudes, lavagem de dinheiro e financiamento ao terrorismo.
Switch: React (Vite) vs Next.js
Por que React (Vite) para KYC?
| Vantagem | Descrição |
|---|---|
| SPA nativo | Fluxo contínuo sem reloads |
| MediaDevices | Acesso direto à câmera |
| ML client-side | TensorFlow.js para edge detection |
| Bundle pequeno | Carrega rápido em mobile |
| Hot Reload | DX excelente |
Arquitetura
UseCamera Hook
typescript
export function useCamera(options: UseCameraOptions = {}): UseCameraReturn {
const { facingMode = 'environment', resolution = { width: 1920, height: 1080 } } = options;
const videoRef = useRef<HTMLVideoElement>(null);
const streamRef = useRef<MediaStream | null>(null);
const [isStreaming, setIsStreaming] = useState(false);
const startCamera = useCallback(async () => {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode, width: { ideal: resolution.width }, height: { ideal: resolution.height } },
audio: false,
});
streamRef.current = stream;
if (videoRef.current) {
videoRef.current.srcObject = stream;
await videoRef.current.play();
setIsStreaming(true);
}
}, [facingMode]);
const captureImage = useCallback((): string | null => {
if (!videoRef.current || !canvasRef.current) return null;
const canvas = canvasRef.current;
canvas.width = videoRef.current.videoWidth;
canvas.height = videoRef.current.videoHeight;
canvas.getContext('2d')!.drawImage(videoRef.current, 0, 0);
return canvas.toDataURL('image/jpeg', 0.92);
}, []);
const stopCamera = useCallback(() => {
streamRef.current?.getTracks().forEach(t => t.stop());
setIsStreaming(false);
}, []);
useEffect(() => () => stopCamera(), [stopCamera]);
return { videoRef, canvasRef, isStreaming, startCamera, stopCamera, captureImage };
}Zustand Store
typescript
export const useKYCStore = create<KYCStore>()(
persist(
(set) => ({
session: null,
initializeSession: (sessionId) => set({ session: { sessionId, currentStep: 'PERSONAL_DATA', status: 'PENDING' } }),
setCurrentStep: (step) => set((s) => ({ session: s.session ? { ...s.session, currentStep: step } : null })),
setDocument: (data) => set((s) => ({ session: s.session ? { ...s.session, document: data } : null })),
setLiveness: (data) => set((s) => ({ session: s.session ? { ...s.session, liveness: data } : null })),
reset: () => set({ session: null }),
}),
{ name: 'kyc-session', storage: createJSONStorage(() => sessionStorage) }
)
);Comparação: React (Vite) vs Next.js
| Aspecto | React (Vite) | Next.js |
|---|---|---|
| Fluxo SPA | Nativo, sem reloads | Hydration overhead |
| Camera/MediaDevices | Acesso direto | Mais complexo |
| ML client-side | TensorFlow.js fácil | Server Components limitam |
| Bundle | ~150KB gzipped | ~300KB+ |
| SEO | Não precisa (KYC) | SSR útil para landing |
| API Routes | Backend separado | Integrado |
Casos Reais
- Nubank (React Native + React) — 80M+ clientes, onboarding < 5min
- C6 Bank (React) — 20M+ clientes, OCR próprio
- Stone (React) — 5M+ merchants, KYC empresarial
Como testar
bash
# React (Vite)
cd packages/frontend/kyc-web
pnpm dev
# Next.js
cd packages/frontend/kyc-portal
pnpm devLições aprendidas
- KYC = porta de entrada — Onboarding rápido (5min) converte 3x mais
- Active liveness é obrigatório — Selfie estática é vulnerável
- Edge detection client-side — Reduz retakes drasticamente
- Logs imutáveis — 5+ anos (BACEN)
- Acessibilidade — Upload como fallback para câmera
- React (Vite) — Melhor para KYC isolado, performance máxima
- Next.js — Melhor para portal unificado (landing + KYC + dashboard)
- CPF validation — Sempre client-side E server-side
- OCR preciso — P95 < 3s, accuracy > 98%
- Face match — > 95% para aprovação automática