Getting Started
First-time setup for the ByteBite monorepo.
Getting Started
Prerequisites
- macOS development environment (primary target)
- Docker Desktop or a compatible Docker runtime (Compose v2+)
- Git
- pnpm (host-side lint / typecheck / test / build)
- Node.js 24 LTS (see
.nvmrc)
Database commands run inside Docker. You do not need a host node_modules install solely to migrate or seed.
First-time setup
-
Clone / open the repository.
-
Copy
.env.exampleto.env. -
Add the required
/etc/hostsentries (see the rootREADME.md). Include both127.0.0.1and::1lines — IPv4-only entries cause ~5s delays on macOS when clients attempt AAAA lookups for.testhostnames. -
Start the Docker development stack:
pnpm devThis runs
docker compose -f compose.yml -f compose.dev.yml up. If a previous localcompose.deploy.ymlbuild left production images in place, runpnpm dev:downfirst so Compose recreates:devcontainers. -
With the stack running, apply the schema and seed Luigi / Mario (restaurants, domains, isolated menus, and example weekly hours) plus demo staff users. Seeds do not create carts or orders:
pnpm db:migrate pnpm db:seed
Local URLs
| Service | URL |
|---|---|
| Local links | http://testlinks.bytebite.test |
| Storefront | http://storefront.bytebite.test |
| Dashboard | http://dashboard.bytebite.test |
| Dashboard hours | http://dashboard.bytebite.test/ |
| Dashboard login | http://dashboard.bytebite.test/login |
| Dashboard menu | http://dashboard.bytebite.test/menu |
| Dashboard orders | http://dashboard.bytebite.test/orders |
| API (direct) | http://api.bytebite.test |
| Docs | http://docs.bytebite.test |
| Landing | http://landing.bytebite.test |
| Luigi | http://luigi.bytebite.test |
| Mario | http://mario.bytebite.test |
| Unknown restaurant | http://unknown.bytebite.test |
| Same-origin API | http://<app-host>/api/... |
| MinIO console | http://localhost:9001 |
| Traefik dashboard | http://localhost:8080 |
| Drizzle Studio | http://localhost:4983 (pnpm db:studio) |
Direct API example: http://api.bytebite.test/health
Same-origin examples (Traefik strips /api before Fastify):
http://luigi.bytebite.test/api/storefront/restauranthttp://luigi.bytebite.test/api/storefront/hourshttp://luigi.bytebite.test/api/storefront/menuhttp://luigi.bytebite.test/api/storefront/carthttp://luigi.bytebite.test/api/storefront/checkouthttp://mario.bytebite.test/api/storefront/restauranthttp://mario.bytebite.test/api/storefront/menuhttp://mario.bytebite.test/api/storefront/carthttp://luigi.bytebite.test/api/healthhttp://dashboard.bytebite.test/api/health
Luigi's public menu must not contain Mario items (and the reverse). Unknown host http://unknown.bytebite.test/api/storefront/menu (and /api/storefront/cart, /api/storefront/checkout, /api/storefront/hours) returns 404. A Luigi bb_cart cookie sent to Mario creates a new empty Mario cart and cannot create a Luigi order. A Luigi orderId on Mario's host returns 404. Dashboard hours/menu/orders/uploads use /dashboard/restaurants/:restaurantId/... and require a staff session (see Opening hours, Menu catalog, Object storage uploads, Guest cart, Checkout & orders, Accept, reject & timeout, Kitchen status, and Staff authentication). Pickup checkout is 409 when the hostname restaurant is closed or has an empty week; cart and menu GETs stay 200. session.restaurantId does not replace the path.
Commands
| Command | Description |
|---|---|
pnpm dev | Start the Docker dev stack |
pnpm dev:down | Stop the dev stack |
pnpm dev:rebuild | Rebuild images and start the stack |
pnpm build | Build all apps/packages (Turborepo, host) |
pnpm lint | Lint the monorepo |
pnpm typecheck | Typecheck the monorepo |
pnpm test | Run unit/integration tests (Vitest) |
pnpm db:generate | Generate Drizzle migrations (API container; stack running) |
pnpm db:migrate | Apply migrations (API container; stack running) |
pnpm db:seed | Seed the local database (API container; stack running) |
pnpm db:studio | Drizzle Studio at http://localhost:4983 |
The API does not auto-migrate on startup. pnpm db:* is the documented workflow.
Environment notes
.envDATABASE_URLuseslocalhost(host network).- Compose overrides
DATABASE_URLinside the API container to hostnamepostgres. - Compose overrides
S3_ENDPOINTinside the API container tohttp://minio:9000. BETTER_AUTH_SECRETis required for/authin production/staging; local/test may use the.env.exampleplaceholder. Without a production secret, auth routes are not registered.- Storefront and Dashboard browser bundles do not receive server secrets. Browser API calls use same-origin
/api. - Twilio/SES env vars are optional. Empty values are a no-op (API still starts). Transactional SMS is sent on accept, reject, timeout, and ready. Checkout does not send.
- Docker dev uses anonymous volumes for
apps/docs/.nextandapps/storefront/.nextso host-sidepnpm buildoutput does not corrupt the in-container Next.js dev/Turbopack cache. After adding new Fumadocs MDX pages, restart thedocsservice if the dev server was already running when the file was created.
Architecture boundaries
- Fastify is the central backend/business boundary. Storefront and Dashboard must not access PostgreSQL directly.
packages/domainis infrastructure-independent.- No
packages/ui; Dashboard shadcn components live atapps/dashboard/src/components/ui/. - No separate
apps/admin; the initial ADMIN area is a protected section inside Dashboard.