---
description: tRPC v11 conventions
globs: ["src/**/*.{ts,tsx}","server/**/*.ts"]
alwaysApply: false
---

# tRPC v11

- Routers live in `server/routers/<domain>.ts` and are merged in `server/routers/_app.ts`. Export `type AppRouter` only, never server code, to the client.
- Every procedure has a zod `.input()`. Return plain serializable data; use the configured transformer (superjson) for Dates/Maps.
- Base procedures: `publicProcedure` and `protectedProcedure` (middleware checks `ctx.session` and narrows its type). Add role checks as further middleware, not inside handlers.
- Throw `TRPCError` with the right `code` (`NOT_FOUND`, `FORBIDDEN`, `BAD_REQUEST`). Don't return `{ error }` objects.
- `query` for reads, `mutation` for writes. Subscriptions only if the adapter supports them.
- Client: use the TanStack Query integration (`trpc.post.list.queryOptions()` with `useQuery`) or the classic hooks the repo already uses; invalidate with the generated query keys after mutations.
- Keep business logic in services so it can be reused outside tRPC (cron jobs, webhooks).
- Server-side calls in RSC/SSR use `createCaller` or the server helpers, not an HTTP round trip.

## Don't
- Don't import server modules in client components.
- Don't widen inputs to `z.any()`.

## Done when
`tsc --noEmit` passes and each new procedure has a test via `createCaller` with a mocked context.
