A platform for an excellent full stack web application developer experience.
Still pretty early WIP!
In web applications, we can bucket most systems into two categories: Product systems and Platform systems. Product systems solve an end user problem and serve the customer. They are built on top of platform systems, which solve foundational problems and enable efficient and correct delivery.
While product systems are specific to the product being built, many products tend to share similar platform problems, especially prior to reaching scale. My pet projects have similarly shaped platform problems. blossom is a shared platform to solve platform problems across my pet projects.
More generally, blossom solves a set of common platform problems that small-to-medium scale monolithic web applications have.
blossom contains opinionated design decisions and modern library choices. All libraries are cohesively integrated together at the platform layer, so that product development can easily use all platform libraries with zero-friction.
blossom contains a platform that solves problems ranging from infrastructure to design.
In this section, we'll cover interesting features and design decisions that blossom contains. Each feature is further documented in its own README. This section links to those READMEs.
Generally, blossom's documentation is stored in READMEs in the repository.
blossom's infrastructure currently solves for developer environments, builds, CI/CD pipelines, and service orchestration.
We operate under the assumption that hardware is already provisioned and managed with a functioning Nomad+Consul cluster. For reference, my NixOS+Nomad+Consul configurations are located here.
- Nix for package management & developer environments.
- Nomad for service orchestration.
- Github Actions CI pipeline.
- Github Actions CD pipeline with Nomad and Tailscale.
blossom's backend is a monolithic Python (+mypy) application backed by Postgres. Python was chosen because I am the most comfortable and efficient with Python.
- Multi-tenant account system.
- RPC framework with TypeScript type codegen.
- Nix dependency management.
- Nix builds.
- Ergonomic test fixture system for concise and maintainable tests.
- Highly performant parallelized tests that share a single database.
- Postgres Row Level Security for secure multi-tenancy.
- Secrets vault for secure encrypted secret storage.
- Database migrations with yoyo-migrations.
- Database table conventions and tests to enforce them.
- Database queries with the sqlc database ORM.
- Monolithic CLI for service operations and developer tooling.
- Quart webserver served with Hypercorn.
- Configuration via environment variables.
- Linting with black, Ruff, and Semgrep.
blossom's frontend is a React SPA written in TypeScript. An SPA was chosen purely for cheap cost of deployment (CDNs 💸).
- Design System built with React Aria and vanilla-extract.
- Light and dark theme support.
- RPC framework with imperative, Jotai, and Tanstack Query bindings.
- Jotai state management.
- Error handling with rich metadata and stacktraces.
- Icon system with tokenized colors and sizes, and lazy-loading.
- Form system for convenient form creation.
- Page layout primitives for consistency and flexibility.
- Loader components for consistent crafted loading states.
- Page routing with code splitting and prefetching.
- Ladle stories with a library for easy story development.
- Unit and integration tests with Vitest.
- Visual snapshot tests with Playwright and Ladle.
- RPC mocks with msw for Ladle stories and Vitest testing.
- Linting with eslint+dprint+Semgrep.
- Builds with the Vite toolchain (SWC+esbuild+Rollup).
- pnpm dependency management.
Designs are built in Figma. The Figma files are still private; might publish them later if I'm feeling cute idk~
- Figma Tokens file.
- Figma component library.
- Figma color palette & theme libraries.
TODO
We use Nix to manage developer environments. All tools we use are declaratively
defined in nix/
. To bootstrap the developer environment and get started:
- Follow the Linux guide or MacOS nix-darwin guide to install Nix.
- Enable Nix Flakes.
- Install
direnv
and rundirenv allow
in the root of the monorepo.
After installing Nix and activating the developer environment, all tools and commands should work.
The monorepo is organized at the top-level by service type. Examples of service types are frontend, backend, nix, and nomad. Each service type has its own internal organization.
The application services (the backend and frontend services) are organized as packages. Each package solves one class of problems or feature and contains a README that document its purpose, context, and usage.
Packages are sorted into package groups. While every application service will have its own set of package groups, mainstays are:
foundation/
contains platform packages.product/
contains the product packages.codegen/
contains the packages that are produced from codegen tooling.
Inside each package group, packages are arranged in a flat structure. All package directories are direct children of a package group directory.
Note: The platform packages live in foundation
instead of platform
because
platform
is a Python standard library package.
Infrastructure is structured similarly. The top level is organized by type of infrastructure.
flake.nix
aggregates all of Nix outputs derivations into a single flake.docker-compose.yaml
defines all services used in the local environment.nix/
contains Nix derivations for our packages, toolchains, and builds.nomad/
contains Nomad service definitions..github/workflows/
contains the CI/CD pipeline configurations.
We try to avoid having multiple local services occupy the same port. The current allocations of services -> ports are:
- 40851: Backend
- 40852: Postgres
- 40853: Frontend
- 40854: Ladle
- 40855: Visual Tests
Copyright 2023 blissful <blissful@sunsetglow.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.