I tracked down a multi-sport fantasy app I remembered building but couldn't find anywhere, proved it had only ever existed as a chat artifact, then adopted and deployed it end-to-end to production-grade standards. That caught a self-inflicted infrastructure bug along the way.
The challenge
I remembered building a multi-sport dynasty fantasy app, but it was nowhere to be found. That kicked off a genuine lost-artifact hunt. An exhaustive search of every development directory, home and archived folders, and my full app registry (including decommissioned apps) turned up zero trace.
The resolution was non-obvious: the app had been built entirely as a chat artifact and was never saved to disk or deployed anywhere. I recovered it by downloading the chat's export. So "what broke" wasn't an outage. It was a prototype that had never been persisted or productionized: no repo, no CI, no real database schema, no monitoring, demo-only data. A single-page app, mostly in one file, talking directly to a self-hosted backend over REST, with hardcoded players and a handful of TODO markers where mock functions stood in for future DB calls.
Approach
My guiding principle was "ship the infrastructure first, wire the data later."
- Infra-complete in demo mode, data deferred. I deployed the full feature surface behind a demo-mode flag to prove out ports, CI, schema, row-level security, and monitoring, then scoped the real database wiring as a separate effort. This de-risks the deploy and keeps scope honest.
- Schema-per-app discipline. The recovered artifact's SQL targeted the shared
public schema. Because every app gets its own dedicated schema, I rewrote it to a dedicated app schema before any database work touched the box. - Least privilege from day one. I granted only to authenticated and service roles; the anonymous role got zero table grants, and the destructive trade-execution function had its anonymous execute permission revoked.
Results
- Deployed to the development server in demo mode, full deploy-checklist completion, reachable only over a private mesh VPN, monitored and green since deploy.
- Database schema live with row-level security on every table; anonymous table grants verified to be zero via a live permission-denied probe.
- CI/CD proven end-to-end: a real push auto-built and restarted the app, verified serving HTTP 200.
- Full feature surface renders and is clickable: dashboard, per-sport schedule, roster, free agents, cross-sport trade center, standings, and commissioner panel.
- Honestly scoped. The app is infra-complete but the product is not functionally complete: persistence, the mock-to-database replacements, and stats ingestion are deliberately deferred to a tracked ticket, not hand-waved as done.
One moment was worth the trip:
The docker-compose restart trap. After editing the database schema list in the environment file, a full docker-compose restart did not pick up the change: a probe still returned the old schema list. Root cause: restart reuses existing containers with their baked-in environment and never re-reads the env file. The fix was to recreate just the affected container, after which the anonymous probe correctly returned permission-denied. I corrected the misleading checklist step and logged a standing rule: compose environment changes require a container recreate, not a restart.
What this demonstrates
- Absence from your source-of-truth registry doesn't mean it was never built: chat-built prototypes can live entirely outside your systems; check exports before concluding something is lost.
- Careful execution surfaces infrastructure bugs you'd otherwise ship past: trusting-but-verifying my own checklist is exactly what caught the restart-vs-recreate trap.
- Least privilege by default, verified live: I confirmed the anonymous role was locked out with a real permission-denied probe rather than trusting the grant statements.
- Ship infra-complete in demo mode, defer data wiring as a tracked ticket: de-risking the deploy while keeping scope honest with documented gaps.