Yowzer Hub

A multi-tenant operations platform for sign manufacturers.

I designed it, built it, tested it and deployed it on my own. It is priced at £350 a month and going live with its first business.

The problem

A sign company runs on things nobody wrote down. An enquiry arrives by email, the quote gets built in someone's head from twenty years of knowing what vinyl costs, the follow-up happens if somebody remembers, and the booking lands on a whiteboard. When it works it is because one person is holding all of it. When that person is busy, ill, or gone, it stops.

Every CRM sold to these businesses answers this by asking them to type it all in. That is why none of them get used. The shop is already at capacity, the thing that is scarce is attention, and a CRM asks for more of it.

So the Hub is built the other way round. It reads the Xero and Dropbox the business already has, does the chasing, quoting and booking itself, and shows a human only what genuinely needs one. The record is a by-product of the work rather than a tax on it.

Three things that were genuinely hard

  1. Tenant isolation that survives my own mistakes

    This is one product sold to many competing businesses. A bug that shows one shop another shop's customers is not a bug, it is the end of the product. Enforcing that in application code means every future query is one forgotten where clause away from a breach.

    Isolation lives in Postgres, not in my code. Row-level security policies on every table, keyed to the tenant in the request's session, so a query that forgets its tenant returns nothing instead of returning everything. The application is not trusted to be careful.

    The interesting failure: Postgres refuses to use a non-leakproof function inside an index condition, which is exactly what a policy referencing session state looks like. Working out why an index was silently unused, then restructuring the policies so the planner would take them, was the difference between a correct system and a usable one.

  2. Moving a Next.js application onto Cloudflare Workers

    The product started on Vercel. Consolidating onto Cloudflare cut the hosting bill and put the app on the same platform as everything else I run, but Workers are not Node: there is no long-lived process, so the usual patterns quietly break.

    Rebuilt the deployment on OpenNext, then found and fixed the things that only fail in production. A Postgres client held as a module singleton works locally and fails in a Worker, so connections became per-request through Hyperdrive. Error reporting was loading a vendored wasm transformer at import time and hanging cold requests; it now initialises lazily, after the response path.

    The general lesson: the runtime you test on has to be the runtime you ship on, or you are only testing your assumptions.

  3. An AI agent people will actually let near their business

    The product is built to do real work on its own: reading enquiries, drafting quotes, chasing, scheduling. The hard part was never capability. It was that nobody hands their livelihood to something they cannot predict.

    Every workflow runs one pipeline, queue then retrieve, verify, route, and resolve or escalate to a human, so there is always a record of what was decided and why. Sixty-one tools sit behind it: forty-two only read, eleven write through a ledger where they can be undone, and eight are the owner's own controls.

    Anything customer-facing or money-touching ships switched off behind a fail-closed flag, where an absent or malformed value means off.

The product decision I got wrong first

I built it agent-first. The home screen told you what the AI had done, because that was the most interesting thing about the product and I wanted it visible.

It was the wrong call. A sign shop does not think in terms of what the assistant did today. It thinks about the week: what is going out, what is late, who is fitting what on Thursday. So the calendar became the product and the agent went quiet underneath it. It stopped narrating and started working.

Frontend
Next.js, React, TypeScript, server components
Data
Postgres on Supabase, row-level security, 44 migrations
Runtime
Cloudflare Workers via OpenNext, Hyperdrive, cron workers, host-based tenant routing
AI
Anthropic API, tool use, evaluation batteries in CI
Integrations
Xero, Dropbox, transactional email
Testing
Vitest, Playwright, accessibility and performance budgets on every push

The full repository is private because the product is commercial. Selected source is public, and I will walk through any part of it on a call.

Read: building an AI agent people will let near their business

Back to edwardradford.co.uk