Bootstrap Your Secure and Fast Multitenant SaaS — Part 1: The Frontend

M. Khaled Badenjki
4 min readJul 20, 2023

--

In this tutorial, I will walk you through the process of building a complete fullstack application, including a backend, a dashboard, a landing page and a database. In addition, an nginx web server is added to route requests accordingly.

The motivation of this project is to help you get started quickly, by doing the necessary steps that every web application needs. You can easily clone the repository and start implementing you business logic.

Although it’s a boilerplate, It’s an opinionated software. Throughout the years I have come to some conclusions regarding projects file structure, repository type, and I tried to put all these in this project to make it as flexible, secure and fast as possible.

By the end of this series, you will have a complete fast and secure system that is ready to ship to production(this is especially useful if you are building an MVP and you want to minimize costs).

Services to be built:

  • Backend API (NodeJs)
  • Landing Page (NextJs)
  • Dashboard (ReactJS)
  • Database (PostgreSql)
  • Web Server (Nginx)
  • Bonus: A message queue (RabbitMQ)

The source code for this tutorial is provided in this this repository.

Monorepo

I have taken the decision to include all the sub-systems in a monorepo. This would allow to handle the code base for different parts as a single unit. Although this approach has its pros and cons, I found this pattern to be a great fit for projects built with NodeJS. For example, you can apply linting rules to the whole codebase.

Landing page

I have used this project as a starter for the landing page. It’s a good fit because it uses NextJS, and it has MIT license. I made a couple of changes to use yarn instead of npm as a package manager. I also added a Dockerfile to make it easier to run and deploy. Here is the Dockerfile content:

FROM node:18.13.0-bullseye-slim as installer
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

FROM node:18.13.0-bullseye-slim as builder
WORKDIR /app
COPY . .
COPY --from=installer /app/node_modules ./node_modules
RUN yarn build-prod

FROM node:18.13.0-bullseye-slim as base
WORKDIR /app
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

EXPOSE 3000
CMD ["yarn", "start"]

I made the Dockerfile multi-staged to decrease the image size. This is needed if we want to save resources while deploying the app. I also used the bullseye-slim image for NodeJS as it’s smaller and has the best fit for NodeJs as per this article.

Dashboard

I have used the free minimal UI kit for the dashboard. This is built using ReactJS. I also updated it to use yarn instead of npm and added a Dockerfile for it. Here is how it looks

FROM node:18.13.0-bullseye-slim as installer
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

FROM node:18.13.0-bullseye-slim as builder
WORKDIR /app
COPY . .
COPY --from=installer /app/node_modules ./node_modules
RUN yarn build

ENV NODE_ENV production
# Expose the port on which the app will be running (3000 is the default that `serve` uses)
EXPOSE 3000
# Start the app
CMD [ "npx", "serve", "build" ]

Composing

Now that we have two frotends, one for the landing page and another for the dashboard. To run them in a single command, I will add a docker-compose.yml file to the parent directory. This is how it will look:

version: '3'
services:
landing-page:
build: ./landing-page
volumes:
- landing-page-static-content:/app/.next/static
- landing-page-public:/app/public
ports:
- 3000:3000
dashboard:
build: ./dashboard
volumes:
- dashboard-public:/app/public
ports:
- 3001:3000
volumes:
landing-page-static-content:
landing-page-public:
dashboard-public:

You will see that I have added some volumes. In a later articles, we will see why they are useful. For now just run:

docker-compose up --build -d

Then the services will be running as follows:

Summary

In this article, we have reused two free open source templates to buid our frontends. We already have a landing page and a dashboard ready to be shipped. But this is not the end of the story; it’s only the beginning. In a future article, I will be creating a backend, a DB, and a web server. We might also talk about deployment and a message queue as a bonus. I hope you enjoyed this article.

If you have any comments please let me know, and feel free to reach me out on LinkedIn, or Github.

The source code of the code above is available here.

--

--