Monorepo

Architecture

Turborepo orchestrates apps (web and api today; mobile planned) and packages (db, validators, types, utils live; ui/config planned). This page describes target layout and boundaries; see Overview for the current tree snapshot.

Repository root

chalo-kumbh/
├── apps/
│   ├── web/                          # Next.js 15
│   ├── mobile/                       # Expo (planned)
│   └── api/                          # Node 20 + Hono
├── packages/
│   ├── ui/                           # planned — bespoke web UI package
│   ├── db/                           # Drizzle schema + migrations
│   ├── types/                        # Shared TypeScript types
│   ├── validators/                   # Zod — shared web + mobile + api
│   ├── config/                       # planned — shared eslint/tsconfig/tailwind
│   └── utils/                        # currency, dates, geo
├── docker/                           # planned — see single-host-deployment.html
│   ├── Dockerfile.web
│   ├── Dockerfile.api
│   └── docker-compose.yml
├── .github/workflows/                # planned — CI/CD
│   ├── deploy-web.yml
│   ├── deploy-api.yml
│   └── mobile-eas.yml
├── turbo.json
├── package-lock.json
└── package.json

Design principles

  • Single Zod sourcepackages/validators imported by API handlers and client forms. Avoid apps/api/src/validators duplicates that drift.
  • Schema-driven types — Drizzle in packages/db; export inferred types into packages/types where helpful.
  • Typed API client — Hono RPC client (or OpenAPI codegen) from a shared entry so web and mobile break compile-time if responses change.
  • Cart state — same Zustand logic on web and mobile; persistence differs (localStorage vs MMKV).
  • UI packagepackages/ui is web-only: bespoke components and patterns from the cultural design language. Native screens stay in apps/mobile with the same token roles.
  • One Stripe webhook receiver — prefer apps/api for signature verification and idempotent state updates. Do not mirror the same webhook on Next unless there is an explicit forwarding reason.

Web app route groups

Next.js App Router groups isolate layouts and concerns:

  • (marketing) — public pages: home, about, gallery, contact.
  • (booking) — packages, cart, checkout, confirmation.
  • (auth) — login, register, OTP.
  • (dashboard) — authenticated: my bookings, profile.
  • app/api/ — reserve for edge cases only (e.g. OAuth callbacks). Prefer Stripe webhooks on the Hono API.

Mobile (Expo Router)

File-based routes under apps/mobile/app/:

  • (tabs)/ — home, packages, bookings, profile.
  • packages/[slug].tsx — detail.
  • booking/ — cart, checkout, confirmation.
  • auth/ — login, register.

API application

Suggested layering under apps/api/src/:

  • routes/ — HTTP surface, thin.
  • controllers/ — parse request, call services.
  • services/ — business rules, transactions.
  • middleware/ — auth, CORS, rate limit, logging.
  • lib/db.ts — re-export from @chalo-kumbh/db (single pool).

Database connection

Instantiate Drizzle/Neon in one place (the db package or a single api import). Multiple ad-hoc connections cause pool exhaustion under load.