Clarity
A mini-ERP for businesses selling through WhatsApp and Instagram. Costs, stock, fixed expenses and real profit — the number most of these businesses never actually see.
The real problem
A business selling over WhatsApp knows how much it sold. It almost never knows how much it earned. Product cost is in one message, the batch shipping fee in another, fixed expenses live in the owner’s head, and stock lives in a notebook. Profit gets estimated, and estimated badly.
Clarity exists to close that gap with the least possible friction: if recording a sale costs more than jotting it in a notebook, nobody records it.
What it solves
- Real per-product costing, including prorating the batch shipping fee. A product does not cost what the supplier invoice says; it costs that plus its share of freight.
- Stock as movements and adjustments, not a number that gets overwritten. Without a movement history there is no way to tell missing inventory from a typo.
- Fixed expenses separated from variable cost, which is what makes net profit computable rather than just gross margin.
- Five real roles — admin, owner, salesperson, accountant and demo — because the salesperson should not see margins and the accountant should not be able to edit stock.
Technical decisions
Serverless Postgres with Drizzle. The schema is the source of truth and types derive from it, not the other way around. In a domain where a rounding error in costing propagates into every report, having the compiler catch a mistyped field is worth more than the speed of writing loose SQL.
Demo mode on SQLite. The public demo runs against better-sqlite3 with seeded data. Nobody needs
to sign up to find out whether it is useful, and no real data is touched.
Billing with signature verification. The payment integration validates the webhook’s HMAC-SHA256 signature and then re-queries the resource against the provider’s API. The incoming notification is never the source of truth for a payment’s state; it is only a hint that you should go ask.
What I learned
The commit I am most satisfied with adds no feature: it closes permission leaks between users. Discovering that an endpoint returned another account’s data when handed a foreign ID is uncomfortable, and fixing it before the system had real users was as much luck as diligence. Since then, authorization tests run per role, not just per endpoint.