Monorepo Structure
Current bootstrap layout vs intended architecture as features are added.
Status: Accepted
Goal
ByteBite uses a TypeScript monorepo with clear boundaries between deployable applications, shared packages, infrastructure, and documentation.
The structure is optimized for:
- independent deployments
- strict separation of frontend and backend responsibilities
- shared schemas and domain logic
- Docker-based development and production
- straightforward future extraction of services only when justified
Current structure
This is what exists now. Product slices: Tenant → Restaurant → Domain → Storefront, Menu → Storefront, Cart → Storefront, Checkout → Order, Accept / Reject + timeout, Kitchen → Status, Menu → Object Storage, Restaurant → weekly opening hours, Hours → Checkout-Gate, Auth → Login, Auth → Dashboard-Gate, Notifications → SMS/E-Mail clients, Notifications → Order-Events (SMS on accept, reject, timeout, ready), then Delivery → Zones + checkout, then Menu → Sizes, then Order pause, then Restaurant → profile. Payments are not implemented. Dashboard mutations still use the path (ADR-021); session.restaurantId is not this slice. /dashboard/* requires a staff session.
Empty feature folders are not created in advance. Modules are added when the feature exists.
bytebite/
├── apps/
│ ├── landing/ # Next.js: public Coming Soon page for the apex host
│ ├── storefront/ # Next.js App Router: tenant storefront + menu + cart + checkout + confirmation
│ ├── dashboard/ # Vite SPA + weekly hours + logo + menu CRUD + media uploads + accept/reject + kitchen + delivery zones + staff login gate + /admin placeholder
│ ├── api/ # Fastify: health, tenant plugin, Better Auth /auth, storefront menu/cart/checkout/hours + dashboard menu/orders/hours/uploads + timeout scheduler + optional Twilio status stub
│ └── docs/ # Fumadocs (canonical documentation)
├── packages/
│ ├── db/ # Drizzle client, restaurants, domains, menu + cart + order + hours + Better Auth tables, migrations, seeds
│ ├── domain/ # Hostname, tenant context, menu visibility, storage keys, cart/checkout/accept/kitchen/hours rules, order/payment/delivery/notification vocab, staff session shape
│ ├── auth/ # Better Auth factory, STAFF_ROLES, session shape (userId, role)
│ ├── schemas/ # Shared Zod contracts (health, storefront, menu, cart, order, hours, auth)
│ ├── types/ # Brands / staff roles not inferred from Zod
│ ├── config/ # parseEnv + base env schema
│ ├── observability/ # pino + Sentry init
│ └── notifications/ # Twilio SMS + SES e-mail clients (SMS on accept/reject/timeout/ready; no-op without credentials)
├── infrastructure/
│ ├── docker/ # App Dockerfiles (dev + prod targets)
│ ├── traefik/dev/ # Local file-provider routing
│ ├── traefik/prod/ # Placeholder for Dokploy Traefik
│ ├── dokploy/ # Placeholder
│ └── scripts/ # Placeholder
├── compose.yml
├── compose.dev.yml
└── README.mdAPI modules that exist
apps/api/src/modules/health/—/health,/health/dbapps/api/src/modules/storefront/— restaurant, menu, cart, checkout, and hours routesapps/api/src/modules/menu/— catalog queries and mutationsapps/api/src/modules/cart/— guest cart queries and mutationsapps/api/src/modules/hours/— weekly opening-window queries and atomic replaceapps/api/src/modules/profile/— public restaurant profile read and replaceapps/api/src/modules/delivery/— zones, suggestions, quote, Mapbox address providerapps/api/src/modules/orders/— checkout snapshot (hours-gated, pickup or delivery), tenant-scoped order reads, accept/reject, kitchen status, timeout tick, transactional SMS on accept/reject/timeout/readyapps/api/src/modules/notifications/— optionalPOST /webhooks/twilio/statusstub (no order writes)apps/api/src/modules/dashboard/— operator menu CRUD, media uploads, hours, order accept/reject, and kitchen writes (ADR-021 path context)apps/api/src/modules/media/— object-storage upload helper andGET /media/*apps/api/src/plugins/auth.ts— Better Auth handler at/auth/*(browser/api/auth/*)apps/api/src/plugins/dashboard-auth.ts— staff session required for/dashboard/*(401 without a cookie)apps/api/src/modules/tenancy/— hostname lookup againstrestaurant_domains
What is explicitly not implemented yet
session.restaurantIdcutover (path remains tenant authority)- Customer accounts
- Payments, realtime, checkout SMS, e-mail sends (no
customer_emailon orders) - Menu extras and allergens (sizes are in Menu sizes)
- Custom-domain verification / onboarding UI
- Staging/production B2 media and CDN
Intended structure as features are added
The following is target architecture. Do not treat it as a file checklist of the current repo.
As slices land, expect feature modules under the API (modules/restaurants, modules/domains, …), Storefront app/ + features/, Dashboard src/features/, and Drizzle tables under packages/db/src/schema/. Integrations (Stripe, Twilio, SES, Mapbox, object storage) stay backend-side, out of packages/domain.
Dashboard routing lives at apps/dashboard/src/app/router.tsx (not a src/routes/ tree).
A future apps/admin or packages/ui extraction is allowed only when actual complexity or duplication justifies it. Neither exists today, by design.
Boundaries
Storefront
Next.js for SSR, SEO, tenant branding, menu, cart, checkout, account and tracking UI. It calls the API (same-origin /api in the browser) and does not own ByteBite business rules.
Dashboard
React + Vite SPA for restaurant operations and the initial ADMIN area. shadcn/ui lives directly under apps/dashboard/src/components/ui. Browser API calls use same-origin /api.
API
Fastify is the central backend and business-logic application layer. Integrations with Stripe, Twilio, AWS SES, Mapbox and object storage stay backend-side.
Docs
Fumadocs is the only maintained documentation source (apps/docs/content/docs). Development uses docs.bytebite.test; production will use docs.getbytebite.co behind Traefik BasicAuth.
Shared packages
packages/domain: framework-independent business rulespackages/db: Drizzle schema, migrations, client and seedspackages/schemas: shared Zod contractspackages/auth: Better Auth factory, roles, staff session shape (userId,role; nosession.restaurantId)packages/types: only types not sensibly inferred from schemaspackages/config: shared config conventionspackages/observability: logging/Sentrypackages/notifications: Twilio SMS + AWS SES clients (optional env; SMS from accept/reject/timeout/ready; e-mail unused)
Explicit decisions
- No
packages/uiinitially. - Dashboard uses shadcn/ui locally.
- Storefront owns its own UI components.
- ADMIN starts as a protected section of Dashboard.
- Backend structure is feature/domain oriented.
- A future
apps/adminorpackages/uiextraction is allowed only when actual complexity or duplication justifies it.