Work · Custom Web Development · Build
Custom Web DevelopmentBuildNext.jsSubscriptionsMigrationEcommerceSEOAustralia

FleaMail

FleaMail posts vet-customised flea, tick and worm treatment to Australian pet owners every month, and ran the whole subscription business on WordPress, WooCommerce and a stack of plugins. We rebuilt it as one custom platform — Next.js, TypeScript and MySQL — with every customer, pet, subscription and order migrated and reconciled to the cent against the old system before anything is switched over.

Client
Fleamail · Australia
Industry
Subscription ecommerce · Pet health
FleaMail

The brief

Replace WordPress, WooCommerce and a stack of plugins with one platform — without losing a record, a renewal or a ranking.

A subscription business is only as good as its renewals, and FleaMail's ran through WooCommerce Subscriptions, two payment gateways, a treatment-code system built out of custom fields, and enough plugins that nobody could say with confidence what any one of them did. Every piece worked. Together they were slow, hard to change, and impossible to reason about — and the thing a re-platform most often breaks is the one thing this business cannot afford to break: the monthly charge that turns a customer into a customer next month.

The constraints were stated before any code was written, and they were absolute. Zero data loss: every customer, pet, subscription, order, line item, address and refund had to come across. Zero billing disruption: existing customers could not be asked to re-enter a card, and nobody could be charged twice or not at all. Zero SEO regression: years of articles about ticks, fleas and cane toads rank in Australian search and bring in most of the new customers, and a re-platform is the classic way to lose that overnight.

Then there is the product itself, which is more specific than it looks. The right treatment depends on the species, the weight and where in Australia the pet lives — paralysis tick country is not the same as Hobart — so the plan a customer is sold is decided by a postcode and a lookup table, and the pack that goes in the envelope by a treatment code the business has refined for years. None of that could be approximated.

The build

We built the replacement as a single Next.js 16 application on TypeScript, Prisma and MySQL: 55 data models, the public site, a customer account area, checkout, a 50-screen admin and a versioned API for a new Flutter mobile app. It was built from FleaMail's own design system — warm cream, coral for action only, Australian spelling throughout — rather than a template.

The data came across from a read-only mirror of the production WordPress database, through idempotent migration scripts that can be re-run at any time without creating duplicates. A reconciliation gate compares the two systems and exits with an error on any mismatch in counts or monthly recurring revenue; it is the thing that decides whether cutover can happen, not a person's confidence. It earned its place early: the first pass imported order headers without their line items, addresses and refunds, and the original gate only checked header counts, so it passed. We tightened the gate to check every relationship, backfilled the missing records, and it now reconciles green to the cent.

Billing continuity is structural rather than hopeful. The new platform uses the same Stripe and PayPal merchant accounts, so every stored customer and subscription reference carries over and nobody re-enters a card. Customers log in with their existing WordPress password, which is verified against the old hash and upgraded to bcrypt on first login. Webhook handling is idempotent, so a payment event delivered twice is processed once. And the whole platform runs in a shadow mode first: it receives the same payment events as the live site and applies them, but sends no email and charges nobody, while a nightly drift report compares it to WordPress subscription by subscription.

The treatment logic was carried across verbatim. The feline, canine and worming lookup tables are seeded from the business's own data and editable in the admin; the code is a pure lookup, and where a record has no code the platform shows none rather than generating one. Postcode decides the parasite tier, weight and species decide the product.

For search, we audited every URL that had earned traffic in the previous twelve months — 227 of them — and found that 118 would have returned a 404 on the new platform, almost all old WooCommerce product pages and WordPress archives. Each now has a 301 to its closest live equivalent, managed from a redirect table in the admin rather than hard-coded, alongside the migrated Yoast titles and descriptions, the 92 blog posts, structured data on every article and plan, and a 404 monitor for the weeks after launch.

The new platform is built and reconciling. Cutover follows the written runbook: a parallel run of at least four weeks with a clean drift report, a freeze on the old checkout, a final sync, the reconciliation gate, and only then the payment webhooks and DNS — with WordPress kept read-only for ninety days as a fallback.

Architecture

One application where there were a dozen plugins.

Public site, account area, checkout, admin and a mobile API share one codebase and one database — so a subscription means the same thing everywhere it appears.

1
Storefront + account
Next.js 16 · React 19
Plan builder, checkout, self-service
→
2
Billing
Stripe · PayPal
Same merchant accounts, idempotent webhooks
→
3
Admin
50 screens · RBAC
Subscriptions, fulfilment, treatment codes
→
4
Mobile API
/api/mobile/v1
Token auth for the Flutter app
→
5
Migration
Mirror → Prisma
Idempotent, gated by reconciliation

Build timeline

Built in the order the risk demanded.

01

Data first

Read-only mirror, migration scripts and the reconciliation gate — before any screen.

● Done
02

Commerce core

Checkout, subscriptions, renewals, treatment codes, WordPress password carry-over.

● Done
03

Admin + CMS

Customer, subscription and fulfilment management; blog, pages, redirects.

● Done
04

App + marketing

Mobile API for Flutter; GA4 and Meta purchase events sent server-side; Merchant feed.

● Done
05

Shadow run → cutover

Parallel run with a nightly drift report, then the runbook.

● Next

Read from the codebase · 27 Sep 2026

By the numbers.

55
Data models
50
Admin screens
78
API routes
118
of 227 ranking URLs redirected

Tech we used

A small stack.

Application
Next.js 16React 19TypeScriptTailwind v4
Data
MySQLPrisma55 models
Payments + email
StripePayPalBrevo
Mobile
FlutterVersioned REST API
Search
301 mapYoast meta migratedStructured data

Outgrown WordPress?

Free 30-minute call — we'll read your stack and tell you whether it needs a rebuild at all.

Trusted by teams like yours