chore: harden generation context baseline
This commit is contained in:
@@ -1,264 +0,0 @@
|
||||
# Backend Generation Process
|
||||
|
||||
Backend generation follows a pipeline aligned with runtime, auth, and validation docs:
|
||||
|
||||
DSL
|
||||
↓
|
||||
CLI scaffolding
|
||||
↓
|
||||
backend code generation
|
||||
↓
|
||||
auth generation
|
||||
↓
|
||||
runtime infrastructure
|
||||
↓
|
||||
database runtime
|
||||
↓
|
||||
migration
|
||||
↓
|
||||
seed
|
||||
↓
|
||||
validation
|
||||
|
||||
Follow:
|
||||
|
||||
- `backend/architecture.md`
|
||||
- `backend/runtime-rules.md`
|
||||
- `backend/prisma-rules.md`
|
||||
- `backend/prisma-service.md`
|
||||
- `backend/database-runtime.md`
|
||||
- `backend/seed-rules.md`
|
||||
- `backend/service-rules.md`
|
||||
- `auth/keycloak-architecture.md`
|
||||
- `auth/backend-auth-rules.md`
|
||||
- `auth/keycloak-realm-template-rules.md`
|
||||
|
||||
---
|
||||
|
||||
# Input Contract
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
# Step 2 — CLI scaffolding
|
||||
|
||||
Use official CLIs before generating backend code:
|
||||
|
||||
- NestJS project scaffold in `server/` (see `generation/scaffolding-rules.md`)
|
||||
- install backend dependencies:
|
||||
- `@prisma/client`
|
||||
- `prisma`
|
||||
- `@nestjs/config`
|
||||
- `jose`
|
||||
- seed runner when needed by the chosen package tooling
|
||||
|
||||
The generator must **not** use deprecated Keycloak-specific Node adapters such as `keycloak-connect`.
|
||||
|
||||
---
|
||||
|
||||
# Step 3 — Core backend code generation
|
||||
|
||||
Generate backend source artifacts:
|
||||
|
||||
1. **Prisma schema** (`server/prisma/schema.prisma`) from the domain DSL:
|
||||
- attributes
|
||||
- primary keys
|
||||
- relations
|
||||
- enums
|
||||
2. **NestJS modules** per entity:
|
||||
- module
|
||||
- controller
|
||||
- service
|
||||
3. **DTO files**:
|
||||
- `create-entity.dto.ts`
|
||||
- `update-entity.dto.ts`
|
||||
- `entity.response.dto.ts` (or equivalent)
|
||||
4. **PrismaService**:
|
||||
- implement `OnModuleInit`
|
||||
- call `await this.$connect()` in `onModuleInit()`
|
||||
- do not use a `beforeExit` hook
|
||||
5. **Service update methods**:
|
||||
- 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`:
|
||||
|
||||
- DSL `decimal` -> DTO `string`
|
||||
- DSL `date` -> DTO `string` (ISO)
|
||||
|
||||
---
|
||||
|
||||
# Step 4 — Backend auth generation
|
||||
|
||||
Generate auth infrastructure as part of the normal backend output. Auth must not be deferred to a manual post-step.
|
||||
|
||||
Required generated auth artifacts:
|
||||
|
||||
- `server/src/auth/auth.module.ts`
|
||||
- JWT auth guard
|
||||
- roles guard
|
||||
- `@Public()` decorator
|
||||
- `@Roles()` decorator
|
||||
- typed authenticated principal interface
|
||||
- typed auth-aware config validation in `server/src/config/`
|
||||
|
||||
JWT verification rules:
|
||||
|
||||
- verify JWTs with issuer, audience, and JWKS
|
||||
- use a standards-based library such as `jose`
|
||||
- resolve JWKS in this exact order:
|
||||
1. explicit `KEYCLOAK_JWKS_URL`
|
||||
2. OIDC discovery
|
||||
3. `${issuer}/protocol/openid-connect/certs`
|
||||
|
||||
RBAC rules:
|
||||
|
||||
- extract authorization roles only from `realm_access.roles`
|
||||
- do not infer roles from other claims
|
||||
- apply CRUD defaults by HTTP method:
|
||||
- `GET` -> `viewer`, `editor`, `admin`
|
||||
- `POST`, `PATCH`, `PUT` -> `editor`, `admin`
|
||||
- `DELETE` -> `admin`
|
||||
- mark `/health` as public with `@Public()`
|
||||
|
||||
Controller generation rules:
|
||||
|
||||
- generated CRUD controllers must receive auth decorators by default
|
||||
- path params must still use the actual entity primary key name (`:id`, `:code`, etc.)
|
||||
- public routes must be explicit rather than implicit
|
||||
|
||||
---
|
||||
|
||||
# Step 5 — Runtime infrastructure
|
||||
|
||||
Generate backend runtime config files:
|
||||
|
||||
- `server/.env`
|
||||
- `server/.env.example`
|
||||
- `server/src/config/*` typed validation helpers
|
||||
- `server/package.json` lifecycle:
|
||||
- `"postinstall": "prisma generate"`
|
||||
- `server/package.json` Prisma seed:
|
||||
- `"prisma": { "seed": "ts-node prisma/seed.ts" }` (or `tsx` equivalent if that is the chosen project standard)
|
||||
|
||||
The generated backend env contract must include:
|
||||
|
||||
- `PORT`
|
||||
- `DATABASE_URL`
|
||||
- `CORS_ALLOWED_ORIGINS`
|
||||
- `KEYCLOAK_ISSUER_URL`
|
||||
- `KEYCLOAK_AUDIENCE`
|
||||
- `KEYCLOAK_JWKS_URL` (optional)
|
||||
|
||||
Fail-fast config rule:
|
||||
|
||||
- backend startup must fail fast when required auth or database env vars are missing
|
||||
- the generator must not silently fall back to production auth values in code
|
||||
|
||||
Commands that must be supported and documented:
|
||||
|
||||
- `npx prisma generate`
|
||||
- `npx prisma migrate dev`
|
||||
- `npx prisma db seed`
|
||||
|
||||
---
|
||||
|
||||
# Step 6 — Database runtime
|
||||
|
||||
Create `docker-compose.yml` at the **project root** with PostgreSQL only.
|
||||
|
||||
Minimum required compose characteristics:
|
||||
|
||||
- `services.postgres`
|
||||
- `image: postgres:16`
|
||||
- `ports: ["5432:5432"]`
|
||||
|
||||
Credentials and database name in compose must match `DATABASE_URL`.
|
||||
|
||||
Keycloak must remain an external runtime dependency and must not be added to `docker-compose.yml` in this repository.
|
||||
|
||||
---
|
||||
|
||||
# Step 7 — Migration
|
||||
|
||||
Apply schema to the development database:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Step 8 — Seed
|
||||
|
||||
Run development seed:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npx prisma db seed
|
||||
```
|
||||
|
||||
Seed file location: `server/prisma/seed.ts`.
|
||||
|
||||
---
|
||||
|
||||
# Step 9 — Validation
|
||||
|
||||
Run runtime, auth, and contract checks from `generation/post-generation-validation.md`, including:
|
||||
|
||||
- docker-compose exists and DB container starts
|
||||
- Prisma lifecycle commands succeed
|
||||
- seed runs
|
||||
- `/health` responds without auth
|
||||
- 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
|
||||
@@ -1,137 +0,0 @@
|
||||
# Developer Workflow
|
||||
|
||||
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
|
||||
|
||||
- **Node.js** (LTS, e.g. 18+)
|
||||
- **npm**
|
||||
- **Docker** and **Docker Compose** (for the development database)
|
||||
- **External Keycloak server** reachable by the generated frontend and backend
|
||||
|
||||
The generated project must not require the developer to invent auth wiring manually after generation.
|
||||
|
||||
---
|
||||
|
||||
# Workflow Steps
|
||||
|
||||
## 1. Prepare Keycloak and env files
|
||||
|
||||
From the project root, the generated project must include:
|
||||
|
||||
- root-level generated Keycloak realm import artifact
|
||||
- repository default example filename: `toir-realm.json`
|
||||
- `server/.env.example`
|
||||
- `client/.env.example`
|
||||
|
||||
Required workflow:
|
||||
|
||||
1. Copy the generated env examples to real env files as needed.
|
||||
2. Fill all required backend and frontend auth variables.
|
||||
3. Import or verify the generated Keycloak realm import artifact in the external Keycloak server before starting the app.
|
||||
|
||||
The generator must document that auth config is fail-fast. Missing required auth env vars must stop startup instead of silently falling back to production values in code.
|
||||
|
||||
---
|
||||
|
||||
## 2. Start the database
|
||||
|
||||
From the **project root**:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This starts the PostgreSQL container defined in `docker-compose.yml`. Wait a few seconds for the database to accept connections.
|
||||
|
||||
Verify if needed:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend setup and start
|
||||
|
||||
From the **server** directory:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npm install
|
||||
npx prisma generate
|
||||
npx prisma migrate dev
|
||||
npx prisma db seed
|
||||
npm run start
|
||||
```
|
||||
|
||||
- `npm install` installs dependencies and runs `postinstall` when configured.
|
||||
- `npx prisma generate` explicitly generates Prisma client.
|
||||
- `npx prisma migrate dev` creates/applies migrations.
|
||||
- `npx prisma db seed` inserts minimal development data.
|
||||
- `npm run start` starts the NestJS backend.
|
||||
|
||||
The API should be available at the configured port (for example `http://localhost:3000`).
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
curl http://localhost:3000/health
|
||||
```
|
||||
|
||||
Expected: `{ "status": "ok" }` (or equivalent).
|
||||
|
||||
Generated backend behavior must also ensure:
|
||||
|
||||
- protected CRUD routes require authentication by default
|
||||
- insufficient roles result in `403`
|
||||
- `/health` remains public
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend setup and start
|
||||
|
||||
In a **separate terminal**, from the **project root**:
|
||||
|
||||
```bash
|
||||
cd client
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
- `npm install` installs frontend dependencies including `keycloak-js`.
|
||||
- `npm run dev` starts the Vite dev server (for example `http://localhost:5173`).
|
||||
|
||||
Open the frontend URL in a browser. The generated React Admin app must:
|
||||
|
||||
- initialize Keycloak before render
|
||||
- use redirect-based login only
|
||||
- authenticate against the configured Keycloak realm/client
|
||||
- call the backend with bearer tokens through the shared request seam
|
||||
|
||||
---
|
||||
|
||||
# Summary
|
||||
|
||||
| Step | Command / location |
|
||||
|------|---------------------|
|
||||
| Prepare Keycloak + env | Fill `server/.env` and `client/.env`; import or verify the generated realm import artifact |
|
||||
| Start database | From root: `docker compose up -d` |
|
||||
| Backend setup/start | `cd server && npm install && npx prisma generate && npx prisma migrate dev && npx prisma db seed && npm run start` |
|
||||
| Frontend setup/start | `cd client && npm install && npm run dev` |
|
||||
|
||||
The generator must produce all required artifacts so that this workflow succeeds:
|
||||
|
||||
- docker-compose
|
||||
- env examples
|
||||
- schema
|
||||
- migrations
|
||||
- seed
|
||||
- health endpoint
|
||||
- frontend auth integration
|
||||
- backend auth infrastructure
|
||||
- root-level Keycloak realm import artifact
|
||||
@@ -1,183 +0,0 @@
|
||||
# Frontend Generation Process
|
||||
|
||||
Frontend generation must produce the React Admin CRUD application **and** the default Keycloak integration required by the runtime architecture.
|
||||
|
||||
Follow:
|
||||
|
||||
- `frontend/architecture.md`
|
||||
- `frontend/react-admin-rules.md`
|
||||
- `auth/keycloak-architecture.md`
|
||||
- `auth/frontend-auth-rules.md`
|
||||
- `auth/keycloak-realm-template-rules.md`
|
||||
|
||||
---
|
||||
|
||||
# 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:
|
||||
|
||||
- entities
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
# Step 2 — Generate frontend runtime structure
|
||||
|
||||
Generate the base frontend structure required by the proven runtime:
|
||||
|
||||
- `client/src/main.tsx`
|
||||
- `client/src/App.tsx`
|
||||
- `client/src/dataProvider.ts`
|
||||
- `client/src/config/env.ts`
|
||||
- `client/src/auth/keycloak.ts`
|
||||
- `client/src/auth/authProvider.ts`
|
||||
- `client/.env.example`
|
||||
|
||||
The generated frontend must:
|
||||
|
||||
- initialize Keycloak before rendering the SPA
|
||||
- register React Admin with a mandatory `authProvider`
|
||||
- enforce authenticated operation rather than anonymous operation
|
||||
- use environment-driven runtime config and fail fast when required auth vars are missing
|
||||
|
||||
---
|
||||
|
||||
# Step 3 — Generate React Admin resources
|
||||
|
||||
For each entity create:
|
||||
|
||||
- `EntityList.tsx`
|
||||
- `EntityCreate.tsx`
|
||||
- `EntityEdit.tsx`
|
||||
- `EntityShow.tsx`
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
# Step 4 — Map fields
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
# Step 5 — Generate auth-aware API layer
|
||||
|
||||
Generate a shared `dataProvider.ts` that:
|
||||
|
||||
- reads the API base URL from `VITE_API_URL`
|
||||
- attaches `Authorization: Bearer <access_token>` to every backend request
|
||||
- uses the same request seam for all React Admin operations, including:
|
||||
- list
|
||||
- get one
|
||||
- get many
|
||||
- get many reference
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- handles token refresh before protected requests
|
||||
- keeps token refresh concurrency-safe by sharing one in-flight refresh operation
|
||||
- does not store access tokens or refresh tokens in `localStorage` or `sessionStorage`
|
||||
|
||||
The generator must not create multiple competing HTTP clients for authenticated and unauthenticated traffic. The shared request seam is the single bearer injection point.
|
||||
|
||||
---
|
||||
|
||||
# Step 6 — Generate frontend auth flow
|
||||
|
||||
Generate Keycloak frontend integration with these required rules:
|
||||
|
||||
- use `keycloak-js`
|
||||
- redirect-based login only
|
||||
- no custom in-app username/password login form
|
||||
- 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
|
||||
|
||||
The generator must not silently fall back to production auth settings in code. Example values belong in `.env.example`, but runtime config must fail fast if required values are absent.
|
||||
|
||||
---
|
||||
|
||||
# Step 7 — Register resources and auth
|
||||
|
||||
Register resources in `App.tsx` and wire them into an authenticated `Admin` root.
|
||||
|
||||
Generated `App.tsx` must:
|
||||
|
||||
- register the shared `dataProvider`
|
||||
- register the mandatory `authProvider`
|
||||
- configure the app so it does not operate anonymously once auth is enabled
|
||||
|
||||
Example shape:
|
||||
|
||||
```tsx
|
||||
<Admin dataProvider={dataProvider} authProvider={authProvider}>
|
||||
<Resource name="equipment" ... />
|
||||
</Admin>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Step 8 — Frontend runtime config
|
||||
|
||||
Generate frontend env examples and config access for:
|
||||
|
||||
- `VITE_API_URL`
|
||||
- `VITE_KEYCLOAK_URL`
|
||||
- `VITE_KEYCLOAK_REALM`
|
||||
- `VITE_KEYCLOAK_CLIENT_ID`
|
||||
|
||||
`client/.env.example` must use filled example values that match the documented Keycloak and local dev topology, while runtime code must fail fast if any required variable is missing.
|
||||
@@ -1,271 +0,0 @@
|
||||
# Post-Generation Validation
|
||||
|
||||
After generating the backend or fullstack application, run these checks to ensure the project will start cleanly and that the default auth model has been generated correctly.
|
||||
|
||||
---
|
||||
|
||||
# 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:
|
||||
- `PORT`
|
||||
- `DATABASE_URL`
|
||||
- `CORS_ALLOWED_ORIGINS`
|
||||
- `KEYCLOAK_ISSUER_URL`
|
||||
- `KEYCLOAK_AUDIENCE`
|
||||
- optional `KEYCLOAK_JWKS_URL`
|
||||
- [ ] `client/.env.example` exists and documents:
|
||||
- `VITE_API_URL`
|
||||
- `VITE_KEYCLOAK_URL`
|
||||
- `VITE_KEYCLOAK_REALM`
|
||||
- `VITE_KEYCLOAK_CLIENT_ID`
|
||||
- [ ] Runtime code fails fast when required auth or database env vars are missing.
|
||||
- [ ] Runtime code does not silently fall back to production auth settings.
|
||||
|
||||
**Failure symptoms:** startup succeeds with undefined auth config, or fails later with opaque auth/runtime errors.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
- [ ] The generated realm artifact is self-contained and reproducible.
|
||||
- [ ] The generated realm artifact parameterizes realm name, frontend client ID, backend audience/client ID, production URLs, and artifact filename consistently with the generated project auth config.
|
||||
- [ ] It defines realm roles:
|
||||
- `admin`
|
||||
- `editor`
|
||||
- `viewer`
|
||||
- [ ] It defines a frontend SPA client consistent with the generated frontend Keycloak client ID.
|
||||
- [ ] It defines a backend audience/resource client consistent with the generated backend audience/client ID.
|
||||
- [ ] It defines explicit audience delivery, such as an `api-audience` client scope.
|
||||
- [ ] It does not rely on undeclared built-in client scopes being present after import.
|
||||
- [ ] It explicitly addresses delivery of:
|
||||
- `sub`
|
||||
- `aud`
|
||||
- `realm_access.roles`
|
||||
|
||||
**Failure symptoms:** access tokens are missing required claims, or realm import succeeds but generated apps still cannot authenticate/authorize reliably.
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend auth files and behavior
|
||||
|
||||
- [ ] Generated frontend includes:
|
||||
- `client/src/config/env.ts`
|
||||
- `client/src/auth/keycloak.ts`
|
||||
- `client/src/auth/authProvider.ts`
|
||||
- `client/src/main.tsx`
|
||||
- `client/src/App.tsx`
|
||||
- `client/src/dataProvider.ts`
|
||||
- [ ] `keycloak-js` is installed.
|
||||
- [ ] Keycloak is initialized before the SPA renders.
|
||||
- [ ] Login is redirect-based only.
|
||||
- [ ] 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
|
||||
- [ ] Generated auth code does not persist access tokens or refresh tokens in `localStorage` or `sessionStorage`.
|
||||
- [ ] React Admin auth semantics distinguish:
|
||||
- `401` -> force logout / re-authentication
|
||||
- `403` -> do not re-authenticate; surface access denied / permission error
|
||||
|
||||
**Failure symptoms:** app renders before auth is ready, reference calls miss auth headers, refresh storms occur, or `403` incorrectly forces logout.
|
||||
|
||||
---
|
||||
|
||||
## 5. Backend auth files and behavior
|
||||
|
||||
- [ ] Generated backend includes:
|
||||
- `server/src/auth/auth.module.ts`
|
||||
- JWT guard
|
||||
- roles guard
|
||||
- `@Public()` decorator
|
||||
- `@Roles()` decorator
|
||||
- typed authenticated principal interface
|
||||
- typed config validation in `server/src/config/`
|
||||
- [ ] `jose` is installed.
|
||||
- [ ] JWT verification uses issuer + audience + JWKS.
|
||||
- [ ] JWKS resolution follows this exact priority:
|
||||
1. `KEYCLOAK_JWKS_URL`
|
||||
2. OIDC discovery
|
||||
3. `${issuer}/protocol/openid-connect/certs`
|
||||
- [ ] Authorization roles are extracted only from `realm_access.roles`.
|
||||
- [ ] Deprecated Keycloak-specific Node adapters are not used.
|
||||
|
||||
**Failure symptoms:** invalid tokens are accepted, valid tokens are rejected due to bad JWKS resolution, or RBAC depends on unstable/non-standard claims.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
- [ ] CRUD RBAC defaults are present:
|
||||
- `GET` -> `viewer | editor | admin`
|
||||
- `POST`, `PATCH`, `PUT` -> `editor | admin`
|
||||
- `DELETE` -> `admin`
|
||||
- [ ] Unauthenticated request to a protected route returns `401`.
|
||||
- [ ] Authenticated user with insufficient role receives `403`.
|
||||
|
||||
**Failure symptoms:** anonymous CRUD access remains open, or insufficient-role users are not denied properly.
|
||||
|
||||
---
|
||||
|
||||
## 7. PrismaService implementation
|
||||
|
||||
- [ ] A `PrismaService` (or equivalent) class exists and extends `PrismaClient`.
|
||||
- [ ] It implements `OnModuleInit` and calls `await this.$connect()` in `onModuleInit()`.
|
||||
- [ ] It does not use `this.$on('beforeExit', ...)` or any `beforeExit` hook.
|
||||
|
||||
**Failure symptom:** deprecation/runtime errors in Prisma 5 when using `beforeExit`.
|
||||
|
||||
**Reference:** `backend/prisma-service.md`
|
||||
|
||||
---
|
||||
|
||||
## 8. Prisma client lifecycle
|
||||
|
||||
- [ ] `package.json` includes a script that runs Prisma client generation:
|
||||
- either `"postinstall": "prisma generate"` (or `npx prisma generate`)
|
||||
- or clear documentation to run `npx prisma generate` after install
|
||||
- [ ] After schema generation or change, `npx prisma generate` has been run or will run via `postinstall`.
|
||||
|
||||
**Failure symptom:** `Cannot find module '@prisma/client'` or missing generated types.
|
||||
|
||||
---
|
||||
|
||||
## 9. Database migration
|
||||
|
||||
- [ ] Migration workflow is documented.
|
||||
- [ ] Instruction to run `npx prisma migrate dev` exists after first generation or schema change.
|
||||
- [ ] Generation pipeline includes or documents the migration step.
|
||||
|
||||
**Failure symptom:** tables do not exist; Prisma errors on first query.
|
||||
|
||||
---
|
||||
|
||||
## 10. REST route parameters
|
||||
|
||||
- [ ] For each entity, path parameters use the correct primary key name from the DSL.
|
||||
- [ ] Entity with PK `id` uses `/:id`.
|
||||
- [ ] Entity with non-`id` primary key (for example `code`) uses the actual PK name such as `/:code`, not `/:id`.
|
||||
|
||||
**Failure symptom:** controller expects one param name while the route defines another, leading to broken CRUD behavior.
|
||||
|
||||
**Reference:** `backend/architecture.md`
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
## 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()`.
|
||||
|
||||
**Failure symptom:** Prisma throws because immutable or invalid fields are passed in update `data`.
|
||||
|
||||
---
|
||||
|
||||
## 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`.
|
||||
- [ ] `docker compose up -d` starts the database successfully.
|
||||
- [ ] `docker-compose.yml` does not add Keycloak in this repository.
|
||||
|
||||
**Failure symptom:** Prisma cannot reach the development database or repo topology drifts from the documented external-Keycloak model.
|
||||
|
||||
---
|
||||
|
||||
## 14. Migrations, seed, and health endpoint
|
||||
|
||||
- [ ] `npx prisma migrate dev` runs successfully from `server/`.
|
||||
- [ ] Seed script exists at `server/prisma/seed.ts` (or equivalent).
|
||||
- [ ] `npx prisma db seed` runs without error.
|
||||
- [ ] Backend exposes `GET /health`.
|
||||
- [ ] `GET /health` returns HTTP 200 with a status payload.
|
||||
|
||||
**Failure symptom:** development bootstrap cannot complete end-to-end.
|
||||
|
||||
---
|
||||
|
||||
# Summary Table
|
||||
|
||||
| Check | Required artifact / rule |
|
||||
| --- | --- |
|
||||
| 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 |
|
||||
| CRUD RBAC | GET viewer/editor/admin; write editor/admin; delete admin |
|
||||
| `/health` | Public and returns 200 |
|
||||
| Protected route unauthenticated | Returns `401` |
|
||||
| Protected route insufficient role | Returns `403` |
|
||||
| Token storage | No `localStorage` / `sessionStorage` persistence |
|
||||
| Token refresh | Concurrency-safe single in-flight refresh |
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
# Integration with generation pipeline
|
||||
|
||||
1. Backend and frontend generation must produce artifacts that satisfy the above by default.
|
||||
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.
|
||||
@@ -1,122 +0,0 @@
|
||||
# Runtime Bootstrap
|
||||
|
||||
After project generation, the following commands and prerequisites must work in order so that the application runs without ad-hoc auth or database setup.
|
||||
|
||||
The generator must produce a **runnable development environment** consisting of:
|
||||
|
||||
- external Keycloak identity provider
|
||||
- backend API
|
||||
- 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.
|
||||
|
||||
---
|
||||
|
||||
# Bootstrap Sequence
|
||||
|
||||
## 1. Prepare Keycloak
|
||||
|
||||
Before starting the application, ensure an external Keycloak server is reachable and import or verify the generated realm artifact:
|
||||
|
||||
- root-level generated Keycloak realm import artifact
|
||||
- repository default example filename: `toir-realm.json`
|
||||
|
||||
The runtime instructions must require importing or verifying this realm before frontend/backend startup.
|
||||
|
||||
Keycloak bootstrap expectations:
|
||||
|
||||
- realm import is self-contained
|
||||
- frontend client exists
|
||||
- backend audience client exists
|
||||
- realm roles exist
|
||||
- issued access tokens reliably contain `sub`, `aud`, and `realm_access.roles`
|
||||
|
||||
The generator must not rely on undeclared built-in client scopes magically existing after realm import.
|
||||
|
||||
---
|
||||
|
||||
## 2. Start the database
|
||||
|
||||
From the **project root**:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This starts the PostgreSQL container. The backend connects to it using `DATABASE_URL` from `server/.env`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend setup and start
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npm install
|
||||
npx prisma generate
|
||||
npx prisma migrate dev
|
||||
npx prisma db seed
|
||||
npm run start
|
||||
```
|
||||
|
||||
- `npm install` installs dependencies and runs `postinstall` if configured.
|
||||
- `npx prisma generate` ensures Prisma client is generated explicitly after install or schema changes.
|
||||
- `npx prisma migrate dev` creates/applies migrations.
|
||||
- `npx prisma db seed` inserts minimal development data.
|
||||
- `npm run start` starts the NestJS server.
|
||||
|
||||
Backend startup requirements:
|
||||
|
||||
- required database and auth env vars must be present
|
||||
- startup must fail fast if required env vars are missing
|
||||
- CORS must support the SPA -> API bearer-token model
|
||||
- `/health` must remain public
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend setup and start
|
||||
|
||||
In a separate terminal, from the **project root**:
|
||||
|
||||
```bash
|
||||
cd client
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
- `npm install` installs frontend dependencies including `keycloak-js`.
|
||||
- `npm run dev` starts the Vite dev server.
|
||||
|
||||
Frontend startup requirements:
|
||||
|
||||
- required Vite auth vars must be present
|
||||
- startup must fail fast if required auth vars are missing
|
||||
- Keycloak must initialize before the SPA is rendered
|
||||
- login must use redirect-based Keycloak authentication only
|
||||
|
||||
---
|
||||
|
||||
# Success Criteria
|
||||
|
||||
After completing the bootstrap sequence:
|
||||
|
||||
- Keycloak is reachable and the generated realm has been imported or verified.
|
||||
- Database container is running and Prisma can connect.
|
||||
- Backend responds on `/health` without auth.
|
||||
- Protected backend routes require a valid bearer token.
|
||||
- Frontend loads, redirects through Keycloak login when needed, and uses bearer auth for all API calls.
|
||||
|
||||
The generator is responsible for producing all artifacts and instructions needed for this sequence:
|
||||
|
||||
- `docker-compose.yml`
|
||||
- schema
|
||||
- migrations
|
||||
- seed
|
||||
- backend/frontend env examples
|
||||
- health endpoint
|
||||
- auth infrastructure
|
||||
- root-level Keycloak realm import artifact
|
||||
|
||||
Docker scope must remain limited to PostgreSQL. Keycloak remains an external dependency in this repository.
|
||||
@@ -1,114 +0,0 @@
|
||||
# Project Scaffolding Rules
|
||||
|
||||
The generator must use **official CLI tools** to create base project structures.
|
||||
|
||||
The AI must **not** manually generate the entire project skeleton by hand. CLI scaffolding reduces drift and keeps the generated project aligned with current NestJS and Vite conventions.
|
||||
|
||||
Auth is part of the default generated runtime. Scaffolding must therefore install the required frontend and backend auth dependencies during the normal project bootstrap path.
|
||||
|
||||
---
|
||||
|
||||
# Backend Scaffolding
|
||||
|
||||
Use **NestJS CLI**.
|
||||
|
||||
## Command
|
||||
|
||||
```bash
|
||||
npx @nestjs/cli@10.3.2 new server --package-manager npm --skip-git
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- **Project directory** must be `server`.
|
||||
- **TypeScript** must be used.
|
||||
- **npm** must be the package manager.
|
||||
- **Git** initialization must be skipped.
|
||||
|
||||
## After scaffolding — install required dependencies
|
||||
|
||||
Run from the `server` directory:
|
||||
|
||||
```bash
|
||||
npm install @prisma/client
|
||||
npm install @nestjs/config
|
||||
npm install jose
|
||||
npm install prisma --save-dev
|
||||
```
|
||||
|
||||
## Backend auth dependency rules
|
||||
|
||||
- `jose` must be installed by default because JWT verification is part of the default generated backend.
|
||||
- The generator must **not** install deprecated Keycloak-specific Node adapters such as `keycloak-connect`.
|
||||
|
||||
---
|
||||
|
||||
# Frontend Scaffolding
|
||||
|
||||
Use **Vite CLI**.
|
||||
|
||||
## Command
|
||||
|
||||
```bash
|
||||
npm create vite@5.2.0 client -- --template react-ts
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- **Project directory** must be `client`.
|
||||
- **React + TypeScript** template must be used.
|
||||
|
||||
## After scaffolding — install required dependencies
|
||||
|
||||
Run from the `client` directory:
|
||||
|
||||
```bash
|
||||
npm install react-admin
|
||||
npm install ra-data-simple-rest
|
||||
npm install @mui/material @emotion/react @emotion/styled
|
||||
npm install keycloak-js
|
||||
```
|
||||
|
||||
## Frontend auth dependency rules
|
||||
|
||||
- `keycloak-js` must be installed by default because redirect-based Keycloak login is part of the default generated frontend.
|
||||
- The generated frontend must use `keycloak-js` for Authorization Code + PKCE and must not generate a custom in-app username/password login form.
|
||||
|
||||
---
|
||||
|
||||
# Scaffolding Strategy
|
||||
|
||||
Generation pipeline order:
|
||||
|
||||
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`, 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 `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.
|
||||
@@ -1,47 +0,0 @@
|
||||
# Update Strategy
|
||||
|
||||
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`.
|
||||
2. Run `npx prisma migrate dev`.
|
||||
3. Regenerate NestJS entity modules, DTOs, controllers, and services.
|
||||
4. Regenerate backend auth infrastructure:
|
||||
- `AuthModule`
|
||||
- guards
|
||||
- decorators
|
||||
- typed authenticated principal
|
||||
- typed config validation
|
||||
- CRUD RBAC decorations
|
||||
5. Regenerate React Admin resources.
|
||||
6. Regenerate frontend auth infrastructure:
|
||||
- `src/config/env.ts`
|
||||
- `src/auth/keycloak.ts`
|
||||
- `src/auth/authProvider.ts`
|
||||
- authenticated `dataProvider.ts`
|
||||
- `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 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
|
||||
|
||||
- Regeneration must not strip auth back out of the project.
|
||||
- Auth remains outside the DSL grammar, but it is part of the default generated runtime.
|
||||
- If a DSL change affects entities or routes, the generator must re-apply the default CRUD RBAC rules automatically.
|
||||
- If a DSL change affects runtime topology or naming, the generator must keep backend/frontend env examples, CORS rules, and the generated realm import artifact aligned with the generated app.
|
||||
Reference in New Issue
Block a user