Origins

Tech Stack behind a Modern SaaS

Introduction

ProAutoma is an API and Website monitoring and alerting SaaS.

A monitor is an API/HTTP call to a specific URL and success is a valid HTTP status code or a series of assertion tests on call latency and/or checks on response for specific words or structure.

Our Tech stack consists of a frontend and a multi-tenant backend with a database, all running in Cloud.

Frontend is a React webapp that enables users to define and schedule monitors, set up alerts, team members, create public status boards and configure the system.

Backend runs the monitors in defined intervals from one of many data centers around the world, sends failure alerts on email, Slack, MS teams etc. It also provides an API for the frontend and developers to configure the system and monitors.

Challenges faced:

Foundation

A fundamental decision in a tech stack is the language and ecosystem to use. Two fundamental concepts drove these decisions.

Statically Typed Language. A statically typed language could be thought of as a dynamically typed language such as JavaScript with a series of unit tests for input/output and validation of all data structures. And, you get all these unit tests for free if your code just compiles!

After 30 years of developing software, it is abundantly clear that a statically typed language is just superior in providing confidence that code runs as intended.

Strong ecosystem provides us with high quality software building blocks to solve most commonly faced problems. This enables us to spend the majority of our time on value-add and solving specific customer problems which differentiates us from competitors.

Isomorphic codebase In my opinion, a linchpin for productivity boon. This entails using the same language for both frontend and backend. This enables engineers to be full-stack and do so with minimal context switching.

ProAutoma chose TypeScript as the typed language across the stack and with associated Node.js ecosystem.

Frontend

ReactJS - We chose React for its pure JavaScript functional component model, hooks and excellent availability of high quality UI components and libraries.

Vite is a great choice as a frontend build tool due its sub-second build speed providing instant feedback essential for quick development.

React Query is an excellent library to manage network state on the client end.

React Hook Form simplifies form state management and validation.

Valtio is a simple reactive library to handle client side state management.

React also has a plethora of UI libraries and we chose Chakra UI for its ability to design our own custom look on top of quality, accessible components like buttons, accordions, dialogs etc.

Backend

Fastify - Fastify is fast and has an excellent plugin model and easy DSL for building REST APIs with validations. Combined with the pino logging library by the same author, TypeScript support and many other quality plugins, we are very happy with this choice.

DB access

While ORMs are a typical choice when communicating with a database, for us, it is not an ideal system. SQL is already a magnificent and time tested language and layering another ORM system felt like a leaky abstraction. Instead, we chose to build upon a query builder approach.

Kysely is a new entrant for a typed query builder library and we’re very happy to have found it.

Database

PostgreSQL - PostgreSQL is an excellent choice for a relational database. However, we chose PostgreSQL for its NoSQL capabilities. Certain features like alerts are inherently modeled as JSON documents and storing them in a SQL database as strings is just not ideal.

Postgres supports JSONB type to efficiently store and retrieve JSON. Now, we have an excellent SQL and NOSQL database.

DevOps

pnpm is not well-known but an awesome tool to replace npm, providing workspaces, fast package downloads.

Kudos to Pulumi. It automates our cloud deployments and uses TypeScript to do so which makes it a perfect fit for our tooling.

Testing

Vitest has been our goto unit and integration test framework. Its exceeding speed and modern packaging is all we needed to replace Jest.

For e2e testing, Playwright is utilized. If you are ever scarred by endless waits and flaky tests of previous generation tooling, you would love this tool. Their codegen tool literally writes tests for you!

Cloud Native Solution

While excellent choices are made to build the system, there is a whole nother dimension of scalability and resiliency that was needed.

ProAutoma is a cloud native system. While we could have chosen any cloud and initially even implemented it on AWS, we eventually decided to use Google Cloud for certain benefits for our specific system.

While microservices are well touted (and are important), implementing them well is not easy. Event-driven architecture is known to work well in this regard as they are inherently distributed, scalable and resilient. This architecture provides elegant solutions to rate limiting, retries, queuing etc.

All our services are written and deployed as containers.

GCP PubSub is an excellent global messaging system that drives the ProAutoma backend. Our scheduler, monitor runners, scripting engine, alerting systems are orchestrated by sending and receiving messages.

GCP Cloud Run - In our previous ventures, we utilized Kubernetes and while it is a powerful system for certain loads, it was way too complex. Ideally, we just like to run our containers in choice data centers with minimal configuration for scalability. Cloud Run provides this and much more.

Our solution now runs as a number of Cloud Run services orchestrated by PubSub. Persistence is provided by Cloud SQL PostgreSQL database and Cloud Storage.

Other SaaS Services

We do rely on a number of other SaaS products to complete our tech stack. We use Firebase for authentication, SendGrid for email handling, and Stripe for payment processing.

Conclusion

Overall, we are very happy with our current stack and efficiency it afforded us.

As a takeaway, I highly recommend to consider an isomorphic stack when possible, a statically typed language such as TypeScript and a powerful ecosystem of readily usable software building blocks.

Cloud native is the way to go, especially for startups, for scalability and resiliency.

Event driven architecture helps tame distributed system complexity.

I hope this throws light on our choices and is helpful in making yours. We’re always available for feedback and discussion.

Get your ProAutoma Free Account to monitor your Website or API. 50K monthly checks are free, that is 5 sites checked every 5 minutes.

Try our Free API Tester tool to explore and test your APIs. All you need is a URL to get started.