diff --git a/AGENTS.md b/AGENTS.md index 9995053..114825c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,10 +9,10 @@ This is a **Turborepo + pnpm monorepo** organized by vertical features. Each fea | Package | Tag | Purpose | |---|---|---| | `@repo/core-shared` | core | Generic primitives (Zod, env, Payload hooks/fields/blocks, tRPC init/context) | -| `@repo/core-cms` | core (composition) | Payload config aggregator — imports `@repo//cms` only | -| `@repo/core-api` | core (composition) | tRPC router aggregator — imports `@repo//api` only | -| `@repo/core-trpc` | core | Frontend tRPC client + framework-specific providers (Next.js, TanStack) | | `@repo/core-ui` | core | Design system (atoms, molecules, generic organisms, templates) | +| `@repo/core-api` | core-composition | tRPC router aggregator — imports `@repo//api` only | +| `@repo/core-cms` | core-composition | Payload config aggregator — imports `@repo//cms` only | +| `@repo/core-trpc` | core-composition | Frontend tRPC client + framework-specific providers (Next.js, TanStack) | | `@repo/auth` | feature | Users collection + sign-in/up/out | | `@repo/blog` | feature | Articles collection + article use-cases | | `@repo/media` | feature | Media collection + upload helpers | @@ -25,42 +25,47 @@ This is a **Turborepo + pnpm monorepo** organized by vertical features. Each fea ## Boundary Rules -### Three tags +### Five tags -- **app** — `apps/web-next`, `apps/web-tanstack`, `apps/cms` -- **feature** — `packages/auth`, `blog`, `media`, `marketing-pages`, `navigation` -- **core** — `packages/core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui` -- (untagged) — `packages/eslint-config`, `typescript-config` +- **app** (4 packages) — `apps/web-next`, `apps/web-tanstack`, `apps/cms`, `apps/storybook` +- **core-composition** (3 packages) — `packages/core-api`, `core-cms`, `core-trpc` +- **core** (2 packages) — `packages/core-shared`, `core-ui` +- **feature** (5 packages) — `packages/auth`, `blog`, `media`, `marketing-pages`, `navigation` +- **tooling** (2 packages) — `packages/core-eslint`, `core-typescript` ### Allowed dependency directions -``` -app → feature, core -feature → core -core → core (restricted; see exceptions below) -``` - -**Disallowed:** `core → feature`, `core → app`, `feature → app`, `feature → feature`. +| Tag | May depend on | +|---|---| +| app | app, core, core-composition, feature, tooling | +| core-composition | core, core-composition, feature, tooling | +| core | core, core-composition, tooling | +| feature | core, tooling | +| tooling | tooling | ### Composition exceptions -Two packages may cross normal boundaries: - -1. **`core-cms`** may import `@repo//cms` subpath exports only (to compose Payload collections). -2. **`core-api`** may import `@repo//api` subpath exports only (to compose tRPC routers). +1. **`core-api`** may import `@repo//api` subpath exports only (to compose tRPC routers). +2. **`core-cms`** may import `@repo//cms` subpath exports only (to compose Payload collections). +3. **`core-trpc`** reaches features transitively through `core-api`'s `AppRouter` type. No other cross-package boundary deviations are permitted. -### Three enforcement layers +### Four enforcement layers 1. **`package.json` dependencies** — only allowed deps are declared; illegal imports fail at install time. 2. **`exports` maps** — feature packages expose `.`, `./cms`, `./api`, `./di/bind-production` only; no deep source paths exist. -3. **ESLint `eslint-plugin-boundaries`** — configured in `packages/eslint-config/`: - - Feature packages may import from `core-*` and tooling only. - - `core-shared`, `core-trpc`, `core-ui` may not import any feature. +3. **ESLint `eslint-plugin-boundaries`** (lint-time) — configured in `packages/core-eslint/`: + - Enforces the five-tag rules at linting + - Feature packages may import from `core` and tooling only. + - `core-shared`, `core-ui` may not import any feature. - `core-api` restricted to `@repo//api` imports. - `core-cms` restricted to `@repo//cms` imports. - No `../../../` cross-package relative imports. +4. **Turborepo `boundaries`** (build-graph time) — configured in root `turbo.json`: + - Validates the entire workspace dependency graph, including transitive dependencies + - Catches issues ESLint might miss (e.g., transitive feature reaches through composition packages) + - Run with `pnpm turbo boundaries` --- @@ -82,7 +87,8 @@ Start with `docs/guides/adding-a-feature.md` for a step-by-step walkthrough cove pnpm install # Install all dependencies pnpm dev # Start all dev servers (Next.js :3000, CMS :3001, Storybook :6006) pnpm typecheck # Type-check all packages -pnpm lint # Lint all packages (boundaries enforced) +pnpm lint # Lint all packages (ESLint boundaries enforced) +pnpm turbo boundaries # Validate workspace dependency graph (Turbo boundaries) pnpm test # Run all unit + integration tests (Vitest) pnpm test:e2e # Run e2e tests (Playwright across both apps) pnpm build # Build all packages (Turborepo) @@ -202,10 +208,8 @@ await bindProductionUsers(authContainer, payloadConfig); Per-package documentation lives in each `AGENTS.md`: - `packages/core-shared/AGENTS.md` -- `packages/core-cms/AGENTS.md` -- `packages/core-api/AGENTS.md` -- `packages/core-trpc/AGENTS.md` +- `packages/core-api/AGENTS.md`, `core-cms/AGENTS.md`, `core-trpc/AGENTS.md` - `packages/core-ui/AGENTS.md` - `packages/auth/AGENTS.md`, `blog/AGENTS.md`, `media/AGENTS.md`, `marketing-pages/AGENTS.md`, `navigation/AGENTS.md` -- `packages/eslint-config/AGENTS.md`, `typescript-config/AGENTS.md` +- `packages/core-eslint/AGENTS.md`, `core-typescript/AGENTS.md` - `apps/cms/AGENTS.md`, `web-next/AGENTS.md`, `web-tanstack/AGENTS.md`, `storybook/AGENTS.md` diff --git a/CLAUDE.md b/CLAUDE.md index 1171dc1..184b093 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,12 +7,13 @@ pnpm install # Install all dependencies pnpm dev # Start all dev servers pnpm build # Build all packages pnpm test # Run all tests +pnpm turbo boundaries # Validate workspace dependency graph docker compose up -d # Start PostgreSQL ``` ## Project Overview -Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`, `blog`, `media`, `marketing-pages`, `navigation`) owns its Clean Architecture layers. Core packages (`core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui`) provide foundation. Supports Next.js and TanStack Start as frontend frameworks, Payload CMS for content management, and comprehensive agent-optimized documentation. +Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`, `blog`, `media`, `marketing-pages`, `navigation`) owns its Clean Architecture layers. Core packages (`core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui`) provide foundation. Two tooling packages (`core-eslint`, `core-typescript`) provide shared configs. Workspace boundaries are enforced by ESLint (lint-time) and Turborepo (build-graph time). Supports Next.js and TanStack Start as frontend frameworks, Payload CMS for content management, and comprehensive agent-optimized documentation. ## Read First diff --git a/docs/architecture/dependency-flow.md b/docs/architecture/dependency-flow.md index db8f887..ec71ca5 100644 --- a/docs/architecture/dependency-flow.md +++ b/docs/architecture/dependency-flow.md @@ -21,13 +21,16 @@ | shared | | | | | +--------+ +-----------+ +----------------+ - Boundary rules (enforced by eslint-plugin-boundaries): - app → app, core, feature, core-composition (any) - feature → core (any), but NOT other features, NOT app - core → core, but NOT feature, NOT app - core-composition → core, feature subpath exports only (`/cms`, `/api`) - core-api → @repo//api - core-cms → @repo//cms + Boundary rules (enforced by ESLint + Turborepo boundaries): + app → app, core, core-composition, feature, tooling + feature → core, tooling + core → core, core-composition, tooling + core-composition → core, core-composition, feature, tooling + tooling → tooling + + Composition exceptions: + core-api → @repo//api (subpath only) + core-cms → @repo//cms (subpath only) ``` ## Concrete examples @@ -65,6 +68,14 @@ import { blogRouter } from "@repo/blog/api"; // ❌ core → feature import { someBlogThing } from "@repo/blog"; // ❌ core → feature (only core-api/core-cms have exception) ``` -## Three-layer enforcement +## Enforcement strategy -ESLint catches accidental cross-package imports at lint time. The `package.json` `exports` map blocks deep imports at module-resolution time. Workspace `dependencies` declarations make the package graph itself the source of truth — if you didn't declare it, you can't import it. +Three layers work in tandem: + +1. **`package.json` dependencies** — if you didn't declare it, you can't import it +2. **`exports` map** — blocks deep imports; only public subpaths are accessible +3. **Two parallel automated checks** (both enforcing the same five-tag model): + - **ESLint `eslint-plugin-boundaries`** runs at lint time, catching direct-import violations + - **Turborepo `boundaries`** runs at build time, validating the entire workspace graph including transitive dependencies + +The two enforcement layers are independent but complementary. ESLint is stricter on per-import context (e.g., file-specific exemptions via `// @boundaries-ignore`), while Turborepo catches transitive issues that lint-time checking misses. Run `pnpm lint` and `pnpm turbo boundaries` in CI to catch all violations. diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index 1ec2301..368c1b9 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -21,8 +21,8 @@ packages/ navigation/ Header global + menu items # Tooling - eslint-config/ Shared ESLint flat config + boundary rules - typescript-config/ Shared tsconfig + vitest base + core-eslint/ Shared ESLint flat config + boundary rules + core-typescript/ Shared tsconfig + vitest base ``` ## Data flow @@ -47,7 +47,36 @@ Payload Local API → Postgres 1. **`package.json` deps** — only declare allowed deps 2. **`exports` map** — each package exposes a small public surface (`.`, `./cms`, `./api`, `./di/bind-production`) -3. **ESLint `eslint-plugin-boundaries`** — three tags (`app`, `feature`, `core`); two composition exceptions (`core-api` may import `@repo//api`; `core-cms` may import `@repo//cms`) +3. **Two parallel automated checks**: + - **ESLint `eslint-plugin-boundaries`** (lint-time) — enforces boundary rules at linting + - **Turborepo `boundaries`** (build-graph time) — validates entire workspace dependency graph, including transitive reaches + +Both use the same five-tag model; see "Five tags" section below. + +## Five tags + +The workspace is organized into five mutually exclusive tags: + +- **app** (4 packages): `apps/cms`, `apps/web-next`, `apps/web-tanstack`, `apps/storybook` +- **core-composition** (3 packages): `packages/core-api`, `packages/core-cms`, `packages/core-trpc` +- **core** (2 packages): `packages/core-shared`, `packages/core-ui` +- **feature** (5 packages): `packages/auth`, `packages/blog`, `packages/media`, `packages/marketing-pages`, `packages/navigation` +- **tooling** (2 packages): `packages/core-eslint`, `packages/core-typescript` + +**Allowed dependency directions:** + +| Tag | May depend on | +|---|---| +| app | app, core, core-composition, feature, tooling | +| core-composition | core, core-composition, feature, tooling | +| core | core, core-composition, tooling | +| feature | core, tooling | +| tooling | tooling | + +**Composition exceptions:** +- `core-api` may import from `@repo//api` subpath exports only +- `core-cms` may import from `@repo//cms` subpath exports only +- `core-trpc` reaches features transitively through `core-api`'s `AppRouter` type ## Per-feature DI containers diff --git a/docs/architecture/vertical-feature-spec.md b/docs/architecture/vertical-feature-spec.md index 63b0f6c..f4fabb8 100644 --- a/docs/architecture/vertical-feature-spec.md +++ b/docs/architecture/vertical-feature-spec.md @@ -40,7 +40,7 @@ The refactor preserves Clean Architecture layering *inside* each feature (the ex - Five `core-*` packages: `core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui` - Five feature packages: `auth`, `blog`, `media`, `marketing-pages`, `navigation` -- Two tooling packages unchanged: `eslint-config`, `typescript-config` +- Two tooling packages renamed: `eslint-config` → `core-eslint`, `typescript-config` → `core-typescript` - Three apps unchanged in name: `apps/web-next`, `apps/web-tanstack`, `apps/cms` - Packages deleted: `packages/core`, `packages/api`, `packages/api-client`, `packages/cms-core`, `packages/cms-client`, `packages/ui` - Per-feature InversifyJS containers (no shared container) @@ -124,9 +124,9 @@ repo/ marketing-pages/ # pages collection + SiteSettings global navigation/ # header global - # ─── TOOLING (untagged) ─── - eslint-config/ - typescript-config/ + # ─── TOOLING (tagged "tooling") ─── + core-eslint/ + core-typescript/ docs/ architecture/ @@ -392,44 +392,47 @@ export default buildConfig({ ## 9. Boundaries + enforcement -### 9.1 Tags +### 9.1 Five tags -Package-level `turbo.json` tags: +Package-level `turbo.json` tags (refined from earlier ADR-006's three-tag model): | Tag | Packages | |---|---| -| `app` | `apps/web-next`, `apps/web-tanstack`, `apps/cms` | +| `app` | `apps/web-next`, `apps/web-tanstack`, `apps/cms`, `apps/storybook` | +| `core-composition` | `packages/core-api`, `core-cms`, `core-trpc` | +| `core` | `packages/core-shared`, `core-ui` | | `feature` | `packages/auth`, `blog`, `media`, `marketing-pages`, `navigation` | -| `core` | `packages/core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui` | -| (untagged) | `packages/eslint-config`, `packages/typescript-config` | +| `tooling` | `packages/core-eslint`, `core-typescript` | + +Note: `core-trpc` is `core-composition` (not plain `core`) because it transitively reaches features through `core-api`'s `AppRouter` type. ### 9.2 Allowed dependency directions -``` -app → feature, core -feature → core -core → core (restricted; see exceptions) -``` - -Disallowed: `core → feature`, `core → app`, `feature → app`, `feature → feature`. +| Tag | May depend on | +|---|---| +| app | app, core, core-composition, feature, tooling | +| core-composition | core, core-composition, feature, tooling | +| core | core, core-composition, tooling | +| feature | core, tooling | +| tooling | tooling | ### 9.3 Composition exceptions - `core-cms` may import `@repo//cms` subpath exports only. - `core-api` may import `@repo//api` subpath exports only. -- No other `core-*` package may import any feature package under any export. +- No other package may deviate from the five-tag rules. -### 9.4 Three enforcement layers +### 9.4 Four enforcement layers 1. **`package.json` dependencies** — only allowed deps declared. 2. **`exports` maps** — feature packages expose `.`, `./cms`, `./api` only (no deep source paths). -3. **ESLint `eslint-plugin-boundaries`** — configured in `packages/eslint-config/` flat config: - - Feature packages may import other packages only through public subpath exports. - - `core-shared`, `core-trpc`, `core-ui` may not import feature packages. - - `core-api` restricted to `@repo//api`. - - `core-cms` restricted to `@repo//cms`. - - No `../../../` cross-package source imports. -4. **TypeScript path aliases** (`tsconfig.base.json`) — only `@repo/`, `@repo//cms`, `@repo//api`; no `@repo//src/...` paths exist, blocking deep imports at editor level. +3. **ESLint `eslint-plugin-boundaries`** (lint-time) — configured in `packages/core-eslint/` flat config: + - Enforces the five-tag rules (same rules as Turbo boundaries) + - File-specific exemptions via `// @boundaries-ignore` comments +4. **Turborepo `boundaries`** (build-graph time) — configured in root `turbo.json`: + - Validates the entire workspace dependency graph, including transitive dependencies + - Catches issues that lint-time checking misses (e.g., transitive feature reaches) + - Run `pnpm turbo boundaries` to validate ### 9.5 Root `turbo.json` (unchanged concept) @@ -469,7 +472,7 @@ Tags govern architectural boundaries; `dependsOn: ["^build"]` governs task execu ### 10.2 Vitest - Each package has its own `vitest.config.ts`. -- Shared base in `packages/typescript-config/vitest.base.ts`; packages extend it and pick `environment: 'jsdom' | 'node'` per need. +- Shared base in `packages/core-typescript/vitest.base.ts`; packages extend it and pick `environment: 'jsdom' | 'node'` per need. - Turbo `test` task runs `vitest run` per package. ### 10.3 DI in tests (per-feature container) diff --git a/docs/decisions/adr-010-turbo-boundaries.md b/docs/decisions/adr-010-turbo-boundaries.md new file mode 100644 index 0000000..648df86 --- /dev/null +++ b/docs/decisions/adr-010-turbo-boundaries.md @@ -0,0 +1,123 @@ +# ADR-010: Turborepo boundaries alongside ESLint enforcement + +**Status:** Accepted +**Date:** 2026-05-04 +**Supersedes:** ADR-006 (partial refinement; not a contradiction) + +## Context + +ADR-006 established the vertical-feature monorepo with three tags (`app`, `feature`, `core`). ESLint with `eslint-plugin-boundaries` was introduced to enforce direct-import boundaries at lint time, catching violations like: + +- Feature package importing from another feature +- Core package importing from a feature +- Deep imports past public `exports` map boundaries + +However, ESLint has two intrinsic limitations: + +1. **No transitive enforcement** — If `core-trpc` imports `core-api` (which imports feature routers), ESLint sees only the direct edge `core-trpc` → `core-api`. The transitive reach into features is invisible. A package can declare `@repo/feature-x` as a dependency without ever importing it directly. + +2. **No declared-dep enforcement** — A `package.json` dependency that doesn't match an actual import goes undetected. Conversely, a `package.json` dependency might be missing but the transitive graph still allows the code to work. + +The result: two types of dependency drift escape lint-time checking: + +- A composition package's transitive reach into features (real problem: `core-trpc` → `core-api` → `feature-blog-routers`) +- Incorrect or missing `package.json` declarations + +## Decision + +Add Turborepo's `boundaries` feature as a second enforcement layer running at **build-graph time** (before build), parallel to ESLint's lint-time checks. + +### Five-tag model (refined from ADR-006) + +ADR-006 mentioned three tags. This ADR refines the model to five, distinguishing composition packages explicitly: + +- **app** — `apps/web-next`, `apps/web-tanstack`, `apps/cms`, `apps/storybook` +- **core** — `packages/core-shared`, `core-ui` (pure foundation, no transitive feature reach) +- **core-composition** — `packages/core-api`, `core-cms`, `core-trpc` (composition or transitively reach features) +- **feature** — `packages/auth`, `blog`, `media`, `marketing-pages`, `navigation` +- **tooling** — `packages/core-eslint`, `core-typescript` + +Why `core-trpc` is `core-composition`: +- `core-trpc` imports `@repo/core-api` (the tRPC app router) +- `core-api` imports feature routers from `@repo//api` +- Therefore, `core-trpc` transitively depends on features through the `AppRouter` type +- This violates ADR-006's "core → NOT feature" rule if we treat `core-trpc` as plain `core` +- Solution: tag `core-trpc` as `core-composition` to make the transitive reach explicit and allowed + +### Implementation + +1. **Root `turbo.json`** declares boundary rules as a `boundaries.tags` config: + ```json + { + "boundaries": { + "tags": { + "app": { "dependencies": { "allow": ["app", "core", "core-composition", "feature", "tooling"] } }, + "core-composition": { "dependencies": { "allow": ["core", "core-composition", "feature", "tooling"] } }, + "core": { "dependencies": { "allow": ["core", "core-composition", "tooling"] } }, + "feature": { "dependencies": { "allow": ["core", "tooling"] } }, + "tooling": { "dependencies": { "allow": ["tooling"] } } + } + } + } + ``` + +2. **Per-package `turbo.json`** declares the package's tag: + ```json + // packages/blog/turbo.json + { "extends": ["../../../turbo.json"], "tasks": { /* ... */ } } + // package.json + { "turbo": { "tasks": { "build": { /* ... */ } }, "tags": ["feature"] } } + ``` + +3. **CLI validation** — `pnpm turbo boundaries` runs the check in <1 second without building anything + +### Two layers, not one + +Both ESLint and Turborepo enforce the same five-tag rules, but for different reasons: + +| Layer | Runs | Sees | Exempts via | +|---|---|---|---| +| ESLint `eslint-plugin-boundaries` | lint-time | Direct imports per file | `// @boundaries-ignore` comments | +| Turborepo `boundaries` | build-graph time | Entire workspace dependency graph including transitives | None (graph-based, not per-import) | + +**Why both?** +- **ESLint** provides fine-grained control (file-level exemptions) and immediate feedback during development +- **Turborepo** catches transitive issues (e.g., feature reach through composition packages) and missing declarations + +**Enforcement** — CI runs both: `pnpm lint` (includes ESLint) and `pnpm turbo boundaries`. + +## Consequences + +1. **Two independent checks** — developers get immediate ESLint feedback and a final Turbo gate in CI +2. **Both must stay in sync** — when adding a new tag rule, update both: + - `packages/core-eslint/base.js` (ESLint `eslint-plugin-boundaries` config) + - Root `turbo.json` (`boundaries.tags` config) + - Per-package `package.json` `turbo.tags` declaration +3. **Stricter than before** — Turborepo sees transitives; some patterns that pass ESLint may fail Turbo: + - Example: `packages/cms` might try to use `@repo/` indirectly (not importing, but depending) + - Solution: declare the dependency explicitly or restructure the import +4. **The five-tag model is a refinement, not a contradiction** — ADR-006 mentioned three tags; this ADR adds `core-composition` and `tooling` explicitly and moves them into the boundary enforcement +5. **`core-trpc`'s new tag** — previously thought of as `core`, now explicitly `core-composition` to match its transitive reach; any code assuming `core-trpc` is `core` must be updated + +## Alternatives considered + +1. **ESLint only** — Simple, immediate feedback. Downside: misses transitive issues; no build-graph validation. +2. **Turborepo only** — Catches everything eventually, but slower feedback cycle; less granular exemptions. +3. **Both in series** — ESLint first (fast), Turbo second (thorough). Chosen. +4. **Custom graph validator** — Over-engineered; Turborepo's built-in feature is stable and designed for this. + +## Related + +- **ADR-006:** Vertical feature packages (the original three-tag model) +- **ADR-009:** Integrations folder naming +- **`packages/core-eslint/base.js`** — ESLint configuration +- **Root `turbo.json`** — Turborepo configuration with boundaries rules +- **`docs/architecture/overview.md`** — Package map and five-tag summary +- **`docs/architecture/dependency-flow.md`** — Enforcement layers and rules +- **`AGENTS.md`** — Per-package boundary documentation + +## Timeline + +- **2026-05-04** — Turborepo boundaries added alongside existing ESLint enforcement +- **CI integration** — `pnpm turbo boundaries` added to lint stage +- **Documentation** — Updated AGENTS.md, overview.md, dependency-flow.md, vertical-feature-spec.md diff --git a/packages/core-api/AGENTS.md b/packages/core-api/AGENTS.md index 5439f12..5cdf8a2 100644 --- a/packages/core-api/AGENTS.md +++ b/packages/core-api/AGENTS.md @@ -1,5 +1,7 @@ # AGENTS.md — core-api +**Tag:** core-composition + **Composition-only package** that aggregates feature tRPC routers into a single root `appRouter`. It does not define procedures; instead, it imports them from feature packages. ## Responsibilities diff --git a/packages/core-cms/AGENTS.md b/packages/core-cms/AGENTS.md index 749714d..f507560 100644 --- a/packages/core-cms/AGENTS.md +++ b/packages/core-cms/AGENTS.md @@ -1,5 +1,7 @@ # AGENTS.md — core-cms +**Tag:** core-composition + **Composition-only package** that aggregates feature Payload collections and globals into a single Payload config. It does not define its own collections; instead, it imports them from feature packages. ## Responsibilities diff --git a/packages/core-eslint/AGENTS.md b/packages/core-eslint/AGENTS.md index 394a766..892f7f2 100644 --- a/packages/core-eslint/AGENTS.md +++ b/packages/core-eslint/AGENTS.md @@ -1,6 +1,8 @@ -# AGENTS.md — eslint-config +# AGENTS.md — core-eslint -Shared ESLint 9 flat configs (rules, plugins, parser settings) consumed by all packages via `eslint.config.js`. +**Tag:** tooling + +Shared ESLint 9 flat configs (rules, plugins, parser settings) consumed by all packages via `eslint.config.js`. Enforces boundary rules alongside Turborepo's `boundaries` feature (which validates the workspace dependency graph at build time). ## What it owns diff --git a/packages/core-trpc/AGENTS.md b/packages/core-trpc/AGENTS.md index 3c1b306..0ae812d 100644 --- a/packages/core-trpc/AGENTS.md +++ b/packages/core-trpc/AGENTS.md @@ -1,6 +1,8 @@ # AGENTS.md — core-trpc -Frontend tRPC platform providing the client and framework-specific providers (Next.js, TanStack). Bridges typed backend (`@repo/core-api`) to frontend applications. +**Tag:** core-composition + +Frontend tRPC platform providing the client and framework-specific providers (Next.js, TanStack). Bridges typed backend (`@repo/core-api`) to frontend applications. Tagged `core-composition` (not `core`) because it transitively reaches features through `core-api`'s `AppRouter` type. ## Responsibilities diff --git a/packages/core-typescript/AGENTS.md b/packages/core-typescript/AGENTS.md index 1dbbf07..872fa7c 100644 --- a/packages/core-typescript/AGENTS.md +++ b/packages/core-typescript/AGENTS.md @@ -1,4 +1,6 @@ -# AGENTS.md — typescript-config +# AGENTS.md — core-typescript + +**Tag:** tooling Shared TypeScript base configs (`tsconfig.json` files) and Vitest base config, consumed by all packages.