Skip to main content
All projects

Case study

Role
Full-stack Web Developer
Organisation
Greggs PLC

Greggs Website

greggs.co.uk, the brand's main digital touchpoint. Click & Collect ordering, digital gift cards, menu and allergen information, account management, a store locator, promotions, careers and investor information, plus integrations with third-party delivery services. Content is editorially managed, so most of the page you see is composed by the brand team rather than written in code.

Greggs Website, Greggs PLC

01 / Overview

What I did.

I worked across the stack. I led the implementation of secure mobile number change in .NET, with policy-driven validation on the server, and integrated Zendesk so support requests landed in a real queue. I improved the News section with pagination that remembers where you were, refined the digital gift card journey, fixed browser-specific failures such as video playback in Firefox, built a dynamic Greggs Foundation form with Power Automate, and contributed to a run of accessibility work that took the score from 72% to 82%.

02 / Architecture

Layers listed outermost first.

How it's put together.

A Nuxt front end over a headless CMS, with .NET services behind it for anything transactional or account-related. The dividing line is ownership: if the brand team should be able to change it without a deploy, it lives in the CMS; if it touches an account, an order or money, it lives in a service.

  1. Content

    Pages the brand team owns.

    Storyblok holds the composable content: campaigns, menu pages, promotions, editorial. Front-end components are written to render whatever an editor assembles, not one fixed page shape.

    • Storyblok
    • CMS
  2. Application

    Rendering and client state.

    Nuxt with Vue and TypeScript, server-rendered for pages that need to be indexable and fast on first load. Pinia holds client state such as the basket and account context.

    • Nuxt
    • Vue.js
    • TypeScript
    • Pinia
  3. Presentation

    A consistent visual system.

    Tailwind for styling with components documented in Storybook, so the same button behaves the same way in a campaign page as in checkout.

    • Tailwind
    • Storybook
  4. Services

    Accounts, orders and anything sensitive.

    .NET services covering account management, Click & Collect and gift cards. The secure mobile number change lives here, with its validation policy enforced server-side.

    • .NET
    • C#
  5. Integrations

    Work that belongs to somebody else's system.

    Zendesk for customer support, third-party delivery platforms for fulfilment, and Power Automate for internal forms such as the Greggs Foundation submission.

    • Zendesk
    • Power Automate
  6. Testing

    Confidence at two levels.

    Vitest for unit coverage on logic and Cypress for the journeys that actually earn money: Click & Collect, gift cards, account changes.

    • Vitest
    • Cypress

03 / Decisions

Each of these had a credible alternative. The trade-off is stated, not hidden.

Choices, and what they cost.

  1. Server-side policy validation for the mobile number change

    Chose
    Validation and the change policy enforced in the .NET service, with the client mirroring it only for feedback
    Instead of
    • Client-side validation with the service trusting the request
    • A generic account-update endpoint with rules in the caller
    Why
    A mobile number is a recovery channel and a route to an account takeover. Anything enforced only in the browser is advisory, because the request can be made without the browser. Putting the policy in the service means the rule holds regardless of what calls it, and the client-side copy exists purely so the customer gets an immediate message instead of a round trip.
    Trade-off
    The rule is expressed in two places, so they can drift. The service is authoritative, which means a drift shows up as a confusing client message rather than as a security hole. An acceptable failure mode, but still a cost.
  2. Headless CMS rather than developer-owned pages

    Chose
    Storyblok composing pages from front-end components
    Instead of
    • Hard-coded pages released with the application
    • A traditional coupled CMS owning templates and rendering
    Why
    The brand and marketing teams change campaigns far more often than engineers change code. Coupling those two release cadences makes engineers a bottleneck for a poster. Keeping rendering in the application and composition in the CMS lets each side move at its own speed.
    Trade-off
    Components have to survive arbitrary composition: any block in any order, with fields an editor might leave empty. That is meaningfully more defensive work than rendering a page you designed yourself.
  3. Pagination with return-to-article on News, not infinite scroll

    Chose
    Explicit pages that restore your position when you come back
    Instead of
    • Infinite scroll
    • A load-more button
    Why
    Infinite scroll breaks the things people actually do with an article list: link to it, use the back button, and reach the footer. It is also hostile to keyboard and screen-reader users, who have no cheap way to skip an endlessly growing list. Real pages are linkable and finite, and remembering the scroll position on return removes the only advantage infinite scroll had.
    Trade-off
    The position has to be preserved and restored deliberately, including across a browser back navigation. That is more state to manage than a list that simply keeps growing.
  4. Zendesk instead of a bespoke support tool

    Chose
    Integrating the existing support platform
    Instead of
    • Building ticketing and triage into the website
    • Email-only contact forms
    Why
    The support team already had a workflow, an SLA and reporting. Building a second inbox inside the website would have meant reimplementing all of that badly, and split the queue in two. Integration put website contact into the same pipeline the rest of support already used.
    Trade-off
    A third-party dependency in a customer-facing path, and customer data flowing to another system, both of which have to be handled explicitly rather than assumed.

04 / Stack

Grouped by the job they do rather than listed as a keyword run.

Technologies.

Front end
  • Vue.js
  • Nuxt
  • TypeScript
  • Tailwind
  • Pinia
Back end
  • .NET
  • C#
Content
  • Storyblok
Testing
  • Cypress
  • Vitest
  • Storybook
Integrations
  • Zendesk
  • Power Automate
  • Axios
Delivery
  • Azure DevOps

06 / Outcome

Where it landed.

Accessibility improved from 72% to 82%. The secure account change and the Zendesk integration together cut the manual handling behind support requests, and the News and gift card refinements addressed the sections where customers were most often getting lost. The Firefox video fix removed a failure that had been silently affecting a whole browser's worth of visitors.