Portfolio

Reach Passengers

The founding booking and campaign platform for a UK out-of-home advertising startup, managing ads on digital screens at airports in the North of England. Built from scratch in five months, before the company was even incorporated.

Reach Passengers

The product

Reach Passengers is a UK out-of-home advertising business that sells space on digital ad screens across high-footfall locations in the North of England, including airports. Advertisers and agencies pick the screens and locations they want by map, choose dates, upload their artwork, pay, and track the campaign. I built the founding booking and campaign-management platform the company runs on, and it is still in use today.

My role

A UK entrepreneur hired me on Upwork three weeks before his company was even incorporated. I was the founding platform developer and built the product end to end: the buyer-facing booking flow, the admin back office that runs the operation, the payment and invoicing pipeline, and the transactional email system. It shipped in five months, and the business has been running on it ever since. This is the kind of from-zero technical ownership a founder leans on when there is no in-house engineering team yet.

Architecture

The platform is a server-rendered PHP application built on a deliberately layered design, so the codebase stayed maintainable as the feature set grew under a hard launch deadline:

  • Clean separation of concerns. A front controller routes each request to a module and an activity (its controller), thin controllers coordinate the request, and the real work lives in a suite of domain service classes such as Booking, Campaign, Payment, Map, Summary, User, and Admin. Each service receives the shared site context and data layer by constructor injection rather than reaching for globals, which keeps business logic out of the view and out of the database access code. This is SOLID applied in practice: single-responsibility services, dependencies passed in rather than hard-wired.
  • Templating separated from logic. All HTML is rendered through Twig with template caching and strict variables turned on, so the presentation layer is fully decoupled from the controllers and fails loudly on a missing variable instead of rendering a silent blank.
  • Configuration as environment. Runtime configuration is loaded from the environment at boot and frozen into immutable constants, so the same codebase moves cleanly between development and production without code changes.
  • A consistent AJAX API surface. The dynamic parts of the app talk to the backend through a small, uniform set of endpoints organized by verb and intent (read, create, update, remove), called from a single typed client wrapper on the frontend. New interactive features reuse that contract instead of inventing one each time.
  • Role separation by module. Buyer-facing flows (account, campaign building, checkout, my-campaigns) and the operator back office (screens, cities, clients, vouchers, campaign approval, stats) are separate modules with their own access checks, so agencies and brands never touch operator tooling.

The engineering challenge

Out-of-home advertising is fundamentally an inventory problem. A finite set of screens, each with a limited number of weekly slots, has to be sold without ever double-booking, while pricing varies by location, audience, and whether a slot is standard or premium. The booking model works in week-aligned date ranges and has to reconcile what a buyer is selecting on a live map against what is actually still available, then hold that selection through to a paid, scheduled campaign. Getting that core right, and getting it done fast enough to launch a company in five months, was the real constraint.

What I built

  • A map-driven inventory picker where buyers select by county, town, location, and audience, with standard and premium frequency, and see availability as they build
  • A week-range booking and cart system that turns a screen selection into a priced, schedulable campaign without double-booking
  • Artwork upload with previews, plus an admin approval workflow so creative is reviewed before it goes live
  • A Stripe-backed checkout with tokenized card capture, promo-code and voucher handling, and VAT-aware totals
  • A payment and invoicing pipeline that records Stripe webhook events (succeeded and failed invoice payments) and exposes downloadable invoices and payment history
  • An operator back office for managing screens, locations, clients, vouchers, and campaign states, with CSV exports for clients, screens, and vouchers
  • A transactional email system covering booking confirmations, payment confirmations and reminders, artwork reminders, and staff and admin notifications

Engineering practices

Schema changes are managed as versioned database migrations rather than hand-edited SQL, so the database evolves in a tracked, repeatable way. The frontend is written in TypeScript and compiled down for the browser, which puts type checking on the client code instead of leaving it untyped. Security basics are handled at the framework level: CSRF tokens are generated per session with a cryptographically secure source, and sensitive flows sit behind explicit authorization checks. The application has its own logging service so failures are recorded instead of swallowed, and error reporting is toggled by environment so production stays quiet while development stays loud. The codebase is version-controlled with a development-to-production branch workflow.

Stack

PHP on a custom layered MVC micro-framework, MySQL for the screen, campaign, and invoicing data, and Twig for server-rendered views with template caching. Stripe handles payments and webhook-driven payment events, PHPMailer over SMTP plus Mailchimp handle transactional and marketing email, and environment configuration is loaded through phpdotenv. The frontend is TypeScript compiled to JavaScript with jQuery and a thin AJAX API client, and the database schema is managed with versioned migrations.

Outcome

I delivered the founding product in five months, before the company was even incorporated, and the business is still running on it today. In the founder’s words: “The best developer I’ve had the pleasure of working with.” The clean service-oriented foundation is also what would carry the obvious next steps, such as smarter automated scheduling and demand-based pricing, on top of a platform that already earns revenue.