Back to Articles

09/10/2022 00:53

CMS Architecture #1

trails in the sky digital art by
Article Cover image

Fullstack WASM CMS

This article focuses on the contents and the architecture revolving around the website you’re currently looking at. So let’s start with the obvious, I wanted to create my personal website, but it shouldn’t be just another generic website like bootstrapping a WordPress CMS. No, I wanted something more large scale, totally overkill… Why? I wanted to put my learning of the past years into an actual large scale project. It’s one thing to say you’re capable to do it but another thing to show it off, you could see this also as kind of portfolio item in the bag. The initial idea was to create my own blog to write about my learning and a big portion also covering RUST and WASM. So I’ve set for myself a set of requirements for this website which transpiled into currently 4 services excluding the frontend. I’ve kept in mind to keep my services as small as possible, and also to keep them generic, so others could use them and maybe build upon them. Who knows if someone eventually might use one of them? Back on track, let’s start with the backend.

The groundwork

The backend should be able to run effortless on k8s, it should be scalable. For the communication protocol service to service / gateway, I went for http/2 gRPC protobuf. In which case the crate tonic will cover most of our needs. As for the database, I went for a nosql based db mongodb. For the most use cases I had and requirements I gathered before, I knew a relational database was not needed. With all these things in mind, I went ahead and created a boilerplate setup on the newest versions of each needed crate. Then there is docker for deploying to the prod system and to have solid dev env utilizing docker-compose

Service Stack

  • tonic grpc
  • mongo connector
  • tokio
  • serde / chrono / crypto/hashing crates

Basic Service Diagram

image describing how the architecture looks like

Authentication

Why do I need authentication? Well I want to create blog entries CMSish and I don’t want some random being able to crate blogs on my page therefore we need authentication and privileges. So we’ll need authentication, there are a couple of solutions like “oauth2” but I opted to go for the following route of my own auth service with “JWT” signing. Obviously, we’ll need some crypto crate to hash our user passwords. The JWT crate to sign our user login. And I ended up with the following endpoints.

  • auth/register
  • auth/login
  • auth/verify (verify if token is valid)
  • auth/refresh (refresh current token)
  • auth/guest (guest token)
  • auth/delete (delete user)
  • auth/info
  • health

User

I’ve also created a service to store user-specific data alias, username, first name, last name, mail they share a mutual connection between the authentication service though is decoupled because most user gathering logic does not always have to come with authentication.

  • user/create
  • user/delete
  • health

Blog

Since you’re reading this blog, you’ll figure that this content is served by this service. It powers most of the content on the page, from the blog section to parts of the Portfolio since most of my projects are also connected to my articles. It saves mostly metadata and base64 encoded content section. Furthermore, it has basic validation in some fields to ensure content is encoded properly, for instance. Also, there is a type field for the content section which allows for serving and parsing encoded data in various formats “markdown”, “orgmode” and plaintext.

  • blog/create
  • blog/get
  • blog/update
  • blog/getActive (to serve only published blogs)
  • blog/getById
  • blog/deleteById
  • blog/getByUrl

Gateway

The Gateway is my bridge between service and public consumers, like the frontend. It offers middlewares for token validation and checks for roles on users accessing the API. The Gateway mirrors the endpoints from http/2 to http/1. Here, our main frameworks are tonic and actix

CI/CD Service

Here I’ll do some basic performance tests against the services. To get an idea on when my service breaks down request wise, what CPU and MEM usage looks like. This allows me to be confident in scaling even thought that might not be needed now.

Frontend

In the frontend we use sycamore for page reactivity and perseus for serverside logic as well as SSR. For the styling I used Tailwind, it allows for easy CSS class splitting depending on which classes you used in the project. Which keeps the CSS small. I kept in mind to have a strong lighthouse score and aimed for 95%-100%. It’s also important to me that the accessibility of the page is as easy as it can be. You should be able to navigate on mobile without issues, as well as tablet to desktop. Even for readers, I hope to achieve a pleasant experience.

the lightouse score of this website

CI/CD Frontend

The pipeline checks for me on every PR how the current lighthouse score of the branch compares against master It creates on merge to master a new docker container which will be uploaded to the GCR and then in turn can be used in GCP in cloud run

Deployment Performance and Keeping cost low.

Currently, I’m running the APP on google cloud run. Any execution time based cloud provider is a win for me to keep costs low. Since RUST offers almost unmatched speed compared to C. I’m running a smaller sized version of the architecture since the full thing would be really expensive to host from multiple containers/pods, VPC, Artifact / Container Registry, Proxy and the domain. Therefore, I decided to add functionality to dump content to files and read them from the server side instead of fetching from an API. This allows me for the scope of this website to run just one container without the need of a VPC.

Epilogue

Those far, this is how the architecture looks like. While fairly low complexity, it covers most of my needs and is easily extensible. I have plans to expand upon this and make it a fully flagged CMS on a high performing tech stack. Therefore, the next plans will be a role and permission system and users being able to interact with the page, for example a comment system on the blog.

Sources

The masccoot of the website mr raccoon!