Case study · Printfection · 2025 — today

We inherited a PHP 5.5 platform with no tests. Five months later its customers had their own branded stores.

Printfection runs swag programs for companies: inventory, kitting, fulfilment and shipping. When we took over its technology in early 2025, customers were asking for the one thing it couldn’t do: let them open a branded company store. We built it as a new application that customers experience as part of the platform they already use.

Client
Printfection (now Swag Pro), a swag fulfilment platform
Industry
E-commerce · Promotional products
What we did
Platform ownership, company stores, design system, PHP 8.2 migration
Timeline
Ownership from early 2025; stores built Mar — Aug 2025
Company stores today, in Printfection’s new Swag Pro brand: build a store in ten steps, then shop it.
from first commit in March 2025 to stores in production in August
5 months
company stores created in the first year, 126 of them live
218
store orders, fulfilled by the existing operations
5,382
stores with more than one order
62

The problem

A missing product on a platform nobody wanted to touch

Printfection’s platform had grown since 2012 into seven PHP services, from the customer app and the operations back office to the public API, uploads and event processing. All of it ran on PHP 5.5, carried years of technical debt and had no test coverage.

Customers wanted company stores: a branded shop where employees, partners or fans pick their own swag, paid by them or covered by the company.

Building stores inside the old code would have been slow and risky, and rewriting the platform first would have delayed them by a long way. Meanwhile fulfilment and accounting, the most complex parts, already worked.

The decision

A new app, one experience

We built company stores as a separate application on a modern JavaScript stack and connected it to the PHP platform. Customers get a modern experience for creating, managing and shopping in stores; fulfilment and accounting keep running on the business logic that already worked.

The hard requirement was that it should never feel like two products. That took three pieces of engineering.

  1. Sign-inOne login across the old and new apps
  2. DesignOne component library for React and PHP pages
  3. DataEvents keep both databases in sync
The build · March — August 2025

Two apps that feel like one

01Single sign-on

Log in once

The new app trusts the platform’s existing session. When a customer moves from the dashboard into their stores, the new back end checks the session with the PHP app, creates or updates the user on its side and carries over their permissions, including whether their account includes stores. Nobody signs in twice.

02Design system

One component library for two front ends

We built a component library in React, documented in Storybook, and also compiled it into framework-free Web Components served from a CDN. The Next.js app uses the React components; the PHP pages drop in the same header, footer, buttons, alerts and popups as plain HTML tags.

Customers see the same navigation and controls everywhere, and a change to a component ships to both apps at once.

The existing PHP dashboard with the shared header, opening Stores from the Campaigns menu
The PHP dashboard, with the shared header
The new stores app showing store orders, with the same header and controls as the PHP dashboard
The new stores app: same header, same controls
03Event-driven sync

Loosely coupled, always in sync

The two apps don’t call each other’s databases. The PHP platform publishes versioned events over RabbitMQ whenever something changes: about 50 kinds, from products, kits and stock levels to orders, shipments and deliveries. The new app keeps its own copy of what it needs, so a storefront stays fast and up to date even when the legacy app is slow.

When a store order is placed, the new app hands it to the platform’s API, and it flows into the same fulfilment, warehouse and accounting processes as every other order.

04The product

Company stores

  • Store builder. Branding, categories, products and kits from the customer’s own inventory, with AI-assisted product descriptions.
  • Who can buy. Public or password-protected stores, vouchers, and shipping limited to chosen countries, with duties and taxes included if needed.
  • Who pays. Shoppers pay by card, or the company covers everything and prices and payment are switched off.
  • Storefronts. A modern, fast storefront for every store, with address validation at checkout and order emails.
Store builder: picking products from the customer’s inventory, with stock levels
Pick products from inventory
Store builder: brand colours, logo, hero text and image for the storefront
Brand the storefront
Store builder: creating a voucher with a usage limit and a dollar discount
Create vouchers
A branded storefront home page in preview mode
A branded storefront
Storefront product page with colour and size options
Product page
Storefront checkout with shipping, vouchers and card payment
Checkout

August 2025 · The outcome

Company stores, live in five months.

Customers create and run stores in a modern app that looks and feels like the rest of the platform. Store orders flow into the same fulfilment and accounting as everything else, with no changes to operations.

The first year

From launch to thousands of orders

By September 2026 customers had created 218 stores, and 126 of them were live. Order volume grew fastest once stores had time to catch on: from a few hundred orders by early 2026 to 5,382 by September, and 62 stores have received more than one order.

stores created
218
stores live
126
store orders
5,382
Meanwhile · 2025 — 2026

Modernising the core

05PHP 5.5 → 8.2

Moving a 13-year-old platform to modern PHP, one service at a time

Stores didn’t remove the need to fix the platform underneath. Alongside them we moved the PHP services from 5.5 to 8.2, one service at a time, each with its own test suite, including tests that replay real production requests, and a staging check before release.

By the end of 2026 all seven services, from the customer app and the operations back office to the public API and event processing, run on PHP 8.2. And every change to the platform now passes automated tests, with a coverage gate on the new code.

Looking back

What made it work

  1. 01

    Build next to the legacy, not inside it

    A new app shipped stores in months and left fulfilment and accounting, the parts that already worked, untouched.

  2. 02

    Make the seams invisible

    Shared sign-in and one component library meant customers never had to know there were two applications.

  3. 03

    Couple through events

    Syncing data through events kept the new app fast and independent, and let each side change without breaking the other.

Tech stack

Stores front endNext.jsReactTanStack QueryZustandTypeScript
Stores back endNestJSFastifyTypeORMMySQLRedisAuthorize.netSendGrid
IntegrationRabbitMQShared sessionsPlatform REST API
Design systemStorybookReactLit Web ComponentsVite
PlatformPHP 8.2KubernetesNew RelicAWS

Bring us
the hard part.

Complex platforms, overdue rewrites, agentic workflows. That’s the work we enjoy most.

Contact Us