
devlog 0 building a saas
/ 4 min read
Table of Contents
I made a few bucks on a freelance project recently. On these platforms, you rarely get your money as soon as you complete the gig. So, awaiting my payoff, I was wondering what am I going to buy. As I said, it wasn’t a lot, so I couldn’t afford something very “useful”. And, it hit me. I’m going to work that hard, and spent all the money I made, and work that hard again… You see where I’m going. As I was thinking about investing, I told myself, why not building a SaaS. SaaS stands for Software as a Service, it’s a kind of subscription you pay to use a software, it’s opposed to lifetime licenses, where, when you pay, the software is yours for life.

With freelancing, I’ll always have to put in a lot of work to earn the relatively same amount of money. Otherwise, with a SaaS, I’ll put a lot of effort upfront and relax later.
First question, what am I going to build? I thought about an old Flutter app I coded a long time ago. It’s a quote management app called Meditations1. I really wanted to add a bunch of exciting features like !@#$%^&
, but never got time (and motivation) to do so. Now, money will be the motivation 😅. A project? Got it. What’s next?
Simply put, the first feature I’m going to ship is quote syncing. To do so, I need a backend and a database to store the user’s quotes. Am I going to code a backend? No! I’m going to use PocketBase2. PocketBase is an open source backend. It lets you create a data model in a UI and generate API endpoints for you. It uses SQLite to persist data (I know, when you think of a database, SQLite isn’t the first option you might think of, but I don’t except my app get a billion concurrent requests anytime soon).
Pros | Cons |
---|---|
API, auth and a nice dashboard out of the box | Still under active development |
Lightweight | Doesn’t scale horizontally |
Pros and cons of using PocketBase.
After not having to code a backend, I decided to add an API management solution called Kong3. I wanted the following features: rate limiting and caching. It was mandatory for me. If my app is going into the wild, I want it to be prepared for that. I designed the following architecture:

Desired backend architecture.
The backend will be connected to Kong and the latter will be reverse-proxied by Caddy (precisely caddy-gen4, a great Docker image that automate caddy for Docker containers). Then, I started playing with the Kong Docker image. First disappointment: it needs Postgres or Cassandra (a column-oriented database) to run. Quickly got over it after digging into the docs and discovered the db-less mode. After spending many hours tweaking my docker-compose.yml
, I found successively that the Kong Manager (their GUI admin dashboard) and rate limiting plugin wasn’t available for the open sourced version. Just at this time, I wondered why I’m not using Traefik5 (Traefik is reverse proxy with automatic HTTPS like Caddy). Back in the day, I struggled to configure Traefik, this is why I switched to Caddy and was using it everywhere. But, I got Traefik to work not so long ago, therefor I checked it out, and it had all the Kong features I wanted, plus a very nice dashboard 😉.

Traefik dashboard.
Finally, I got this architecture6:

Actual backend architecture.
Once my setup was working on localhost
, I had to make it available through the Internet. I spun up my infrastructure with Terraform7 and Ansible8 on GCP9. Spent like two days on this, writing IaC10. Now that I have my backend up and running, it’s time to dust off the mobile app. See you in the next one 😉

At least I haven’t failed 😅
Footnotes
-
Terraform lets you describe and deploy (also called provisioning) cloud infrastructure with code. ↩
-
Ansible automate server configuration (system updates, install software, and more) with files called “playbooks”. ↩
-
Google Cloud Platform (GCP) is Google cloud computing offering. It’s Google equivalent of AWS and Azure. ↩
-
Infrastructure as Code (IaC) consists of managing and deploying infrastructure (aka servers, load balancers, etc.) through code instead of doing it manually through provider UI. ↩