The Stack
The Stack
Surplus is one Bun workspace. This section is a guided tour of what lives in it — the apps you can run, the packages they share, and the scheduled jobs that keep things current.
Monorepo layout
| Path | Role |
|---|---|
apps/client/ | React 19 + TanStack Router + Vite — the staff, driver, and partner web app |
apps/server/ | Hono + ORPC API; also serves the generated OpenAPI spec and Scalar UI at /openapi |
apps/docs/ | This documentation site (Next.js + Fumadocs) |
packages/contracts/ | ORPC procedure contracts shared by client and server |
packages/services/ | Domain logic as dependency-injected service classes |
packages/postgres/ | Drizzle schema (the database source of truth) and the Neon client |
packages/types/ | Zod schemas and the TypeScript types inferred from them |
packages/utils/ | Pure helpers, constants, and business rules — no I/O |
packages/redis/ | Upstash Redis client and cache/lock helpers |
packages/sharedDeps/ | Curated re-exports of third-party dependencies |
crons/ | Scheduled workers — analytics cache warming and backups |
scripts/ | One-off migration and backfill utilities |
tests/ | Playwright end-to-end tests |
How to think about it
Two layers, one direction of dependency:
- Apps wire up the real world — they create database clients, the Redis connection, the S3 client, and inject those into services. Apps are deployable; packages are not.
- Packages hold everything reusable: the API contract, domain logic, schema, types, and utilities. They never import from
apps/*, and they never read environment variables. That keeps them portable and testable.
This separation is what lets the same domain logic run inside the API server today and inside a cron worker or a script tomorrow, with different concrete dependencies injected each time.
Tour the pieces
Apps
Shared code
- Shared packages — contracts, services, postgres, types, utils, redis, and sharedDeps, plus how they depend on each other.
Background jobs
- Cron workers — analytics caching and backups.
Naming and data conventions
A few rules hold across every part of the workspace:
- camelCase everywhere — tables, columns, files, CSS variables, and identifiers.
- UUID primary keys — never auto-incrementing integers.
- Unix epoch timestamps — stored as integers, not
Dateobjects.
The full set is on the Conventions page.