Codesloci ERP
Retail back office on one Flutter codebase
Stock, orders and reporting for product-led retail. Twelve resources behind one versioned Express API, and a Flutter client that deliberately surfaces four of them — dashboard, products, orders, settings — as one adaptive layout that serves a phone, a tablet and a desktop browser from a single widget tree.
The problem
Retail operators outgrow spreadsheets fast. Stock drifts from reality, purchase orders live in a supplier’s inbox, and nobody can say what margin looked like last month without an afternoon of reconciliation. The moment a second location opens, a single stock number stops meaning anything at all.
Our approach
One Flutter codebase for every surface, with a single adaptive shell rather than a layout tree per platform: a bottom navigation bar under 600dp, a collapsed rail under 1024, an extended rail above. Behind it an Express and MongoDB API where all twelve resources sit under one router with the auth guard mounted once — the previous backend attached its check to four routes out of fifty-five, and mounting it at the boundary is what stops the next module shipping unprotected. Totals and stock are the server’s business: the client posts product ids and quantities, and a client-supplied total is rejected as an unknown field.
The outcome
A back office that runs as a web app, a phone app and a desktop app from one build, over an API where a stock position can be explained and an order cannot be moved to a status the business does not allow.
What is inside
Twelve API resources: products, categories, customers, suppliers, stores, countries, orders, sales, purchases, returns, discounts and users
A four-destination Flutter client — dashboard, products, orders, settings — adaptive across phone, tablet and desktop
Order lifecycle as an explicit state machine, with the permitted transitions declared per status
Stock consumed on order creation and released exactly once on cancel or refund
Role-based access — administrator, manager, cashier, staff — enforced server-side and mirrored in the UI so no button returns a 403
JWT access tokens with server-side refresh tokens, so a password change can invalidate other sessions
One dashboard request backing the whole overview: summary, revenue trend, top products and customers, low stock, orders by status
Engineering notes · 4 min read
Stock is a ledger, not a number
12
Modules
one folder eachMovements
Stock writes
never a running totalMany
Stores
per-store positionsThe single most common way retail software loses trust is storing stock as a mutable quantity. Someone edits it to fix a discrepancy, the discrepancy is now invisible, and three months later nobody can explain the position.
Every change here is written as a movement with a cause: goods received, sale, return, adjustment, transfer. The position is derived. That makes the stock ledger the screen everything else is judged against — if the ledger and the dashboard disagree, the dashboard is wrong.
Module-per-domain, and what that actually buys
- Adding a module means adding a folder, not reworking the shell
- A module owns its routes, its grid columns and its permissions in one place
- Role-based access is declared per module, so a clerk’s build of the app is genuinely smaller
- Reporting reads the same movements the operational screens write — no export step, no BI layer
Virtualised grids were a requirement, not an optimisation
An operator with 20,000 SKUs scrolls. A non-virtualised table renders 20,000 rows into the DOM and the browser stops responding, which reads as "the system is broken" rather than "the table is naive". MUI X DataGrid handles windowing so the interaction stays flat as the catalogue grows.
| Step | Writes | Visible in |
|---|---|---|
| Purchase order received | Goods-in movement | Stock ledger, stock value KPI |
| Sale | Sale movement | Stock ledger, revenue chart |
| Return | Return movement | Stock ledger, returns rate |
| Adjustment | Adjustment movement with a reason | Stock ledger only — never silent |
If you cannot explain a stock position from the movements that produced it, you do not have inventory management. You have a number somebody typed.
Client
Back end
Data
Platforms
Web · iOS · Android · Desktop
Need a platform like Codesloci ERP?
We can walk you through how this was built, what it cost to run, and what the equivalent looks like for your business.
Or email us directly at [email protected]