# KIS-TOiR — Agent Operating Rules Read this file at the start of every session before reading any other file. --- ## What this repository is KIS-TOiR is a fullstack CRUD application (NestJS backend + React Admin frontend) for equipment maintenance management (Техническое обслуживание и ремонт). Generation is driven by a single authoritative source file: - `domain/toir.api.dsl` — the complete API contract: enums, DTOs, endpoints, HTTP methods, pagination --- ## Source-of-truth hierarchy ### Tier 1 — authoritative (hand-authored; never overwritten by generation) | File | Authoritative for | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `domain/*.api.dsl` | Enums, DTO shapes per operation, nullability, HTTP verb+path per endpoint, endpoint names, pagination contracts. Single source of truth. Drives: NestJS modules + React Admin resources + Prisma schema. | | `prompts/*.md` | Auth rules, runtime rules, framework scaffold rules, Prisma rules, validation rules, generation policy, naming conventions. | | `AGENTS.md` (this file) | Agent workflow, mutation boundaries, verification contract. | | `docs/completion-contract.md` | Operational definition of done, success tiers, failure modes, recovery rules. | | `.codex/AGENTS.md` | Codex-specific agent governance supplement. | | `.claude/CLAUDE.md` | Claude-specific agent governance supplement. | ### Tier 2 — deterministic derivative (generated by script; never edited manually) | File | Generated from | Command | | ------------------ | ------------------ | ------------------------------ | | `api-summary.json` | `domain/*.api.dsl` | `npm run generate:api-summary` | ### Tier 3 — LLM-generated artifacts (never edit manually after generation) These outputs are end-state generation targets. During a repo-wide full regeneration driven by `prompts/general-prompt.md`, they may be absent at the start of the run and are recreated from Tier 1 sources plus official CLI scaffolding. | Zone | Generated from | | -------------------------------- | ------------------------------------------------------ | | `server/src/modules//` | `domain/*.api.dsl` + `prompts/backend-rules.md` | | `client/src/resources//` | `domain/*.api.dsl` + `prompts/frontend-rules.md` | | `server/src/app.module.ts` | Module registrations derived from api.dsl api blocks | | `client/src/App.tsx` | Resource registrations derived from api.dsl api blocks | | `server/prisma/schema.prisma` | `domain/*.api.dsl` + `prompts/prisma-rules.md` | | `server/src/auth/` | `prompts/auth-rules.md` | | `client/src/auth/` | `prompts/auth-rules.md` | | `client/src/dataProvider.ts` | `prompts/auth-rules.md` | | `toir-realm.json` | `prompts/auth-rules.md` | | `docker-compose.yml` | `prompts/runtime-rules.md` | | `server/Dockerfile` | `prompts/runtime-rules.md` | | `client/Dockerfile` | `prompts/runtime-rules.md` | | `client/nginx/default.conf` | `prompts/runtime-rules.md` | | `server/docker-entrypoint.sh` | `prompts/runtime-rules.md` | | `db-seed/Dockerfile` | `prompts/runtime-rules.md` | | `db-seed/import.sh` | `prompts/runtime-rules.md` | | `server/.env.example` | `prompts/runtime-rules.md` | | `client/.env.example` | `prompts/runtime-rules.md` | ### Tier 4 — handwritten / framework-managed support files - Framework scaffold and bootstrap helpers that remain manually maintained unless a repair task says otherwise: `server/nest-cli.json`, `server/tsconfig*.json`, `client/vite.config.*`, etc. ### Runtime / Deploy Contract - Tier 3 runtime/deploy outputs are first-class generation targets and must be regenerated from the companion rules when they drift. - Tier 4 support files are framework-managed rather than hand-authored sources of truth. - Runtime/deploy readiness is part of completion, not an optional follow-up. ## Approved Stack Version Policy Future full-regeneration runs must normalize scaffolded package manifests and runtime inputs to the approved versions below. Do not use `latest`, caret ranges, or unreviewed major bumps when the repository regenerates or repairs the stack. Runtime baseline: - Node.js: prefer the Node 22 LTS line; minimum approved version is `22.12.0` - Package manager: `npm` only, with committed `package-lock.json` files; do not switch the repo to `pnpm`, `yarn`, or `bun` Backend generation baseline: - `@nestjs/common`, `@nestjs/core`, `@nestjs/platform-express`, `@nestjs/testing`: `11.1.18` - `@nestjs/config`: `4.0.3` - `@nestjs/cli`: `11.0.17` - `@nestjs/schematics`: `11.0.10` - `prisma` and `@prisma/client`: `6.16.2` exactly, kept on the same version - `class-validator`: `0.15.1` - `class-transformer`: `0.5.1` - `jose`: `6.2.2` - `reflect-metadata`: `0.2.2` - `rxjs`: `7.8.1` - backend `typescript`: `5.7.3` Frontend generation baseline: - `react` and `react-dom`: `19.2.4` - `react-admin` and `ra-data-simple-rest`: `5.14.5` - `@mui/material` and `@mui/icons-material`: `7.3.9` - `@emotion/react`: `11.14.0` - `@emotion/styled`: `11.14.1` - `vite`: `8.0.3` - `@vitejs/plugin-react`: `6.0.1` - frontend `typescript`: `5.9.3` - `keycloak-js`: `26.2.3` Policy rules: - When official CLIs scaffold newer dependency sets, repair the scaffold and then pin it back to the approved versions above before generation continues. - `prisma` and `@prisma/client` must always stay on the same exact version. - Do not upgrade Prisma from v6 to v7 as part of routine regeneration; treat that as a separate explicit migration task with updated prompts, runtime checks, and verification. --- ## Forbidden mutations during any generation run **NEVER write to `*.dsl` files.** They are read-only inputs. To change the API contract or domain model, edit `domain/*.api.dsl` as a separate explicit task. **NEVER manually edit files under `server/src/modules/` or `client/src/resources/`.** To change generated code: update `domain/*.api.dsl` and regenerate. **NEVER edit `server/prisma/schema.prisma` directly.** It is LLM-generated from `domain/*.api.dsl` following `prompts/prisma-rules.md`. --- ## Multi-agent orchestration model Full-generation runs use a parent-orchestrated, bounded multi-agent model. The parent agent is the orchestrator/integrator. It is not the default broad feature implementer. Parent-only responsibilities: - discovery orchestration - docs verification orchestration - contract freeze - shared platform scaffold - auth platform skeleton - deploy/runtime skeleton - shared platform wiring and env/runtime conventions - launching specialized generators - accepting or rejecting generator outputs - final integration - validation - final handoff to reviewer Specialized generation agents: - `generator_prisma` — schema/model generation only - `generator_nest_resources` — NestJS resource modules only - `generator_react_admin_resources` — React Admin resource UI only - `generator_data_access` — frontend data-access seam only The old universal `generator` agent is removed from the active orchestration model and must not be used for full-generation workflows. ### Delegation order Use agents in this order: 1. `explorer` for repository discovery, execution-path inspection, scaffold checks, and local seam tracing 2. `docs_researcher` for official documentation verification and version-sensitive framework behavior 3. parent contract freeze and shared scaffold/auth/runtime planning 4. specialized generators after contract freeze, in parallel when safe: - `generator_prisma` - `generator_nest_resources` - `generator_react_admin_resources` - `generator_data_access` 5. parent integration and validation 6. `reviewer` only at the final review stage If a runtime does not expose named subagents, keep the same separation of responsibilities inside one agent and preserve the same handoff boundaries. ### Write-zone ownership Parent-only write zones: - shared scaffold and framework repair surfaces - `server/src/auth/` - `client/src/auth/` - `toir-realm.json` - `docker-compose.yml` - `server/Dockerfile` - `client/Dockerfile` - `client/nginx/default.conf` - `server/docker-entrypoint.sh` - `db-seed/Dockerfile` - `db-seed/import.sh` - `server/.env.example` - `client/.env.example` - shared integration seams and final validation outputs explicitly delegated by prompts Specialized generator write zones: - `generator_prisma` - `server/prisma/schema.prisma` - optional machine-readable schema summary or structured handoff artifact when the parent explicitly requests it - `generator_nest_resources` - `server/src/modules/**` - backend registration touchpoints only when explicitly delegated by the parent contract - `generator_react_admin_resources` - `client/src/resources/**` - frontend resource registration touchpoints only when explicitly delegated by the parent contract - `generator_data_access` - `client/src/dataProvider.ts` - narrowly delegated frontend integration seams only when explicitly delegated by the parent contract Specialized generators must not redesign shared auth, runtime, deploy, scaffold, or platform seams outside their delegated zones. ### Contract freeze (required before specialized generation) Before launching specialized generators, the parent must produce a normalized structured handoff from the DSL and prompt contracts. This contract freeze is a required protocol owned by the parent; it does not replace `domain/*.api.dsl`. The frozen contract must cover, where relevant: - entities - fields - scalar and enum types - ids and composite keys - relations - enums - endpoint conventions - route and path conventions - naming rules - auth surface expectations - validator and eval compatibility constraints - allowed write-zones per generator Specialized generators start only after the parent freezes this contract and delegates a bounded write-scope. ### Acceptance protocol for generator outputs Parent acceptance is explicit, never implicit. A delegated output is accepted only if all of the following are true: - only allowed zones were modified - the frozen contract is respected - there are no unauthorized cross-layer edits - the output is integration-ready - relevant validation or build checks were attempted where applicable - unresolved issues are surfaced explicitly Failure handling: - allow at most one bounded repair pass for a rejected generator output - reject explicitly if the output is still not usable after that pass - use manual fallback only after explicit rejection, never as a silent completion of half-finished delegated work ### Role guidance - `explorer` - use first for codebase discovery, file/symbol tracing, scaffold inspection, and local evidence gathering - `docs_researcher` - use for official documentation verification, framework semantics, and version-sensitive claims - `generator_prisma` - launch after contract freeze when schema/model artifacts need generation or repair - `generator_nest_resources` - launch after contract freeze when backend resource modules need generation or repair - `generator_react_admin_resources` - launch after contract freeze when frontend resource views and registrations need generation or repair - `generator_data_access` - launch after contract freeze when React Admin to backend integration seams need generation or repair - `reviewer` - use only after parent integration and validation, as the final correctness/security/test-gap review gate ### Documentation-first rule for parent planning Before the parent designs or repairs framework-sensitive shared seams, it must review current official documentation rather than relying on memory alone. Use Context7 first for: - React Admin authProvider and dataProvider expectations - NestJS modules, controllers, providers, guards, and auth attachment patterns - Prisma schema and relation behavior - Vite, Docker, and nginx behavior relevant to scaffold/runtime work - Keycloak, OIDC, JWT, and JWKS integration guidance when available Use external web research only for current, unstable, or missing documentation details. Parent auth, data-access, and runtime planning must not be done purely from memory when framework-specific guidance matters. --- ## Generation workflow (required sequence) 0. For a repo-wide full regeneration driven by `prompts/general-prompt.md`, start from the Tier 1/Tier 2 contract without pre-existing Tier 3 app/runtime outputs. In that mode, `server/`, `client/`, `db-seed/`, and root runtime artifacts such as `docker-compose.yml` and `toir-realm.json` are recreated; they are not prerequisites. 1. Read `AGENTS.md` and `prompts/general-prompt.md`. 2. Run discovery first with `explorer` and verify framework-sensitive behavior with `docs_researcher` before designing shared seams. 3. Read the active `api API.` block + its DTOs + its enums from `domain/toir.api.dsl` (entity-scoped — do not inject the full DSL as a blob). 4. Load the companion rule files required for the active stage: - `prompts/prisma-rules.md` - `prompts/backend-rules.md` - `prompts/frontend-rules.md` - `prompts/auth-rules.md` - `prompts/runtime-rules.md` - `prompts/validation-rules.md` 5. Freeze a normalized structured contract and bounded write-zones before launching any specialized generator. 6. Verify or repair framework scaffolds before domain generation: - official Nest CLI for backend workspace creation/repair - official Vite React TypeScript CLI for frontend workspace creation/repair - official Prisma CLI when Prisma initialization or repair is required 7. Parent generates shared auth platform skeleton and deploy/runtime skeleton per `prompts/auth-rules.md` and `prompts/runtime-rules.md`. 8. Launch specialized generators after contract freeze, in parallel when safe: - `generator_prisma` for `server/prisma/schema.prisma` - `generator_nest_resources` for backend resource modules - `generator_react_admin_resources` for frontend resource modules - `generator_data_access` for `client/src/dataProvider.ts` 9. Accept or reject each delegated output using the acceptance protocol above. Only after acceptance may the parent integrate results. 10. Refresh `api-summary.json` only when validation/tooling requires the auxiliary freshness artifact: `npm run generate:api-summary`. 11. Run: `node tools/validate-generation.mjs --artifacts-only` 12. Run: `npm run eval:generation` 13. Fix all failures before considering the task complete. 14. Hand the final integrated result to `reviewer` before claiming completion. **Context budget rule:** Before generating any DTO or component, quote the field definitions from the DSL api block verbatim, then generate from those quotes. This prevents training-data contamination. See `prompts/general-prompt.md`. --- ## Type mappings | DSL type | Prisma type | TS DTO type | React Admin component | | --------- | ----------------------------- | ----------- | ----------------------------- | | `uuid` | `String @id @default(uuid())` | `string` | `TextInput` / `TextField` | | `string` | `String` | `string` | `TextInput` / `TextField` | | `text` | `String` | `string` | `TextInput` / `TextField` | | `integer` | `Int` | `number` | `NumberInput` / `NumberField` | | `number` | `Float` | `number` | `NumberInput` / `NumberField` | | `decimal` | `Decimal` | `string` | `NumberInput` / `NumberField` | | `date` | `DateTime` | `string` | `DateInput` / `DateField` | | `boolean` | `Boolean` | `boolean` | (appropriate boolean input) | | enum name | enum name | `string` | `SelectInput` / `SelectField` | --- ## Naming conventions Resource name (plural, kebab-case): - `Equipment` → `equipment` (irregular — stays as-is) - `EquipmentType` → `equipment-types` - `RepairOrder` → `repair-orders` - General: PascalCase → kebab-case → append `s` (or `es` if ends in `s`; irregular cases explicit) Default sort field (when not declared in api.dsl): Priority: `inventoryNumber` > `number` > `code` > `name` > primary key --- ## Verification gate (two-stage) ### Stage 1 — Structural gate ``` node tools/validate-generation.mjs --artifacts-only ``` Checks: scaffold/build readiness, required runtime/deploy artifact presence, api-summary freshness, auth seam contracts, realm structure, env/runtime contract, Docker/nginx/compose invariants, and whether build verification ran or was explicitly skipped. This gate validates the post-generation repository state. It is not a prerequisite for the clean-slate start of a full regeneration run. Full structural verification (requires installed `node_modules`): ``` node tools/validate-generation.mjs ``` ### Stage 2 — Eval harness (Rule 6) ``` npm run eval:generation ``` Fixture-based semantic checks from `tools/eval/fixtures/`. Checks: DSL fidelity, CRUD method/path behavior, DTO field coverage and decorators, natural-key semantics, FK/reference wiring, Content-Range behavior, and React Admin UX/component invariants. Reviewed eval fixtures are the authoritative semantic gate. They may be scaffolded from source-of-truth as a helper, but a full regeneration run must not auto-rewrite the committed eval corpus as part of step 0. See `tools/eval/README.md` for fixture authoring and eval-driven development workflow. **Generation is incomplete unless both stages pass.** --- ## Proven-Good Runtime References Existing runnable runtime/deploy artifacts are baseline behavior, not disposable examples. - Preserve repository-proven behavior in `docker-compose.yml`, `server/Dockerfile`, `client/Dockerfile`, `client/nginx/default.conf`, `server/.env.example`, and `client/.env.example` unless the DSL, prompt contract, or an explicit task requires a change. - When these artifacts are regenerated, preserve still-valid production behavior such as SPA routing, `/api` proxying, external Keycloak, PostgreSQL topology, and container startup flow. - Do not claim runtime/deploy readiness from file presence alone; these artifacts remain part of completion and verification. ## Prisma Migration Policy Current repository policy: - `server/prisma/schema.prisma` is generated from the DSL and is the immediate database contract for generation runs. - Committed Prisma migrations are preferred but not currently required for every schema change. - The current repository state is accepted temporary technical debt: when `server/prisma/migrations/` is absent, local/runtime flows may fall back to `prisma db push`; when migrations exist, runtime must use `prisma migrate deploy`. Target policy: - Every DSL-driven schema change should produce a reviewed committed migration under `server/prisma/migrations/`. - Production/runtime execution should rely on `prisma migrate deploy` only, with the `db push` fallback removed after migration discipline is established. ## Pre-commit hook Install with `npm run install-hooks`. The hook runs **both** the structural gate and the eval harness before every commit. Commits are blocked when either fails. --- ## Auth and runtime defaults Full auth contract: `prompts/auth-rules.md` Working defaults (do not regress to localhost): - Keycloak base: `https://sso.greact.ru` - Realm/client: `toir` / `toir-frontend` / `toir-backend` - Production frontend: `https://toir-frontend.greact.ru` - CORS: `http://localhost:5173,https://toir-frontend.greact.ru` --- ## OpenRouter configuration ``` OPENAI_API_KEY= OPENAI_BASE_URL=https://openrouter.ai/api/v1 OPENAI_MODEL= ``` These variables are used by `tools/api-format-to-openapi/convert.mjs --mode llm`. --- ## Reading order for generation tasks **Critical zone (load first, never drop):** 1. `AGENTS.md` (this file) — project governance, mutation boundaries, tier hierarchy 2. `prompts/general-prompt.md` — master orchestration prompt: mission, stage ownership, delegation model, completion criteria 3. `domain/toir.api.dsl §API.` — active api block only, plus its referenced DTOs and enums **Companion zone (load when the matching stage is active):** 4. `prompts/prisma-rules.md` — Prisma schema generation details 5. `prompts/backend-rules.md` — NestJS generation details 6. `prompts/frontend-rules.md` — React Admin generation details 7. `prompts/auth-rules.md` — auth seam and realm requirements 8. `prompts/runtime-rules.md` — scaffold, env, and bootstrap requirements 9. `prompts/validation-rules.md` — success gate requirements **Auxiliary zone (never authoritative):** 10. `api-summary.json` — optional inventory/freshness artifact for validators and supporting tooling; do not use it instead of the DSL **Reference only (do not load proactively):** - `domain/dsl-spec.md` — DSL syntax reference; load only if DSL is ambiguous - `docs/generation-playbook.md` — step-by-step workflow reference - `docs/future-work.md` — deferred items (Rules 7 and 8)