Auditing Backend Production Readiness
Auditing Backend Production Readiness
Most apps work fine with one developer and zero users. They break on real traffic because of invisible gaps: missing indexes, no transactions, unhandled race conditions, no backups, wide-open CORS. This skill turns a 62-item backend checklist into a systematic audit, prioritized by what breaks first.
Don't audit all 62 items one by one. Start broad, then drill into what matters:
Which of these 62 backend items is my app missing, and which one will hurt first?
Paste the full checklist (see Reference below) alongside the app's codebase. Claude will triage: flag missing items, then rank by blast radius (data loss > security hole > outage > slowness > annoyance).
Progress:
- Step 1: Run the triage prompt to get a prioritized gap list
- Step 2: Group gaps into the 4 categories (Database, Scaling, Failure Handling, Security)
- Step 3: Fix data-loss and security risks first, regardless of category
- Step 4: Work through remaining gaps category by category
- Step 5: Re-run the triage prompt after fixes to confirm closure
- Step 6: Add a recurring check (e.g. before every major release)
Step 1: Triage
Use the master prompt above. If the codebase is large, scope it:
Audit just the /api and /db folders against this checklist. Which items are missing?
Step 2: Categorize
The 62 items fall into four buckets — use them to decide fix order, not reading order:
- Database (1–17) — indexes, N+1, pooling, migrations, backups, transactions, race conditions, locking, constraints, soft deletes, pagination, timezones, caching
- Scaling under users (18–33) — load testing, cold starts, timeouts, retries, idempotency, queues, background jobs, dead letter queues, cron, webhooks, debouncing, autoscaling, CDN, image optimization, bundle size
- Failure handling (34–47) — error tracking, structured logs, uptime monitoring, alerts, health checks, error boundaries, friendly error pages, status pages, rollbacks, feature flags, kill switches, circuit breakers, fallbacks, postmortems
- Security (48–62) — input validation, SQL injection, XSS, CSRF, CORS, SSRF, password hashing, session expiry, token rotation, OAuth scopes, 2FA, webhook signatures, upload limits, dependency updates, (+ remaining security items)
Step 3: Fix in risk order, not list order
Within any category, prioritize:
- Things that lose or corrupt data (no backups, no transactions, race conditions)
- Things that let in attackers (SQL injection, XSS, CSRF, SSRF, plaintext passwords)
- Things that cause full outages (no timeouts, no circuit breakers, no rollback plan)
- Things that degrade under load (N+1 queries, no pagination, no caching)
- Things that are just unpolished (friendly error pages, status page)
Step 4: Use one targeted prompt per item
Each checklist item has a matching fix prompt (see Reference). Don't batch too many fixes in one request — one item per prompt gives Claude a tight, checkable scope.
Example 1:
Input: "Check my app for N+1 queries"
Output: Claude scans query call sites, flags loops that issue one query per iteration (e.g. fetching comments inside a post loop), and rewrites them using eager loading / batched WHERE id IN (...) queries, with a before/after query count.
Example 2: Input: "Which of these 62 is my app missing, and which one will hurt first?" Output: A ranked list like:
MISSING & URGENT:
1. No backups (data loss risk — fix today)
2. Passwords stored with plain MD5, not bcrypt/argon2 (security — fix today)
3. No idempotency on payment endpoint (double-charge risk)
MISSING & IMPORTANT:
4. No connection pooling (will fail under concurrent load)
5. No pagination on /users list (will slow down as table grows)
MISSING & LOW RISK FOR NOW:
6. No status page
7. No feature flags
Example 3:
Input: "Make my webhook handlers safe when the same event arrives twice"
Output: Claude adds an events_processed table keyed on the webhook's event ID, checks it before processing, and inserts after success — so retried webhooks are no-ops instead of duplicate charges/emails.
- Triage before fixing. Never start at item #1 and work forward — some apps have #1 fine and #47 on fire.
- One prompt, one concern. "Fix idempotency" and "add row locking" are different fixes even though both prevent race-like bugs — keep them separate so Claude's changes are reviewable.
- Security and data-loss items jump the queue regardless of which numbered category they're in.
- Re-run the triage prompt after each fix round. Fixing one item (e.g. adding a queue) can surface a new one (e.g. now you need a dead letter queue).
- Turn this into a pre-launch ritual, not a one-time audit — re-run before every major release or when traffic is about to spike (launch, press mention, etc.).
- Ask "what happens when this is down?" for every external dependency — that single question surfaces timeouts, retries, circuit breakers, and fallbacks all at once.
- Treating all 62 items as equal priority. A missing CDN is not as urgent as plaintext passwords or no backups.
- Fixing in list order instead of risk order. The list is organized by theme, not severity.
- Adding retries without idempotency. Retrying a non-idempotent action (like charging a card) multiplies the bug instead of fixing it.
- Adding caching without invalidation. A cache that's never cleared is just a bug that serves stale data confidently.
- Declaring victory after one audit pass. New features reintroduce old gaps (a new endpoint without pagination, a new webhook without signature verification).
- Skipping the "test the restore" step. A backup nobody has restored from is unverified and should be assumed broken.
Keep the full 62-item prompt list in a separate reference file if pasted into context repeatedly — group into database-prompts.md, scaling-prompts.md, failure-handling-prompts.md, security-prompts.md so only the relevant category needs to be loaded per audit session.