docs: trpc now optional — prerequisite notes + conditional HTML
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# AGENTS.md — apps/web-next
|
# AGENTS.md — apps/web-next
|
||||||
|
|
||||||
Next.js 15 reference application using App Router. Demonstrates consuming feature packages via tRPC, using `@repo/core-trpc/next` for client setup, and importing UI components from `@repo/core-ui`.
|
Next.js 15 reference application using App Router. Demonstrates consuming feature packages via tRPC and importing UI components from `@repo/core-ui`. Both `@repo/core-trpc` and `@repo/core-ui` are optional packages — scaffold them with `pnpm turbo gen core-package trpc` / `ui` if needed.
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
@@ -24,40 +24,44 @@ pnpm dev --filter @repo/web-next # Next.js on port 3000
|
|||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `src/app/layout.tsx` | Root layout — wraps app with `<TrpcProvider>` from `@repo/core-trpc/next` |
|
| `src/app/layout.tsx` | Root layout — wraps app with `<Providers>` |
|
||||||
| `src/app/providers.tsx` | Client component for tRPC + React Query setup |
|
| `src/app/providers.tsx` | Client component wrapper (add tRPC/React Query here after scaffolding `@repo/core-trpc`) |
|
||||||
| `src/app/page.tsx` | Home page — navigation + marketing content |
|
| `src/app/page.tsx` | Home page — navigation + marketing content |
|
||||||
| `src/app/blog/[slug]/page.tsx` | Dynamic blog post route |
|
| `src/app/blog/[slug]/page.tsx` | Dynamic blog post route |
|
||||||
| `src/app/api/trpc/[trpc]/route.ts` | tRPC fetch adapter endpoint |
|
|
||||||
| `e2e/` | Playwright end-to-end tests |
|
| `e2e/` | Playwright end-to-end tests |
|
||||||
|
|
||||||
## tRPC Setup
|
## tRPC Setup (optional)
|
||||||
|
|
||||||
The tRPC endpoint handler (in `src/app/api/trpc/[trpc]/route.ts`):
|
`@repo/core-trpc` is not installed by default. After scaffolding with `pnpm turbo gen core-package trpc`:
|
||||||
|
|
||||||
|
1. Create `src/app/api/trpc/[trpc]/route.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
||||||
import { appRouter } from "@repo/core-api";
|
import { appRouter } from "@repo/core-api";
|
||||||
|
import { bindAll } from "../../../../server/bind-production";
|
||||||
|
|
||||||
const handler = (req: Request) =>
|
const handler = async (req: Request) => {
|
||||||
fetchRequestHandler({
|
await bindAll();
|
||||||
|
return fetchRequestHandler({
|
||||||
endpoint: "/api/trpc",
|
endpoint: "/api/trpc",
|
||||||
req,
|
req,
|
||||||
router: appRouter,
|
router: appRouter,
|
||||||
createContext: () => ({}),
|
createContext: () => ({}),
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export { handler as GET, handler as POST };
|
export { handler as GET, handler as POST };
|
||||||
```
|
```
|
||||||
|
|
||||||
The provider (in `src/app/providers.tsx`):
|
2. Update `src/app/providers.tsx`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
"use client";
|
"use client";
|
||||||
import { TrpcProvider } from "@repo/core-trpc/next";
|
import { NextTrpcProvider } from "@repo/core-trpc/next";
|
||||||
|
|
||||||
export function Providers({ children }: React.ReactNode) {
|
export function Providers({ children }: { children: React.ReactNode }) {
|
||||||
return <TrpcProvider>{children}</TrpcProvider>;
|
return <NextTrpcProvider trpcUrl="/api/trpc">{children}</NextTrpcProvider>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -66,8 +70,8 @@ export function Providers({ children }: React.ReactNode) {
|
|||||||
| Dependency | Purpose |
|
| Dependency | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `@repo/core-api` | `appRouter` for tRPC endpoint |
|
| `@repo/core-api` | `appRouter` for tRPC endpoint |
|
||||||
| `@repo/core-trpc/next` | Next.js tRPC client + provider |
|
| `@repo/core-trpc/next` | Next.js tRPC client + provider (optional — scaffold first) |
|
||||||
| `@repo/core-ui` | Design system components |
|
| `@repo/core-ui` | Design system components (optional — scaffold first) |
|
||||||
| `@repo/auth`, `@repo/blog`, etc. | Feature packages (indirectly via core-api) |
|
| `@repo/auth`, `@repo/blog`, etc. | Feature packages (indirectly via core-api) |
|
||||||
| `next` | Next.js 15 framework |
|
| `next` | Next.js 15 framework |
|
||||||
| `@trpc/server` | tRPC server (fetch adapter) |
|
| `@trpc/server` | tRPC server (fetch adapter) |
|
||||||
@@ -103,5 +107,5 @@ Run: `pnpm test:e2e` starts the dev server and runs all `.spec.ts` files.
|
|||||||
|
|
||||||
- **Feature packages:** `packages/{auth,blog,media,marketing-pages,navigation}/`
|
- **Feature packages:** `packages/{auth,blog,media,marketing-pages,navigation}/`
|
||||||
- **tRPC composition:** `packages/core-api/AGENTS.md`
|
- **tRPC composition:** `packages/core-api/AGENTS.md`
|
||||||
- **tRPC client + provider:** `packages/core-trpc/AGENTS.md`
|
- **tRPC client + provider (optional):** scaffold `@repo/core-trpc` first, then see `turbo/generators/templates/core-package/trpc/AGENTS.md.hbs`
|
||||||
- **UI components:** `packages/core-ui/AGENTS.md`
|
- **UI components (optional):** scaffold `@repo/core-ui` first, then see `packages/core-ui/AGENTS.md`
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ TanStack Start reference application using TanStack Router with file-based routi
|
|||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Proof that features are framework-portable. This app consumes the exact same feature packages and tRPC routers as `apps/web-next`, but through TanStack Start's server/client architecture instead of Next.js App Router.
|
Proof that features are framework-portable. This app consumes the exact same feature packages as `apps/web-next`, but through TanStack Start's server/client architecture instead of Next.js App Router. Once `@repo/core-trpc` is scaffolded, it can use the same tRPC routers via `TanstackTrpcProvider`.
|
||||||
|
|
||||||
## Port: 3002
|
## Port: 3002
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ Proof that features are framework-portable. This app consumes the exact same fea
|
|||||||
pnpm dev --filter @repo/web-tanstack # http://localhost:3002
|
pnpm dev --filter @repo/web-tanstack # http://localhost:3002
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires tRPC endpoint (from `apps/web-next` or another backend):
|
When `@repo/core-trpc` is installed, this app requires a tRPC endpoint (from `apps/web-next`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm dev --filter @repo/web-next # Serves tRPC at http://localhost:3000/api/trpc
|
pnpm dev --filter @repo/web-next # Serves tRPC at http://localhost:3000/api/trpc
|
||||||
@@ -23,7 +23,7 @@ pnpm dev --filter @repo/web-tanstack # http://localhost:3002
|
|||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `src/routes/__root.tsx` | Root layout — wraps all routes with `<TrpcProvider>` from `@repo/core-trpc/tanstack` |
|
| `src/routes/__root.tsx` | Root layout — wraps all routes with `<Outlet />` (add `<TanstackTrpcProvider>` after scaffolding `@repo/core-trpc`) |
|
||||||
| `src/routes/index.tsx` | Home page (`/`) |
|
| `src/routes/index.tsx` | Home page (`/`) |
|
||||||
| `src/routes/blog/index.tsx` | Blog listing (`/blog`) |
|
| `src/routes/blog/index.tsx` | Blog listing (`/blog`) |
|
||||||
| `src/routes/blog/$slug.tsx` | Dynamic blog post (`/blog/:slug`) |
|
| `src/routes/blog/$slug.tsx` | Dynamic blog post (`/blog/:slug`) |
|
||||||
@@ -45,30 +45,30 @@ Naming conventions:
|
|||||||
- `index.tsx` — index route for its directory
|
- `index.tsx` — index route for its directory
|
||||||
- `$paramName.tsx` — dynamic segment
|
- `$paramName.tsx` — dynamic segment
|
||||||
|
|
||||||
## tRPC Setup
|
## tRPC Setup (optional)
|
||||||
|
|
||||||
The root route wraps with `<TrpcProvider>`:
|
`@repo/core-trpc` is not installed by default. After scaffolding with `pnpm turbo gen core-package trpc`:
|
||||||
|
|
||||||
|
1. Update `src/routes/__root.tsx`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// src/routes/__root.tsx
|
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
||||||
import { TrpcProvider } from "@repo/core-trpc/tanstack";
|
import { TanstackTrpcProvider } from "@repo/core-trpc/tanstack";
|
||||||
import { Outlet } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
component: () => (
|
component: () => (
|
||||||
<TrpcProvider trpcUrl="http://localhost:3000/api/trpc">
|
<TanstackTrpcProvider trpcUrl="http://localhost:3000/api/trpc">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</TrpcProvider>
|
</TanstackTrpcProvider>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: `trpcUrl` must point to a running tRPC endpoint (e.g., from `apps/web-next`).
|
Note: `trpcUrl` must point to a running tRPC endpoint (e.g., from `apps/web-next`).
|
||||||
|
|
||||||
## Fetching data in routes
|
2. Fetch data in routes:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// src/routes/blog/$slug.tsx
|
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { useTRPC } from "@repo/core-trpc";
|
import { useTRPC } from "@repo/core-trpc";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
@@ -80,11 +80,7 @@ export const Route = createFileRoute("/blog/$slug")({
|
|||||||
function BlogPostPage() {
|
function BlogPostPage() {
|
||||||
const { slug } = Route.useParams();
|
const { slug } = Route.useParams();
|
||||||
const trpc = useTRPC();
|
const trpc = useTRPC();
|
||||||
|
const { data, isLoading } = useQuery(trpc.blog.getBySlug.queryOptions({ slug }));
|
||||||
const { data, isLoading } = useQuery(
|
|
||||||
trpc.blog.getBySlug.queryOptions({ slug })
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isLoading) return <p>Loading...</p>;
|
if (isLoading) return <p>Loading...</p>;
|
||||||
return <article>{data?.title}</article>;
|
return <article>{data?.title}</article>;
|
||||||
}
|
}
|
||||||
@@ -94,9 +90,9 @@ function BlogPostPage() {
|
|||||||
|
|
||||||
| Dependency | Purpose |
|
| Dependency | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `@repo/core-api` | AppRouter type (via core-trpc) |
|
| `@repo/core-api` | AppRouter type |
|
||||||
| `@repo/core-trpc/tanstack` | TanStack tRPC client + provider |
|
| `@repo/core-trpc/tanstack` | TanStack tRPC client + provider (optional — scaffold first) |
|
||||||
| `@repo/core-ui` | Design system components |
|
| `@repo/core-ui` | Design system components (optional — scaffold first) |
|
||||||
| `@tanstack/react-router` | File-based routing |
|
| `@tanstack/react-router` | File-based routing |
|
||||||
| `@tanstack/react-query` | Data fetching + caching |
|
| `@tanstack/react-query` | Data fetching + caching |
|
||||||
| `react` / `react-dom` | React 19 runtime |
|
| `react` / `react-dom` | React 19 runtime |
|
||||||
@@ -113,6 +109,6 @@ Parallel to `apps/web-next` e2e: validates that features work across frameworks.
|
|||||||
|
|
||||||
- **Feature packages:** `packages/{auth,blog,media,marketing-pages,navigation}/`
|
- **Feature packages:** `packages/{auth,blog,media,marketing-pages,navigation}/`
|
||||||
- **tRPC composition:** `packages/core-api/AGENTS.md`
|
- **tRPC composition:** `packages/core-api/AGENTS.md`
|
||||||
- **tRPC client + provider:** `packages/core-trpc/AGENTS.md`
|
- **tRPC client + provider (optional):** scaffold `@repo/core-trpc` first, then see `turbo/generators/templates/core-package/trpc/AGENTS.md.hbs`
|
||||||
- **UI components:** `packages/core-ui/AGENTS.md`
|
- **UI components (optional):** scaffold `@repo/core-ui` first, then see `packages/core-ui/AGENTS.md`
|
||||||
- **Next.js app (serves tRPC):** `apps/web-next/AGENTS.md`
|
- **Next.js app (serves tRPC):** `apps/web-next/AGENTS.md`
|
||||||
|
|||||||
@@ -2801,7 +2801,7 @@ function makeStages(F) {
|
|||||||
meta: `@repo/${F.name}/ui`,
|
meta: `@repo/${F.name}/ui`,
|
||||||
file: `packages/${F.name}/src/ui/query.ts`,
|
file: `packages/${F.name}/src/ui/query.ts`,
|
||||||
tag: "client",
|
tag: "client",
|
||||||
prose: `<code>${F.queryName}</code> on the client builds a typed React Query option object. The args type is inferred all the way back from the use case's <code>${F.inputSchemaName}</code>, exported from the feature root.`,
|
prose: `<code>${F.queryName}</code> on the client builds a typed React Query option object. The args type is inferred all the way back from the use case's <code>${F.inputSchemaName}</code>, exported from the feature root. <em>Note: <code>useTRPC()</code> is provided by <code>@repo/core-trpc</code> — an optional package. Scaffold it with <code>pnpm turbo gen core-package trpc</code> if not yet present.</em>`,
|
||||||
code: F.queryName.startsWith("(") ?
|
code: F.queryName.startsWith("(") ?
|
||||||
`// auth procedures are mutations — invoked via useMutation, not useQuery
|
`// auth procedures are mutations — invoked via useMutation, not useQuery
|
||||||
const trpc = useTRPC();
|
const trpc = useTRPC();
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ tests/
|
|||||||
- Any other feature package (`@repo/blog`, `@repo/media`, etc.)
|
- Any other feature package (`@repo/blog`, `@repo/media`, etc.)
|
||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Cross-links
|
## Cross-links
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ tests/
|
|||||||
- Any other feature package (`@repo/auth`, `@repo/media`, etc.)
|
- Any other feature package (`@repo/auth`, `@repo/media`, etc.)
|
||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Cross-links
|
## Cross-links
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-shared`, `@repo/core-api`, `@repo/core-trpc`, `@repo/core-ui`
|
- `@repo/core-shared`, `@repo/core-api`, `@repo/core-trpc`, `@repo/core-ui`
|
||||||
|
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Public exports
|
## Public exports
|
||||||
|
|
||||||
From `package.json`:
|
From `package.json`:
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ Feature-specific organisms (e.g., `ArticleCard`, `ArticleList`, `HeaderNavMenu`)
|
|||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`
|
||||||
|
|
||||||
|
> Note: `@repo/core-trpc` is an optional package scaffolded via `pnpm turbo gen core-package trpc`. If not present, this constraint still applies to any future installation.
|
||||||
|
|
||||||
## Public exports
|
## Public exports
|
||||||
|
|
||||||
From `package.json`:
|
From `package.json`:
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ tests/
|
|||||||
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Cross-links
|
## Cross-links
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ src/
|
|||||||
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Cross-links
|
## Cross-links
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ src/
|
|||||||
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
- Any other feature package (`@repo/auth`, `@repo/blog`, etc.)
|
||||||
- Any app package
|
- Any app package
|
||||||
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-trpc`, `@repo/core-ui` directly; only `@repo/core-shared`
|
||||||
|
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
|
||||||
|
|
||||||
## Cross-links
|
## Cross-links
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user