← All work

Oil & Gas ERP

Jan 2022 – 2024 (~3 years, 2 phases) · Senior Frontend → Lead FE (CRM)

  • 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.