What I build day to day belongs to my employer and its clients, so there are no screenshots or source code here. These are projects I lead, and testing is where I put the most care: every one ships with a suite that fakes the systems it depends on, pins down past bugs and proves who can reach what.
Lead engineer • 2020 to present
Council Waste Portals
Resident self-service for UK local authorities
Self-service waste portals for multiple UK councils, each a Laravel application integrated with the back-office waste management platform over its API. Together they serve millions of residents.
Laravel
JavaScript
REST APIs
Azure
Lead engineer • Client portal
Commercial Waste Customer Portal
Over 1,100 PHPUnit tests and 88 Playwright tests
An account portal where a council's business customers manage their sites, contacts, orders and documents. The Playwright suite drives a real browser against the test environment in phases: one saved login, read-only checks in parallel, then write and session tests in series, with anything that creates real data kept behind an opt-in flag.
Laravel
PHPUnit
Playwright
Azure
Lead engineer • Client portal
Subcontractor Portal
Tested at every level, from unit to load
Subcontractors browse and bid on available work, submit completed jobs with photos, and manage pricing, documents and users across four roles. Over 500 PHPUnit tests fake every external API call and assert on call counts and payload shapes, backed by a route-by-role access matrix, Dusk browser tests, Playwright end-to-end checks and k6 load-test journeys.
Laravel
PHPUnit
Dusk
Playwright
k6
GitHub Actions
Internal tool • 2022 to present
Portal Extension
A Chrome extension my team uses every day
Published on the Chrome Web Store and now at version 2.5. A popup lists 19 portals with their test and live links, versions and hosting details. On the portals themselves it labels which environment you are in, autofills test forms and payment pages, and remembers the properties you have looked up. On the service desk it opens a whole list of tickets in background tabs with one click. I moved it to Manifest V3 and refactored it so adding a portal is one config entry.
JavaScript
Chrome Extension
Manifest V3
Maintainer • 2020 to present
Inherited .NET Council Site
Picking up someone else's codebase
A public waste site for a council, written in C# on ASP.NET MVC by developers who had since moved on. I took it over and keep it running: tracing a live bug where requests were being logged against the wrong property and patching it in a shared base controller, removing retired features, and shipping versioned releases through the existing build pipeline.
C#
ASP.NET MVC
.NET Framework
SOAP
Sole owner • 2025 to 2026
Collection Dates API
From a client's question to a live service, handled end to end
It started as a question: could a council's website show residents a full year of collection dates? The existing integration only returned the last and next collection, so new subscribers had to be loaded by hand and often missed their first one. Rather than wait for a change to the core product, I proposed a standalone API and took it the whole way. I ran the scoping call with the client, the council and their web supplier, wrote the specification with example requests and responses, broke the work into an itemised estimate, and quoted both the build and the monthly running cost.
Then I built it. Given a property reference and a date range, it queries the back-office waste platform over SOAP and returns clean JSON: each collection with its original date, any rescheduled date and a bank holiday flag. Requests are strictly validated, authenticated by a key in the header, and rate limited per caller and per property. I deployed it to Azure Functions and delivered it with client-facing API documentation, Application Insights logging and 50 scripted test cases covering success, failure and edge conditions.
Node.js
Azure Functions
SOAP
Application Insights
Lead engineer • Client portal
Self-Service Admin Panel
Client staff change the portal without a developer
A super-admin area built into a customer portal so the client's own staff can run it themselves. They switch tabs and services on or off globally or per customer, schedule bilingual banners aimed at everyone, one customer type or named accounts, edit translations, manage help videos, and export settings from one environment to import into another. Every change lands in an audit trail with before and after values, alongside a system health page, a log viewer and a test runner that streams results in the browser. Its switches are a ceiling, not a floor: off removes a feature for everyone, on still leaves the role checks in place.
Laravel
Feature Flags
Role-Based Access
Audit Logging
Internal tool • 2026
Ticket & Quote Tracker
A dashboard for my team's workload
Syncs open tickets and their quotes from the company service desk into a local dashboard, then tracks approved, issued and used days per ticket, separates recurring and pre-sales work, and exports a categorised PDF report.
Laravel 13
SQLite
DomPDF