--- description: Conventions for the Next.js web app globs: - apps/web/**/*.{ts,tsx} alwaysApply: false --- # `apps/web` — Next.js 15 + React 19 ## Routing - App Router only. Pages live under [apps/web/app](mdc:apps/web/app). - `(app)` is the authenticated app; `(auth)` is sign-in/up. Workspace-scoped pages live at `app/(app)/[workspaceSlug]/...`. - Server Components are the default. Add `"use client"` only when you need state, refs, effects, or browser APIs. ## Data layer - Use **tRPC** for all client ↔ server data flow. Routers live in [apps/web/server/routers](mdc:apps/web/server/routers); the root router is [apps/web/server/root.ts](mdc:apps/web/server/root.ts). - Call procedures via `@trpc/react-query` in client components and via direct procedure invocation in server components / actions. **Don't** `fetch` your own `/api/trpc` routes. - Auth is **NextAuth v5**, configured in [apps/web/lib/auth.ts](mdc:apps/web/lib/auth.ts). Every protected procedure must check the session and resolve a `workspace_id` before touching the DB. ## UI - Tailwind + Radix primitives. Compose with `cva`, `clsx`, and `tailwind-merge`. - Reuse components from `apps/web/components/ui/`. Don't reinvent buttons, dialogs, dropdowns, popovers, etc. - Icons: `lucide-react` (preferred) or `@radix-ui/react-icons`. - Theming via `next-themes`. ## Editor / collab - The document editor is **TipTap 3** with **Yjs** docs synced through a Hocuspocus provider ([apps/web/lib/yjs-provider.ts](mdc:apps/web/lib/yjs-provider.ts)). - When a `Y.Doc` is available, mutate through Yjs / TipTap commands. Don't replace doc state by overwriting JSON unless you know what you're breaking. ## State - Server state → React Query (via tRPC). - Local UI state → component state or **Zustand** stores in `apps/web/lib/stores/`. Don't add Redux, Jotai, or another store library. ## Don't - Don't import from `@tasks/database/client` in client components — DB access is server-only. - Don't add `pages/` directory routes. App Router only. - Don't bypass NextAuth by reading cookies directly.