# Scaffolding a feature `turbo gen feature` produces a feature package under `packages//` matching the shape of the reference `navigation` feature. ## Invoking the generator Interactive (recommended for first runs — Plop will prompt for each value): ```bash pnpm turbo gen feature ``` Non-interactive (positional bypass — order matches the prompts in `turbo/generators/config.ts`): ```bash pnpm turbo gen feature --args ``` | Position | Prompt | Example | Conventions | | ------------------- | -------------------- | --------- | ----------------------------------------------------------- | | `` | Feature package name | `widgets` | `kebab-case`, becomes `@repo/` and `packages//` | | `` | Entity name | `Widget` | `PascalCase` singular, drives class/symbol/use-case names | | `` | Entity plural slug | `widgets` | `kebab-case`, used for the future Payload collection slug | Example end-to-end: ```bash pnpm turbo gen feature --args widgets Widget widgets pnpm install # link the new workspace package pnpm --filter @repo/widgets lint typecheck test ``` ## Conformance-ready by default Since milestone v of the conformance system, `pnpm turbo gen feature ` emits two conformance artefacts: - **`src/feature.manifest.ts`** declaring the scaffolded `getX` use case - **`src/di/bind-production.ts`** with `assertFeatureConformance(...)` called at the tail Run `pnpm conformance` after generating a feature — it should pass cleanly. If you add `bus.publish("X")` calls in a factory body, you'll also need to add `"X"` to the manifest's `publishes[]` array for that use case, or the `no-undeclared-event-publish` ESLint rule will warn. See `docs/guides/conformance-quickref.md` for the manifest field reference. ## What it generates - Package files: `package.json`, `tsconfig.json`, `vitest.config.ts`, `eslint.config.js`, `turbo.json`, `AGENTS.md` - One entity (`src/entities/models/.ts`) with a Zod schema + unit test - One use case (`src/application/use-cases/get-.use-case.ts`) with exported input/output schemas, factory function, and tests - One controller (`src/interface-adapters/controllers/get-.controller.ts`) with the canonical safeParse → presenter shape - Mock + real repository (`src/infrastructure/repositories/.repository{,.mock}.ts`). Both wrap calls in `tracer.startSpan`; the real repo also calls `logger.captureException` on errors. The real repo body is a stub that returns `null` until you wire a Payload collection. - DI: `symbols.ts`, `module.ts`, `container.ts`, plus `bind-production.ts` and `bind-dev-seed.ts` that compose `withSpan(tracer, opts, withCapture(logger, tags, factory(deps)))` at bind time (span + capture sandwich pattern) - tRPC integration: `procedures.ts` (feature-scoped error middleware) and `router.ts` exposing `get` with full router tests including `BAD_REQUEST` / `NOT_FOUND` mapping - Contract suite (`__contracts__/`), dev seed (`__seeds__/dev.ts`), and empty stubs for `__factories__/` and `ui/` ## Scope (intentionally limited) The generator does NOT yet emit: - Payload CMS collection / global templates (`integrations/cms/**`) - React Query option builders (`ui/query.ts`) - Faker-driven `defineFactory` factories (only stubs) - Multi-entity / multi-use-case (one `get` only) - Aggregator wiring across the monorepo Add these by hand once the entity stabilises. The generator's stub files clearly mark each `TODO`. ## Manual aggregator wiring (printed on success) After running the generator, hand-edit these files to mount the new feature on the app's runtime composition graph: 1. **`apps/web-next/src/server/bind-production.ts`** — import `bindProduction` and `bindDevSeed` and call them from the `bindAll()` dispatcher (production branch + dev-seed branch). 2. **`packages/core-api/src/root.ts`** — import `Router` from `@repo//api` and mount it on the app router. 3. **`packages/core-api/package.json`** — add `"@repo/": "workspace:*"` to dependencies. 4. **`apps/web-next/package.json`** — add `"@repo/": "workspace:*"` to dependencies. 5. **(Later) Payload CMS** — add a collection at `packages//src/integrations/cms/collections/.ts` and register it in `packages/core-cms/...`. 6. **Verify**: `pnpm --filter @repo/ lint typecheck test` The same checklist is printed by the generator when it finishes. ## Adding events and jobs to a feature Once a feature exists, augment it with cross-feature events or background jobs using the dedicated generators. See [`docs/guides/events-and-jobs.md`](./events-and-jobs.md) for full walkthroughs. ```bash pnpm turbo gen event publish # publisher contract pnpm turbo gen event consume # consumer handler + Payload event-task pnpm turbo gen job # background job + TaskConfig pnpm turbo gen realtime channel # realtime channel descriptor (ADR-016) pnpm turbo gen realtime handler # inbound realtime handler (ADR-016) pnpm turbo gen reader # cross-feature reader interface + implementation ``` The event/job generators insert at six fixed `// ` anchor comments. Generated features include four of them automatically (the `// ` location is in `integrations/cms/index.ts`, which is manually authored as part of the post-scaffold wiring); pre-existing features were retrofitted in ADR-015. The realtime generators insert at three additional fixed `// ` anchor comments (`// ` in `src/index.ts`, `// ` in `src/di/symbols.ts`, `// ` in both `bind-*.ts` files). Generated features include all three automatically; pre-existing features were retrofitted in ADR-016. ## Cross-links - `CLAUDE.md` — Key Conventions (factory-style use cases, `.toDynamicValue()`, schemas-in-use-case, three binding modes per feature, span + capture sandwich) - `packages/navigation/AGENTS.md` — canonical reference shape the templates mirror - `docs/architecture/vertical-feature-spec.md` — design rationale for the layout - `docs/decisions/adr-012-feature-conventions.md` — file naming + factory pattern - `docs/decisions/adr-013-input-output-unification.md` — schemas-in-use-case + presenter - `docs/decisions/adr-014-instrumentation-sentry.md` — span + capture wiring - `docs/decisions/adr-015-events-and-jobs.md` — cross-feature events + background jobs - `docs/decisions/adr-026-cross-feature-readers.md` — cross-feature synchronous readers - `docs/decisions/adr-016-realtime-layer.md` — Socket.IO realtime channels + handlers