Back to the Blog
Essay

We Built Our Own Back Office. Here's What We Still Buy

We took our own advice and started replacing the SaaS back office with systems we own. The build, the two bugs testing caught, and what we keep paying for.

By Sean Gowing
Jul 25, 20266 min read

We spend a lot of time telling clients which of their tools to switch off. It would be a bit rich to say that while quietly paying eleven vendors ourselves, so this year we started taking our own advice, beginning with the least glamorous system a business owns. The books.

What follows is the honest version. What we're replacing, what we're deliberately still paying for, and the two bugs that would have shipped if we hadn't tested the boring parts.

CompanySocial Catnip, veteran-owned marketing engineering studio, Glenrock, Wyoming
Founded2016 · senior-only bench, 11-year average engineer tenure
ProjectReplace the SaaS back office with systems we own
StatusBack office live · ledger core shipped · accounting migration in progress

The situation

Our back office was the same accretion we diagnose in other people's stacks. Accounting in one platform, payments through that platform's processor, a CRM that was really an inbox, a scheduling tool, a forms handler, a portal that had been superseded but never turned off. Every one of those was a sensible decision on the Tuesday it happened.

The tell wasn't the invoices. It was that nobody could answer a simple question, which system is the source of truth for a client?, without qualifying the answer. When that question needs a qualifier you don't have a stack. You have a disagreement with a monthly bill attached.

The second tell was worse, and it's the kind of thing you only find when you go looking. Our own admin had an invoicing screen with a "Send invoice via Stripe" button. Clicking it showed a cheerful confirmation that a hosted invoice had been emailed to the customer. It hadn't. There was no Stripe integration behind it at all. No API key, no webhook, not even the library installed. The button wrote a row to a local database and then lied about it.

That had been sitting there, in our own software, telling us we'd billed people.

The task

Two decisions, and they pull in opposite directions.

What do we build? Not everything. That's how you end up maintaining a portfolio of bespoke systems nobody has time to patch, which is precisely the trap we tell clients to avoid. A small senior bench is a quality advantage and a capacity ceiling at the same time.

What do we keep buying, forever? This is the part most "build it in-house" stories skip, and it's the part that makes the rest credible.

The test we settled on: buy the things where being wrong is catastrophic and someone else has already absorbed that risk. Build the things where being wrong costs you a Tuesday afternoon.

Filing drawer with most folders removed, a few remaining squared neatly

The action

We built the back office. One application now carries the client CRM, the sales pipeline, the appointments calendar and dispatch board, email templates, visual trigger-and-wait automations, and a relationship CRM assembled automatically from ingested mail. It runs on a single small server against a single SQLite file. Genuinely boring infrastructure, which is the point, and the same approach we take to custom development for clients.

Contacts list in the back office, showing people auto-built from ingested email with company, message count and last contact date The relationship CRM. Contacts assemble themselves from mail. Nobody types these in, and every contact stays private to whoever holds the relationship unless it's explicitly shared.

Sales pipeline board with deals in New, Discovery, Proposal, Negotiation and Won columns The pipeline, sitting next to the mail it came from rather than in a separate tool.

Invoice list showing paid, open, overdue and draft invoices with amounts and due dates Invoicing. The screen that used to lie to us.

We built a real double-entry ledger. Not a transactions table with a status column. Accounts, journal entries, debits and credits, a trial balance that has to balance. Four rules enforced in code and again in the database itself:

  • Money is integer cents. Floating-point money accumulates error, and every payment processor speaks cents anyway.
  • Entries are append-only. A correction is a reversing entry, never an edit. This matters more than it sounds. An ACH payment can be returned days after it reports success, and an append-only ledger models that as a fifth event rather than an awkward undo.
  • Every entry balances, checked at write time.
  • Closed periods reject new entries, so numbers you've already filed cannot quietly change.

We picked ACH over cards, deliberately. The processor comparison everyone runs is card rate versus card rate, and it's the wrong comparison for a business that invoices in five figures. ACH direct debit is typically priced around 0.8% capped at a few dollars. Cards run near 2.9% plus a fixed fee. On a single $17,000 invoice that's roughly $494 against $5. Which processor you choose barely matters next to which payment method your clients actually use.

We wrote the tests first for the parts nobody enjoys. 136 automated assertions across the ledger, the permission gates, the CRM purge, and the alerting.

Accounting reports view with net income, sales, receivables and overdue tiles above a line chart of income, expenses and net by month, and a bar chart of net earnings Reporting off our own ledger. The screenshots throughout use sample data. The real book stays where it belongs.

The result

The back office is live. The ledger core is shipped and tested. The accounting migration is sequenced across a parallel run and a clean quarter boundary, because being mid-migration during year-end close is how you turn a project into an incident.

The honest headline result is what the tests caught before any of it touched real money.

A contra-account inversion. Refunds carry a debit balance, and the profit-and-loss calculation was summing every income line by its own natural direction. A refund was reading as positive revenue. Every refund would have inflated income, silently, from the first import.

A one-second blind spot. Database timestamps are second-granularity. Anything created in the same second someone clicked "mark all read" compared as not newer and was swallowed permanently. A lead could arrive and never once show as unread.

Neither is exotic. Both are the kind of defect that produces confidently wrong numbers for months. That's the actual argument for owning your core systems. Not that you'll write better software than a vendor, but that when the number is wrong you can open the file, find out why, and fix it that afternoon.

Heavy closed vault door, matte finish, shot straight on

What we're still buying, forever

Payment processing, because card data is a regulated liability and Stripe employs a compliance team larger than our whole company. Email deliverability, because you can build a sender but you cannot build a decade of IP reputation. Authentication. Anything with an annual filing obligation.

And we're keeping our accounting platform running in parallel until the last tax year filed from it is closed. Not because the ledger isn't ready, but because "ready" and "proven against a full quarter" are different words.

If your stack has grown past the point where anyone can explain it in one breath, the first conversation isn't a demo. It's a walk through what you're paying for and what you'd stop paying for. Let's map your stack, or if the interesting part for you is a model running on hardware you control, that's here.

Want this for your team?

Send us a brief and we'll come back with a fixed-price plan in 48 hours.