Going live, and the checklist to run first
This is the last lesson of the course, and it is a checklist — because going live is the one moment where a list beats judgement. You will be tired, slightly nervous, and certain you have remembered everything.
Run it anyway.
Before you open the doors
Security
- No secrets in the repository.
git log -p | grep -i secretacross the whole history, not just the working tree. If one was ever committed, it is compromised — rotate it. Deleting the commit does not help: it is in every clone and every reflog. - Every secret is 32+ characters and generated, not typed.
openssl rand -base64 32. -
CORS_ORIGINis your real domain, not*and not localhost. - The session cookie is
httpOnly,secureandsameSite: lax— andsecureis on, which it is only whenNODE_ENV=production. - HTTPS everywhere, with HTTP redirecting to it. Every platform in this module does it for free; the only work is checking.
- The admin account has a real password.
shop@example.comwithkirana-dev-adminexists in the seed, and the seed must never have been run here. - Rate limiting on login and checkout.
@nestjs/throttleris an afternoon. Without it, a password can be guessed at a thousand attempts a minute. - The payment webhook secret is the live one, and the gateway is in live mode.
Data
-
Automated backups are on, with point-in-time recovery.
-
You have restored one, into a scratch database, and looked at the data. Until you have, you have a belief rather than a backup.
-
migrate deployhas run, andmigrate devhas not. -
The seed has not run against production — and cannot:
```ts if (process.env.NODE_ENV === "production") { throw new Error("Refusing to seed: this deletes data and NODE_ENV is production."); } ``` -
Real products are loaded, with real prices and real stock counts.
-
Delivery slots exist for the days you intend to deliver.
The application
-
Every test is green, including the browser ones.
-
The API refuses to start with a bad configuration. Try it once against staging. It should name the variable.
-
/api/health/readyreturns 200, and returns 503 with the database stopped. -
A missing product returns 404, not 200. The soft 404 from decision 0012 renders a perfect page with the wrong status, and Google indexes it:
```text curl -s -o /dev/null -w "%{http_code}\n" https://kirana.example/products/nope ``` -
The admin area 404s for a signed-in customer.
-
A test order goes all the way through on the live site, with a real card in the gateway's live mode, and is then refunded. This is the one step people skip and the one that finds the broken thing.
Being found
-
robots.txtallows the catalogue and blocks/admin,/cart,/checkout,/ordersand/account. - A sitemap exists, listing the product pages.
- Personal pages carry
robots: { index: false }— cart, checkout, orders, account. Not reachable without a session today is not a policy. - Every product page has a real title and description.
- Open Graph images for anything shared on WhatsApp, which for an Indian kirana shop is most of the traffic.
Operations
- Uptime checks on both halves, hitting
/api/health/readyand a real page, alerting to a phone that is not on silent. - Error tracking installed, with personal data scrubbed and the release set to the commit SHA.
- The expiry sweep is scheduled and logs every run — including the runs that cancel nothing, so you notice when the lines stop.
- You know how to roll back, and have done it once on staging.
- Somebody other than you can reach the shopkeeper, and the shopkeeper knows who to ring.
On the day
Go live on a Tuesday morning. Not Friday afternoon. Not the evening before you travel. You want the whole team awake and available for the next eight hours, and you want two clear working days before a weekend.
Watch for an hour. Not the dashboard — the actual shop. Place an order. Have the shopkeeper place one. Look at the logs while doing it.
Tell the shopkeeper what to do when something looks wrong. They are your best monitoring: they will notice an order that did not arrive long before any alert fires. Give them a number and permission to use it.
The first week
Expect to find things. Everybody does. What matters is which kind.
Wrong data — a price, a pack size, an image. Trivial, and the shopkeeper can fix most of it themselves from the admin area, which is why that screen exists.
Wrong assumptions — somebody orders 40 kg of onions; somebody's address does not fit the form; a customer from outside the delivery pincodes tries anyway. These are product decisions, not bugs. Write them down and decide.
Real bugs. Fix, test, deploy. You have a test suite for exactly this, and a rollback if the fix is worse.
The instinct to redesign something in week one is almost always wrong. You have three days of real usage. Wait for a month.
What you have actually built
Sixteen modules ago this was a brief. It is now an application that:
- serves a catalogue with search, filters and pagination, indexable by Google
- keeps a cart that survives a refresh, a new device and a sign-in
- cannot oversell, because stock is claimed with a conditional
UPDATErather than read and written back - takes money through a gateway and believes only a signed webhook about it
- moves orders through a state machine that cannot be talked into an illegal transition
- gives the shopkeeper the screens they actually need
- has 124 tests across five layers, and a CI pipeline that runs them
- refuses to start if it is misconfigured, and shuts down without dropping a request
That is not a tutorial project. That is the shape of a real system, and the parts that were hard — the race conditions, the transactions, the webhook, the dates — are hard in every system you will work on.
What is genuinely missing
Being honest about this matters more than a triumphant ending, because the gap is where you will get stuck if you take this to production.
A raw webhook log. Every event stored before it is processed. Three weeks later, in a payment dispute, that table is the only thing that can answer what happened.
Reconciliation. Every gateway sends a daily settlement report, and something
has to compare it with your payments table. Discrepancies are normal;
finding them a month later is not.
A notifications queue. Right now a failed SMS is logged and gone. Production wants a row, a worker, retries with backoff and a dead-letter table somebody reads.
Rate limiting. Named in the checklist because it belongs in the first week, not the first year.
Invoices and GST. Unglamorous, and a legal requirement for a real shop.
Accessibility beyond the basics. This application labels its controls and uses semantic markup, which is a start rather than an audit.
Each of those is an addition beside what exists rather than a rewrite of it. That is the sign the shape underneath is right — and it is the most useful thing to be able to judge about any codebase you inherit.
Check your work
Why a checklist rather than judgement: you will be tired and certain you have remembered everything.
Why a committed secret must be rotated: it is in every clone and every reflog, and deleting the commit does not unpublish it.
Why restore a backup before going live: an untested backup is a belief.
Why the status code check matters: a soft 404 renders a perfect page with a 200, and Google indexes it.
Why place a real order on the live site: it is the step people skip, and the one that finds the broken thing.
Why personal pages carry a robots directive: "not reachable today" is not a policy.
Why the expiry sweep must log every run: if it stops silently, the shop slowly runs out of stock it has.
Why Tuesday morning: the team is awake, and there are two working days before the weekend.
Why the shopkeeper is monitoring: they notice a missing order before any alert fires.
Why not to redesign in week one: three days of usage is not evidence.
Practice
- Run the whole checklist against your own deployment. Write down every box you could not tick.
- Run
git log -p | grep -iE "secret|password|key" | head -50over the full history of a project you own. - Restore a backup into a scratch database and query it.
- Check the status code of a missing product on your deployed site.
- Place a real order on your live site and refund it. Note everything that surprised you.
- Write the
robots.txtthis shop should have, and explain each line. - Add
@nestjs/throttlerto the login and checkout routes, then try to brute force your own password. - Stop the database on your deployment and confirm what your uptime check says and how long it takes.
- Roll back a deployment on staging. Time it.
- Write the five-line runbook you would leave for somebody covering for you, and give it to somebody who has not seen this project.
That is the course. You have built the whole thing — go and build the next one.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship