DIBS ON STUFF
The Brave Little CRM:
A Cautionary Tale
Hand-written by Alex Lance, 1st September 2025
A Cautionary Tale
Hand-written by Alex Lance, 1st September 2025

Well, what a colossal waste of time. I don't regret a minute of it.
We have enough paying customers now for Dibs On Stuff that I went ahead and put together the world's jankiest customer relationship management system.
It is comprised of:
I named it DirtyCRM as it was meant to be quick and dirty, and it lives over here: https://github.com/alexlance/dirtycrm
But beware, for it shall bring shame upon you!
We have enough paying customers now for Dibs On Stuff that I went ahead and put together the world's jankiest customer relationship management system.
It is comprised of:
- an Sqlite database file that lives in a private S3 bucket
- a text-based UI written in python
- a webhook receiver for Stripe's payment notification system
- and the last skerricks of my dignity
I named it DirtyCRM as it was meant to be quick and dirty, and it lives over here: https://github.com/alexlance/dirtycrm
But beware, for it shall bring shame upon you!
So why do this?
... I asked myself.
It's 4pm on a warm Saturday afternoon, I am sure the sun is shining and that there are people "out there" frolicking. My fingers race over the keys, making up stuff as I go - this was shortly before "vibe coding" (aka "creating technical debt") went mainstream. There is a glaring question upon my brow: why not just use one of the other CRMs?
Well, because. Why does anyone build anything? And there's just so much chaff. Who can be arsed going through them all? Also because:
There's a lot of sentences starting with "I" in that list. As my uncle once said rather scathingly, "it seems like you're becoming a bit of an eye-expert". Ho ho. The things that live rent free, but I digress!
It's 4pm on a warm Saturday afternoon, I am sure the sun is shining and that there are people "out there" frolicking. My fingers race over the keys, making up stuff as I go - this was shortly before "vibe coding" (aka "creating technical debt") went mainstream. There is a glaring question upon my brow: why not just use one of the other CRMs?
Well, because. Why does anyone build anything? And there's just so much chaff. Who can be arsed going through them all? Also because:
- I have trust issues with mischievous software
- I wanted something that I could run on a tiny mail server that contained basically zero risk to the server's security
- I wanted something that could be accessed from other systems without exposing new endpoints (customer database leaks get the special level of hell)
- and I wanted something that could be used by Stripe's webhook event notification system, to auto-update payment info for client subscriptions
There's a lot of sentences starting with "I" in that list. As my uncle once said rather scathingly, "it seems like you're becoming a bit of an eye-expert". Ho ho. The things that live rent free, but I digress!
So with an onion on my belt...
I created a four table database. I chose Postgres initially because it
will forever be in my heart (if Postgres were standing on the prow
of the Titanic, I would stand proudly behind that database and proclaim a most
manly and enthusiastic affection).
But really, I wanted my mail server to be doing less, not running postgres. And if I wanted other systems to update DirtyCRM, then they would need to somehow access that server.
Which "Eye" Did Not Want.
But if the database was an Sqlite file that sat in an S3 bucket, well then any system that can get to the S3 bucket, can also work with the CRM. My lambda functions. My terminal. My mail server. (Worth noting that I ended up piecing together a locking mechanism to avoid contentious writes, and that it makes me feel a bit gross).
Undaunted, I pivoted, changed the schema from Postgres to Sqlite, converted the data and apt-purged postgres from the little server that couldn't.
Gotta say, it is possible to regret both nothing and everything all at once. Contradictions arrive in pairs.
Regret nothing: because holy shit what an age we live in. Need a tool? It's out there. And if it ain't right? Build it yourself.
And regret everything: because are we really drowning in tens of thousands of client interactions and payments? Well, no. It may not have been the best use of my time. But we have crossed the milestone of several hundred clients, and my "keep all the clients in a vim buffer" system was starting to raise eyebrows.
But really, I wanted my mail server to be doing less, not running postgres. And if I wanted other systems to update DirtyCRM, then they would need to somehow access that server.
Which "Eye" Did Not Want.
But if the database was an Sqlite file that sat in an S3 bucket, well then any system that can get to the S3 bucket, can also work with the CRM. My lambda functions. My terminal. My mail server. (Worth noting that I ended up piecing together a locking mechanism to avoid contentious writes, and that it makes me feel a bit gross).
Undaunted, I pivoted, changed the schema from Postgres to Sqlite, converted the data and apt-purged postgres from the little server that couldn't.
Gotta say, it is possible to regret both nothing and everything all at once. Contradictions arrive in pairs.
Regret nothing: because holy shit what an age we live in. Need a tool? It's out there. And if it ain't right? Build it yourself.
And regret everything: because are we really drowning in tens of thousands of client interactions and payments? Well, no. It may not have been the best use of my time. But we have crossed the milestone of several hundred clients, and my "keep all the clients in a vim buffer" system was starting to raise eyebrows.
Four tables, that doesn't seem like very many tables
The rather unexciting Sqlite database consists of four brave little toasters, er, tables:
And once there's data in them you can do some rather neat queries to get at-a-glance customer summaries, that'll also help you spot missed payments.
- client: for the organizations and their subscription plan info
- contact: for all the contacts and what their role is, eg "payer"
- payment: for subscription and payment information from Stripe's webhook
- event: for all sorts of client interaction, so that no conversation or issue gets left behind
And once there's data in them you can do some rather neat queries to get at-a-glance customer summaries, that'll also help you spot missed payments.
Stripe payment notifications
The stripe side of the system is a big part of why this thing exists.
It allows the customer's account to proceed with the advanced Dibs features
as soon as the CRM receives the Stripe webhook event.
Some days Dibs requires a twelve hour work day, some days you kind of toodle around and play the 10 by 10 game too much (thank me later) as your database gets quietly updated by other automated systems.
Some days Dibs requires a twelve hour work day, some days you kind of toodle around and play the 10 by 10 game too much (thank me later) as your database gets quietly updated by other automated systems.
"My name's Alex and I've been creating unnecessary things for far too long."
One of those things was Dibs On Stuff, and it unexpectedly seems to be
popular with dev teams for taking turns with staging servers. You should adopt
it for your team. Don't use DirtyCRM for anything however, it is not unlike a
bag of um, lego that someone has dumped on your doorstep in the dark hours of a
long Saturday night.
And if you're ever building something and the voices are telling you to stop, it's probably best just to pack it in and call it a night. They're right. But also, you shouldn't be hearing voices. That's not normal. Go to bed.
< Home
And if you're ever building something and the voices are telling you to stop, it's probably best just to pack it in and call it a night. They're right. But also, you shouldn't be hearing voices. That's not normal. Go to bed.
< Home