LeadFlow CRM Rescue and Improvement by Nikita DanilovLeadFlow CRM Rescue and Improvement by Nikita Danilov

LeadFlow CRM Rescue and Improvement

Nikita Danilov

Nikita Danilov

A "finished" AI-generated CRM. 12 problems the founder couldn't see.

LeadFlow is a typical vibe-coded app: looks done in a screenshot, falls apart in the first real session. Below is the full rescue - audit, triage, repair - exactly the process I run on client projects.
Data lost on every refresh, save confirmation is fake
OpenAI API key shipped to every visitor
Adding two leads quickly silently drops one
Export, Settings, Bulk Email buttons do nothing
1101-line single component
Data truly persists; storage layer is a 2-function seam for a real backend
No secrets in the client; deterministic fit scoring
Race-free state updates, validated forms, honest UI
CSV export actually exports
10 focused files, thin 100-line App shell

The 12 findings

Triaged the way I quote real rescues: blockers first (the client sees these), traps second (the client can't see these - that's what they pay for), debt last.
Blocker Fake persistence: all data in React state, "Synced to database" toast unconditional, POST to a dead URL swallowed by an empty catch.
Blocker Race conditions: every mutation wrapped in setTimeout over stale state - fast actions silently lose writes; duplicate ids break React keys.
Blocker Forms accept garbage: empty names, $NaN deal values that corrupt totals.
Trap OpenAI API key hardcoded in the client bundle - extractable by any visitor in devtools.
Trap .env with a Supabase service_role key committed to git, no .gitignore.
Trap Fake auth: any credentials log in, "admin123" hardcoded in the bundle, delete button hidden in UI only.
Trap Empty catch blocks and zero loading states - every failure is a silent frozen UI.
Trap README promises Supabase sync, RBAC, CSV export, mobile support - none exist.
Debt No viewport meta, fixed 1200px layout, 3-column grid with min-width cards: broken below 900px.
Debt Dead buttons: Export CSV, Bulk Email, Settings rendered with empty handlers.
Debt 1101-line single component: all state, both modals, data layer and styling in one file, plus two dead Button components.
Debt 343 KB bundle: moment + lodash + axios + uuid imported for one date format and two sums; console.log noise (including a partial API key) in production.

Measured, not claimed

Numbers from the build, not adjectives.
MetricBeforeAfter Data survives refreshNoYes Secrets in client bundle2 keys0 Bundle size (gzip)343 KB (114)155 KB (50) Runtime dependencies62 (react, react-dom) Largest component1101 lines~150 lines Buttons that do nothing30 Usable at 380pxNoYes

The method

Same four phases on every rescue - because the visible bug is never the only bug.

Have an app that's "90% done" for three months?

This rescue took ~5 hours end to end. The first step is always a fixed-price audit - you get this exact report for your codebase, whether or not we continue.
Full audit: AUDIT.md · Decisions: DECISIONS.md · Commit history tells the story, one fix per commit · Nikita, frontend developer - GitHub @niki-deone
Like this project

Posted Aug 2, 2026

An AI-generated app that demoed well and broke on real data. Audited it, moved credentials out of the browser, shipped it working and documented.