Architecture

Folder Structure

Kit is a Turborepo monorepo with clear separation between applications and shared packages. Apps consume packages; packages never depend on apps.

Overview

kit/
├── apps/
│   ├── web/               # Next.js 16 web app
│   ├── mobile/            # Expo mobile app
│   ├── extension/         # Chrome extension (WXT)
│   └── desktop/           # Electron desktop app
├── packages/
│   ├── api/               # tRPC router + better-auth
│   ├── db/                # Drizzle schema + Supabase config
│   └── ui/                # Shared React components
├── scripts/               # bootstrap.ts (starter trimming)
├── package.json           # Root workspace scripts
├── turbo.json             # Turborepo pipeline + env
└── pnpm-workspace.yaml    # Workspaces + version catalog

Applications (apps/)

Web App (apps/web/)

Next.js 16 with the App Router:

apps/web/
├── content/
│   └── docs/              # These docs (fumadocs MDX)
├── src/
│   ├── app/
│   │   ├── (auth)/        # Login, register, password reset
│   │   ├── (dashboard)/   # Protected dashboard
│   │   │   └── dashboard/
│   │   │       ├── [slug]/    # Org pages: todos, members, settings, billing
│   │   │       └── account/   # User account settings
│   │   ├── (docs)/        # Docs routes (fumadocs)
│   │   ├── (marketing)/   # Public landing page
│   │   └── api/
│   │       ├── auth/[...all]/  # better-auth handler
│   │       ├── trpc/[trpc]/    # tRPC endpoint
│   │       ├── chat/           # AI chat endpoint
│   │       ├── health/         # Liveness check
│   │       └── search/         # Docs search
│   ├── components/        # App-level components (header, nav, theme)
│   ├── lib/               # auth-client, site-config, fumadocs source
│   ├── trpc/              # tRPC client setup (react, server, query-client)
│   └── proxy.ts           # Markdown content negotiation for agents
├── next.config.js
└── package.json

Route Conventions

  • (auth)/, (dashboard)/, (marketing)/, (docs)/ - route groups
  • [slug]/ - dynamic org routes
  • _components/ - colocated components, not routes

Mobile App (apps/mobile/)

Expo + React Native with NativeWind:

apps/mobile/
├── src/
│   ├── app/               # Expo Router (_layout.tsx, index.tsx)
│   ├── utils/             # auth (SecureStore), api (tRPC), base-url
│   └── styles.css
├── app.config.ts
└── package.json

Chrome Extension (apps/extension/)

Built with WXT:

apps/extension/
├── src/
│   ├── entrypoints/       # background, popup, options
│   ├── assets/
│   └── lib/
└── wxt.config.ts

Desktop App (apps/desktop/)

Electron via electron-vite:

apps/desktop/
├── src/
│   ├── main/              # Main process
│   ├── preload/           # Preload scripts
│   └── renderer/          # UI
├── electron.vite.config.ts
└── electron-builder.yml

Shared Packages (packages/)

API Package (packages/api/)

tRPC router and better-auth config:

packages/api/src/
├── auth/                  # auth.ts (better-auth), auth-schema.ts, utils
├── organization/          # organization-router.ts, -schema.ts, -test
├── todo/                  # Example CRUD router
├── waitlist/              # Waitlist router
├── root-router.ts         # Router composition
├── trpc.ts                # Context + procedures
├── test-utils.ts          # Vitest helpers
└── index.ts               # Exports: appRouter, RouterInputs/Outputs

Convention per feature: *-router.ts (procedures), *-schema.ts (Zod), *.test.ts (tests).

Database Package (packages/db/)

packages/db/
├── src/
│   ├── drizzle-schema.ts       # App tables (waitlist, todo)
│   ├── drizzle-schema-auth.ts  # better-auth generated tables
│   ├── drizzle-client.ts       # postgres.js + Drizzle client
│   └── index.ts                # Re-exports drizzle-orm operators
├── supabase/
│   └── config.toml             # Local Supabase (auth + data API off, storage on)
├── drizzle.config.ts
└── package.json                # db scripts (start, push, reset, studio)

UI Package (packages/ui/)

shadcn-style components on Base UI (base-vega registry):

packages/ui/
├── src/
│   ├── components/        # Flat primitives + ai-elements/
│   ├── hooks/
│   ├── lib/utils.ts       # cn()
│   └── styles/globals.css
├── components.json        # shadcn config (style: base-vega)
└── postcss.config.mjs

Apps import explicit paths:

  • @repo/ui/components/<name>
  • @repo/ui/lib/utils
  • @repo/ui/globals.css

Add components from the registry:

cd packages/ui && pnpm dlx shadcn@latest add <component>

Documentation

No separate docs package - these pages are MDX files in apps/web/content/docs/, rendered by fumadocs (apps/web/src/lib/source.ts).

Configuration Files

  • package.json - Workspace scripts (dev:web, db:push, ...)
  • turbo.json - Pipeline + globalEnv allow-list for env vars
  • pnpm-workspace.yaml - Workspaces and the shared version catalog
  • .oxlintrc.json - Linting (oxlint); formatting is oxfmt

Key Design Principles

  1. Separation of concerns - Apps own UX; packages own logic, data, and primitives
  2. Code sharing - One tRPC router, one auth config, one schema for every platform
  3. Type safety - Types flow from schema through API to UI, no codegen
  4. Explicit imports - @repo/ui/components/button, not barrel files

Adding New Features

New API Routes

  1. Add packages/api/src/<feature>/ with router + schema
  2. Register in packages/api/src/root-router.ts
  3. Consume with full types via useTRPC()

New UI Components

  1. Add to packages/ui/src/components/ (or pnpm dlx shadcn@latest add)
  2. Import as @repo/ui/components/<name>

New Database Tables

  1. Define in packages/db/src/drizzle-schema.ts with .enableRLS()
  2. Run pnpm db:push
  3. Types flow everywhere automatically

On this page