An abstract field of flowing contour lines, like a topographic map, rising gently to the right and dissolving into deep blue.

Quality flexible work, at platform scale

A third of adults now want work, but not a conventional job. We build and run the platform that lets public agencies and private employers offer them flexible work with real employment protections — not another gig app.

The problem with “flexible” work

Plenty of people can’t take a nine-to-five — because of childcare, caring responsibilities, health, study, or a dozen other reasons — but still want to work and earn. The market’s answer has been the gig app: flexible in name, but precarious, opaque, and built to extract margin from the worker. BeyondJobs exists to offer the opposite.

Their platform, GoodFlexi, is a labour marketplace run by public agencies and private-sector employers, not a gig app. Work comes with employment status and protections, pay is transparent, and the data feeds interventions that help people progress — including into conventional jobs if that’s what they want. It started in UK government programmes and now runs for public agencies in California (FlexLA, WorkLB) and Oregon (FlexPDX) too. We’re the team that builds and operates it. Including:

  • Architecture
  • Back-end platform
  • API
  • Database
  • Mobile app
  • Day-to-day operations

One platform, many agencies, two regions

The hard part is a marketplace that has to behave differently for each organisation that runs it, in different regulatory regimes, without forking into separate codebases nobody can maintain. The same platform has to be a UK government tool and a Californian one and an Oregonian one at the same time. It runs as two isolated regional stacks — one in the UK, one in the US — each serving multiple agencies from the same codebase.

The codebase, by the numbers

It’s a serious piece of engineering: in continuous development since 2017 and still shipping, with around 320,000 lines of Java across some 2,300 files, held together by 2,200+ automated tests. The service exposes 180+ API endpoints, backed by a PostgreSQL database of nearly 300 tables that we’ve evolved through 247 schema migrations without downtime for the agencies running on it.

One core codebase deployed as two isolated regional stacks — UK and US — each serving multiple agencies and employers. GoodFlexi core UK stack US stack — CA & OR
One codebase, deployed as two isolated regional stacks — each serving multiple public agencies and employers, not a fork per customer.

How it’s put together

The platform is a server-rendered Java application — Spring and Hibernate on Apache Tomcat, over PostgreSQL. The mobile app and the per-agency web interface talk to the same back-end and the same API; a reverse proxy gives each agency its own branded entry point onto the one shared platform.

It all runs on AWS, defined top to bottom in Terraform. The application tier auto-scales behind a load balancer; sessions live in Redis so any instance can serve any request; files go to S3 and email through SES; and secrets, dashboards and alarms mean we can see and trust what production is doing. Each region is its own isolated stack — its own database and cache — brought up from the same infrastructure code. Changes ship through a CI pipeline that runs the full test suite on every push before anything reaches an environment.

The mobile app and per-agency web both reach the platform through a CDN and reverse proxy into an auto-scaled Java application tier on AWS, backed by PostgreSQL, Redis, S3 and SES — all defined in Terraform. AWS — defined in Terraform workers & agencies Mobile app Web (per agency) CDN + proxy App tier Java · Tomcat PostgreSQL Redis S3 · SES
Mobile and web reach the same Java application tier through a CDN and reverse proxy; it’s backed by PostgreSQL, Redis, S3 and SES, and the whole stack is replicated per region.

Running it on AWS

The serving path is deliberately conventional — no exotic moving parts. Route 53 and CloudFront handle DNS and TLS at the edge and serve static assets from S3. Traffic then enters a private VPC, where a load balancer spreads it across an Elastic Beanstalk tier, Tomcat on Amazon Corretto, that auto-scales with demand.

State lives in managed data services, so the app tier itself stays stateless and disposable: a PostgreSQL database on RDS — encrypted at rest, with automated backups, deletion protection and Performance Insights — paired with a read replica that takes read-only query load off the primary, and a Redis cache on ElastiCache holding sessions, so any instance can serve any request.

Around the application sit the other AWS services it leans on, every one declared in Terraform: Cognito for authentication, S3 for file storage, SES for email, SNS for alerts, Secrets Manager for credentials, and CloudWatch — with Synthetics canaries probing the site from the outside — for monitoring. The same code stands the whole stack up again for each environment and each region.

A request flows from workers and agencies through Route 53 and CloudFront into a VPC, where a load balancer fronts an auto-scaling Elastic Beanstalk tier of Tomcat instances; the app writes to a primary PostgreSQL RDS database, reads from a read replica, and uses a Redis ElastiCache for sessions. AWS — provisioned with Terraform Workers & agencies CloudFront CDN Route 53 · TLS · S3 origin VPC Load balancer Elastic Beanstalk Tomcat · Corretto · auto-scaling Redis sessions RDS primary writes RDS replica reads replicates
The serving path: Route 53 and CloudFront at the edge, then a load balancer and an auto-scaling Elastic Beanstalk tier in the VPC. The app writes to the primary PostgreSQL database and serves reads from a replica, with Redis for sessions — stood up per region from the same Terraform.
The application on Elastic Beanstalk uses a set of managed AWS services: Cognito for authentication, S3 for files, SES for email, SNS for alerts, Secrets Manager for credentials, and CloudWatch with Synthetics canaries for monitoring. Application on Elastic Beanstalk Cognito authentication Secrets Manager credentials CloudWatch + Synthetics canaries S3 file storage SES email SNS alerts → email / SMS
The managed AWS services the application leans on — authentication, files, email, alerts, secrets and monitoring — all declared in Terraform alongside the rest of the stack.

Shipping it, and keeping it healthy

Every change goes out the same way. A push triggers a Bitbucket pipeline that builds the app, runs the full test suite (parallelised across workers), and packages a WAR; only then does Elastic Beanstalk roll it out, up a ladder of environments — test, UAT, and finally production — so problems surface long before they reach a real agency.

In production it’s watched continuously: CloudWatch dashboards and health alarms, wired through SNS to page the team by email and SMS the moment an environment degrades. Non-production databases even stop themselves outside working hours to keep the bill down. It’s routine plumbing, and it’s why a small team can run a system this size.

Every push runs through Bitbucket Pipelines — build, the full test suite, then packaging a WAR — before Elastic Beanstalk deploys it up the environment ladder; in production, CloudWatch health alarms page the team by email and SMS through SNS. Delivery — Bitbucket Pipelines & Terraform git push Build & full tests Package WAR Elastic Beanstalk deploy: test → prod Operate — always-on monitoring CloudWatch dashboards · alarms SNS On-call — email & SMS
Nothing reaches production untested: every push builds and runs the full suite before Elastic Beanstalk promotes it up the environment ladder. In production, a failed health check pages the team within minutes.

Long-lived software that keeps changing

The system has run since 2017 and has to keep evolving — new agencies onboarded, new programme rules, new regions — while the existing ones stay live and dependable. More than 8,700 commits in, it’s still under active development. Keeping a codebase this large adaptable — instead of letting it ossify into the kind of legacy system nobody dares touch — is the unglamorous part of the job, and the part the whole thing depends on.

Modernising it from the inside

Keeping it adaptable isn’t passive — parts of the platform are being modernised while it runs. The biggest is a steady migration off the web framework the app was first built on and onto Spring MVC. We don’t rewrite it in one go; we move it a slice at a time — a strangler-fig migration. Several hundred legacy actions still run alongside the Spring controllers we’ve already migrated, all behind the same front and sharing the same domain model, so users never see the seams.

Requests enter a single front controller and are served by both the legacy framework layer, which is shrinking, and a growing Spring MVC layer; both share one domain model over PostgreSQL. Front controller new · growing Spring MVC Legacy actions legacy · shrinking Domain + PostgreSQL
Strangler-fig migration: the legacy framework and Spring MVC run side by side behind one front, sharing the same domain model, while functionality moves from the old layer to the new one action by action.

The other big push is authentication: consolidating login onto AWS Cognito — a hosted, hardened flow with multi-factor authentication and a centrally-managed password policy. It’s being rolled out incrementally, without interrupting the people who log in every day.

The GoodFlexi app hands login to AWS Cognito, which provides multi-factor authentication, a hosted login flow, and one centrally-managed password policy. GoodFlexi app AWS Cognito MFA · hosted login One policy passwords · MFA
Login is handled by AWS Cognito — MFA, a hosted login flow, and one centrally-managed password policy.
How we’re set up

A small, senior team owns the platform end to end — architecture, build, test and operations — in a long-term partnership with BeyondJobs.

Why it matters

GoodFlexi puts people into quality work on terms that fit their lives — protected and paid transparently. That’s a good thing to have built and to keep running well.

Building something durable that has to serve real people at scale? That’s the kind of work we like — let’s talk.