use only TOiR.domain.dsl like single source of truth for generation, update context for pinned .gitignore
This commit is contained in:
@@ -35,15 +35,47 @@ Follow:
|
||||
|
||||
---
|
||||
|
||||
# Step 1 — Parse DSL
|
||||
# Input Contract
|
||||
|
||||
Read DSL inputs and extract:
|
||||
Required input:
|
||||
|
||||
- `domain/*.dsl`
|
||||
|
||||
Optional extension input:
|
||||
|
||||
- `overrides/api-overrides.dsl`
|
||||
|
||||
Optional extension layout:
|
||||
|
||||
```text
|
||||
overrides/
|
||||
api-overrides.dsl
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Parse `domain/*.dsl` as the only authoritative DSL input.
|
||||
- Generate DTOs and REST API contracts automatically from the parsed domain model.
|
||||
- The generator must work when `overrides/api-overrides.dsl` is absent.
|
||||
- Optional overrides may refine derived API behavior but must not redefine entities, attributes, primary keys, foreign keys, relations, or enums.
|
||||
- Supplemental DTO/API DSL inputs must not participate in backend parsing, dependency resolution, or backend generation decisions.
|
||||
- Do not read standalone DTO or API DSL files.
|
||||
|
||||
---
|
||||
|
||||
# Step 1 — Parse Domain DSL
|
||||
|
||||
Read `domain/*.dsl` and extract:
|
||||
|
||||
- entities
|
||||
- attributes, including the actual primary key attribute per entity
|
||||
- enums
|
||||
- foreign keys
|
||||
|
||||
All entities, attributes, primary keys, foreign keys, relations, and enums used by the backend pipeline must come from the parsed domain DSL.
|
||||
|
||||
If `overrides/api-overrides.dsl` exists, process it only after the domain model has been parsed and only as optional non-authoritative metadata.
|
||||
|
||||
The generator must treat auth as default runtime infrastructure, not as a DSL feature toggle.
|
||||
|
||||
---
|
||||
@@ -89,6 +121,12 @@ Generate backend source artifacts:
|
||||
- sanitize update payload before Prisma
|
||||
- remove `id`, the entity primary key, and readonly attributes from `data`
|
||||
- do not pass the raw request body directly to `prisma.*.update()`
|
||||
6. **List/query sorting methods**:
|
||||
- use only actual model field names in ORM `orderBy`
|
||||
- if the API exposes synthetic `id` for React Admin but the real primary key is different, map incoming `_sort=id` to the real primary key field before building `orderBy`
|
||||
- apply this rule to every entity with a non-`id` primary key
|
||||
|
||||
All backend DTOs and REST endpoints are derived artifacts. The generator must not require or parse separate DTO/API DSL documents.
|
||||
|
||||
Use mapping rules from `backend/prisma-rules.md`:
|
||||
|
||||
@@ -223,3 +261,4 @@ Run runtime, auth, and contract checks from `generation/post-generation-validati
|
||||
- protected routes reject unauthenticated requests with `401`
|
||||
- authenticated users with insufficient role receive `403`
|
||||
- React Admin-compatible API responses include `id` for every record
|
||||
- natural-key entities translate React Admin `_sort=id` to the real primary key field
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
This document describes the **developer workflow** for running a generated fullstack application locally. The generator must produce a project that supports this workflow so the app is **fully runnable** after generation, including authentication.
|
||||
|
||||
This workflow assumes the project was generated from `domain/*.dsl` plus optional non-duplicating overrides only. Developers must not need to prepare separate DTO/API/UI DSL inputs before running the app.
|
||||
|
||||
---
|
||||
|
||||
# Prerequisites
|
||||
|
||||
@@ -12,7 +12,35 @@ Follow:
|
||||
|
||||
---
|
||||
|
||||
# Step 1 — Parse DSL
|
||||
# Input Contract
|
||||
|
||||
Required input:
|
||||
|
||||
- `domain/*.dsl`
|
||||
|
||||
Optional extension input:
|
||||
|
||||
- `overrides/ui-overrides.dsl`
|
||||
|
||||
Optional extension layout:
|
||||
|
||||
```text
|
||||
overrides/
|
||||
ui-overrides.dsl
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Parse `domain/*.dsl` as the only authoritative DSL input.
|
||||
- Generate React Admin resources, views, and field mappings automatically from the parsed domain model.
|
||||
- The generator must work when `overrides/ui-overrides.dsl` is absent.
|
||||
- Optional overrides may refine derived UI behavior but must not redefine entities, attributes, primary keys, foreign keys, relations, or enums.
|
||||
- Supplemental UI DSL inputs must not participate in frontend parsing, dependency resolution, or frontend generation decisions.
|
||||
- Do not read a standalone UI DSL file.
|
||||
|
||||
---
|
||||
|
||||
# Step 1 — Parse Domain DSL
|
||||
|
||||
Extract:
|
||||
|
||||
@@ -20,6 +48,10 @@ Extract:
|
||||
- attributes
|
||||
- relation fields required for reference inputs and reference displays
|
||||
|
||||
All frontend resources, fields, references, routes, and type-driven widget choices must be derived from the parsed domain DSL before optional overrides are considered.
|
||||
|
||||
If `overrides/ui-overrides.dsl` exists, process it only after the domain model has been parsed and only as optional non-authoritative metadata.
|
||||
|
||||
The generator must treat auth as default frontend infrastructure rather than as an optional feature.
|
||||
|
||||
---
|
||||
@@ -54,7 +86,7 @@ For each entity create:
|
||||
- `EntityEdit.tsx`
|
||||
- `EntityShow.tsx`
|
||||
|
||||
Resource generation must remain compatible with the auth-aware shared request seam.
|
||||
Resource generation must remain compatible with the auth-aware shared request seam and must be derived from domain metadata rather than a separate UI DSL.
|
||||
|
||||
---
|
||||
|
||||
@@ -62,6 +94,14 @@ Resource generation must remain compatible with the auth-aware shared request se
|
||||
|
||||
Map DSL attributes to React Admin components according to existing field rules and relation semantics.
|
||||
|
||||
Minimum type mapping:
|
||||
|
||||
- `string`, `text` -> `TextInput`, `TextField`
|
||||
- `integer`, `decimal` -> `NumberInput`, `NumberField`
|
||||
- `date` -> `DateInput`, `DateField`
|
||||
- `enum` -> `SelectInput`
|
||||
- foreign key -> `ReferenceInput`, `ReferenceField`
|
||||
|
||||
Reference/resource lookups must continue to flow through the same shared authenticated request layer used by the main CRUD resources.
|
||||
|
||||
---
|
||||
@@ -98,6 +138,11 @@ Generate Keycloak frontend integration with these required rules:
|
||||
- Authorization Code + PKCE with `S256`
|
||||
- initialize Keycloak before React render
|
||||
- provide a React Admin `authProvider`
|
||||
- derive `authProvider.getIdentity()` from token claims already present in the parsed token
|
||||
- prefer `sub`, `preferred_username`, `email`, and `name` for identity resolution
|
||||
- do not call `keycloak.loadUserProfile()` by default
|
||||
- do not rely on the Keycloak `/account` endpoint for baseline CRUD/admin generation
|
||||
- avoid the `/account` request entirely by default rather than broadening Keycloak CORS behavior
|
||||
- distinguish auth failures from authorization failures:
|
||||
- `401` -> force logout / re-authentication
|
||||
- `403` -> do not re-authenticate; surface access denied / permission error
|
||||
|
||||
@@ -6,6 +6,17 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
# Validation Checklist
|
||||
|
||||
## Source-of-truth input contract
|
||||
|
||||
- [ ] Fullstack generation succeeds when `domain/*.dsl` is the only required DSL input.
|
||||
- [ ] The generator can produce backend and frontend outputs from `domain/*.dsl` alone before optional overrides are considered.
|
||||
- [ ] DTO, API, and UI artifacts are derived automatically from the domain model, keys, relations, and enums.
|
||||
- [ ] Optional override files are not required for a successful generation run.
|
||||
- [ ] Optional overrides, if present, refine only derived API/UI output and do not duplicate the domain model.
|
||||
- [ ] No generator step depends on duplicated domain structures outside `domain/*.dsl`.
|
||||
|
||||
**Failure symptoms:** generation requires extra DSL inputs, generated layers drift from the domain model, or the pipeline fails when override files are absent.
|
||||
|
||||
## 1. Frontend and backend env files
|
||||
|
||||
- [ ] `server/.env.example` exists and documents:
|
||||
@@ -27,7 +38,22 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 2. Keycloak realm artifact
|
||||
## 2. Git ignore hygiene
|
||||
|
||||
- [ ] Root `.gitignore` exists.
|
||||
- [ ] `server/.gitignore` exists.
|
||||
- [ ] `client/.gitignore` exists.
|
||||
- [ ] Generated gitignore rules exclude local dependency directories such as `node_modules/`.
|
||||
- [ ] Generated gitignore rules exclude build artifacts such as `dist/` and `dist-ssr/`.
|
||||
- [ ] Generated gitignore rules exclude local env files such as `.env`, `.env.local`, and `.env.*.local`.
|
||||
- [ ] Generated gitignore rules exclude `coverage/` and `*.tsbuildinfo`.
|
||||
- [ ] Generated gitignore rules do **not** exclude committed project artifacts such as source files, docs, and `.env.example`.
|
||||
|
||||
**Failure symptoms:** `npm install`, local builds, or local env setup explode git status with thousands of files that should remain untracked.
|
||||
|
||||
---
|
||||
|
||||
## 3. Keycloak realm artifact
|
||||
|
||||
- [ ] A root-level generated Keycloak realm import artifact exists.
|
||||
- [ ] If the repository default filename `toir-realm.json` is not used, the project-specific equivalent is documented consistently across bootstrap and workflow docs.
|
||||
@@ -50,7 +76,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontend auth files and behavior
|
||||
## 4. Frontend auth files and behavior
|
||||
|
||||
- [ ] Generated frontend includes:
|
||||
- `client/src/config/env.ts`
|
||||
@@ -65,6 +91,9 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
- [ ] No custom in-app username/password login form is generated.
|
||||
- [ ] `Authorization Code + PKCE (S256)` is encoded in the frontend auth flow.
|
||||
- [ ] `client/src/dataProvider.ts` or the documented shared request seam injects `Authorization: Bearer <access_token>` into all API requests.
|
||||
- [ ] `authProvider.getIdentity()` derives identity from parsed token claims such as `sub`, `preferred_username`, `email`, and `name`.
|
||||
- [ ] Generated frontend auth code does not call `keycloak.loadUserProfile()`.
|
||||
- [ ] Generated frontend auth code does not rely on the Keycloak `/account` endpoint for baseline CRUD/admin generation.
|
||||
- [ ] Token refresh is concurrency-safe:
|
||||
- one shared in-flight refresh operation
|
||||
- no parallel refresh stampede
|
||||
@@ -77,7 +106,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 4. Backend auth files and behavior
|
||||
## 5. Backend auth files and behavior
|
||||
|
||||
- [ ] Generated backend includes:
|
||||
- `server/src/auth/auth.module.ts`
|
||||
@@ -100,7 +129,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 5. CRUD protection and RBAC defaults
|
||||
## 6. CRUD protection and RBAC defaults
|
||||
|
||||
- [ ] `/health` is public.
|
||||
- [ ] Each generated CRUD controller method other than explicit public routes is protected by the generated auth/RBAC infrastructure.
|
||||
@@ -115,7 +144,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 6. PrismaService implementation
|
||||
## 7. PrismaService implementation
|
||||
|
||||
- [ ] A `PrismaService` (or equivalent) class exists and extends `PrismaClient`.
|
||||
- [ ] It implements `OnModuleInit` and calls `await this.$connect()` in `onModuleInit()`.
|
||||
@@ -127,7 +156,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 7. Prisma client lifecycle
|
||||
## 8. Prisma client lifecycle
|
||||
|
||||
- [ ] `package.json` includes a script that runs Prisma client generation:
|
||||
- either `"postinstall": "prisma generate"` (or `npx prisma generate`)
|
||||
@@ -138,7 +167,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 8. Database migration
|
||||
## 9. Database migration
|
||||
|
||||
- [ ] Migration workflow is documented.
|
||||
- [ ] Instruction to run `npx prisma migrate dev` exists after first generation or schema change.
|
||||
@@ -148,7 +177,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 9. REST route parameters
|
||||
## 10. REST route parameters
|
||||
|
||||
- [ ] For each entity, path parameters use the correct primary key name from the DSL.
|
||||
- [ ] Entity with PK `id` uses `/:id`.
|
||||
@@ -160,18 +189,20 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 10. DTO type mapping and React Admin ID compatibility
|
||||
## 11. DTO type mapping and React Admin ID compatibility
|
||||
|
||||
- [ ] DSL `decimal` maps to DTO/API `string`.
|
||||
- [ ] DSL `date` maps to DTO/API `string` (ISO) or equivalent string serialization.
|
||||
- [ ] Every API response object contains a field named `id`.
|
||||
- [ ] If the entity primary key is not named `id`, the response maps the primary key to `id`.
|
||||
- [ ] For entities with non-`id` primary keys, backend list/query logic translates React Admin `_sort=id` to the real primary key field.
|
||||
- [ ] Generated ORM `orderBy` clauses never reference synthetic `id` when the underlying model field does not exist.
|
||||
|
||||
**Failure symptoms:** serialization issues for decimals/dates, or React Admin cannot identify records.
|
||||
|
||||
---
|
||||
|
||||
## 11. Update payload sanitization
|
||||
## 12. Update payload sanitization
|
||||
|
||||
- [ ] Update endpoints do not pass `id` or the primary key in Prisma `data`.
|
||||
- [ ] Generated update methods remove `id`, the entity primary key, and readonly attributes before calling `prisma.*.update()`.
|
||||
@@ -180,7 +211,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 12. Database runtime
|
||||
## 13. Database runtime
|
||||
|
||||
- [ ] `docker-compose.yml` exists at the project root.
|
||||
- [ ] It defines a PostgreSQL service with image `postgres:16`, port `5432`, and credentials matching `DATABASE_URL`.
|
||||
@@ -191,7 +222,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
|
||||
---
|
||||
|
||||
## 13. Migrations, seed, and health endpoint
|
||||
## 14. Migrations, seed, and health endpoint
|
||||
|
||||
- [ ] `npx prisma migrate dev` runs successfully from `server/`.
|
||||
- [ ] Seed script exists at `server/prisma/seed.ts` (or equivalent).
|
||||
@@ -209,9 +240,11 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
| --- | --- |
|
||||
| Frontend env | `client/.env.example` with required Vite auth vars |
|
||||
| Backend env | `server/.env.example` with DB, CORS, and Keycloak vars |
|
||||
| Git ignore | Root/server/client `.gitignore` exclude local-only artifacts |
|
||||
| Fail-fast config | Startup fails when required auth env is missing |
|
||||
| Realm artifact | Root generated realm import artifact with self-contained auth setup |
|
||||
| Frontend auth | `keycloak.ts`, `authProvider.ts`, authenticated `dataProvider.ts` |
|
||||
| Frontend identity | Token-claim based `getIdentity()`; no `loadUserProfile()` / `/account` dependency |
|
||||
| Backend auth | `AuthModule`, guards, decorators, typed principal |
|
||||
| JWKS strategy | explicit URL -> discovery -> certs fallback |
|
||||
| Role source | `realm_access.roles` only |
|
||||
@@ -224,6 +257,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
| Prisma lifecycle | `OnModuleInit` + `$connect()`, no `beforeExit` |
|
||||
| Update sanitization | Strip `id` / PK / readonly before Prisma update |
|
||||
| React Admin `id` | Every record includes `id` |
|
||||
| Natural-key sorting | Map React Admin `_sort=id` to the real primary key field |
|
||||
| Database runtime | PostgreSQL compose exists and starts |
|
||||
|
||||
---
|
||||
@@ -231,6 +265,7 @@ After generating the backend or fullstack application, run these checks to ensur
|
||||
# Integration with generation pipeline
|
||||
|
||||
1. Backend and frontend generation must produce artifacts that satisfy the above by default.
|
||||
2. Runtime bootstrap must include Keycloak realm import/verification before app startup.
|
||||
3. After generation, run this checklist manually or via an automated script.
|
||||
4. If any check fails, update the generator context so future runs pass without manual repair.
|
||||
2. The generator must successfully build the fullstack app from `domain/*.dsl` alone; optional overrides may refine output but cannot be required.
|
||||
3. Runtime bootstrap must include Keycloak realm import/verification before app startup.
|
||||
4. After generation, run this checklist manually or via an automated script.
|
||||
5. If any check fails, update the generator context so future runs pass without manual repair.
|
||||
|
||||
@@ -9,6 +9,8 @@ The generator must produce a **runnable development environment** consisting of:
|
||||
- frontend SPA
|
||||
- PostgreSQL database
|
||||
|
||||
Runtime bootstrap assumes the application was generated from `domain/*.dsl` plus optional non-duplicating overrides only. There is no separate DTO/API/UI DSL bootstrap step.
|
||||
|
||||
The generator must also produce the runtime artifacts required to bootstrap auth from zero, including a root-level Keycloak realm import artifact. The repository default example filename is `toir-realm.json`, but future generations must allow a project-specific equivalent.
|
||||
|
||||
---
|
||||
|
||||
@@ -80,13 +80,35 @@ npm install keycloak-js
|
||||
|
||||
Generation pipeline order:
|
||||
|
||||
1. **Parse DSL** — Read domain, DTO, API, and UI DSL files.
|
||||
1. **Parse DSL** — Read `domain/*.dsl` as the single required input. If present, optional override files under `overrides/` may be applied after domain parsing, but DTO/API/UI DSL files must not be required.
|
||||
2. **Run CLI scaffolding** — Create `server` with NestJS CLI and `client` with Vite CLI; install runtime and auth dependencies listed above.
|
||||
3. **Code generation** — Generate Prisma schema, NestJS modules/DTOs/PrismaService/auth infrastructure, and React Admin resources/auth integration.
|
||||
4. **Runtime infrastructure** — Generate backend/frontend `.env.example`, runtime config files, lifecycle scripts, and a root-level Keycloak realm import artifact (repository default example filename: `toir-realm.json`).
|
||||
4. **Runtime infrastructure** — Generate backend/frontend `.env.example`, root/package `.gitignore` files, runtime config files, lifecycle scripts, and a root-level Keycloak realm import artifact (repository default example filename: `toir-realm.json`).
|
||||
5. **Database runtime** — Generate `docker-compose.yml` in project root with PostgreSQL service (`postgres`, image `postgres:16`, port `5432:5432`).
|
||||
6. **Migration** — Apply schema with `npx prisma migrate dev`.
|
||||
7. **Seed** — Populate minimal development data with `npx prisma db seed`.
|
||||
8. **Validation** — Run checks from `generation/post-generation-validation.md`, including auth validation and realm-template validation.
|
||||
|
||||
Scaffolding (steps 1–2) must be done with the CLI. Steps 3–8 must be generated from the DSL and the project context documents, including the auth-specific context in `auth/*.md`.
|
||||
Scaffolding (steps 1–2) must be done with the CLI. Steps 3–8 must be generated from `domain/*.dsl`, optional non-duplicating overrides in `overrides/`, and the project context documents, including the auth-specific context in `auth/*.md`.
|
||||
There is no separate DTO/API/UI DSL preparation step in the scaffolding workflow.
|
||||
|
||||
## Git ignore rules
|
||||
|
||||
The generated project must include:
|
||||
|
||||
- root `.gitignore`
|
||||
- `server/.gitignore`
|
||||
- `client/.gitignore`
|
||||
|
||||
These files must keep local-only artifacts out of git, including at minimum:
|
||||
|
||||
- `node_modules/`
|
||||
- `dist/`
|
||||
- `dist-ssr/`
|
||||
- `coverage/`
|
||||
- `*.tsbuildinfo`
|
||||
- `.env`
|
||||
- `.env.local`
|
||||
- `.env.*.local`
|
||||
|
||||
The generator must not ignore committed source, documentation, or `.env.example` files.
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
When the DSL changes, regeneration must preserve the default auth-enabled runtime rather than falling back to CRUD-only output.
|
||||
|
||||
`domain/*.dsl` remains the single required source of truth for regeneration. DTOs, API contracts, and React Admin resources must be re-derived from it on every run. Optional overrides in `overrides/api-overrides.dsl` and `overrides/ui-overrides.dsl` may be applied after derivation, but they must never duplicate or redefine the domain model.
|
||||
Regeneration must not resurrect or depend on supplemental DTO/API/UI DSL inputs. Every derived layer must be recalculated from `domain/*.dsl` plus optional non-duplicating overrides only.
|
||||
|
||||
## Required regeneration sequence
|
||||
|
||||
1. Regenerate `prisma/schema.prisma`.
|
||||
@@ -23,13 +26,17 @@ When the DSL changes, regeneration must preserve the default auth-enabled runtim
|
||||
- `App.tsx` auth wiring
|
||||
- `main.tsx` init-before-render flow
|
||||
7. Regenerate backend and frontend `.env.example` files so the auth env contract stays in sync.
|
||||
8. Regenerate the root-level Keycloak realm import artifact. The repository default example filename is `toir-realm.json`, but the generator must allow a project-specific equivalent.
|
||||
9. Re-run post-generation validation, including:
|
||||
8. Regenerate root/package `.gitignore` files so local-only artifacts remain out of git after regeneration.
|
||||
9. Regenerate the root-level Keycloak realm import artifact. The repository default example filename is `toir-realm.json`, but the generator must allow a project-specific equivalent.
|
||||
10. Re-run post-generation validation, including:
|
||||
- gitignore coverage for dependency, build, env, coverage, and tsbuildinfo artifacts
|
||||
- auth dependency checks
|
||||
- fail-fast env checks
|
||||
- token-claim based identity with no `loadUserProfile()` / `/account` dependency
|
||||
- `/health` public check
|
||||
- unauthenticated protected route -> `401`
|
||||
- insufficient role -> `403`
|
||||
- natural-key `_sort=id` mapping checks
|
||||
- realm-template validation
|
||||
|
||||
## Guardrails
|
||||
|
||||
Reference in New Issue
Block a user