docs(dev-seed): canonical doc updates + refactor-log entry
- CLAUDE.md Key Conventions: 'App bootstrap' rule rewritten as 'Three binding modes per feature' — describes USE_DEV_SEED + NODE_ENV resolution order and the new ./di/bind-dev-seed export. - AGENTS.md (root): exports list now mentions ./ui + ./di/bind-dev-seed; Per-feature public-API surface table gains a row; Apps section shows the bindAll() dispatcher with three-rule logic. - docs/architecture/vertical-feature-spec.md §6: file shape now includes bind-dev-seed.ts, bind-dev-seed.test.ts, __seeds__/dev.ts; package.json exports list updated to include ./di/bind-dev-seed. - docs/architecture/data-flow-explainer.html: anatomy tree gains __seeds__/ row; LAYERS.di description updated with new binders + cross-link to di-explainer.html; new LAYERS.seeds entry; public- surface card expanded to six subpaths. - docs/superpowers/refactor-logs/2026-05-06-input-output-unification.md §7: new 'Post-Plan-9: dev-seed binders' entry summarizing the rollout (commits, per-feature additions, app wiring, tests, turbo, docs). - bind-production.test.ts: dispatcher tests use vi.stubEnv (typesafe way to test process.env in TypeScript 5+ with @types/node read-only process.env types). 4 dispatcher tests + 2 bindAllProduction tests = 7 tests total.
This commit is contained in:
24
AGENTS.md
24
AGENTS.md
@@ -55,7 +55,7 @@ No other cross-package boundary deviations are permitted.
|
||||
### 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.
|
||||
2. **`exports` maps** — feature packages expose `.`, `./ui`, `./cms`, `./api`, `./di/bind-production`, `./di/bind-dev-seed` only; no deep source paths exist.
|
||||
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.
|
||||
@@ -282,7 +282,8 @@ Each feature package exposes exactly these subpath exports:
|
||||
| `./ui` | Query builders (`queryOptions`), UI components | App packages |
|
||||
| `./api` | tRPC router (`xRouter` + `XRouter` type) | `@repo/core-api` only |
|
||||
| `./cms` | Payload collections | `@repo/core-cms` only |
|
||||
| `./di/bind-production` | App boot side-effect | App packages only |
|
||||
| `./di/bind-production` | App boot side-effect — swaps mock for real Payload impl | App packages only |
|
||||
| `./di/bind-dev-seed` | App boot side-effect — swaps empty mock for populated mock | App packages, storybook |
|
||||
|
||||
Apps import schemas/types from `@repo/<feature>` (root) and React Query builders from `@repo/<feature>/ui`. Deep source paths are not accessible — the `exports` map enforces this.
|
||||
|
||||
@@ -305,9 +306,13 @@ export class ArticlesRepository implements IArticlesRepository {
|
||||
|
||||
Class names carry no `Payload` prefix — `ArticlesRepository`, `PagesRepository`, `HeaderRepository`, etc. The config comes from the app at boot time (see below).
|
||||
|
||||
### Apps call `bindProduction*()` per feature at boot
|
||||
### Apps call `bindAll()` per feature at boot
|
||||
|
||||
Each app (`web-next`, `web-tanstack`, `cms`) imports feature `bindProduction*` functions and calls them at startup to swap mock implementations for Payload-backed ones:
|
||||
Each app (`web-next`, `web-tanstack`, `cms`) imports both binders per feature and uses a small dispatcher (`bindAll()`) that picks based on environment:
|
||||
|
||||
- `USE_DEV_SEED === "true"` → dev seed (explicit override; works in any `NODE_ENV`)
|
||||
- `NODE_ENV === "production"` → production (real Payload)
|
||||
- otherwise → dev seed (developer default; `pnpm dev` boots without Payload)
|
||||
|
||||
```typescript
|
||||
// apps/web-next/src/server/bind-production.ts
|
||||
@@ -316,8 +321,19 @@ import { bindProductionAuth } from "@repo/auth/di/bind-production";
|
||||
import { bindProductionMarketingPages } from "@repo/marketing-pages/di/bind-production";
|
||||
import { bindProductionNavigation } from "@repo/navigation/di/bind-production";
|
||||
import { bindProductionMedia } from "@repo/media/di/bind-production";
|
||||
import { bindDevSeedBlog } from "@repo/blog/di/bind-dev-seed";
|
||||
import { bindDevSeedAuth } from "@repo/auth/di/bind-dev-seed";
|
||||
import { bindDevSeedMarketingPages } from "@repo/marketing-pages/di/bind-dev-seed";
|
||||
import { bindDevSeedNavigation } from "@repo/navigation/di/bind-dev-seed";
|
||||
import { bindDevSeedMedia } from "@repo/media/di/bind-dev-seed";
|
||||
import config from "@repo/core-cms";
|
||||
|
||||
export async function bindAll(): Promise<void> {
|
||||
if (process.env.USE_DEV_SEED === "true") return bindAllDevSeed();
|
||||
if (process.env.NODE_ENV === "production") return bindAllProduction();
|
||||
return bindAllDevSeed();
|
||||
}
|
||||
|
||||
export async function bindAllProduction(): Promise<void> {
|
||||
const resolvedConfig = await config;
|
||||
bindProductionAuth(resolvedConfig);
|
||||
|
||||
Reference in New Issue
Block a user