The opening claim
Most people think building software is typing code. Typing is the fourth thing that happens, and by the time you get there most of the outcome has already been decided.
A production platform is a pipeline with four stages, and they are ordered for a reason. Requirements, then data model, then secure backend, then interface. Skip one and it does not disappear. It resurfaces later, in the most expensive possible form, usually about six months in, usually as a rewrite.
I have watched projects die in each of the four. They rarely die from bad code. They die from a schema that could not represent the business, or from a feature list nobody pruned, or from an owner who could not operate his own platform without calling the developer.
The mechanism 🧠
Stage one: the cahier des charges, and the cutting. The purpose of requirements is not to write down what the client wants. It is to find the twenty percent of features that carry the business and delete the rest. A first meeting reliably produces forty features. Perhaps eight of them matter. Building all forty does not give the client a richer product, it gives him a product that ships a year late, costs four times more, and buries the eight that mattered under a menu.
The useful question is not "do you want this?" because the answer is always yes. It is "if this did not exist on launch day, what would break?" Most features survive that question badly, and that is the point.
Stage two: the schema. This is the stage with the longest shadow. Code is cheap to change. A data model with live customer data in it is not, because changing it means a migration, a backfill, and a coordinated deployment across every client that reads it. Get this wrong and every later stage inherits the damage.
The specific failures repeat. Storing state where you should store events, so history is destroyed. Storing money as floats. Denormalising early for a performance problem you do not have. Missing the relationship that the business actually runs on, so it gets faked later with a JSON column and string parsing. Six months in, the symptom is always the same: simple questions from the owner become slow queries or impossible ones.
Stage three: the secure backend. Authentication, authorisation, business logic, payment hooks. The rule that matters here is that entitlements are server truth. Anything the client can send you, the client can lie about. If a browser can tell your server which price to charge, or which store a product belongs to, you do not have a backend, you have a suggestion box.
With Postgres this means row level security, so a leaked key still cannot read another seller's orders. It means the operations that must not tear in half live in a single transaction or a database function: stock decrement and order creation, payment capture and ledger write.
Stage four: the interface, and the back office. Two audiences, and the second one gets forgotten. Customers need the storefront. The business owner needs a back office where he can do his own job without calling you: change a price, refund an order, suspend a user, read yesterday's numbers.
An admin panel is not a nice to have. It is the difference between a platform the client owns and a platform he rents from your phone number. If every operational change requires a developer, you have not delivered software, you have delivered a dependency.
Comparative Breakdown
| Dimension | Bloated ready made template | Custom architecture |
|---|---|---|
| Day one cost | Very low | Higher |
| Fit to the business | Roughly seventy percent | Built around the actual workflow |
| The last thirty percent | Plugins, workarounds, a spreadsheet | Part of the model |
| Data model | Generic, designed for everyone | Designed for this operation |
| Cash on delivery flow | Bolted on, if at all | The primary path |
| Courier integration | A plugin that may be abandoned | Direct against the courier API |
| Arabic right to left | Usually broken in the theme | Designed in |
| Performance | Carries features you never use | Carries what you built |
| Who can change a price | Whoever can survive the admin | The owner, in one screen |
| Cost at eighteen months | A migration, and a rewrite | Incremental |
| Failure mode | You outgrow it and restart | You extend it |
The honest version: for a shop selling twelve items, a template is the correct answer and I will tell a client so. Custom architecture earns its cost when the workflow is the business, which for anything touching cash on delivery, couriers and multiple sellers, it is.
The Algerian reality
Each stage has a local variant that Western tutorials will not warn you about.
Requirements. Algerian clients frequently ask for the feature set of a company a hundred times their size, because that is the reference they have seen. The job in stage one is not to say no, it is to sequence. Ship the eight features that produce revenue, prove the thing works, then expand. This is also a trust exercise: an owner who has been burned before will not believe a twelve month plan, but he will believe a working checkout in three weeks.
Schema. If you model an order as a row with a status column here, you have already lost. The life of an Algerian order is a sequence of events spread over days: placed, confirmed by phone, parcel created with a courier, out for delivery, failed attempt, second attempt, delivered, cash collected, remitted by the courier at the end of the week minus a fee. Overwrite a status and you have destroyed the record you need when the courier's weekly remittance does not match your total. Model it as an append only timeline and reconciliation becomes a query instead of an argument.
Wilaya and commune belong in the schema as real reference tables, not free text, because your delivery pricing and your courier API both depend on them being exact.
Backend. Payments here are mostly cash collected at a doorstep by somebody who does not work for you. The money hook is not a Stripe webhook, it is a reconciliation problem: expected collections against actual remittances. Build that on a ledger, with row level security so a seller sees only his own orders. Chargily exists for online collection and is worth integrating, but if you make prepayment the primary path you have built for a customer who does not exist here yet.
Interface. The seller is on a mid range Android in Arabic, right to left, on a connection that drops. Test on the device, not the emulator. And the back office matters more here than anywhere, because the alternative is not "the client hires an operations team", it is "the client calls you at 21:00 to change a price".
What to actually do 🛠️
Run stage one as a deletion exercise. Write the forty features down, then force rank them against one question: what breaks on launch day without this? Ship the top eight. Put the rest in a document called Later and actually revisit it, because that document is what stops the conversation being a fight.
Draw the schema before you write a line of application code. Entities, relationships, and for every table one decision: is this a fact about the past, or the current state of something? Facts about the past are append only. Money, orders, stock movements, job milestones are all facts about the past.
Put the invariants in the database, not the application. Foreign keys, check constraints, unique constraints on external references for idempotency, row level security policies. A rule enforced by Postgres holds when a second client, a mobile app, or a future developer arrives. A rule enforced in your controller holds until Tuesday.
Make the risky operations atomic. Stock decrement plus order insert in one transaction or one function. Never read a quantity, subtract in application code, and write it back. Two customers will find that race.
Build the back office in the same sprint as the storefront, not after. Minimum: products, orders with status transitions, users, refunds or corrections, and one screen of real numbers. If the owner cannot run a normal Tuesday without you, the project is not finished no matter how good the storefront looks.
Ship in that order and demo at every stage. Requirements signed, schema reviewed out loud with the client in plain language, backend with a working end to end order, then the interface. Clients cannot review a schema diagram, but they can absolutely tell you "no, a customer can have two addresses" if you describe it as a sentence.
TL;DR 🧾
Requirements, schema, secure backend, interface. In that order, no skipping. Code is cheap to change and a data model with live customers in it is not, so the hour you spend on the schema is worth a month of the hour you spend typing.
LINKEDIN VERSION
Most people think building software is typing code. Typing is the fourth thing that happens, and by then most of the outcome is already decided.
A production platform has four stages, ordered for a reason.
One: requirements. The purpose is not to record what the client wants, it is to delete. A first meeting produces forty features and about eight of them carry the business. The useful question is never "do you want this", because the answer is always yes. It is "if this did not exist on launch day, what would break?"
Two: the schema. This has the longest shadow. Code is cheap to change. A data model with live customer data in it is not, because changing it means a migration and a backfill. Six months later the symptom is always the same: simple questions from the owner become impossible queries.
Three: the secure backend. Entitlements are server truth. If a browser can tell your server which price to charge, you do not have a backend, you have a suggestion box. Row level security, and atomic transactions for anything that must not tear in half.
Four: the interface, including the back office. If the owner cannot change a price without calling you, you did not deliver software, you delivered a dependency.
In Algeria stage two is where most projects die. An order is not a row with a status column. It is days of events: confirmed, dispatched, failed, retried, delivered, cash collected, remitted minus a fee. Overwrite that and you cannot reconcile your own money.