Macadam is a full-stack, software-as-a-service (SaaS) "boilerplate" application. It is meant to serve as a complete, exemplary, starting point for building new SaaS-type projects.
- Provide a complete, production-ready toolset to get a SaaS product started as quickly as possible, all parts included, using best practices.
- Fully self-hostable in a Kubernetes environment.
Many "starter projects" and "boilerplates" are incomplete or contrived examples that will still require a huge amount of effort to get a production-ready MVP shipped. But most SaaS projects have a common set of features that will be needed for a maintainable, production-ready deployment, i.e.: authentication, logging, tracing, error reporting, analytics, unit testing, database interactivity, user-facing client(s), an API server, infrastructure, etc. Providing this base is the primary goal of the project.
This is not meant to be highly configurable with a many options available to the developer from the outset. Some tooling can be easily swapped out, while other pieces may require significant work. But ultimately it is, by design, very opiniated.
The only prerequisite to getting a fully-usable environment up and running is a Docker environment with Docker Compose capabilities.
- Clone the repo (i.e.
git clone https://github.com/joekrill/macadam.git
) docker compose up
The resulting web application will be accessible by visiting https://localtest.me in your browser.
Any mail sent during development will ba accessible using a local maildev instance by visiting https://mail.localtest.me.
The auto-generated certificates will not be trusted by default and you will need to manually trust them. Alternatively, you can add the underlying Caddy certificate authority as a trusted root on your local machine.
# On MacOS
docker cp $(docker-compose ps -q caddy):/data/caddy/pki/authorities/local/root.crt /tmp/macadam_caddy.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/macadam_caddy.crt
# On Linux
docker cp $(docker-compose ps -q caddy):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/macadam_caddy.crt && sudo update-ca-certificates
# Firefox on MacOS - `security.enterprise_roots.enabled` must be `true` in `about:config` (see https://support.mozilla.org/en-US/kb/setting-certificate-authorities-firefox for other OSes)
docker cp $(docker compose ps -q caddy):/data/caddy/pki/authorities/local/root.crt ~/Library/Application\ Support/Mozilla/Certificates/macadam_caddy.crt
Some services are not run by default in the development environment. These can be include by passing the appropriate profile to docker-compose. For example, to run a Storybook instance:
docker compose --profile storybook up
Multiple profiles can be passed:
docker compose --profile storybook --profile metrics up
Available profiles:
analytics
runs a Plausible Analytics instance and it's depdenencies.error-tracking
runs a GlitchTip instance for collecting crash and error reports.metrics
runs Prometheus and Grafana instances.storybook
runs a Storybook instance for explorting the web application UI components.
- https://localtest.me - Main site
- https://mail.localtest.me - Mail trap UI for viewing any emails sent during development
- https://pgweb.localtest.me - UI for interacting with PostgreSQL
- https://api.localtest.me - Direct access to api-server (normally proxied via https://localtest.me/api)
- https://kratos.localtest.me - Direct access to kratos API (normally proxied via https://localtest.me/kratos/public)
- https://kratos-admin.localtest.me - Direct access to kratos admin endpoints
- https://kratos-courier.localtest.me - Direct access to kratos-courier instance
- https://echo.localtest.me -A generic echo server
- https://storybook.localtest.me - Storybook instance (requires compose profile
storybook
) - https://plausible.localtest.me - (requires compose profile
analytics
) - https://prometheus.localtest.me - Prometheus (requires compose profile
metrics
) - https://grafana.localtest.me - Grafana, login: "admin"/"admin" (requires compose profile
metrics
) - https://glitchtip.localtest.me - Glitchtip, login: "macadam@localtest.me"/"macadam!" (requires compose profile
error-tracking
)
Commands using exec
assume that the accompanying service/container is up and running. In most cases exec
can be replaced with run
to start the command in a new container.
-
Connect to Redis via
redis-cli
:docker compose exec redis redis-cli
-
Create/update the
plausible
database seed file:docker-compose exec postgres pg_dump -U plausible plausible > services/postgres/imports/plausible.sql
Macadam is a monorepo that uses Yarn Package Manager and it's workspaces feature to organize code and provide tooling and scripts.
The basic folder structure highlighting the most important paths:
├── docs
├── packages
│ ├── api-server
│ ├── client-web
├── services
│ ├── caddy
│ ├── clickhouse
│ ├── glitchtip
│ ├── ...
├── package.json
├── docker-compose.yml
docs/
- project-level documentationpackages/
- the root folder that contains individual yarn workspacespackages/api-server/
- source code for the API serverpackages/client-web/
- source code for the frontend web clientservices/
- configuration, scripts, and other files needed for running external services.package.json
- root-level package.jsondocker-compose.yml
- docker compose definition for the default development environment.
Macadam is built as a series of (micro)services that can roughly be broken down into:
- Web Client
- API Server
- Database
- Authentication
- Error Reporting
- Analytics
- Metrics
- UI Component Explorer
- Gateway Web Server
- Mail Interceptor (development)
The frontend web application (found at packages/client-web
) is a Typescript application bootstrapped with Create React App.
- Written in Typescript.
- Chakra UI for a consistent UI and component library - a simple, modular and accessible component library with theming support.
- Storybook for streamlining UI development, testing, and documentation.
- Declarative routing with React Router
- Local state management with Redux Toolkit
- Data fetching and caching with RTK Query
- Crash reporting using Sentry.io's React SDK
- Document head management with React Helmet Async
- Icons included using react-icons
- [Internationalization] with Format.JS (with React-Intl)
- Unit testing with Vitest and Testing Library
- Validation using zod
The backend API servier (found at packages/api-server
) is NodeJS application built using the Koa framework.
- Written in Typescript.
- Database integration with MikroORM.
- Low-overhead logging with pino
- Crash reporting using Sentry.io's Node SDK.
- Prometheus Metrics reporting.
- Health reporting endpoints
- Unit testing with Jest and [SuperTest]](https://github.com/visionmedia/supertest)
PostgreSQL is used by the API server, Kratos, Plausible Analytics, and GlitchTip. Each application is it's own database
Identity & User Management is implemented using Ory Kratos - a cloud native user management system.
GlitchTip is used for error reporting collection and analysis. GlitchTip is a branch of, and (currently) compatible with, Sentry.io - and the reporting clients use the Sentry.io SDKS. Switching to Sentry would simply require changing the DSNs used.
TODO: Plausible Analytics
TODO: Prometheus/Grafana
In development, Caddy acts as the gateway web server and routes all incoming requests. services/caddy/Caddyfile
tells Caddy how to do this.
In development, all mail is routed through Maildev, which allows viewing emails in the browser by visiting https://mail.localtest.me.
pgweb is a web-based client for PostgreSQL. This allows browsing and querying the database directly to aid in debugging and development. Visit https://pgweb.localtest.me to access the running pgweb instance.
git clone https://github.com/joekrill/macadam my-new-project