My own product · 2026 to now
PumpkinPatch
A multi-tenant SaaS that gives a small company one login for three things at once: the public website they can edit themselves, the customers and conversations behind it, and the quotes, orders, invoices and stock underneath that.
C# · .NET 10 · EF Core · PostgreSQL · Astro · React 19 · TypeScript · MUI · TanStack Router and Query · Zod · Supabase · Cloudflare Workers · QuestPDF · TipTap
The shape of it
Four pieces against one API. Per-tenant public sites built with Astro and resolved by hostname. A React and MUI back office on TanStack Router covering all three pillars plus the provider side. A .NET 10 API split into six layered projects, with thirty-six controllers, forty-nine services and its own reporting library. And a set of per-tenant template packages that define what any of it is allowed to contain.
Auth, storage and Postgres come from Supabase, each behind an interface so the provider is swappable, and the API client the admin and the sites both consume is generated from the OpenAPI document rather than written twice.
A CMS where the shape is code
A tenant's template package is the single source of truth for their content: a registry of content types, each one a Zod schema, plus the image slots each type has, with how many are allowed and which aspect ratios the site crops them to.
The admin renders its editing forms straight off those schemas, and the site reads the same registry, so adding a content type in one place makes it editable and renderable at once. Images carry a focal point the editor drags around, and every crop on the site reflows to keep it. The API stores content as opaque JSON and never needs to know the shape at all.
Above that sits a slot registry, which is the part I am happiest with. Content types define shape, slots define placement: which editable region sits on which page, bound to a single row or a whole collection, sometimes feeding several regions from one row. Rendering a field through the slot helper tags the markup automatically, which is what makes live preview work without anyone maintaining a second list of what is editable where.
Site images are optimised at build time rather than hot-linked at runtime, so a deployed site serves its own bytes and only touches storage while it is building.
CRM and ledger
The CRM side holds customers, contacts and email threads in both directions. Inbound replies arrive through a Cloudflare Worker on the tenant's domain, which signs the message and hands it to the API so it lands on the right conversation.
The ERP side runs quotes through to orders, invoices, payments and credit notes, on a real double-entry general ledger with a chart of accounts, journal entries, a trial balance and receivable and payable ageing. State changes go through small hand-written state machines that expose the permitted transitions in the response, so the interface never hardcodes the rules. Documents render out of a separate library that has a one-way dependency and never touches a database entity.
Keeping tenants apart
Isolation is enforced in the application layer through EF query filters rather than in the database, so there is one place to audit and one place it can go wrong, with two explicit and deliberately awkward escape hatches for the provider side. An interceptor stamps the tenant on write, so it is not something a service has to remember.
Where it stands
Live and in use by paying tenants since mid 2026. Releases go out with notes written in plain language for the people using it rather than for me, and the test suite is weighted towards the ledger and the money edge cases.