The same story, two registers.
Two separate layers: a public site for reporting, with a three-step verification, plus an internal application where investigators manage the cases, correlate offenders across cases and prepare the material for a referral to the authorities. Every action leaves a trace, every access passes through two-factor authentication, sensitive content never exists in clear on disk.
Public site as a Next.js 14 static export; internal application on Next.js 14 + NestJS 11 + PostgreSQL 16 (pg_trgm for fuzzy name matching). Argon2id on passwords, AES-256-GCM on the sensitive fields (IP, TOTP secrets), TOTP 2FA with progressive lockout. Evidence images pass through PDQ-WASM (an open-source perceptual hash) and optionally PhotoDNA, isolated on separate paths (quarantine / clean / flagged) with strict permissions, never stored in clear. SSE for live notifications, BullMQ for asynchronous jobs, an append-only audit log indexed by user and IP.
The same facts, two readings. The CEO reads the top register and knows what was delivered. The CTO reads the bottom one and knows how. No one is forced to translate in their head.

