PHP 8.2 (OOP, PDO) · MySQL · JavaScript · Chart.js
WebAudit: accessibility auditing tool
Enter a public web address and WebAudit runs 15 automated WCAG 2.1 AA checks, explains each issue with the offending HTML and a fix, scores the page out of 100 and tracks the score over time.

The problem
Accessibility reports are often long lists of errors. Developers struggle to see what matters most, so serious problems stay unfixed.
What I built
An object-oriented PHP audit engine using DOMDocument and XPath, a JSON API, and a six-table MySQL schema with foreign keys. Every query that uses input is a prepared statement.
A decision I made
Because the tool fetches any address a user types, I protected it against server-side request forgery: only public http and https addresses are allowed, private ranges are blocked, and every redirect is checked again.
What I learnt
Auditing my own React app gave a perfect score, because the crawler only sees the empty root element before JavaScript runs. I documented the limitation and planned a warning for JavaScript-rendered pages.
SvelteKit · Svelte 5 · TypeScript · MapLibre GL JS · Tailwind CSS · Vitest
North East Places: accessible map
An interactive map of towns across North East England, with a searchable list beside it. Selecting a place in the list flies the map to it, and clicking a marker highlights it in the list.

The problem
Interactive maps are hard or impossible to use with a keyboard or a screen reader, so the information on them is often out of reach for the people who need it most.
What I built
A SvelteKit app using Svelte 5 runes. One piece of shared state keeps the MapLibre map and the place list in sync in both directions, and a search filters the list by town or county. The search logic is a separate function covered by five Vitest unit tests.
A decision I made
I built the list as the accessible alternative to the map, not an afterthought: real buttons with aria-pressed, a labelled search box, and a results count that screen readers announce as you type.
What I learnt
The map worked in development but its tiles were blank in production. I traced it to MapLibre's background worker, whose path broke when the build bundled the library, and fixed it by importing the worker as a URL. Now I always check a production build locally before deploying.
PHP · MySQL · JavaScript · HTML · CSS
Padfect Store: gaming e-commerce platform
My highest-scoring MSc project: an online shop where gamers can browse and buy gaming accessories, with customer accounts, live search, a cart, checkout and an admin dashboard for managing orders.

The problem
Gamers needed one place to find accessories, compare them and buy them, and the shop needed a simple way to manage orders.
What I built
A full-stack PHP application with sign-up and login using hashed passwords, separate session-based access for customers and admins, and a six-table MySQL database (users, admins, products, cart, orders and order items) queried with joins.
A decision I made
I made the PHP endpoints return JSON, so JavaScript could update the search results and cart without reloading the page, and I used prepared statements for every query that takes user input.
What I learnt
Looking back, the white tagline over a busy hero photo does not meet colour contrast requirements. Since specialising in accessibility, I check contrast while designing rather than after.
React · Tailwind CSS · Node.js · Express · MongoDB · Vercel
Infinisculpt: booking platform for a local business
A full website and booking system I built, unpaid, for a local beauty business, so customers could choose a treatment and book a time online.

The problem
The business needed customers to book treatments online without the risk of two people booking the same slot.
What I built
A five-step booking journey backed by a REST API, with an admin area secured by bcrypt and JWT, a CORS allowlist, a health-check route and clear error responses.
A decision I made
I generated the available slots and checked for overlaps on the server, not in the browser, so double bookings could not happen even if two customers booked at the same moment.
What I learnt
Working for a real client taught me to turn their needs into features and to keep the booking journey simple for customers on their phones.
Next.js · TypeScript · Tailwind CSS · Jest · GitHub Actions
Foodash: delivery app for corner shops (in progress)
A delivery app for local corner shops, which I'm building the way a professional team would: planned on a Jira board, with unit tests and a CI pipeline from the start.
The problem
Local corner shops rarely have a simple way to take orders for delivery, so customers go to larger chains instead.
What I built
So far: postcode validation covered by Jest unit tests, and a GitHub Actions pipeline with branch protection and preview deployments.
A decision I made
I set up testing and continuous integration before building features, so every change is checked automatically from the first commit.
What I learnt
Planning work in sprints on a Jira board has helped me break a large app into small, testable pieces.