Part 8

Shipping, security, and operations

4 min read

8.1 The merge is the middle of the chain, not the end

Merging your change into main feels like the finish line. It isn't. Merge deploys the code, but a lot happens after: the build runs, the deploy publishes, the cache may need clearing, the schema may need a separate migration. "Merged" is not "live and correct." Confirm live.

8.2 Deploying code is not deploying the schema

Your code and your database change on different tracks. A deploy ships code. It does not run your database migration. If the new code expects a column the migration hasn't added yet, it breaks in production while your local looks fine. Order matters: usually the schema change goes first, and stays backward compatible, then the code. Never assume one carried the other.

8.3 The cache: the invisible deploy that never happens

MergeBuildDeployCachethe deploy that never happensThe merge is the middle of the chain, not the end.until you have seen the thing alive with your own eyes, it is not shipped
The cache is the only link that lies without erroring: everything is green, and the old version is still being served.

You deploy, you check, nothing changed. The most common reason: a cache, a layer that serves a saved copy for speed, is still handing out the old version. On some surfaces you must purge the cache after each deploy, or users see yesterday's product. The deploy that "didn't take" is almost always a cache that wasn't cleared.

8.4 Rollback

Shipping without a way back is a bet, not a plan. Before you deploy anything hard to reverse, know how you'd undo it: revert the code, or roll forward with a fix, and what to do about data that already changed. The time to figure out rollback is not during the incident.

8.5 Security as a declarative surface

Most of your security is not clever code, it's a few declarations you either made or forgot. Secrets live outside version control, set in the host. The powerful database key is server-side only; the frontend gets the restricted public key. Row-level security is on for every table. Rate limits cap abuse. These aren't features you build once and admire. They're surfaces you keep flat. One table with security off, or one full-access key in the browser, and the rest of your care doesn't matter.

8.6 Auth is two questions, not one

Authentication asks who are you. Authorization asks what are you allowed to do. They are different, and confusing them is a classic hole: a logged-in user is not automatically an allowed user. Check both, on every sensitive action, on the server. And apply least privilege everywhere: every key, every role, every integration gets the smallest set of permissions that lets it do its job, and nothing more. The blast radius of a leak is exactly the privilege you granted.

Two reflexes that cost nothing and save you: never log a secret (tokens and keys must never land in your logs, where they live forever and get shared around), and serve everything over HTTPS, always.

8.7 Privacy and personal data

If you touch personal data (a name, an email, anything that identifies a human), you inherit responsibilities, not just features. The basics a builder must hold: collect the minimum you need, know where it lives, be able to delete it on request, and never store more than you can protect. If your customers are in Europe, this is the ground floor of privacy law, and "we're a small product" is not an exemption. Privacy is a design constraint you carry from day one, not a checkbox before launch.

8.8 Observability: how you know production is fine

You cannot fix what you can't see. Three layers. Logs: the running record of what happened, which you can stream live to watch a problem as it occurs. Error tracking: a service that captures every crash with its context, so you learn about a bug from a dashboard instead of a furious user. Alerting: a signal that reaches you when a key number goes wrong, before customers notice. Early on, you often find out something broke because someone told you. Closing that gap, from "a user told me" to "my dashboard told me," is one of the first upgrades that separates a toy from a product.

8.9 The incident and rollback playbook

Things will break in production. Panic is the expensive part. Have a plan before you need it. When it breaks: first stop the bleeding (roll back to the last known-good version, or disable the feature behind its flag), then diagnose calmly, then fix forward with a real correction and its regression check (Law 4). Decide in advance what "roll back" means for you: reverting the code is easy, but data that already changed may need its own undo. A rehearsed rollback is a shrug. An improvised one is an outage.

Two cheap safety valves make this easier. Put your risky paths, anything touching money or third-party webhooks, behind a feature flag, so you can switch them off in one move without a redeploy. And sequence releases so you validate before you promote: prove the thing works before you build the marketing pages that send people to it. Validate, then promote, never the reverse.

8.10 Versioning and releases

Give your releases names and a history. Semantic versioning is the common convention: a version like major.minor.patch, where the numbers signal how big the change is (a patch fixes, a minor adds, a major breaks). Tag each release, and keep a changelog: the dated, human-readable list of what shipped. During a beta you can suffix the version to mark the phase. The point isn't ceremony, it's being able to say exactly what's in production and to walk back to any prior point on purpose.

8.11 Cost is a first-class concern

A builder who ignores cost ships a product that can't survive its own success. Three lines to watch. Infrastructure: what your host, database, and services bill as usage grows. Third-party per-use costs: payments, email, and especially AI model calls, which are billed by the token and add up faster than you expect. And your own pricing metric: if you charge for a usage-based unit, you need to know what each unit costs you to deliver, or you're selling below cost without noticing. Cost is not an afterthought for the finance person. It's a design input, the same as speed or security.

8.12 Telling the world it shipped

Shipping isn't finished until you've told the story. A good release note answers: what shipped (the value, not the technical list), why (the problem solved), a demo or a screenshot, and what's next. Formats that work: a dated changelog oriented on value, a short demo of the real journey, build-in-public along the way, a team note about what changes for them. You speak value and impact, not jargon. The glossary exists precisely to translate the technical into plain terms for this.