Work 2024
DCRM
A customer relation portal for the Denim division — SAP integrations on one side, business-process tracking on the other.
- Year
- 2024
- Role
- Full-stack Engineer
- Client
- SAPPHIRE / Diamond Fabrics — Denim
The DCRM dashboard for the Denim division, showing business-process tracking modules.
Stack
- React
- Express
- MUI
- SAP
- Node.js
- Redux
- Tanstack Query
DCRM — Denim Customer Relation Management — is the web portal for Diamond Fabrics' Denim division. It is built around two kinds of module: ones that are integrations of SAP, surfacing data that already lives in the ERP, and ones that track the business process the division runs on.
The client is React styled with MUI; the server is Express.
It's an internal tool. The people who open it are Denim division staff and management who need what's already sitting in SAP, from wherever they happen to be — not a fixed desk with a Windows machine and an SAP seat in front of them.
Problem
SAP's client at Diamond Fabrics is SAP GUI, a thick desktop application that only runs on a Windows machine — there is no getting to SAP data without sitting down at a machine that has both a Windows install and a licensed SAP seat. Licenses are limited, so only a fixed number of people can be in front of that machine at any time. Leadership wanted the data reachable over the internet, from portable devices, including phones, by people who were never going to get a Windows box or an SAP seat of their own.
DCRM exists to answer that constraint, not to duplicate SAP. It is a web front end that sits in front of SAP: one side holds the SAP integration — the one piece that actually needs SAP access — and the other side fans that data out to browsers and mobile devices, so many more people can read and act on SAP data than could ever hold a license to it directly. It doesn't replace SAP; it is a single, controlled point of entry to it.
To put a rough shape on it: the division ran on a handful of licensed seats, while the people who needed to see the data — staff and management across the Denim business — outnumbered them many times over. Most of what they needed was read access to the records a customer-facing division runs on: orders, customer records, and the state of the process behind them. Nobody was asking to post journal entries from a phone; they were asking to see, from wherever they were, what the person at the SAP terminal could already see.
Research
I learned the division's process the only way that actually works: from the people who run it. There was no written spec of how the Denim business moves an order from enquiry to delivery — the knowledge lived with the staff and managers who did it daily, so requirements came out of sitting with them and walking through real cases. My first mental model was too clean: I pictured the process as a straight line of stages, when in practice it loops — things get revised, sent back, and handled as exceptions far more often than a diagram admits. The screens that survived are the ones that were corrected by someone pointing at them and saying "that's not how this actually goes".
The SAP side was a different kind of learning. I didn't reverse-engineer the ERP from nothing — Sapphire has people who own SAP, and the integration surface DCRM reads through was worked out with them rather than around them. My work was learning what data actually existed, what shape it arrived in, and what could be relied on: which fields meant what the label claimed, which records the division actually used, and where the ERP's view of the process diverged from how staff described it. That mapping — SAP's vocabulary on one side, the division's on the other — took longer than any of the code.
Architecture
React + MUI front end, Express API, modules that integrate SAP alongside modules that track business process. The SAP integration is centralized on the server: Express is the one piece that holds SAP access, so the license constraint from the Problem section lives in exactly one place, and every browser or mobile client behind it reaches SAP data without needing an SAP session of its own.
That server reads from the ERP through a single, controlled integration point that the team maintained — a narrow surface exposing only the data DCRM needed, rather than DCRM reaching into the ERP's internals directly. Keeping that surface deliberately small is what makes the rest of the system tractable: the integration can change on its own schedule without every screen changing with it, and there is exactly one place where access to the ERP has to be guarded.
That guarding is the real work. When you read a system of record at this level, you're responsible for the checks it would otherwise apply for you — so the boundary has to be treated as the security perimeter it is, not as a trusted pipe. It's the same centralisation point as above: one guarded connection in, many browser and mobile clients out, none of them needing a seat of their own.
The modules fall into the two families already described, and the source-of-truth rule follows the family. For anything that lives in SAP — orders, customer records, the financial side — DCRM is strictly a mirror: it reads, it displays, it never becomes a second copy that can drift. For the process-tracking modules — the day-to-day workflow the division runs that SAP doesn't model — DCRM's own records are the truth, because there is nowhere else for that state to live. Keeping that rule crisp per module mattered more than any individual feature: the worst failure mode for a system like this is two databases that each half-believe they own the same fact.
When SAP is slow, that slowness is DCRM's to absorb — the reads are kept narrow and per-module, so a sluggish ERP call degrades one panel rather than the whole screen, and the process-tracking side keeps working regardless, since it doesn't depend on the ERP being reachable at all.
DCRM's own store holds what SAP doesn't: the process-tracking records, plus users and roles. Users are DCRM's own — they had no SAP identity, which is the entire premise — and access is role-based, with a person's role deciding which modules they see and what they can do inside them. Management sees more; staff see the modules their part of the process touches.
Development
This was built by a small in-house team during my time at Sapphire's Diamond Fabrics, and it ran alongside the Invoice Portal — same employer, same period, sibling systems rather than one codebase. My scope was full-stack: the React/MUI client and the Express server both. DCRM deployed to company infrastructure at its internal domain (dcrm.dfl.com.pk); this was an on-premises corporate environment, not a push-to-deploy cloud pipeline, so releases went through the company's own process rather than a public CI service.
The shape every SAP-backed module shares is worth walking once, because it's where the work was. The screen never talks to SAP; it calls an Express endpoint. That endpoint asks the integration point for exactly the records the screen needs, reshapes what comes back — ERP data is structured for the ERP's convenience, not for a JSON API — and returns something the React client can render directly. The edge cases live in the reshaping: fields that are optional in practice but not on paper, records the division has stopped using but SAP still returns, and identifiers that mean one thing to the ERP and something subtly different to the people reading the screen. Every module repeated that pattern; the hard ones were hard because their reshaping step encoded the most business knowledge.
Challenges
Three stand out, and all three come back to the same fact: the system of record belonged to someone else.
Data shape. SAP's data is shaped for SAP. What the integration point returned was correct but built around the ERP's own vocabulary — codes where a screen needs names, wide records where a screen needs six fields, and conventions that only make sense if you know the module they came from. The resolution was to do all of that translation in one place, on the server: each module's endpoint owns the mapping from ERP shape to screen shape, so the React client never sees a raw ERP record and never needs to know the vocabulary.
Latency you don't control. A read that crosses into the ERP is as fast as the ERP feels like being, and there's no tuning it from the outside. The answer was to stop pretending otherwise: requests are narrow (one module's data, not a page's worth of everything), the UI loads each panel independently so one slow call doesn't freeze the screen, and the process-tracking side — which doesn't touch SAP at all — stays fast no matter what the ERP is doing.
A system you can't experiment on. You don't get a throwaway copy of a production ERP to break. That enforced a discipline that turned out to be healthy anyway: the integration stayed read-only wherever it possibly could, new reads were checked against known records with the people who knew what the numbers should say, and anything uncertain was verified before a screen shipped rather than after.
Results
DCRM is working — it's still running.
Lessons learned
I'd draw the line in the same place again. Putting SAP access behind one service — and making everything else an ordinary web client that knows nothing about the ERP — is what kept the system tractable. The constraint, the security perimeter, and the translation from ERP vocabulary to screen vocabulary all live in a single layer, and every screen on the other side of it stays simple. If I split it differently, it would only be finer: the translation layer earned enough responsibility that it could justify being its own module inside the server, rather than living in each endpoint.
The transferable lesson is the pattern itself. Any time a limited resource — a license, a legacy desktop client, a rate-limited API — has to serve more people than can hold it directly, the answer is the same shape: put the scarce thing behind one service you own, keep that surface deliberately narrow, treat it as the security boundary it is, and fan everything else out as plain clients. DCRM is where I learned that the narrowness is the point — every capability you don't expose is a screen that can't break and a hole that can't open.