From 2c110b33e96b15192782be7b30d5ac98688f04d0 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 6 Apr 2026 15:04:15 +0200 Subject: [PATCH] feat: add AGENTS.md for all packages and apps (9 files) --- apps/cms/AGENTS.md | 18 +++++++++++ apps/storybook/AGENTS.md | 24 ++++++++++++++ apps/web-next/AGENTS.md | 16 ++++++++++ apps/web-tanstack/AGENTS.md | 15 +++++++++ packages/api-client/AGENTS.md | 27 ++++++++++++++++ packages/api/AGENTS.md | 17 ++++++++++ packages/cms-client/AGENTS.md | 39 +++++++++++++++++++++++ packages/cms-core/AGENTS.md | 40 ++++++++++++++++++++++++ packages/ui/AGENTS.md | 59 +++++++++++++++++++++++++++++++++++ 9 files changed, 255 insertions(+) create mode 100644 apps/cms/AGENTS.md create mode 100644 apps/storybook/AGENTS.md create mode 100644 apps/web-next/AGENTS.md create mode 100644 apps/web-tanstack/AGENTS.md create mode 100644 packages/api-client/AGENTS.md create mode 100644 packages/api/AGENTS.md create mode 100644 packages/cms-client/AGENTS.md create mode 100644 packages/cms-core/AGENTS.md create mode 100644 packages/ui/AGENTS.md diff --git a/apps/cms/AGENTS.md b/apps/cms/AGENTS.md new file mode 100644 index 0000000..5b27c37 --- /dev/null +++ b/apps/cms/AGENTS.md @@ -0,0 +1,18 @@ +# apps/cms — Payload CMS Admin Shell + +Thin Next.js shell that imports config from `@repo/cms-core` and serves the Payload admin panel. Contains almost no custom code. + +## Rules + +- All collections, hooks, globals, and payload.config.ts live in `@repo/cms-core` +- This app only contains Next.js routing boilerplate for the admin panel +- Import `@payload-config` which resolves to `@repo/cms-core/src/payload.config.ts` +- NEVER import from `@repo/core/infrastructure` + +## Development + +```bash +pnpm dev --filter @repo/cms # Starts on port 3001 +``` + +Requires PostgreSQL running (via `docker compose up postgres`). diff --git a/apps/storybook/AGENTS.md b/apps/storybook/AGENTS.md new file mode 100644 index 0000000..1cf469d --- /dev/null +++ b/apps/storybook/AGENTS.md @@ -0,0 +1,24 @@ +# apps/storybook — Centralized Storybook + +Pulls stories from `packages/ui/src/**/*.stories.tsx`. Uses `@storybook/react-vite` with `@tailwindcss/vite` plugin. + +## Development + +```bash +pnpm dev --filter @repo/storybook # Starts on port 6006 +``` + +## Configuration + +- `.storybook/main.ts` — Framework config, story globs, Tailwind vite plugin +- `.storybook/preview.ts` — Global CSS import, control matchers + +## Story Organization + +Stories are organized by Atomic Design level via title: +- `"Atoms/Button"`, `"Molecules/FormField"`, `"Organisms/DataTable"` + +## MCP + +When running, Storybook MCP is available at `http://localhost:6006/mcp`. +Install `@storybook/addon-mcp` to enable. diff --git a/apps/web-next/AGENTS.md b/apps/web-next/AGENTS.md new file mode 100644 index 0000000..aabf338 --- /dev/null +++ b/apps/web-next/AGENTS.md @@ -0,0 +1,16 @@ +# apps/web-next — Next.js 15 Reference App + +Thin Next.js app consuming `@repo/api-client` for data and `@repo/ui` for components. + +## Key Files + +- `src/app/api/trpc/[trpc]/route.ts` — tRPC HTTP endpoint (fetch adapter) +- `src/app/providers.tsx` — Wraps with `` +- `src/app/layout.tsx` — Root layout + +## Rules + +- Use `@repo/api-client` hooks for all data fetching +- Use `@repo/ui` components for all UI +- tRPC endpoint imports `appRouter` from `@repo/api` +- Payload instance initialization goes in `src/lib/payload.ts` diff --git a/apps/web-tanstack/AGENTS.md b/apps/web-tanstack/AGENTS.md new file mode 100644 index 0000000..faeb3df --- /dev/null +++ b/apps/web-tanstack/AGENTS.md @@ -0,0 +1,15 @@ +# apps/web-tanstack — TanStack Start Reference App + +TanStack Start app consuming `@repo/api-client` for data and `@repo/ui` for components. + +## Key Files + +- `src/routes/__root.tsx` — Root layout with `` +- `src/routes/index.tsx` — Home page + +## Rules + +- Use `@repo/api-client` hooks for all data fetching +- Use `@repo/ui` components for all UI +- File-based routing via TanStack Router (`src/routes/`) +- Payload instance initialization goes in `src/lib/payload.ts` diff --git a/packages/api-client/AGENTS.md b/packages/api-client/AGENTS.md new file mode 100644 index 0000000..2ad7465 --- /dev/null +++ b/packages/api-client/AGENTS.md @@ -0,0 +1,27 @@ +# @repo/api-client — Shared React Query Hooks + +Framework-agnostic tRPC + React Query provider consumed by all apps. + +## Rules + +- NEVER import framework-specific code (no next/, no tanstack/) +- NEVER put business logic in hooks +- Hooks use `useTRPC()` from `./trpc.ts` +- Both Next.js and TanStack Start apps use the same `` + +## Usage in Apps + +```tsx +import { ApiProvider, useTRPC } from "@repo/api-client"; + +// Root layout: +{children} + +// In components: +const trpc = useTRPC(); +const articles = trpc.content.listArticles.useQuery({}); +``` + +## Adding a New Hook (optional wrapper) + +Custom hooks are optional — `useTRPC()` provides typed access to all procedures directly. Only create wrapper hooks if you need shared query logic across multiple components. diff --git a/packages/api/AGENTS.md b/packages/api/AGENTS.md new file mode 100644 index 0000000..ddc1e62 --- /dev/null +++ b/packages/api/AGENTS.md @@ -0,0 +1,17 @@ +# @repo/api — tRPC Router Definitions + +tRPC routers that call controllers from `@repo/core`. Each procedure validates input and delegates to a controller. + +## Rules + +- NEVER put business logic in routers — delegate to controllers +- Input validation uses Zod schemas +- Each domain gets its own router file + +## Adding a New tRPC Router + +1. Create `src/router/{domain}.router.ts` +2. Import `router` and `publicProcedure` from `../trpc.js` +3. Define procedures (`.query()` for reads, `.mutation()` for writes) +4. Each procedure calls a controller from `@repo/core` +5. Add router to root `appRouter` in `src/router/index.ts` diff --git a/packages/cms-client/AGENTS.md b/packages/cms-client/AGENTS.md new file mode 100644 index 0000000..b17e307 --- /dev/null +++ b/packages/cms-client/AGENTS.md @@ -0,0 +1,39 @@ +# @repo/cms-client — Dual-Mode Payload Client + +Provides typed access to Payload CMS via Local API (primary) or HTTP REST (fallback). + +## THIS PACKAGE IS STANDALONE + +- NEVER import from: `@repo/cms-core`, `@repo/core`, `apps/*` +- The Payload instance is INJECTED, not imported +- Types are generated via `payload generate:types` + +## Initialization + +| Context | Mode | How | +|---|---|---| +| apps/cms server | Local | `getPayload({config})` from @repo/cms-core | +| apps/web-next server | Local | `getPayload({config})` from @repo/cms-core | +| apps/web-tanstack server | Local | `getPayload({config})` from @repo/cms-core | +| Client-side (browser) | N/A | Goes through tRPC — server handles it | +| External services | HTTP | `createPayloadClient({mode:"http",baseURL})` | + +```typescript +// In app startup (e.g., apps/web-next/src/lib/payload.ts): +import { getPayload } from "payload"; +import { config } from "@repo/cms-core"; +import { createPayloadClient } from "@repo/cms-client"; + +const payload = await getPayload({ config }); +const client = createPayloadClient({ mode: "local", payload }); +``` + +## Available Methods + +All methods support full Payload query capabilities (where, sort, limit, depth, page, populate): + +- `find(collection, options)` — paginated query +- `findByID(collection, id, options)` — single document +- `create(collection, data, options)` — create document +- `update(collection, id, data, options)` — update document +- `delete(collection, id)` — delete document diff --git a/packages/cms-core/AGENTS.md b/packages/cms-core/AGENTS.md new file mode 100644 index 0000000..ba6a2fe --- /dev/null +++ b/packages/cms-core/AGENTS.md @@ -0,0 +1,40 @@ +# @repo/cms-core — Payload CMS Definition + +All Payload configuration lives here: payload.config.ts, collections, globals, hooks, access control. The `apps/cms` app is a thin shell that imports this config. + +## Hook Rules + +| Category | Location | Examples | +|---|---|---| +| CMS-operational | Stay in hook | Slugify, image resize, default values | +| Business logic | Delegate to use case | Notifications, validation, cross-domain updates | + +### DO + +- Keep hooks thin (max 5-10 lines) +- Import use cases from `@repo/core/application` +- Map Payload hook args to use case input types + +### DON'T + +- Import from `@repo/core/infrastructure` +- Put business validation in hooks +- Call external services directly from hooks +- Duplicate logic that exists in a use case + +## Adding a New Collection + +1. Create folder: `src/collections/{name}/` +2. Create: `index.ts` (CollectionConfig), `fields.ts` +3. Optionally: `hooks/`, `access/` +4. Import in `src/payload.config.ts` collections array +5. Export from `src/index.ts` + +## Adding a Hook That Calls a Use Case + +1. Create `src/collections/{name}/hooks/{hook-name}.ts` +2. Import use case from `@repo/core` (application layer only) +3. Map Payload's hook args to use case input +4. Call use case, return data + +**Rule of thumb:** If deleting the hook would break a business requirement, the logic must be in a use case. diff --git a/packages/ui/AGENTS.md b/packages/ui/AGENTS.md new file mode 100644 index 0000000..4152a65 --- /dev/null +++ b/packages/ui/AGENTS.md @@ -0,0 +1,59 @@ +# @repo/ui — Atomic Design Component Library + +shadcn/ui + Tailwind CSS v4 + Atomic Design. Components organized by level with co-located stories. + +## Atomic Classification Guide + +| Level | Definition | Examples | +|---|---|---| +| Atom | Single element, can't break down further | Button, Input, Label, Badge, Separator | +| Molecule | 2-3 atoms, single responsibility | FormField, SearchBar, Tooltip, Select | +| Organism | Complex section, self-contained | DataTable, Dialog, Header, Sidebar, Card | +| Template | Page layout, content-agnostic | DashboardLayout, AuthLayout | +| Page | Template + real data | **LIVES IN apps/, NOT HERE** | + +## Import Rules + +| Level | Can import from | NEVER import from | +|---|---|---| +| Atoms | lib/, hooks/, styles/ | molecules/, organisms/, templates/ | +| Molecules | atoms/, lib/, hooks/ | organisms/, templates/ | +| Organisms | atoms/, molecules/, lib/, hooks/ | templates/ | +| Templates | atoms/, molecules/, organisms/, lib/, hooks/ | (top level) | + +## Component Rules + +- **Atoms:** No margins/positioning, no state, no business logic +- **Molecules:** Single responsibility, minimal controlled state +- **Organisms:** Can have internal state and sub-components +- **Templates:** Use children/slots, NEVER hard-code content +- **All:** Co-locate `.stories.tsx` next to component + +## shadcn/ui Workflow + +1. `pnpm dlx shadcn@latest add [component]` — lands in atoms/ by default +2. Check classification guide above +3. If not atom → move to correct directory +4. Create `.stories.tsx` with title: `"{Level}/{ComponentName}"` +5. Update level's `index.ts` barrel + +## Story Template + +```tsx +import type { Meta, StoryObj } from "@storybook/react"; +import { MyComponent } from "./my-component.js"; + +const meta = { + title: "{Level}/{ComponentName}", + component: MyComponent, + tags: ["autodocs"], +} satisfies Meta; +export default meta; +``` + +## Storybook MCP + +Before creating UI components, query Storybook MCP: +- `list-all-documentation` — check for existing components +- `get-documentation` — understand props/variants +- After creating: `run-story-tests` to validate