xtablo-source/.planning/codebase/STRUCTURE.md
2026-05-14 16:01:31 +02:00

296 lines
12 KiB
Markdown

# Structure
_Last updated: 2026-05-14_
Directory layout, conventions, and where to look for things in the `xtablo-source` monorepo.
## Top-Level Layout
```
xtablo-source/
├── apps/ # Deployable applications
│ ├── main/ # Authenticated dashboard SPA (Vite + CF Workers)
│ ├── external/ # Public booking widget (Vite)
│ ├── clients/ # Client portal (Vite + CF Workers)
│ ├── admin/ # Internal admin tools (Vite + CF Workers)
│ ├── api/ # Hono REST API (Node, GCP Cloud Run)
│ └── chat-worker/ # Cloudflare Durable Object worker for chat
├── packages/ # Shared workspace packages (source-only)
│ ├── shared/ # Contexts, hooks, API client, toast, supabase client
│ ├── ui/ # Radix + Tailwind component library
│ ├── shared-types/ # Pure TypeScript types (zero runtime deps)
│ ├── auth-ui/ # Auth screens (login/register shells)
│ ├── chat-ui/ # Chat-specific UI components
│ └── tablo-views/ # Tablo detail / sections components
├── backend/ # Legacy / auxiliary backend code
├── go-backend/ # Go services (separate stack)
├── frontend_v2/ # Frontend v2 prototype
├── xtablo-expo/ # React Native (Expo) app
├── supabase/ # Supabase project (migrations, config)
├── infra/ # Infrastructure-as-code
├── docs/ # Architecture, deployment, integration docs
├── prompts/ # Prompt templates
├── scripts/ # Repo scripts
├── CLAUDE.md # Claude Code guidance (root)
├── DEVELOPMENT.md # Dev guide
├── turbo.json # Turborepo pipeline config
├── pnpm-workspace.yaml
└── package.json
```
## Apps
### `apps/main` (`@xtablo/main`)
Primary dashboard. Internal layout:
```
apps/main/src/
├── main.tsx # Vite entry
├── App.tsx # Root component, providers
├── i18n.ts # i18next setup
├── main.css # Tailwind entry
├── components/ # UI components (Modals, Sections, Cards, ...)
├── contexts/ # App-local React contexts (UpgradeBlockContext, ...)
├── hooks/ # Feature hooks (tablos, events, tasks, stripe, ...)
├── lib/
│ ├── api.ts # API client wrapper
│ ├── supabase.ts # Supabase client re-export
│ ├── routes.tsx # Protected routes
│ ├── publicRoutes.tsx # Public/auth routes
│ ├── billing.ts # Stripe-related helpers
│ ├── env.ts # Env validation
│ └── rum.ts # Datadog RUM init
├── pages/ # Route page components
├── providers/
│ └── UserStoreProvider.tsx # Zustand user store
├── locales/ # i18n JSON
├── utils/
└── assets/
```
### `apps/external` (`@xtablo/external`)
Embeddable booking widget. Internal layout:
```
apps/external/src/
├── main.tsx
├── routes.tsx
├── EmbeddedBookingPage.tsx
├── FloatingBookingWidget.tsx
├── CustomModal.tsx
├── UserStoreProvider.tsx
├── lib/
└── locales/
```
Mode is driven by query string: `?mode=embed&eventTypeId=...` or `?mode=floating`.
### `apps/clients` (`@xtablo/clients`)
Public-facing client portal.
```
apps/clients/src/
├── main.tsx
├── App.tsx
├── routes.tsx
├── components/
├── hooks/
├── lib/
├── pages/
├── locales/
└── test/
```
### `apps/admin` (`@xtablo/admin`)
Internal admin app.
```
apps/admin/src/
├── main.tsx
├── App.tsx
├── routes.tsx
├── components/
├── hooks/
├── lib/
├── pages/
└── registry/
```
### `apps/api` (`@xtablo/api`)
Hono REST API. Internal layout:
```
apps/api/src/
├── index.ts # Entry: tracer, secrets, server start
├── config.ts # createConfig(secrets) -> AppConfig
├── secrets.ts # loadSecrets() (env or GCP Secret Manager)
├── client.ts # Supabase admin client factory
├── middlewares/
│ ├── middleware.ts # MiddlewareManager singleton + supabase/r2/stripe
│ ├── stripeSync.ts # Stripe<->Supabase sync engine
│ └── transporter.ts # Email transport middleware
├── routers/
│ ├── index.ts # getMainRouter — composition + ordering
│ ├── public.ts # Unauthenticated endpoints
│ ├── authRouter.ts # Requires JWT
│ ├── maybeAuthRouter.ts # Optional auth (booking-aware)
│ ├── tablo.ts # Tablo CRUD
│ ├── tablo_data.ts # Tablo content blocks
│ ├── tasks.ts # Tasks
│ ├── notes.ts # Notes
│ ├── events.ts (in user.ts/tablo_data.ts)
│ ├── stripe.ts # Stripe webhook + ops
│ ├── revenuecat.ts # RevenueCat webhook
│ ├── invite.ts # Tablo invites
│ ├── user.ts # User profile / settings
│ ├── admin*.ts # admin.ts, adminActions.ts, adminAuth.ts,
│ │ # adminDatasets.ts, adminOverview.ts, adminTables.ts
│ ├── clientAuth.ts # Client portal magic-link auth
│ ├── clientPortal.ts # Client portal endpoints
│ └── clientInvites.ts # Public client invites
├── helpers/
├── types/ # BaseEnv, app.types.ts
└── __tests__/
```
### `apps/chat-worker`
```
apps/chat-worker/src/
├── index.ts # Worker entry
├── durable-objects/ # Durable Object classes
└── lib/
```
## Packages
### `packages/shared` (`@xtablo/shared`)
Public surface via `packages/shared/src/index.ts`.
```
packages/shared/src/
├── index.ts # Barrel
├── contexts/
│ ├── SessionContext.tsx # Supabase session listener
│ └── ThemeContext.tsx
├── hooks/
│ ├── auth.ts # useSignIn / useSignOut / useSession ...
│ ├── book.ts # Booking hooks
│ ├── public.ts # Public data hooks
│ └── useClickOutside.ts
├── lib/
│ ├── api.ts # HTTP client w/ Bearer token
│ ├── supabase.ts # Supabase JS client
│ ├── toast.ts # toast.add() wrapper (sonner)
│ └── cn.ts # clsx + tailwind-merge
├── types/ # Re-exported domain types
└── utils/
└── helpers.ts
```
### `packages/ui` (`@xtablo/ui`)
Radix UI + Tailwind component library. Source-only.
```
packages/ui/src/
├── components/ # button.tsx, dialog.tsx, select.tsx,
│ # popover.tsx, tabs.tsx, dropdown-menu.tsx, ...
├── hooks/
└── styles/
```
### `packages/shared-types` (`@xtablo/shared-types`)
Zero-dependency TypeScript types — safe to import from API and frontend.
```
packages/shared-types/src/
├── index.ts
├── database.types.ts # Auto-generated by supabase gen types
├── tablos.types.ts
├── tablo-data.types.ts
├── events.types.ts
├── kanban.types.ts
├── stripe.types.ts
├── admin.types.ts
└── utils.ts
```
### `packages/auth-ui` (`@xtablo/auth-ui`)
Auth screens shared between apps: `AuthCardShell.tsx`, `AuthEmailPasswordForm.tsx`, `AuthInfoBanner.tsx`.
### `packages/chat-ui` (`@xtablo/chat-ui`)
Chat-specific UI (`components/`, `hooks.ts`, `security.ts`, `types.ts`, `chat-ui.css`).
### `packages/tablo-views` (`@xtablo/tablo-views`)
Tablo detail sections and shell: `TabloDetailsShell.tsx`, `TabloEventsSection.tsx`, `TabloFilesSection.tsx`, `TabloTasksSection.tsx`, `TabloDiscussionSection.tsx`, `TabloHeaderActions.tsx`, `EtapesSection.tsx`, `RoadmapSection.tsx`, plus `single-tablo/`, `components/`, `hooks/`, `styles/`.
## Naming Conventions
- **Modals**: `*Modal.tsx` — e.g. `apps/main/src/components/CreateTabloModal.tsx`, `EventDetailsModal.tsx`.
- **Sections**: `*Section.tsx` — e.g. `packages/tablo-views/src/TabloFilesSection.tsx`.
- **Cards**: `*Card.tsx` — e.g. `apps/main/src/components/EventTypeCard.tsx`, `AvailabilityCard.tsx`.
- **Pages**: live in `apps/<app>/src/pages/`, lowercased file names matching the route (`planning.tsx`, `events.tsx`, `login.tsx`).
- **Tests**: co-located as `*.test.tsx` / `*.test.ts` next to the source (`AvailabilityCard.test.tsx`, `auth.signup.test.ts`).
- **Hooks**: lowercase domain file in `hooks/` (`tablos.ts`, `events.ts`, `tasks.ts`); each exports multiple named hooks.
- **UI primitives**: lowercase in `packages/ui/src/components/` (`button.tsx`, `select.tsx`).
## Key File Locations (Cheatsheet)
| Concern | Path |
|-------------------------------|---------------------------------------------------------|
| Main app routes (protected) | `apps/main/src/lib/routes.tsx` |
| Main app public routes | `apps/main/src/lib/publicRoutes.tsx` |
| External app routes | `apps/external/src/routes.tsx` |
| Clients app routes | `apps/clients/src/routes.tsx` |
| Admin app routes | `apps/admin/src/routes.tsx` |
| Session context | `packages/shared/src/contexts/SessionContext.tsx` |
| User store (Zustand) | `apps/main/src/providers/UserStoreProvider.tsx` |
| HTTP API client | `packages/shared/src/lib/api.ts` |
| Supabase client (browser) | `packages/shared/src/lib/supabase.ts` |
| API entry | `apps/api/src/index.ts` |
| API router composition | `apps/api/src/routers/index.ts` |
| API middleware singleton | `apps/api/src/middlewares/middleware.ts` |
| API config | `apps/api/src/config.ts` |
| API secrets loader | `apps/api/src/secrets.ts` |
| Auto-generated DB types | `packages/shared-types/src/database.types.ts` |
| Shared barrel export | `packages/shared/src/index.ts` |
| UI component barrel | `packages/ui/src/components/index.ts` |
| Turborepo pipeline | `turbo.json` |
| Workspace definition | `pnpm-workspace.yaml` |
| Root Claude guidance | `CLAUDE.md` |
## Adding New Features (5-Step Flow)
From `CLAUDE.md`, the canonical workflow for a new feature is:
1. **Define types** in `packages/shared-types/src/` (or run `npx supabase gen types typescript > packages/shared-types/src/database.types.ts` if you changed the DB schema).
2. **Add API endpoint** in `apps/api/src/routers/` — pick the right router (`public.ts`, `maybeAuthRouter.ts`, `authRouter.ts`, or a domain router like `tasks.ts`). Mount it in `apps/api/src/routers/index.ts` if it's new.
3. **Create a React Query hook** in either `packages/shared/src/hooks/` (cross-app) or `apps/main/src/hooks/` (app-local). Use the hierarchical query-key convention so mutations can invalidate predictably.
4. **Build the UI** using primitives from `@xtablo/ui` and patterns from `@xtablo/tablo-views` / `@xtablo/chat-ui` where applicable. Follow the `*Modal.tsx` / `*Section.tsx` / `*Card.tsx` naming convention and co-locate a `*.test.tsx`.
5. **Wire the route** in `apps/main/src/lib/routes.tsx` (or the equivalent in the relevant app) so the new page is reachable.
## Testing Locations
- **API tests**: `apps/api/src/__tests__/` (Vitest, mock Supabase).
- **Frontend tests**: co-located `*.test.tsx` next to source, run via `pnpm test` per app (`apps/main/src/setupTests.ts` configures happy-dom + Testing Library).
- **Docs on testing**: `docs/API_TESTS.md`, `docs/MIDDLEWARE_TESTS.md`.
## Documentation Index (in `docs/`)
- `DEVELOPMENT.md` — broad dev guide.
- `API_*.md` — API testing and integration.
- `STRIPE_*.md` — Stripe integration deep-dives.
- `AUTH_*.md` — Authentication patterns.
- `DOCKER_*.md` — Docker build optimization.
- `CLOUD_BUILD_*.md` — GCP Cloud Build setup.