jedarlington
Blog

Treatdiary: turning a dog grooming app into one for clinics

October 20, 2026

Pawdiary was built for dog groomers. Over the last ten days it has also become Treatdiary, a booking and records app for aesthetics clinics. It isn’t a fork or a copy. It’s the same Vue app, the same Supabase database and the same edge functions, and the first Treatdiary commit went in on 10 October. Sign-up opened to any clinic on 18 October.

Running two products off one codebase sounded tidy. Mostly it has been, but the interesting part was everywhere the dog grooming kept leaking through.

A client is their own pet

The first decision was the data model. Everything in Pawdiary hangs off a pet: bookings, the rebook list, the waitlist, packages. In a clinic, the person being treated is the client. I could have rewritten all of that around clients, or I could cheat a bit.

I cheated. Each business now has a vertical column, either grooming or clinic, set once when it’s created. Every clinic client gets one hidden row in the pets table with a species of person:

alter table public.pets add constraint pets_species_check check (species in ('dog', 'cat', 'person'));
create unique index if not exists pets_one_self_per_client on public.pets (client_id) where species = 'person';

A trigger stops the two mixing, so grooming businesses only hold animals and clinics only hold those self rows. The upside is that bookings, rebooking, the waitlist and packages kept their pet_id and worked on day one without changes. The downside is a table called pets full of people, which I’m choosing not to think about too hard.

The address decides

Which product you see depends on where you are. If the hostname contains treatdiary, you get Treatdiary’s name, design, landing page and prices. Locally I add ?brand=treatdiary to any page and it sticks for that browser tab, which saves running two dev servers.

That rule had a gap. The clinic wording was switched on by checking whether the signed-in business was a clinic. When a grooming business opened app.treatdiary.com, it got Treatdiary’s branding with Pawdiary’s pet and groom wording underneath. The fix was a one-line change so clinic wording holds on any Treatdiary address, whatever business signs in. Related to that, logins now stay on the product you signed in on, instead of quietly bouncing grooming accounts back to Pawdiary.

Finding every dog

The longest job by far was the words. Pawdiary talks about pets, grooms, breeds, vaccinations, pick-ups and vans, and those words live in far more places than the screens. The big clean-up commit touched 62 files. Clinic businesses now see client, treatment, practitioner, clinic and car instead, across:

  • app screens and the client portal;
  • emails, texts and push notifications;
  • the prompts for the AI helpers;
  • calendar events synced to Google and Apple calendars.

The one I’m most glad I caught was the booking terms. Every new business was seeded with the grooming terms, so clinics were starting life with sections on vaccinations, matted coats and muzzles. New clinics now get terms written for an aesthetics clinic, and clinics that had never touched the grooming terms were moved over. Terms a client has already signed are never edited; a new version is added instead.

The bits that weren’t wording

A few things broke outright rather than just reading oddly. The edge functions only accepted cross-origin requests from Pawdiary’s addresses, so on Treatdiary the calendars, payments and other server calls simply failed. The treatdiary.com addresses are on the allowed list now.

The admin side got split too. Treatdiary’s admin panel only covers clinics and Pawdiary’s only covers grooming businesses, with each admin database function taking an optional vertical. New two-step login set-ups name the authenticator entry after the product, so you don’t end up with two identical “Pawdiary” codes on your phone.

Pricing is separate as well. Clinic plans are £29, £45 and £79 a month, or ten months’ worth for a year, billed through their own Stripe prices with no fallback to the groomers’ ones. I’d rather a misconfigured price fail loudly than charge a clinic a grooming rate.

What clinics get that groomers don’t

Sharing the engine meant most of the time went on things clinics actually need:

  • clinical records, with a face chart and clinical photos;
  • consent forms clients sign in the portal on their own phone, locked to that version of the form and recorded with the IP address and browser;
  • forms emailed to clients before a treatment, and aftercare after it;
  • stock tracked by batch and expiry, where recalled or out-of-date batches can’t be used, and the clinical team can list everyone treated from a batch by typing in the number from a recall notice.

Would I do it this way again?

Probably. One codebase means a fix to booking or payments lands in both products at once, and Treatdiary got all of Pawdiary’s plumbing for free. The cost is that every new feature now needs a moment’s thought about which product it’s for, and every bit of copy needs checking for a stray dog. I’ve already found enough of those to know there are more.