Contributing
Repository layout
What lives where in the monorepo, and the boundaries that are enforced rather than agreed.
A pnpm monorepo: apps/* are deployable applications, packages/* are shared libraries.
Applications depend on packages; packages never depend on an application; two applications
never import each other.
| Path | |
|---|
packages/shared | @sthora/shared — contract schemas for every resource crossing a package boundary. Reached only through explicit subpath exports. |
packages/email | @sthora/email — the email transport seam: contracts, configuration, header safety, and one file per provider. Knows no subject line and no template. |
packages/server-driver | @sthora/server-driver — the ServerDriver contract and the implementation that drives the machine it runs on. A package because two applications run it. |
| Path | |
|---|
apps/backend | @sthora/backend — the NestJS control-plane API. |
apps/agent | @sthora/agent — the process a customer runs on their own machine. Listens on nothing. |
apps/dashboard | @sthora/dashboard — the TanStack Start operator portal. |
apps/website | @sthora/website — the public marketing site. |
apps/docs | @sthora/docs — this site. |
| Path | |
|---|
src/servers/driver | Which machine a call acts on. ServerDriverRegistry resolves a driver per server row. |
src/agent | The channel a customer's server dials into. |
src/deployments | Source materialisation, build-type detection, the compose sanitiser and renderer, the per-application lock, the queues, and the log bus. |
src/git | Deploy-key generation, cloning through the driver, repository-URL validation, the optional GitHub App. |
src/webhooks | The one public route that can start work, behind an HMAC check. |
src/proxy | Traefik's compose project, and the ingress and certificate state read back from it. |
src/notifications | Alert rules and their copy, the alert lifecycle, delivery channels, the notify queue. |
src/services | Managed PostgreSQL, Redis, and MinIO, and their scheduled backups. Everything kind-specific in one catalogue. |
src/billing | Plans, the one subscription an organization has, the usage meter, and the ceilings they impose. |
src/emails | React Email templates, one subfolder per audience. |
src/crypto | AES-256-GCM at rest. |
prisma/ | The schema and its checked-in migrations. The generated client lands in src/generated/prisma and is git-ignored. |
| Rule | Enforced by |
|---|
child_process, dockerode, and node:fs appear nowhere in apps/backend/src outside src/servers/driver/ | scripts/lint-driver-boundary.mjs |
| No barrel files; imports are explicit files or subpath exports | Lint and review |
process.env is read only inside configuration factories | Review, and one env schema per area |
| Clients import contracts only, never persistence schemas | Package exports |
| Path | |
|---|
apps/*/Dockerfile | One image per application. |
deploy/docker-compose.yml | The platform's own compose file. |
install.sh | The installer — see the installer. |
.github/workflows/ci.yml | Publishes multi-arch images to GHCR after the suite passes on main. |
| Folder | Contains |
|---|
.ai/ | Coding standards and procedures. Project-independent and copy-safe — no product names, packages, ports, or domain concepts. |
docs/ | Everything about this project: the fact sheet, the implementation plan, the runbook, the tenancy design. |
apps/docs/content/ | These pages — the product documentation, written for whoever is using the platform. |
Learn something about the project, write it to docs/. Establish a coding standard, write it
to .ai/ — and only if it would still make sense in an unrelated project.