Production rescue
Two existing apps for one client in appraisal tech: a FastAPI and React pipeline made stable, and a Next.js app hardened right after its production database was wiped.
- Engineer, hired to stabilize two existing apps
- March to September 2026
- FastAPI, React, TypeScript, Next.js, Prisma, PostgreSQL
The problem
One client in appraisal tech had two existing apps, and neither was stable. I was brought in to make them dependable rather than to build something new.
For the second app, the production database had been wiped a few days before I took it over. The core records had been re-imported from exports, but the data was uneven, some of it still needed rebuilding, and nothing stood between a stray command and the production database.
What I built
The first app was a FastAPI and React (Vite, TypeScript) appraisal pipeline the client had built. I was hired to fix its stability. The problems the engagement addressed are listed below.
The second was a Next.js, TypeScript, Prisma and PostgreSQL app on Vercel, built by the founder. I took it over right after its production database was accidentally wiped. Once the data was recovered, my work started: a guard in front of the production database, cleanup of the recovered data, and fixes for reliability bugs.
The hard parts
The FastAPI and React pipeline
A clean start for a two-process setup
The pipeline runs as two processes, and getting it to start cleanly was part of the work.
Restarts that created blank sessions
When the server restarted it created a blank session instead of loading the saved state. Making a restart pick up where the work left off was part of the engagement.
Finished phases that ran again
Pipeline phases that had already finished re-ran instead of loading their cached results. Fixing that was part of the engagement.
Errors that went unseen
Errors were silent and there were no error boundaries, so the app could not recover without a full restart. Making it able to recover was part of the engagement.
The Next.js app
Making the dangerous path hard to take
The wipe was consistent with a destructive database command run against the production connection. I wired a guard into the commands people actually type: it refuses to run them against a production host and points them at a local database instead.
Cleaning up data without a second incident
The recovered data carried free-text values that no longer matched the controlled set the app expected. I fixed it in two parts: a one-time migration for what was already there, and normalization at import so new data could not reintroduce the problem.
Bugs that looked like bad data
Two problems that looked like wrong data were caching. A public page only refreshed on a short cache window, and an admin view served a stale response. Admin schedule changes now trigger revalidation on demand, and the admin view reads uncached.
Rows that vanished from an export
A spreadsheet export built one row per person, so any entry without a person attached silently disappeared from the file. It had no test coverage, which is why nobody noticed. I moved those entries to their own worksheet and wrote regression tests around it.
A scheduler that blocked its own drops
In the drag-and-drop planner, the card being moved still counted as occupying its target slot, so valid drops were refused. The fix was to exclude the dragged card from the occupancy check.
Where it is now
The engagement ended in September 2026.