Oil & Gas ERP
- React
- Next.js
- TypeScript
- GraphQL
- Apollo Client
- Ant Design
- Turborepo
Senior frontend engineer on a 12-person delivery team building an ERP for a US oil & gas client (anonymized as a client in the oil & energy sector, ~1,500 employees across 17 offices). In Phase 1 I was one of three frontend developers building a Billing MVP from scratch; that MVP converted the client into a multi-year ERP engagement, after which I chose to lead the frontend on the CRM sub-system for roughly 22 months.
Engagement shape
- Client: an anonymized US oil & gas company, ~1,500 employees, 17 offices.
- Team: 12 specialists at the project’s end state (3 FE, 3 BE, a UX lead, 2 QA, PM, PO, DevOps, Delivery Manager, Product Owner). At peak — during the most active phase of the full ERP build — the team was meaningfully larger, around eight frontend developers organized two per sub-system, with the other roles scaling proportionally.
- Dates: Jan 2022 onward, roughly three years. I moved to another product before the very end; the ERP continued without me.
- Cadence: two-week sprints; the MVP shipped in 30 sprints (~14 months).
Two phases
- Phase 1 — Billing MVP (~14 months): I built the frontend from scratch as one of three FE developers, consulting with the company’s FE tech lead on key architectural calls while owning day-to-day execution.
- Phase 2 — full ERP (~22 months): after the MVP launch the client expanded the contract and I moved to the CRM sub-system. The company’s FE tech lead operated at cross-ERP coordination level, so I was the de-facto lead frontend on CRM — owning the architectural calls for the sub-system (state shape, module boundaries, conventions, technology choices). The scope was architectural rather than people-management.
Tech stack
- Frontend: React, Next.js, TypeScript, Apollo Client, GraphQL, Ant Design (heavily customized), React Hook Form + Zod for validation, Storybook, and React Testing Library.
- Monorepo tooling: Turborepo, managing a shared UI library, date utilities, a validation library, and per-sub-system modules.
- Backend (per the client’s public case study): Java 11+, Spring, GraphQL, Elasticsearch, Redis, PostgreSQL, RabbitMQ/Nats, an API Gateway. Third-party integrations (IRS, DocuSign, QuickBooks, FedEx) were all backend-side; the frontend communicated only with our backend.
Architectural through-lines
- Monorepo with horizontal shared modules. UI library, date utilities, and validation library lived as shared modules consumable by any ERP sub-system, while sub-system business logic stayed in its own module — shared libraries were infrastructure, never domain.
- URL as the source of truth for view state. Consistent across the codebase: multi-step forms persist step state in query params (plus a server-side draft), and data tables persist sort / filter / pagination in query params. The result is refresh-safe, tab-close-safe, shareable URLs.
Selected work
- Analytics-view configuration wizard (Billing MVP). A five-to-six step form with state in URL query params plus a server-side draft, so back / refresh / accidental tab-close all recover. Later steps branch conditionally on the first, with per-step validation.
- Customized Ant Design data tables — the headline frontend complexity on CRM. Server-side sort / filter / pagination with state in the URL; column resize / reorder / hiding with persistence; inline editing. The customization extended Ant Design components directly rather than wrapping them behind a thin facade, which required deep familiarity with the library’s internals and made upgrades costlier — a deliberate trade-off for bending the components to the project’s conventions.
- Dashboard charts. Many chart types via ECharts, library-driven with no custom chart code.
- Performance for large dropdown option lists. Solved with server-side pagination and server-side search inside the dropdown — it lazy-loads matches from the backend as the user types, so the rendered option list stays small regardless of total option count.
Business outcome
The Billing MVP shipped and converted a 1,500-employee US oil & gas client into a multi-year ERP engagement — the headline business story of this project.
What I’d do differently
I would replace the OOP / class-based data layer (entity classes, service classes) with plain data plus pure functions. This is not about React class components — we used hooks from day one — but about the data layer: as the code grew, classes made it harder to read and test, where plain data and standalone transformations would have stayed legible and unit-testable at scale.
Wezom (the software company) published a public case study of the ERP engagement that followed the Billing MVP.