rebase generation

This commit is contained in:
MaKarin
2026-04-07 19:40:41 +03:00
parent 73ddb1a948
commit aab7bfa691
180 changed files with 15512 additions and 364 deletions

View File

@@ -0,0 +1,333 @@
# Generation Playbook
Step-by-step instructions for generating and regenerating artifacts in this repository.
Read `AGENTS.md` and `docs/source-of-truth.md` first.
---
## Pipeline overview
```
Tier 1 — Single Source of Truth (hand-authored, never generated)
domain/toir.api.dsl ──┐ enums, DTOs, endpoints, HTTP methods,
│ entity field mappings, primary keys
Tier 2 — Deterministic Preprocessing (npm scripts, no LLM)
api-summary.json ←─ npm run generate:api-summary
openapi.json ←─ npm run generate:openapi (auxiliary)
Tier 1 (api.dsl) + prompts/*.md ──► LLM Generation
prompts/general-prompt.md
parent orchestrator ──► discovery, docs verification, contract freeze, shared scaffold, auth/runtime skeleton, integration
prompts/prisma-rules.md ──► generator_prisma ──► server/prisma/schema.prisma
prompts/backend-rules.md ──► generator_nest_resources ──► server/src/modules/<entity>/
prompts/frontend-rules.md ──► generator_react_admin_resources ──► client/src/resources/<entity>/
prompts/auth-rules.md ──► parent + generator_data_access ──► server/src/auth/, client/src/auth/, client/src/dataProvider.ts, toir-realm.json
prompts/runtime-rules.md ──► parent ──► docker-compose.yml, server/client Dockerfiles, nginx config, env templates, docker-entrypoint, db-seed artifacts
prompts/validation-rules.md ──► (validation gate reference)
Tier 4 — Validation Gate
node tools/validate-generation.mjs --artifacts-only
npm run eval:generation
```
---
## Prerequisites
Before any generation run:
1. `domain/*.api.dsl` is current and valid.
2. Read `AGENTS.md` and `prompts/general-prompt.md`.
3. If this is a repo-wide full regeneration, begin from Tier 1/Tier 2 inputs without relying on existing Tier 3 outputs such as `server/`, `client/`, `db-seed/`, `docker-compose.yml`, or `toir-realm.json`.
4. Refresh the Tier 2 intermediate context only when validator/tooling or a supporting workflow needs it:
```bash
npm run generate:api-summary
```
Do not require `node tools/validate-generation.mjs --artifacts-only` to pass before a clean-slate full regeneration. That command validates the post-generation repository state.
---
## Standard generation workflow
### Step 0 — Full-regeneration reset when requested
For a repo-wide full regeneration driven by `prompts/general-prompt.md`:
- do not assume `server/`, `client/`, `db-seed/`, Dockerfiles, env templates, `docker-compose.yml`, or `toir-realm.json` already exist
- recreate backend and frontend workspaces from the official NestJS and Vite React TypeScript CLIs
- regenerate Tier 3 runtime/deploy artifacts after scaffold recreation
- treat the validator and eval harness as end-state checks after generation
### Step 1 — Refresh auxiliary derived artifacts only when needed
```bash
# From repo root
npm run generate:api-summary
```
### Step 2 — Read generation inputs (context budget)
> **`prompts/general-prompt.md` is the master generation prompt.** It contains all core
> type mappings, naming conventions, DTO/controller/service/frontend rules, mutation
> boundaries, and the complete generation workflow. Load it as the single entrypoint.
>
> For artifact-specific details (Prisma FK rules, auth JWKS chain, detailed validation
> groups), load the relevant companion file: `prompts/prisma-rules.md`,
> `prompts/auth-rules.md`, `prompts/validation-rules.md`, or `prompts/runtime-rules.md`.
>
> See `prompts/general-prompt.md §CONTEXT BUDGET` for the full budget model.
1. `prompts/general-prompt.md` — master generation prompt (always load)
2. `domain/*.api.dsl §API.<EntityName>` — **only the api block + its referenced DTOs + enums** (entity-scoped)
3. `api-summary.json` — only when validator/tooling explicitly needs the auxiliary freshness artifact
4. **If needed:** `prompts/prisma-rules.md` (Prisma), `prompts/auth-rules.md` (auth seams), `prompts/runtime-rules.md` (deploy/runtime artifacts), or `prompts/validation-rules.md` (gate ownership)
Before generating any DTO or component: **quote the relevant DSL field definitions verbatim first**, then generate from those quotes. This prevents training-data contamination.
If a new or changed entity behavior is not already covered by an eval contract, write or review the failing eval first so the semantic gate leads the generation change. Helpers may scaffold candidate fixtures from source-of-truth, but committed evals remain reviewed artifacts rather than auto-regenerated outputs.
### Step 3 — Discovery and docs verification
- Use `explorer` first for repo discovery, scaffold inspection, and tracing shared seams.
- Use `docs_researcher` before planning framework-sensitive auth, runtime, Prisma, NestJS, or React Admin work.
- Prefer Context7 for official framework/library docs; use web fallback only for current or missing details.
### Step 4 — Freeze the contract
Before specialized generation, the parent must freeze a normalized structured handoff that captures:
- entities, fields, types, ids/composite keys, relations, and enums
- endpoint, route, and naming conventions
- auth surface expectations
- validator/eval compatibility constraints
- allowed write-zones for each delegated generator
This freeze is a parent-owned protocol. It does not replace the DSL as source of truth.
### Step 5 — Shared scaffold and parent-owned seams
- repair or recreate official Nest/Vite/Prisma scaffolds as needed
- parent owns auth platform skeleton, deploy/runtime skeleton, env conventions, and shared wiring
- do not start specialized generators before scaffold and frozen-contract inputs are ready
### Step 6 — Generate Prisma schema
Generate `server/prisma/schema.prisma` from `domain/*.api.dsl` following `prompts/prisma-rules.md`.
Preferred migration policy:
- if the DSL changes the schema, create or update Prisma migrations in `server/`
- keep `db push` only as a bootstrap fallback for fresh environments that do not yet have migration history
- treat schema changes shipped without a migration as temporary technical debt that must be called out explicitly
If the schema changed, follow the explicit repository migration policy:
```bash
cd server
npx prisma migrate dev --name <description>
```
If committed migrations do not yet exist, the current repository accepts `prisma db push` only as temporary bootstrap debt. Do not present that fallback as the target steady state.
Use `generator_prisma` for this bounded scope. It must not modify backend modules, frontend resources, auth, or runtime/deploy artifacts.
### Step 7 — Generate backend modules
For each `api` block in `domain/*.api.dsl`, generate:
1. `server/src/modules/<kebab>/<entity>.module.ts`
2. `server/src/modules/<kebab>/dto/create-<kebab>.dto.ts`
— fields from the `DTO.<Entity>Create` block in api.dsl
3. `server/src/modules/<kebab>/dto/update-<kebab>.dto.ts`
— fields from the `DTO.<Entity>Update` block in api.dsl
4. `server/src/modules/<kebab>/<entity>.service.ts`
— CRUD operations using Prisma; respect type mappings from `prompts/backend-rules.md`
5. `server/src/modules/<kebab>/<entity>.controller.ts`
— one method per `endpoint` in the `api` block; HTTP verb and path from the `label`
Register the module in `server/src/app.module.ts`.
Use `generator_nest_resources` for this bounded scope. It must stay within backend resource zones and must not redesign the shared auth or runtime platform.
### Step 8 — Generate frontend resources
For each `api` block in `domain/*.api.dsl`, generate:
1. `client/src/resources/<kebab>/<Entity>List.tsx`
— columns from `DTO.<Entity>` (response shape)
2. `client/src/resources/<kebab>/<Entity>Create.tsx`
— fields from `DTO.<Entity>Create`
3. `client/src/resources/<kebab>/<Entity>Edit.tsx`
— fields from `DTO.<Entity>Update`
4. `client/src/resources/<kebab>/<Entity>Show.tsx`
— fields from `DTO.<Entity>`
Register the resource in `client/src/App.tsx`.
Use `generator_react_admin_resources` for this bounded scope. It must stay within frontend resource zones and must not redesign shared data-access or auth strategy.
### Step 9 — Generate data-access and auth/runtime/deploy artifacts
Use `generator_data_access` for `client/src/dataProvider.ts` and only the narrowly delegated frontend integration seam. Parent retains ownership of the shared auth platform skeleton and all deploy/runtime skeleton artifacts.
Generate or repair:
1. `server/src/auth/`
2. `client/src/auth/`
3. `client/src/dataProvider.ts`
4. `toir-realm.json`
5. `docker-compose.yml`
6. `server/.env.example`, `client/.env.example`
7. `server/Dockerfile`, `client/Dockerfile`
8. `client/nginx/default.conf`
9. `server/docker-entrypoint.sh`
10. `db-seed/Dockerfile`, `db-seed/import.sh`
Preserve the proven-good runtime behaviors from `prompts/runtime-rules.md` unless the repository contract explicitly changes them.
### Step 10 — Accept delegated outputs and integrate
Parent acceptance is explicit. Accept a delegated output only if:
- only allowed zones changed
- the frozen contract is respected
- no unauthorized cross-layer edits occurred
- the result is integration-ready
- relevant checks were attempted where applicable
- unresolved issues are surfaced explicitly
Allow at most one bounded repair pass. If still unusable, reject explicitly.
Manual fallback is allowed only after rejection.
### Step 11 — Verify (two-stage gate)
**Stage 1 — Structural gate:**
```bash
node tools/validate-generation.mjs --artifacts-only
```
Checks scaffold/build readiness, auth/runtime/realm seams, required runtime/deploy artifacts, and other stable repository invariants.
Full structural verification (requires installed deps):
```bash
node tools/validate-generation.mjs
```
**Stage 2 — Eval harness:**
```bash
npm run eval:generation
```
Fixture-based semantic checks. See `tools/eval/README.md`.
Both must pass before the task is complete.
### Step 12 — Final review
Run `reviewer` only after integration and validation. Reviewer is the final
correctness/security/test-gap gate, not a substitute for parent validation.
---
## Adding a new entity
1. Add the entity's enums, DTOs, and `api` block to `domain/toir.api.dsl`.
2. Run `npm run generate:api-summary`.
3. **Before generating:** create `tools/eval/fixtures/<kebab>/meta.json`, `backend.assertions.json`, and `frontend.assertions.json` with expected patterns.
4. Run `npm run eval:generation` — it will fail (entity files don't exist yet). That's expected.
5. Generate backend, frontend, and runtime-facing artifacts (Steps 36).
6. Run `npm run eval:generation` again — now it should pass.
7. Run `node tools/validate-generation.mjs --artifacts-only` — both gates must pass.
> This is **eval-driven development**: write the failing eval first (step 3), then generate to make it pass (step 6). A passing eval confirms the LLM followed the rules.
---
## Changing an existing entity
**If the domain model changes** (new field, changed type, new FK, new enum):
1. Update `domain/toir.api.dsl` (enums, DTO attributes, `map` references).
2. Run `npm run generate:api-summary`.
3. Regenerate `server/prisma/schema.prisma`, run migration.
4. Regenerate the affected modules/resources and any affected runtime artifacts (Steps 47).
**If only the API contract changes** (different nullability, new endpoint, different HTTP method):
1. Update `domain/toir.api.dsl` only.
2. Run `npm run generate:api-summary` to refresh `api-summary.json`.
3. Run Steps 47. No Prisma migration needed.
---
## Artifact traceability matrix
| Artifact | DSL source | Prompt rule | Validator check |
| ---------------------------------------------- | ---------------------- | ---------------------------------------------- | --------------------------------------- |
| `server/prisma/schema.prisma` | `domain/*.api.dsl` | `prompts/prisma-rules.md` | `§validateBuildChecks` (file exists) |
| `api-summary.json` | `domain/*.api.dsl` | — (deterministic) | `§validateBuildChecks` (freshness) |
| `server/src/modules/<e>/*.ts` | `domain/*.api.dsl` | `prompts/backend-rules.md` | `npm run eval:generation` |
| `server/src/modules/<e>/dto/create-<e>.dto.ts` | `DTO.<E>Create` fields | `prompts/backend-rules.md §DTO-field-coverage` | `npm run eval:generation` |
| `server/src/modules/<e>/dto/update-<e>.dto.ts` | `DTO.<E>Update` fields | `prompts/backend-rules.md §DTO-field-coverage` | `npm run eval:generation` |
| `client/src/resources/<e>/<E>*.tsx` | `domain/*.api.dsl` | `prompts/frontend-rules.md` | `npm run eval:generation` |
| `client/src/auth/keycloak.ts` | auth/runtime contract | `prompts/auth-rules.md` | `§validateAuthChecks` |
| `toir-realm.json` | auth/runtime contract | `prompts/auth-rules.md` | `§validateRealmChecks` |
| `docker-compose.yml` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
| `server/Dockerfile` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
| `client/Dockerfile` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
| `client/nginx/default.conf` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
| `server/docker-entrypoint.sh` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
| `db-seed/Dockerfile`, `db-seed/import.sh` | runtime contract | `prompts/runtime-rules.md` | `§validateRuntimeContractChecks` |
---
## Verification commands reference
| Command | When to use |
| ----------------------------------------------------- | ------------------------------------------ |
| `npm run generate:api-summary` | After any change to `domain/*.api.dsl` |
| `npm run generate:openapi` | To regenerate OpenAPI 3.0.3 documentation |
| `node tools/validate-generation.mjs --artifacts-only` | After every generation run (required) |
| `node tools/validate-generation.mjs` | Before committing; requires installed deps |
| `node tools/validate-generation.mjs --run-runtime` | End-to-end; requires running DB |
---
## OpenRouter invocation
Set environment variables before any LLM-mode tool call:
```
OPENAI_API_KEY=<openrouter-key>
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=<model-id>
```
The `OPENAI_BASE_URL` variable is consumed by `tools/api-format-to-openapi/convert.mjs --mode llm`.
For agent-driven generation via Cursor or direct API calls, the standard workflow above
applies regardless of model provider.
---
## Auxiliary tools
### `tools/api-summary-to-openapi.mjs`
Generates `openapi.json` (OpenAPI 3.0.3) from `api-summary.json` deterministically.
This is a documentation/integration artifact, not part of the core generation pipeline.
```bash
npm run generate:openapi
```
### `tools/api-format-to-openapi/`
Auxiliary integration tool for external consumers using the `api-format` JSON schema.
Not connected to the main DSL pipeline. See `docs/AID_EXPORT_README.md` for details.