CASE STUDY 10 / 16BACKEND APIENGINEERING LEADERSHIPTEAM LEADERSHIP

Central API Platform.

Decided and directed a three-year move of BMI Global Ed's systems onto one shared API platform: seven modules, 200+ REST endpoints, and the legacy PHP API retired.

MY PART
Directed the migration onto one shared API and ran the offshore team that built it.
PROBLEM
Fair registration, the fair websites, staff reporting and fair-day check-in all ran on one ageing PHP API, and every new product risked building its own backend, data access and third-party integrations beside it.
SOLUTION
One Node.js and Express codebase with a module per product domain, each built on the same Router → Controller → Business logic → Data access layering, behind a REST API and a Hasura GraphQL layer on PostgreSQL. Systems moved across one at a time while the old API kept serving the rest.
RESULT
Every system that used the legacy PHP API now runs on one platform of 200+ endpoints, and the legacy API has been switched off. The platform serves 60⁠–⁠80 fairs a year across 18 countries, and every change passes blocking security and test checks before release.
FIG.01 · THE PLATFORM ESTATE, SIMPLIFIED
200+REST endpoints
7Business modules in one codebase
5Consumer systems migrated onto it
39Versioned specs, each with its own unit and integration test
01WHAT IT DOES

One backend instead of seven

Each product line risked rebuilding its own backend, data access and integrations. The platform gives all of them one governed integration boundary instead.

Seven business modules

Business logic, data access and authentication for every product line, from the event booking CRM and reporting to the mobile app and the B2C platform, in one Node.js and Express codebase. A shared-services module absorbs the legacy API's scripts, webhooks and small utilities that belong to no single product.

REST and GraphQL

Over 200 REST endpoints, with a Hasura GraphQL layer on PostgreSQL alongside them. Callers authenticate with JWT bearer tokens, keyed to one internal identity per product domain.

Background jobs

BullMQ queues on Redis take the work that should not hold up a request and run it in the background, outside the request cycle.

Payments and integrations

Adyen payment webhooks, their HMAC signatures checked with Adyen’s own validator against a key held in the environment, ActiveCampaign marketing webhooks, and file storage on AWS S3, handled once for every product.

Push notifications

Web push notifications to users' browsers, identified to the browser with VAPID keys.

A door for AI agents

A read-only Model Context Protocol (MCP) server lets AI agents query the platform's GraphQL data in natural language, with no way to change it.

02ARCHITECTURE

Every module has the same shape

One layering convention runs through all seven modules, so anyone who knows one domain can find their way around the rest. Two data stores sit under it while the move to PostgreSQL continues.

REQUEST PATH, EVERY MODULE
ROUTER
Express routes for the module
CONTROLLER
Reads the request, shapes the response
BUSINESS LOGIC
The rules of each product
DATA ACCESS
MySQL pools or Hasura GraphQL
RUNTIME AND DATA
RUNTIME
Node.js 24, Express 4
DATA
MySQL moving to PostgreSQL via Hasura
QUEUES
BullMQ on Redis
HOSTING
AWS EC2 under PM2, files on S3
ERRORS
Sentry
03HOW IT WORKS

Moved one system at a time

Systems moved off the legacy PHP API one at a time, while the old API kept running for the ones still waiting. After the move, every change to the platform passes checks that block a release until they pass.

FIG.02 · MIGRATION ORDER AND DELIVERY PATH, SIMPLIFIED
04ENGINEERING PROCESS

The standards it runs on

The team was offshore, so the standards had to live in the process rather than in anyone's head: written specs, tests tied to them, and checks that block a merge rather than warn about it.

A spec for every behaviour

Versioned Markdown specifications, SPEC-000 to SPEC-038, each linked one to one to a test-case document, a unit test and an integration test. A separate governance repository holds 96 specifications in seven folders that mirror the seven modules.

Two layers of tests

Jest unit tests with their dependencies mocked, and Supertest integration tests against the real application: two independent layers of confidence rather than one.

Security scanning that blocks

Semgrep static analysis runs on every pull request, every push and a daily schedule. A failure blocks the merge, replacing reliance on periodic external audits.

Risk-tiered dependency updates

Renovate raises dependency upgrades automatically. Low-risk patches go through on their own; payment, authentication and cloud-SDK upgrades wait for a person to review them.

Build, deploy, observe

AWS CodeBuild builds each release and CodeDeploy rolls it out to EC2, where PM2 runs the process. Sentry reports errors from production as they happen.

Migration signed off on evidence

The MySQL to PostgreSQL move ran as its own changelog-documented programme beside feature work, with no delivery freeze. Core specs were re-verified against the migrated system and API contracts checked against live platform metadata before sign-off.

05MY ROLE

What I led

Led a team of three on this platform (the wider offshore team peaked at five), who designed, built and run it, day to day through verbal direction, written specifications and wireframes. The calls below were mine.

  • Decided and drove the migration of five consumer systems off a legacy PHP API onto the platform, backed by a 96-specification quality-governance programme, sequencing the systems and keeping the legacy contract alive throughout.
  • Managed the offshore team that built and runs the platform, through daily stand-ups, task assignment, written specifications and wireframes.
  • Oversaw a platform-wide database migration from MySQL to PostgreSQL, with a Hasura GraphQL layer alongside the REST API.
  • Architected the platform’s AI tooling, which the team built: a read-only MCP server giving AI agents natural-language queries against the GraphQL data layer, and custom agents that automate the release pipeline up to QA-gated production cherry-picks.
  • Authored a cross-repository tooling recommendations document covering CI automation, contract testing, OpenAPI conversion, and dependency and security scanning.
  • Contributed targeted fixes, including retry-with-fallback logic that resolved intermittent QR-badge generation failures.
06TECH STACK

Tech stack

[a] RUNTIME & DATA
Node.js 24Express 4PostgreSQLHasura GraphQLMySQLRedis
[b] JOBS & INTEGRATIONS
BullMQJWTAdyen webhooksActiveCampaign webhooksWeb Push (VAPID)MCP server
[c] CLOUD & DELIVERY
AWS S3AWS EC2AWS CodeBuildAWS CodeDeployPM2Sentry
[d] QUALITY & GOVERNANCE
JestSupertestSemgrepRenovateVersioned Markdown specs

Say hello.

LINKEDINlinkedin.com/in/danielgorgonia

Hidden from bots until you click.

LOCATIONLondon, United Kingdom
LOCAL TIME--:--