Skip to the content
Agent Tools

Backend readiness checklist

An app built fast with AI can look finished while its backend is not. These are 16 things to have in place before real users arrive. Site Check reads 5 of them from outside; the rest you check yourself, and each one says how.

To run the outside part, use the leak check on the Site Check paste page, or ask your agent to call exposure_check through the Site Check MCP server. It works only on a site you own: the first call asks you to publish a short token. Each answer is labeled confirmed, needs verification, not checked or looks handled, and the items it cannot see come back as a list of your own checks, never as a pass or fail.

The 16 items

  1. Validate all input. Checked by Site Check from outside.
    Site Check reads: One request with a broken query to the page you name, plus the not-found page: an answer of 500 is reported.
  2. Hashed passwords. You check it.
    A leaked table of plain or fast-hashed passwords unlocks your users' other accounts too.
    How to check: Look at one row of your users table: the password column must hold an argon2id or bcrypt hash, which names its algorithm at the start, never readable text or a bare MD5 or SHA-256 value.
  3. Secrets outside the repo. You check it.
    A key in git history stays readable after you delete the file.
    How to check: Run a secret scanner such as gitleaks or trufflehog over the whole git history, and keep keys in your host's secret store; rotate anything it finds.
  4. Server-side auth on every route. You check it.
    Hiding a button in the browser does not stop anyone calling the API directly.
    How to check: Sign out, then call one of your private API routes with curl and no cookie or token; it must answer 401 or 403, not data.
  5. Rate limit on login and reset. Checked by Site Check from outside.
    Site Check reads: One plain GET of the sign-in or reset page your page links to, looking for 429 or rate-limit headers. It never tries to sign in.
  6. Timeouts on external calls. You check it.
    One slow payment, email or AI provider can hold every request open and take your app down.
    How to check: Search the code for each fetch or SDK call to another service and confirm it sets a timeout of a few seconds and handles the error.
  7. Idempotent payments. You check it.
    A retried request or a double click must not charge a customer twice.
    How to check: Send each charge with an idempotency key (Stripe Idempotency-Key), and replay one webhook event twice in test mode: the order must change once.
  8. Transactions for multi-step writes. You check it.
    A crash between two writes leaves half an order or a balance that does not add up.
    How to check: Find each handler that writes to more than one table and confirm the writes run inside one database transaction or batch.
  9. Indexes on the columns you query. You check it.
    A query that is fast on 100 rows times out on 100,000.
    How to check: Run EXPLAIN on your most used queries and add an index for any full table scan on a column you filter or join on.
  10. Versioned migrations. You check it.
    Schema changes made by hand cannot be repeated or rolled back safely.
    How to check: Every schema change should be a numbered migration file in the repo, applied by a tool such as Prisma, Drizzle or wrangler d1 migrations.
  11. Logs with a request id and no tokens. Partly checked by Site Check.
    A request id ties a user's report to the log line; tokens in logs are leaks waiting to happen. Only public error pages were read here.
    Site Check reads: The error pages it already fetched are read for stack traces, tokens and keys. Whether your logs carry a request id is yours to check.
    How to check: Read one log line of a real request: it should carry a request id, and no password, cookie, Authorization header or API key.
  12. Health check that verifies the database. Checked by Site Check from outside.
    Site Check reads: GET /health, /healthz and /api/health: whether one answers, and whether the answer names a database.
  13. Backups with a tested restore. You check it.
    A backup you have never restored is a guess, not a backup.
    How to check: Restore last night's backup into a fresh database once a quarter, open the app against it and write down how long it took.
  14. CORS locked down. Checked by Site Check from outside.
    Site Check reads: One GET of your page with a made-up Origin header: an echoed origin or a wildcard is reported.
  15. 429 not 500 when saturated. You check it.
    Under load the app should turn requests away politely, not crash; this check never loads your site.
    How to check: On a staging copy, send more requests than your limit with a load tool such as k6 or oha and confirm the extra ones get 429 with Retry-After, not 500.
  16. One user cannot read another user's data. You check it.
    Changing an id in the address is the most common way apps leak other people's data.
    How to check: Sign in as test user A, request an object that belongs to test user B by its id, and expect 403 or 404.

Where this list comes from

The list of item names follows a post on X by @precisox about what a vibe-coded backend often skips. The explanations and the ways to check each item are our own.

Frequently asked questions

Does Site Check test my login or load my server?

No. It sends plain GET requests to a host you proved you own, at most 32 in one run. It never tries to sign in, never sends a password and never runs a load test, so the items that need those are on your own list.

Why are most items marked as yours to check?

Password hashing, transactions, indexes, migrations, backups and access between users live inside your code and your database. No outside request can see them, so Site Check gives you the way to check each one instead of a guess.