SAAS · FULL-STACK
KejeHub
From first commit to a business platform with paying clients.
The context
A multi-tenant cloud business management platform for Malaysian retail and gold trading businesses. Gold shops run on paper — sales, buybacks, supplier purchases and customer records live in notebooks and spreadsheets, while gold prices move all day. Generic accounting software has no concept of a gold price or a buyback flow. Malaysia’s e-invoicing mandate turned that from an inconvenience into a deadline: gold retailers cross LHDN’s turnover thresholds easily, because gold is expensive even when the shop is small. I lead the technical build alongside my full-time role, working with a small team including a UX/UI designer.
What I contributed
- Owned technical architecture, data modelling, API design, and release delivery.
- Built multi-company and multi-branch workflows, menu-level access control, invoicing, payment tracking, and financial reporting.
- Integrated LHDN MyInvois e-invoicing, live gold price feeds, historical trends, and buyback management.
- Delivered a React interface with virtualised tables, internationalisation, and export workflows.
What I decided, and why
Bought the admin shell, built the domain
The frontend sits on a licensed Material UI admin template. Building a design system from scratch would have cost weeks I did not have against a fixed regulatory deadline, and it is not the part of this product that matters. That time went into the data model, the tenancy rules and the MyInvois integration instead.
Chose boring database technology
MySQL, not something newer. The risk in this project was entirely in the domain — tax compliance, gold pricing, multi-branch accounting. I did not want a second source of unknowns sitting in the database layer.
Queued e-invoice submission instead of blocking the request
Submitting to LHDN is a call to a government service I do not control. It can be slow and it can fail, but it must eventually succeed. Invoices go onto a Bull queue and retry on failure, so a slow response never becomes a stuck page or a lost submission.
Kept validation deterministic
E-invoicing is statutory, so a wrong submission is a legal problem rather than a UX one. Every field is checked against explicit rules before it leaves the system, and anything uncertain goes back to a person.
Built multi-tenancy on day one
Building for one shop and generalising later would have been faster, but retrofitting tenant isolation into a live system holding financial records is not a migration worth risking. Multi-company and multi-branch support, with access control down to individual menu items, went in from the start.
The hard part
The hard part was not the code — it was that the people using it have no interest in software. A gold shop owner will not read documentation, and will not forgive a system that makes invoicing slower than a notebook. Every requirement the mandate imposes had to disappear behind something that felt like ordinary work. That constraint shaped most of the interface decisions, and it is why a UX designer was on the project from the start rather than added at the end.
The outcome
- First commit to production in 6 months.
- First paying client onboarded on 1 July 2025 — the day LHDN Phase 3 e-invoicing became mandatory.
- Three further clients followed from the January 2026 Phase 4 wave; live with 4 paying clients.
- Replaced manual invoice entry with integrated e-invoicing.
What I’d do differently
- Automated tests earlier. Validation logic around tax compliance is exactly the kind of code that deserves a test suite, and I built it under deadline pressure without one.
- One data-fetching approach instead of two. The codebase carries dependencies inherited from the starting template that I deferred pruning rather than decided on.
- Cost and latency visibility from the start. I know the system works; I have less insight than I would like into what each operation costs under load, and that is harder to add afterwards.
Inside KejeHub



