Shuja Ur Rahman, home, Lead Software Developer
Back to projects
Material Matters logoFeatured · ERP & internal tools

Material Matters: ERP, store and AI assistant

As sole engineer, I built a lead-to-cash ERP for Material Matters, the India distributor of SAGA. It has 150+ API routes, and one 917-product catalogue feeds every quote, GST invoice, vendor PO and the website. I also re-platformed materialmatters.in as a headless Next.js store on the CRM API, and shipped a CRM assistant that answers staff questions with citations.

2025–Present Sole engineer: architecture to production 4 min readmaterialmatters.in (opens in a new tab)
  • 150+ERP API routes
  • 917products in one catalogue
  • 31CRM API routes behind the store
  • 1.65 GBmigrated off Sanity, zero failures
VideoRecordings of the live site: materialmatters.in on desktop, and material Matters: ERP, store and AI assistant — phone recording

01 · The brief

One catalogue, every document, one engineer

Material Matters is the India distributor of SAGA. It sells furniture and workplace products from its own range and from partner houses such as Kokuyo, Minister and Boss Design, then delivers and installs them across India. Every part of that business needs the same product data. A quote needs it, a GST invoice needs it, a purchase order to a vendor needs it, and so does the website.

I was the sole engineer, from architecture to production. The goal was a lead-to-cash ERP where all of these read from one catalogue, so a product is defined once and every document and the website agree. The design had to respect a few hard rules:

  • GST invoice numbers can't have gaps, even when two people raise invoices at the same moment.
  • Several staff edit the same records, so one person's save must never silently overwrite another's.
  • A payment must be applied exactly once, however many times the gateway retries.
  • Each role sees only its own data, in every page and on every API call.
  • One engineer builds and runs it all, so every part has to be simple enough to own.
Role
Sole engineer, architecture to production
Client
India distributor of SAGA
Company
The Sixty One (61 FZCO)
Timeline
2025 — Present
Scope
ERP · CRM API · storefront · AI assistant · payments
Architecture diagram: one catalogue feeds every quote, GST invoice, vendor PO and the website. The ERP is private, so it's drawn from the system design, not shown in screenshots.Architecture diagram: one catalogue feeds every quote, GST invoice, vendor PO and the website. The ERP is private, so it's drawn from the system design, not shown in screenshots.
Diagramone catalogue feeds every quote, GST invoice, vendor PO and the website. The ERP is private, so it's drawn from the system design, not shown in screenshots.

The store reads the same catalogue

materialmatters.in is the public face of the catalogue. I re-platformed it as a headless Next.js store that gets everything from the CRM API, so nothing is typed in twice.

The filters, category counts and prices come from that API. So does each product's choice between Buy now and Price on request. Product images are served straight from the CRM's storage. When staff change a product in the ERP, the website shows the change.

Material Matters on materialmatters.in, desktop view
Product page: price, GST, variants and lead time all come from one catalogue
On a phone

Product page: price, GST, variants and lead time all come from one catalogue

materialmatters.in/products/robust-1

02 · Re-platform

Cached pages that refresh when the catalogue changes, and a migration with zero failures

A cached page is fast, but it can show an old price. A live page is always current, but it's slow. The store uses tag-based cache revalidation to get close to both. Pages stay cached until a staff edit invalidates the matching tag, and then only those pages are rebuilt with the new data. Open tabs also check a small content-version endpoint and refresh when the catalogue changes.

The old site ran on Sanity. I moved its products and media into the new system and checked every file against its SHA-1 hash after the move. The site no longer depends on Sanity's CDN.

778products migrated off Sanity
1,371media files moved
0migration failures
Architecture diagram: the headless store on a 31-route CRM API, and the verified migration off SanityArchitecture diagram: the headless store on a 31-route CRM API, and the verified migration off Sanity
Diagramthe headless store on a 31-route CRM API, and the verified migration off Sanity

03 · Integrity and payments

Correctness built into the data layer

In an ERP, a bug can mean a wrong invoice, so I put the guards in the data layer instead of relying on everyone being careful. Optimistic locking and compare-and-swap gapless invoice numbering protect concurrent writes, per-page RBAC is enforced at the edge and on every API call, and Razorpay runs on the raw REST API, where every webhook has to pass three checks.

Architecture diagram: each Razorpay webhook passes a constant-time HMAC check, an amount-matched re-fetch and idempotent handling, and invoice numbers stay gapless. The invoice numbers shown are illustrative.Architecture diagram: each Razorpay webhook passes a constant-time HMAC check, an amount-matched re-fetch and idempotent handling, and invoice numbers stay gapless. The invoice numbers shown are illustrative.
Diagrameach Razorpay webhook passes a constant-time HMAC check, an amount-matched re-fetch and idempotent handling, and invoice numbers stay gapless. The invoice numbers shown are illustrative.

04 · CRM assistant

An assistant that shows its sources

Staff ask the CRM questions in plain language, and the assistant answers with citations. Answers cite the CRM records they came from, so anyone can check them.

There is no vector database. Retrieval is BM25 keyword ranking across 10 record types, filtered by the asker's role. Answers are generated through a gateway over Gemini, GPT and DeepSeek, with fallbacks between providers.

Architecture diagram: the CRM assistant filters by role, ranks with BM25 and cites its sources. A private system, so this is a diagram, not a screenshot.Architecture diagram: the CRM assistant filters by role, ranks with BM25 and cites its sources. A private system, so this is a diagram, not a screenshot.
Diagramthe CRM assistant filters by role, ranks with BM25 and cites its sources. A private system, so this is a diagram, not a screenshot.

Stack

Next.jsTypeScriptPostgreSQL (Supabase)Supabase StorageRazorpay REST APIClerkVercelBM25 retrievalGemini · GPT · DeepSeek