Cyber maturity model
A cyber self-assessment for a global insurer, delivered three ways
A cyber maturity assessment shipped as a forty-question version on its own site, a ten-question version embeddable on the insurer's group sites, and the API serving both.
Role: Full-stack build across API, site and embeddable component
Details
- Questions, ratings and result copy are stored translated in the database across six locales, with the locale resolved per API request rather than per deployment.
- The short version ships as a Vue custom element, so it drops onto third-party pages with a script tag and two attributes and configures itself per integration from the API.
- The full site is statically generated per locale from the API's own locale list, with content-security-policy nonces injected at the web-server layer.
- Respondents verify their email with a throttled PIN before results are released.
2021–present
- Laravel
- PHP
- Nuxt
- Vue
- Web Components
- Pug
- Tailwind CSS
- PostgreSQL
Cyber risk research tool
An internal cyber risk research tool for a global insurer
Staff at the insurer search a domain and get a cyber risk report assembled from external intelligence sources, with company, user and export administration around it.
Role: Full-stack developer
Details
- Reports draw on BitSight, Shodan, Clearbit and BuiltWith, plus security ratings imported over Microsoft Graph, assembled in queued jobs and rendered to PDF through headless Chrome.
- Mandatory two-factor authentication with a configurable grace period, role-based permissions governing each export, and a token API for sibling services.
- Pulls data from two neighbouring products: maturity-assessment responses over that product's API, and security-training policy validations read from its database, so exports cover the whole product family.
- Grew out of an earlier single-page risk dashboard built in Vue in 2020, which covered the same domain lookup before the tool became a full application.
2020–present
- Laravel
- Livewire
- Alpine.js
- Tailwind CSS
- PostgreSQL
- Horizon
- Chart.js
- Puppeteer
- Vite
Cyber fusion portal
A service-request portal and content site for an insurer's cyber team
An authenticated portal where staff read the team's content and submit service requests, with that content managed inside the same application.
Role: Full-stack build
Details
- Single sign-on against the organisation's Microsoft Entra ID directory.
- Payload CMS on PostgreSQL inside the Next.js application, with collections for pages, services, requests and media, Azure Blob storage for uploads, and server-side video processing through ffmpeg.
- Request forms are rate-limited per user with lockout after repeated attempts, validated server-side and verified with reCAPTCHA before being forwarded to an internal endpoint.
- Integration tests in Vitest and end-to-end tests in Playwright; deployed as a standalone Docker image.
2025–present
- Next.js
- React
- TypeScript
- Payload CMS
- PostgreSQL
- NextAuth
- Tailwind CSS
- Docker
Art museum website
A London museum of modern art
The museum's public website, covering the collection, exhibitions, events and memberships, with content maintained by a small in-house team.
Role: Build and ongoing maintenance
Details
- Moved onto Statamic in 2016: content as flat files in Git, Antlers templates, maintained by a small in-house team through the control panel.
- A Statamic 5 rebuild was started in 2025, with static generation, Tailwind and Vite; the Statamic 2 site remains the live one.
2011–present · on Statamic since 2016
- Statamic
- Laravel
- Antlers
- Sass
- Gulp
Home builder brand network
Brand sites, a custom CMS and a shared API for a US manufactured-home builder
A network of brand sites drawing home models, retailers and communities from a single API, with the client's own editors maintaining content in a purpose-built CMS.
Role: Full-stack lead – architecture, build and ongoing evolution
Details
- Three tiers — a REST API over MongoDB, a browser CMS that writes to it, and the brand sites that read from it — so adding a brand meant adding a front end rather than duplicating content and business logic.
- The CMS uploads media straight from the browser to object storage, with cropping, galleries, and a field builder for each site's enquiry forms.
- Location search maps a visitor's postcode or IP address to nearby retailers and communities, and enquiries route to whichever CRM a given brand used.
2015–present
- Laravel
- Blade
- MongoDB
- AngularJS
- Gulp
- Cloudinary
- Redis
- AWS
AI-readiness assessment
A lead-generating AI-readiness assessment for a global digital-services firm
Visitors sign in with LinkedIn, confirm their company, and work through generated challenges and questions to a set of recommendations, which reaches the client as a qualified lead.
Role: Build – front end and serverless back end
Details
- Challenges, questions and recommendations are generated per respondent by a language model from prompt templates, with company context enriched from a third-party company-data provider.
- Sign-in with LinkedIn rather than a registration form, identifying respondents without a separate sign-up step.
- Serverless on Firebase Cloud Functions with Firestore, scaling with demand and incurring no cost while idle.
- Completed assessments write notes into HubSpot, and scheduled functions email generated PDF reports.
- Shipped twice from one codebase: under the client's own brand, and as a white-labelled variant whose recommendation prompts align to a cloud provider's products.
2023–2026
- React
- Vite
- Tailwind CSS
- Firebase
- Firestore
- OpenAI
- LinkedIn OAuth
- HubSpot
- SendGrid
Premium tea storefront
An online shop for a premium tea retailer
A custom Shopify theme covering the storefront from catalogue browsing through to checkout.
Role: Lead build
Details
- Built on a Vite and TypeScript pipeline rather than Shopify's default asset handling, keeping the storefront's own CSS and JavaScript small.
- Accessibility handled in the theme itself: semantic markup, keyboard-operable navigation and cart, live regions for cart and search updates, and visible focus states.
2023–2026 · rebuilt in 2025; theme since replaced
- Shopify
- Liquid
- TypeScript
- Vite
- Tailwind CSS
- Alpine.js
Reinsurance marketing site
A marketing site for a specialty broker's reinsurance business
A WordPress site for the reinsurance arm of a specialty insurance broker, composed by editors from blocks, with a searchable directory of the firm's people.
Role: Full-stack build
Details
- WordPress managed through Bedrock, keeping the site under version control and Composer dependency management.
- A Roots Sage theme rendering Gutenberg blocks through Blade, with each block packaged as its own must-use plugin so blocks can be shared between sibling sites.
- A people content type with country, expertise and job-role taxonomies, and a restricted editor role for the team who maintain it.
- Full-page caching at the web-server layer, with sitemap-driven cache warming after each publish.
2024–2026
- WordPress
- Bedrock
- Roots Sage
- Blade
- PHP
- Tailwind CSS
- Gutenberg
Shipping innovation centre site
The website for a global shipping company's innovation centre
The centre's public site, publishing its work and insights, with member registration and sections gated to approved members.
Role: Build and ongoing maintenance
Details
- Two applications over one database: Directus provides the editorial interface and owns the schema, while a Laravel front end reads its tables directly.
- Draft preview through token-verified routes, so editors review unpublished content on the real front end; publishing triggers a webhook that clears the front end's page cache.
- Member registration with email verification and manual approval, and per-block gating so individual sections of a page can be restricted.
2022–2025
- Laravel
- Livewire
- Alpine.js
- Tailwind CSS
- Directus
- PostgreSQL
Specialty broker marketing site
A marketing site for a specialty insurance broker
The broker's main site, on the WordPress foundation later reused for its reinsurance arm.
Role: Full-stack build
Details
- WordPress managed through Bedrock, with a Roots Sage theme rendering Gutenberg blocks through Blade.
2023–2024
- WordPress
- Bedrock
- Roots Sage
- Blade
- PHP
- Tailwind CSS
- Gutenberg
Community trust site
A site for an insurance broker group's charitable trust
A static site covering community grants, volunteering, match funding and charity partnerships, handed over as compiled pages and reusable modules.
Role: Front-end build
Details
- Built from Pug templates into static pages, with a build step that also emits each module as a standalone HTML file and syncs the output to a separate delivery repository for the client's integration.
2022–2023
- Pug
- Tailwind CSS
- Alpine.js
- Gulp
Broker group corporate site
Front-end modules for an insurance broker group, for integration into Umbraco
Around fifty front-end modules — business portfolio, financial results, leadership, announcements, media library — delivered as standalone HTML, CSS and JavaScript for the client's team to wire into their CMS.
Role: Lead front-end developer
Details
- Built from a design prototype into a Pug, Tailwind and Stylus component system, with each module emitted as its own HTML file so it could be mapped to an Umbraco document type independently of the others.
- Lottie animations and a responsive-image pipeline, served over local HTTPS in development to match the client's environment.
2021–2023
- Pug
- Tailwind CSS
- Stylus
- Alpine.js
- Lottie
- Gulp
Frontflow
The static-site toolchain behind the agency's front-end builds
An in-house build system for static marketing sites — Pug templates, Tailwind, Alpine and a Gulp pipeline — used as the starting point for client front ends.
Role: Author and maintainer
Details
- The resolved Tailwind config is passed into the templates, so breakpoints, spacing and container padding are read from one source rather than restated in markup.
- Images are generated in AVIF and WebP at five widths and two pixel densities, lossless for graphics and lossy for photographs. Sources are mirrored into a cache so only changed images are reprocessed, and derivatives whose source has gone are purged.
- Each image's
sizes attribute is computed from its layout — column span, grid columns, gutter, container padding, container width — resolved against the Tailwind breakpoints into calc() expressions per media query, so the browser picks a file from the grid description rather than a hand-written guess.
- SVG icons are parsed and rewritten as template mixins with
aria-hidden and focusable set and attributes passed through, so icons inline at the call site without a sprite sheet.
- A generate step renders every module as a standalone page alongside the site, producing a browsable catalogue for client handover and CMS integration.
2018–2022
- Pug
- Tailwind CSS
- Alpine.js
- Gulp
- PostCSS
Enterprise story microsite
A story-driven marketing microsite for a global technology company, built twice
A grid of short stories about the client's work in the UK, each with its own page and per-platform share pages. Built in 2018 with around eighty stories, then rebuilt in 2020 on a different stack.
Role: Front-end build
Details
- Statically generated into the client's own path structure and delivered as an archive for their deployment process, wrapped in their shared header and footer shell.
- The rebuild moved to the client's design-system web components alongside Pug and Tailwind, with build-time image optimisation.
- The first version predated widespread
:focus-within support and shipped a polyfill and a PostCSS transform to keep keyboard navigation working.
2018–2022
- Nuxt
- Vue
- Pug
- Tailwind CSS
- Nunjucks
- Sass
- Gulp
HTML email programme
Campaign and newsletter emails for enterprise clients
A long-running stream of campaign and newsletter email builds, mostly for one global technology client and occasionally for others, each produced from a shared template set.
Role: Front-end build
Details
- A Gulp pipeline with separate inline and embedded stylesheets, producing markup that renders consistently from Outlook 2007 through Gmail, iOS and Android.
- Each build tested against a fixed client matrix before delivery, with plain-text and Lotus Notes variants where the audience required them.
2012–2022
- Gulp
- Swig
- Sass
- HTML email
- Litmus
- AWS
Micro-fulfilment configurator
An interactive configurator for an intralogistics vendor
A lead-generation page where visitors answer questions about their operation and get a matched micro-fulfilment configuration.
Role: Front-end build
Details
- Delivered as static HTML injected at build time into a captured copy of the client's page shell, so it matched the surrounding site without access to their CMS.
- Lottie animations for the hero, loading and result states.
2020–2021