My Journey Creating My First Solo Project (part 3): Cloud Architecture
Tags: cloud, project, hasura, firebase
Published: 2020-08-29 14:22:56

*This article was originally published on [my personal blog](https://arnaudcortisse.com/blog).*

## Introduction

In my [previous blog post](https://dev.to/arnaudcortisse/my-journey-creating-my-first-solo-project-part-2-technologies-and-tools-3ecm), I talked about the technologies and tools I used to create [DoNotSkip](https://donotskip.com/en/).

In this blog post, I'd like to describe the overall cloud architecture of [DoNotSkip](https://donotskip.com/en/).

## Cloud Architecture

Below, the big picture of the cloud architecture.
Many things are not represented in the schema, but it gives you an idea.

![DoNotSkip Architecture](https://dev-to-uploads.s3.amazonaws.com/i/iyha34gl4yet5svjwjpi.png)

- [Firebase](https://firebase.google.com/)
  - [Hosting](https://firebase.google.com/docs/hosting): Serves static files such as HTML files, CSS files, JavaScript files, images, etc. with a global CDN.
  - [Storage](https://firebase.google.com/docs/storage): Stores coaches' assets such as images. These assets are only available to those uploading them.
  - [Authentication](https://firebase.google.com/docs/auth): Allows authentication via identity providers such as Google, Apple, etc.
  - [Cloud Functions](https://firebase.google.com/docs/functions): Hosts the backend logic. Examples of what is done in those functions: crop and resize images, transfer images from one bucket to another, etc.
- [Heroku](https://www.heroku.com/)
  - [Hasura](https://hasura.io/): GraphQL API over postgreSQL, event system (enabling the [3factor app] architecture), etc.
  - [PostgreSQL](https://www.postgresql.org/).
- [Google Cloud](https://cloud.google.com/)
  - [Storage](https://cloud.google.com/storage): Host workout programs' assets for the public.
  - [App Engine](https://cloud.google.com/appengine): Host [Next.js app](https://nextjs.org/).

In reality, things are a bit more complex than they are in the schema:

- There are several instances of Hasura and postgreSQL.
- There are two different Firebase projects: one for the coaches and one for clients.
- Everything is duplicated between staging and production environments.

## A few examples

To give you an idea of how everything is put together, I want to show some practical examples of how every piece communicates with one another in some user use cases.

### What happens when logging in?

Below is an overview of how the login process takes place. This logic is the same across the different parts of the platform.

![Login Workflow](https://dev-to-uploads.s3.amazonaws.com/i/61nikiga0u1h91zdbf7v.png)

1. Using the [Firebase SDK](https://firebase.google.com/), sends a request to the **Google Authentication service**.
2. In the client, an observer is listening to all Firebase auth state changes. When the previous request succeeds, the observer gets information about the user such as their unique **User ID** and a **JWT token**. The _User ID_ allows to uniquely identify in the whole platform while the _JWT token_ is used to confirm the identity of the user making requests.
3. When the user is identified successfully, the client sends a request to the backend (in this case, [Hasura](https://hasura.io/)) to notify that the user has actually logged in.
4. The **Hasura GraphQL Engine** automatically checks the validity of the JWT token.
5. Communicates with the _Authentication Service_ if JWK has expired to get a new one.
6. When the JWT token is valid, the database is updated.
7. The backend replies with a successful response.

### How are coaches' assets uploaded?

Below is an overview of how images are uploaded in [DoNotSkip Coaches](https://app.coaches.donotskip.com/).

![Asset Upload Workflow](https://dev-to-uploads.s3.amazonaws.com/i/wok5r3a3imjalx6oqicr.png)

1. Using the [Firebase SDK](https://firebase.google.com/), an upload task is started client-side.
2. The file is uploaded successfully, the client receives a successful response.
3. Metadata about the file is added to the SQL database via Hasura. The JWT token is sent automatically with every request.
4. The **Hasura GraphQL Engine** automatically checks the validity of the JWT token.
5. If the JWK has expired, get a new one.
6. The token is valid, Hasura proceeds with the update.
7. Sends a successful response to the client.

### How are workout programs published?

Below is an overview of how program publications work inside [DoNotSkip Coaches](https://app.coaches.donotskip.com/). The architecture used here is called [3factor app](https://3factor.app/).

![Program Publication Workflow](https://dev-to-uploads.s3.amazonaws.com/i/07m2o45cxzfazg33nru6.png)

1. A _GraphQL mutation_ is sent to Hasura. This GraphQL mutation inserts a row in a table called _Publish Program_.
2. The **Hasura GraphQL Engine** automatically checks the validity of the JWT token.
3. If the JWK has expired, get a new one.
4. The token is valid and a row is added to _Publish Program_.
5. A response is sent to the client saying that the row has been added successfully.
6. Because the response is successful, the client creates a _GraphQL subscription_ to get real-time updates on the publication of the program (using WebSocket).
7. An _event trigger_ is set up in the database so that whenever a row is added in _Publish Program_, a request is sent to a custom webhook (in this case, it's a cloud function hosted on Firebase).
8. The cloud function does everything it needs to do in order to make the program available publicly (compresses images, sanitizes text, etc.). Once everything is done, it updates the SQL database to notify that the program has been successfully uploaded. The client is in-turn notified.

The publication process itself is explained in more details below.

![Program Publication Backend](https://dev-to-uploads.s3.amazonaws.com/i/sh1pfezrj1xfzx6jtno7.png)

1. The webhook "Publish Program" is called. A cloud function is started. This function has two purposes: **1)** the creation of the landing page for the program and **2)** the creation of the program that's going to be used in the app.
2. All information regarding the program to publish is retrieved in Hasura.
3. Various stuff is done in the function:
   1. Images are cropped and optimized (if required).
   2. Pieces of text are sanitized.
   3. Images are moved in a public bucket.
   4. Various JSON documents are created.
4. The JSON documents are published to an Hasura instance hosting the published programs.

## Final words

As you can see, [Hasura](https://hasura.io/) plays a crucial role in this architecture ([3factor app](https://3factor.app/)): most of the time, whenever the frontend app wants to perform a backend action that requires authorization, it does so by inserting a new row in the SQL database via the GraphQL API and then subscribes to some database row changes. The cloud functions are invoked behind the scene via a clever event system provided by Hasura.

This cloud architecture would be able to accept a high volume of traffic:

- It's going to be a long time before Hasura becomes a bottleneck (see [Scaling to 1 million active GraphQL subscriptions with Hasura](https://github.com/hasura/graphql-engine/blob/master/architecture/live-queries.md)). Furthermore, I have set up three different Hasura instances that can scale vertically independently of each other (one for **Coaches**, one for **Publications** and another one for **User savings**). It wouldn't be difficult to put a load-balancer in front of the Hasura instances in order to scale horizontally.
- Cloud functions automatically scale.

I could go on and on and explain other use cases, but I think you get the gist of [DoNotSkip](https://donotskip.com/en/)'s cloud architecture.
In the next blog post, I'd like to talk about the code architecture of [DoNotSkip App](https://donotskip.com/en/mobile-app), the mobile app of the platform built with [React Native](https://reactnative.dev/).