# STACK

Technology stack reference for the xtablo monorepo. Last updated 2026-05-14.

## Languages & Runtimes

- **TypeScript** — pinned at `^5.7.0` across most workspaces (api uses `^5.8.3`). Root devDependency in `package.json`.
- **Node.js** — `>=20.0.0` enforced via the `engines` field in the root `package.json`. The API Dockerfile builds on `node:20-alpine` (`apps/api/Dockerfile`).
- **Package manager** — pnpm `10.19.0` (declared as `packageManager` in the root `package.json`). Cloudflare Workers builds and the API container use `corepack` to install pnpm.
- **Go** — a parallel `go-backend/` service exists alongside the TS monorepo (`go-backend/go.mod`, `go 1.26.0`) using `chi`, `templ`, `pgx/v5`, and `sqlc`. It is included in the pnpm workspace but is otherwise its own toolchain.
- **Python** — a small infra utility at `infra/app/main.py` with `infra/requirements.txt` (not part of the runtime stack of the apps).

## Frameworks

### Frontend (React)
- **React 19.0.0** + **React DOM 19.0.0** — used by `apps/main`, `apps/external`, `apps/admin`, `apps/clients`, and all React packages.
- **React Router** — `react-router-dom ^7.9.4`.
- **Vite 6.2** — bundler/dev server for every web app (`apps/main/vite.config.ts`, `apps/external/vite.config.ts`, `apps/admin/vite.config.ts`, `apps/clients/vite.config.ts`).
- **TailwindCSS 4.1** — utility CSS via `@tailwindcss/vite`, with `tw-animate-css` and `tailwind-merge`.
- **Radix UI** + **React Aria** — primitives composed in `@xtablo/ui` (see `packages/ui/package.json`).
- **BlockNote** — rich-text editor (`@blocknote/core`, `@blocknote/mantine`, `@blocknote/react`) used in `apps/main`.
- **AG Grid Community** — data grid in `apps/main` (`ag-grid-community`, `ag-grid-react`).
- **React Hook Form** + **Zod** — forms and validation, wired through `@hookform/resolvers`.
- **i18next** + `react-i18next` — translations (`apps/main/src/i18n.ts`, plus `external`, `clients`, `tablo-views`).
- **react-day-picker** — calendar UI.
- **PWA** — `vite-plugin-pwa` + `workbox-window` in `apps/main`.

### Backend (Hono)
- **Hono ^4.7.7** — HTTP framework for both `apps/api` and `apps/chat-worker`.
- **@hono/node-server** — Node adapter that drives `apps/api` (`apps/api/src/index.ts`).
- **hono-sessions** — session helpers in the API.
- **Cloudflare Workers + Durable Objects** — `apps/chat-worker` uses Hono with a `ChatRoom` SQLite-backed DO class (`apps/chat-worker/wrangler.toml`, `apps/chat-worker/src/durable-objects/ChatRoom.ts`).

## Core Dependencies

### Server State / Data Fetching
- `@tanstack/react-query ^5.69.0` — primary server-state cache. Hierarchical query keys; 5-minute default cache. Used in `apps/main`, `apps/clients`, `apps/admin`, `apps/external`, and `@xtablo/tablo-views`.
- `axios ^1.12.2` — HTTP client wrapper at `packages/shared/src/lib/api.ts`.

### Client State
- `zustand ^5.0.5` — global stores (notably user). Lives in `@xtablo/shared` and is consumed via `useUser` / `useMaybeUser`.

### Auth & JWT
- `@supabase/supabase-js ^2.49.x` — front-end and API client.
- `jwt-decode ^4.0.0` — decode access tokens on the client.
- `jose ^6.0.0` — JWT verification in the chat worker (`apps/chat-worker/src/lib/auth.ts`).

### UI Primitives
- Radix: `react-avatar`, `react-checkbox`, `react-collapsible`, `react-dialog`, `react-dropdown-menu`, `react-label`, `react-popover`, `react-select`, `react-separator`, `react-slider`, `react-slot`, `react-switch`, `react-tabs`, `react-tooltip`, `react-radio-group` (`packages/ui/package.json`).
- `react-aria` / `react-aria-components ^1.7.0`, `@react-stately/*`, `@react-aria/*`.
- `lucide-react ^0.460.0` — iconography.
- `class-variance-authority`, `clsx`, `tailwind-merge` — class composition.
- `sonner ^2.0.7` — toast notifications (re-exported via `packages/shared/src/lib/toast.ts`).

### Dates, IDs, Utilities
- `date-fns ^4.1.0`, `luxon ^3.7.2` (API only), `@internationalized/date`.
- `uuid ^11.1.0`, `pluralize ^8.0.0`, `ts-pattern ^5.6.2`.
- `jspdf ^3.0.3` — PDF export (main + shared).

### Payments / Billing
- `stripe ^20.0.0` — server SDK (`apps/api`).
- `@stripe/stripe-js ^8.2.0` — browser SDK (`apps/main`).
- `@supabase/stripe-sync-engine ^0.45.0` — Stripe ↔ Supabase sync (`apps/api/src/middlewares/stripeSync.ts`).

### Storage / Email
- `@aws-sdk/client-s3 ^3.850.0` — used against Cloudflare R2 in `apps/api/src/middlewares/middleware.ts` (`r2Middleware`).
- `multer ^2.0.2`, `sharp ^0.34.5` — file upload handling and image processing.
- `nodemailer ^7.0.4` + `googleapis ^161.0.0` — Gmail OAuth2 SMTP (`apps/api/src/middlewares/transporter.ts`).

### Observability
- `@datadog/browser-rum ^6.13.0` + `@datadog/browser-rum-react ^6.13.0` — initialised in `apps/main/src/lib/rum.ts` and `apps/clients/src/lib/rum.ts`.
- `dd-trace ^5.74.0` — APM tracer started at the top of `apps/api/src/index.ts`.
- `@datadog/datadog-ci`, `@datadog/datadog-ci-base`, `@datadog/datadog-ci-plugin-cloud-run` — CI source-map upload and Cloud Run integration.
- `static-analysis.datadog.yml` — repo-level Datadog static analysis config.

## Build / Dev Tooling

- **Turborepo `^2.5.8`** — pipeline orchestration (`turbo.json`). Tasks: `build`, `dev`, `deploy(:staging|:prod)`, `build:staging`, `build:prod`, `lint`, `lint:fix`, `typecheck`, `test`, `test:watch`, `format`, `clean`. Caches `dist/**` and `tsconfig.tsbuildinfo`.
- **Biome `2.2.5`** — formatter + linter, config at `biome.json` with explicit per-package `files.includes`.
- **Vite `^6.2.2`** with `@vitejs/plugin-react ^4.3.4`, `vite-tsconfig-paths`, `@tailwindcss/vite`, `@cloudflare/vite-plugin`, `rollup-plugin-visualizer`, `vite-plugin-pwa`.
- **Vitest** — `^3.2.4` in frontend apps, `^4.0.8` in `apps/api`. Browser env via `happy-dom` (main, admin) or `jsdom` (clients).
- **Testing Library** — `@testing-library/react`, `@testing-library/jest-dom`, `@testing-library/user-event`.
- **tsc** — every package has its own `tsconfig.json` and runs `tsc -b` or `tsc --noEmit` for typecheck.
- **Wrangler `^4.24.3`** — Cloudflare Workers CLI used by `main`, `external`, `admin`, `clients`, `chat-worker`.
- **tsx `^4.7.1`** — dev runner for the API (`pnpm dev` invokes `tsx watch src/index.ts`).

## Configuration

### Environment loading
- API: `dotenv.config({ path: `.env.${NODE_ENV}` })` in `apps/api/src/config.ts`. `createConfig(secrets)` synthesizes a typed `AppConfig` from env + Google Secret Manager values.
- Frontend: Vite `import.meta.env.*`; modes `dev`, `staging`, `production` selected via `vite build --mode`.

### Secret loading
- `apps/api/src/secrets.ts` pulls all sensitive values from `projects/xtablo/secrets/*/versions/latest` using `@google-cloud/secret-manager`.
- Test mode bypasses Secret Manager and uses raw env vars.

### Build targets per app
| App | Bundler | Output | Deploy target |
| --- | --- | --- | --- |
| `apps/main` | Vite + `@cloudflare/vite-plugin` | `dist/` + worker | Cloudflare Workers (`apps/main/wrangler.toml`, routes `app.xtablo.com`, `app-staging.xtablo.com`) |
| `apps/external` | Vite + Cloudflare plugin | `dist/` | Cloudflare Workers (`apps/external/wrangler.toml`) |
| `apps/admin` | Vite + Cloudflare plugin | `dist/` | Cloudflare Workers (`apps/admin/wrangler.toml`) |
| `apps/clients` | Vite + Cloudflare plugin | `dist/` | Cloudflare Workers (`apps/clients/wrangler.toml`) |
| `apps/chat-worker` | Wrangler-native | Worker bundle | Cloudflare Workers + Durable Objects, `chat.xtablo.com` |
| `apps/api` | `tsc` → `dist/` | Node 20 container | Google Cloud Run (`apps/api/Dockerfile`, `apps/api/cloudbuild.yaml`) |
| `go-backend` | `go build` | Binary | Separate (see `go-backend/justfile`) |

### Static configs
- `biome.json` — single source of truth for formatting/linting scope.
- `turbo.json` — task graph; `globalDependencies` include `**/.env.*local`.
- `tsconfig.json` per workspace; project references across packages.

## Workspace Structure

`pnpm-workspace.yaml` defines:
```yaml
packages:
  - 'apps/*'
  - 'go-backend'
  - 'packages/*'
```

### Apps (`apps/`)
- `@xtablo/main` — authenticated dashboard (port 5173).
- `@xtablo/external` — embeddable public booking widget (port 5174).
- `@xtablo/clients` — read-only client portal (port 5175, `clients.xtablo.com`).
- `@xtablo/admin` — internal admin app (port 5176).
- `@xtablo/api` — Hono REST API (port 8080).
- `@xtablo/chat-worker` — Cloudflare Worker hosting Durable-Object chat (`chat.xtablo.com`).

### Packages (`packages/`)
- `@xtablo/shared` — React contexts, hooks, supabase wrapper, axios client, toast helper. **Source-only** (no build step; consumers import TS directly — see `packages/shared/package.json` `"main": "./src/index.ts"`).
- `@xtablo/ui` — Radix + Tailwind + react-aria component library. **Source-only**.
- `@xtablo/shared-types` — pure TS types including Supabase-generated `database.types.ts`. **Source-only**, zero runtime deps.
- `@xtablo/auth-ui` — shared auth screens. **Source-only**.
- `@xtablo/chat-ui` — chat UI components consumed by main, clients, tablo-views. **Source-only**.
- `@xtablo/tablo-views` — tablo view components shared between main and clients. **Source-only**.

All shared packages export `./src/*` directly, so Vite HMR / tsc project references pick up changes instantly without a build step.

### pnpm overrides
Root `package.json` pins `form-data ^4.0.4` and `linkifyjs ^4.3.2`, plus a `packageExtensions` entry adding `zod` as a peer of `@hookform/resolvers`.
