Merge feat/keycloak into add_filters with manual conflict resolution.

Preserve Keycloak auth/RBAC contracts while retaining filter behavior and generator consistency for future regenerations.

Made-with: Cursor
This commit is contained in:
MaKarin
2026-03-24 13:52:20 +03:00
78 changed files with 2949 additions and 3880 deletions

View File

@@ -1,159 +0,0 @@
# Backend Generation Process
Backend generation follows a pipeline aligned with runtime and validation docs:
DSL
CLI scaffolding
code generation
runtime infrastructure
database runtime
migration
seed
validation
Follow **backend/runtime-rules.md**, **backend/prisma-rules.md**, **backend/prisma-service.md**, **backend/database-runtime.md**, **backend/seed-rules.md**, and **backend/service-rules.md**.
---
# Step 1 — Parse DSL
Read DSL inputs and extract:
- entities
- attributes (including primary key attribute name per entity)
- enums
- foreign keys
---
# 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`, and seed runner when needed)
---
# Step 3 — Code generation
Generate backend source artifacts:
1. **Prisma schema** (`server/prisma/schema.prisma`) from domain DSL:
- attributes
- primary keys
- relations
- enums
2. **NestJS modules** per entity:
- module
- controller (path params use actual PK name: `:id`, `:code`, etc.)
- service (must sanitize update payload before Prisma — see **backend/service-rules.md**)
3. **DTO files**:
- `create-entity.dto.ts`
- `update-entity.dto.ts`
- `entity.response.dto.ts` (or equivalent)
4. **PrismaService**:
- `OnModuleInit` + `await this.$connect()`
- no `beforeExit` hook
5. **Service update methods**: Sanitize update payload before passing to Prisma (remove `id`, primary key, and readonly attributes from `data`). Do not pass the raw request body as `data` to `prisma.*.update()`.
Use mapping rules from `backend/prisma-rules.md`:
- DSL `decimal` -> DTO `string`
- DSL `date` -> DTO `string` (ISO)
## Filtering & search contract (must be generated)
React Admin uses query parameters for pagination, sorting, and filtering.
- **Pagination**: `_start`, `_end`
- **Sorting**: `_sort`, `_order`
- **Filtering**: arbitrary field keys in query string
Additionally, to support `AutocompleteInput` search for references, list endpoints must support:
- `q`: a generic search term that can be applied as an `OR` over a few human-meaningful fields (e.g. code/name/manufacturer, inventoryNumber/name, etc.)
### Multi-value filter support
For enum-like fields (e.g. `status`) the backend must accept both:
- `status=Active` (single value)
- `status=Active&status=Repair` (multiple values)
Services must treat repeated query params as arrays and translate them to Prisma `in` filters.
---
# Step 4 — Runtime infrastructure
Generate runtime config files:
- `server/.env`
- `server/.env.example`
- `server/package.json` lifecycle:
- `"postinstall": "prisma generate"`
- `server/package.json` Prisma seed:
- `"prisma": { "seed": "ts-node prisma/seed.ts" }` (or `tsx` variant by project standard)
Commands that must be supported/documented:
- `npx prisma generate`
- `npx prisma migrate dev`
- `npx prisma db seed`
---
# Step 5 — Database runtime
Generator must create `docker-compose.yml` at the **project root** with PostgreSQL.
Minimum required compose characteristics:
- `services.postgres`
- `image: postgres:16`
- `ports: ["5432:5432"]`
Credentials/database in compose must match `DATABASE_URL`.
---
# Step 6 — Migration
Apply schema to development database:
```bash
cd server
npx prisma migrate dev
```
---
# Step 7 — Seed
Run development seed:
```bash
cd server
npx prisma db seed
```
Seed file location: `server/prisma/seed.ts`.
---
# Step 8 — Validation
Run runtime 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
- React Admin receives `id` in every record

View File

@@ -1,106 +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.
## Regenerating code from DSL
If the domain DSL changes (e.g. a new entity is added), regenerate backend + frontend artifacts from `examples/TOiR.domain.dsl`:
```bash
cd server
npm run generate:from-dsl
```
Then apply the updated schema and seed data:
```bash
cd server
npx prisma db push
npx prisma db seed
```
---
# Prerequisites
- **Node.js** (LTS, e.g. 18+)
- **npm**
- **Docker** and **Docker Compose** (for the development database)
---
# Workflow Steps
## 1. 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 (optional):
```bash
docker compose ps
```
---
## 2. 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` (for example `prisma generate`).
- `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 NestJS backend.
The API should be available at the configured port (e.g. `http://localhost:3000`). Verify with:
```bash
curl http://localhost:3000/health
```
Expected: `{ "status": "ok" }` (or equivalent).
---
## 3. 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.
- `npm run dev` — starts the Vite dev server (e.g. `http://localhost:5173`).
Open the Vite URL in a browser; the React Admin app should load and use the backend API.
---
# Summary
| Step | Command / location |
|------|---------------------|
| 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 (docker-compose, env, schema, migrations, seed, health endpoint) so that this workflow succeeds and the development environment is fully runnable.

View File

@@ -1,56 +0,0 @@
# Frontend Generation Process
Frontend generation uses the DSL and API specification.
---
# Step 1 — Parse DSL
Extract entities and attributes.
---
# Step 2 — Generate React Admin Resources
For each entity create:
EntityList.tsx
EntityCreate.tsx
EntityEdit.tsx
EntityShow.tsx
## List UX requirements (must be generated)
- Lists must include **filtering UI** via `filters` prop on `List` and an explicit actions toolbar with:
- `FilterButton` (so non-`alwaysOn` filters are discoverable)
- `CreateButton`
- `ExportButton`
- Lists must include a **default sort** (`sort={{ field: "...", order: "ASC|DESC" }}`) appropriate for the entity.
## Reference selection UX (must be generated)
- For foreign keys (`ReferenceInput`) in Create/Edit forms, prefer `AutocompleteInput` over `SelectInput` to support search.
- Autocomplete must send search text to backend using `filterToQuery={(searchText) => ({ q: searchText })}`.
- Option text must include a **code** (or business identifier) and a name when available, e.g. `CODE — NAME`.
## Enum filters (must be generated)
- For enum fields in **list filters**, use:
- `SelectInput` for single-select filters
- `SelectArrayInput` for multi-select filters when users need to filter by multiple enum values (e.g. Status).
---
# Step 3 — Map Fields
Map DSL attributes to React Admin components.
---
# Step 4 — Register Resources
Register resources in App.tsx.
Example:
<Resource name="equipment" ... />

View File

@@ -332,7 +332,7 @@ function renderBackendModule(entityName, entity, resourceName, pk) {
}
updateDtoLines.push('}');
const controller = `import { Controller, Get, Post, Patch, Delete, Param, Body, Query, Res } from '@nestjs/common';\nimport { Response } from 'express';\nimport { ${serviceName} } from './${folder}.service';\nimport { Create${className}Dto } from './dto/create-${folder}.dto';\nimport { Update${className}Dto } from './dto/update-${folder}.dto';\n\n@Controller('${resourceName}')\nexport class ${controllerName} {\n constructor(private readonly service: ${serviceName}) {}\n\n @Get()\n async findAll(@Query() query: any, @Res() res: Response) {\n const result = await this.service.findAll(query);\n res.set('Content-Range', \`${resourceName} \${query._start || 0}-\${query._end || result.total}/\${result.total}\`);\n res.set('Access-Control-Expose-Headers', 'Content-Range');\n return res.json(result.data);\n }\n\n @Get(':${pk}')\n findOne(@Param('${pk}') id: string) {\n return this.service.findOne(id);\n }\n\n @Post()\n create(@Body() dto: Create${className}Dto) {\n return this.service.create(dto);\n }\n\n @Patch(':${pk}')\n update(@Param('${pk}') id: string, @Body() dto: Update${className}Dto) {\n return this.service.update(id, dto);\n }\n\n @Delete(':${pk}')\n remove(@Param('${pk}') id: string) {\n return this.service.remove(id);\n }\n}\n`;
const controller = `import { Controller, Get, Post, Patch, Delete, Param, Body, Query, Res } from '@nestjs/common';\nimport { Response } from 'express';\nimport { Roles } from '../../auth/decorators/roles.decorator';\nimport { RealmRole } from '../../auth/roles/realm-role.enum';\nimport { ${serviceName} } from './${folder}.service';\nimport { Create${className}Dto } from './dto/create-${folder}.dto';\nimport { Update${className}Dto } from './dto/update-${folder}.dto';\n\n@Controller('${resourceName}')\nexport class ${controllerName} {\n constructor(private readonly service: ${serviceName}) {}\n\n @Roles(RealmRole.Viewer, RealmRole.Editor, RealmRole.Admin)\n @Get()\n async findAll(@Query() query: any, @Res() res: Response) {\n const result = await this.service.findAll(query);\n res.set('Content-Range', \`${resourceName} \${query._start || 0}-\${query._end || result.total}/\${result.total}\`);\n res.set('Access-Control-Expose-Headers', 'Content-Range');\n return res.json(result.data);\n }\n\n @Roles(RealmRole.Viewer, RealmRole.Editor, RealmRole.Admin)\n @Get(':${pk}')\n findOne(@Param('${pk}') id: string) {\n return this.service.findOne(id);\n }\n\n @Roles(RealmRole.Editor, RealmRole.Admin)\n @Post()\n create(@Body() dto: Create${className}Dto) {\n return this.service.create(dto);\n }\n\n @Roles(RealmRole.Editor, RealmRole.Admin)\n @Patch(':${pk}')\n update(@Param('${pk}') id: string, @Body() dto: Update${className}Dto) {\n return this.service.update(id, dto);\n }\n\n @Roles(RealmRole.Admin)\n @Delete(':${pk}')\n remove(@Param('${pk}') id: string) {\n return this.service.remove(id);\n }\n}\n`;
const service = `import { Injectable } from '@nestjs/common';\nimport { Prisma } from '@prisma/client';\nimport { PrismaService } from '../../prisma/prisma.service';\nimport { Create${className}Dto } from './dto/create-${folder}.dto';\nimport { Update${className}Dto } from './dto/update-${folder}.dto';\n\nfunction serializeRecord(record: any) {\n return {\n ...record,\n${entity.attributes
.filter((a) => a.type === 'decimal')
@@ -367,13 +367,31 @@ function renderBackendModule(entityName, entity, resourceName, pk) {
.map((a) => ` if (data.${a.name} !== undefined && data.${a.name} !== null) data.${a.name} = new Prisma.Decimal(data.${a.name});`)
.join('\n')}\n\n const record = await this.prisma.${lowerFirst(className)}.update({ where: { ${pk}: id } as any, data });\n return ${pk === 'id' ? 'serializeRecord(record)' : `{ id: (record as any).${pk}, ...serializeRecord(record) }`};\n }\n\n async remove(id: string) {\n const record = await this.prisma.${lowerFirst(className)}.delete({ where: { ${pk}: id } as any });\n return ${pk === 'id' ? 'serializeRecord(record)' : `{ id: (record as any).${pk}, ...serializeRecord(record) }`};\n }\n}\n`;
let serviceContent = service
.replace(
`const sortField = query._sort || '${getBestSortField(entity, pk)}';\n const sortOrder = (query._order || 'ASC').toLowerCase() as 'asc' | 'desc';`,
`const sortField = query._sort || '${getBestSortField(entity, pk)}';\n const prismaSortField = sortField === 'id' ? '${pk}' : sortField;\n const sortOrder = (query._order || 'ASC').toLowerCase() as 'asc' | 'desc';`
)
.replace('orderBy: { [sortField]: sortOrder }', 'orderBy: { [prismaSortField]: sortOrder }')
.replace(
`data.map((r: any) => ({ id: r.${pk}, ...serializeRecord(r) }))`,
`data.map((item: any) => ({ id: item.${pk}, ...serializeRecord(item) }))`
);
if (pk !== 'id') {
serviceContent = serviceContent.replace(
`const data: any = { ...(dto as any) };\n delete data.id;\n delete data.${pk};`,
`const { id: _pk, ${pk}, ...rest } = (dto as any);\n const data: any = { ...rest };`
);
}
const mod = `import { Module } from '@nestjs/common';\nimport { ${controllerName} } from './${folder}.controller';\nimport { ${serviceName} } from './${folder}.service';\n\n@Module({\n controllers: [${controllerName}],\n providers: [${serviceName}],\n})\nexport class ${moduleName} {}\n`;
return {
folder,
files: {
[`server/src/modules/${folder}/${folder}.controller.ts`]: controller,
[`server/src/modules/${folder}/${folder}.service.ts`]: service,
[`server/src/modules/${folder}/${folder}.service.ts`]: serviceContent,
[`server/src/modules/${folder}/${folder}.module.ts`]: mod,
[`server/src/modules/${folder}/dto/create-${folder}.dto.ts`]: createDtoLines.join('\n') + '\n',
[`server/src/modules/${folder}/dto/update-${folder}.dto.ts`]: updateDtoLines.join('\n') + '\n',
@@ -621,7 +639,7 @@ function main() {
const args = process.argv.slice(2);
const apply = args.includes('--apply');
const dslArgIdx = args.indexOf('--dsl');
const dslPath = dslArgIdx >= 0 ? args[dslArgIdx + 1] : 'examples/TOiR.domain.dsl';
const dslPath = dslArgIdx >= 0 ? args[dslArgIdx + 1] : 'domain/TOiR.domain.dsl';
const absDsl = path.resolve(ROOT, dslPath);
const dslText = readFile(absDsl);

View File

@@ -1,160 +0,0 @@
# Post-Generation Validation
After generating the backend or fullstack application, run these checks to ensure the project will run without runtime errors.
---
# Validation Checklist
## 1. Environment file
- [ ] **`.env` exists** in the backend root (e.g. `server/.env`).
- [ ] **`.env.example` exists** with at least `DATABASE_URL` and a placeholder value.
- [ ] **`DATABASE_URL`** is present in `.env` (or documented in `.env.example` so the user can copy and set it).
**Failure symptom:** `Environment variable not found: DATABASE_URL` at startup.
---
## 2. 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`
---
## 3. 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 types at build/run.
---
## 4. Database migration
- [ ] **Migration workflow** is documented (e.g. in README or generation docs).
- [ ] Instruction to run **`npx prisma migrate dev`** (or `prisma migrate deploy` for production) after first generation or schema change.
- [ ] Generation pipeline (see `generation/backend-generation.md`) includes or documents the migration step.
**Failure symptom:** Tables do not exist; Prisma errors on first query.
---
## 5. REST route parameters
- [ ] For each entity, path parameters use the **correct primary key name** from the DSL.
- [ ] **Entity with PK `id` (uuid):** routes use **`/:id`** (e.g. `GET /equipment/:id`, `PATCH /equipment/:id`).
- [ ] **Entity with non-`id` primary key (e.g. `code`):** routes use **`/:code`** (or the actual PK attribute name), e.g. `GET /equipment-types/:code`, **not** `GET /equipment-types/:id`.
**Example:**
| Entity | Primary key | Correct path | Incorrect path |
| ------------- | ----------- | ---------------------- | -------------------- |
| Equipment | id | /equipment/:id | — |
| EquipmentType | code | /equipment-types/:code | /equipment-types/:id |
| RepairOrder | id | /repair-orders/:id | — |
**Failure symptom:** Controller expects `params.id` but route is defined with `:code`; or vice versa; 404 or wrong resource updated.
**Reference:** `backend/architecture.md` — API path rules for non-id primary keys.
---
## 6. DTO type mapping (serialization)
- [ ] **DSL `decimal`** → In DTO/API response, use **`string`** (or a type that serializes to string), not Prisma `Decimal`, to avoid JSON serialization issues.
- [ ] **DSL `date`** → In DTO/API response, use **`string`** (ISO 8601) or ensure DateTime is serialized to string, so React Admin and JSON consumers receive a string.
**Reference:** `backend/prisma-rules.md` — DTO type mapping table.
---
## 7. React Admin ID field in API responses
- [ ] **Every API response object** (list items and single-resource GET) contains a field named **`id`**.
- [ ] If the entity primary key is **not** named `id`, the response must **map** the primary key to `id`: e.g. `id: record.code` for EquipmentType, so the payload includes both `id` and `code` (or at least `id` with the PK value).
- [ ] The `id` field value must be the **primary key value** (string or uuid as appropriate).
**Failure symptom:** React Admin fails to identify records, breaks cache/references, or throws when expecting `record.id`.
**Reference:** `frontend/react-admin-rules.md` — React Admin ID Field Requirement.
---
## 8. Update payload sanitization (service layer)
- [ ] **Update endpoint must not pass `id` (or primary key) in Prisma `data`.** The service must sanitize the incoming DTO before calling `prisma.*.update({ where, data })`: remove `id`, remove the entity primary key field (e.g. `code`), and remove any readonly attributes. Only updatable fields should be passed as `data`.
- [ ] Generated update methods follow the pattern from **backend/service-rules.md** (e.g. `const { id, code, ...data } = dto` then pass `data` to Prisma).
**Failure symptom:** Prisma throws when `data` contains `id` or another field that is not on the model or not writable (e.g. entity with PK `code` receives body with `id` from React Admin).
**Reference:** `backend/service-rules.md`
---
## 9. Database runtime (docker-compose)
- [ ] **`docker-compose.yml` exists** at the project root (or documented location).
- [ ] It defines a **PostgreSQL** service with image (e.g. `postgres:16`), port `5432`, and credentials/DB name matching `DATABASE_URL` in `server/.env`.
- [ ] **Database container starts:** `docker compose up -d` runs without error and the container is reachable on the configured port.
**Failure symptom:** `PrismaClientInitializationError P1001: Can't reach database server at localhost:5432`.
**Reference:** `backend/database-runtime.md`
---
## 10. Migrations and seed
- [ ] **`npx prisma migrate dev`** runs successfully from `server/` when the database is up (schema is applied or created).
- [ ] **Seed script** exists at `server/prisma/seed.ts` (or equivalent) and creates minimal sample data (e.g. one EquipmentType, one Equipment, one RepairOrder).
- [ ] **`npx prisma db seed`** runs without error (package.json has `prisma.seed` configured and seed runner installed).
**Reference:** `backend/seed-rules.md`, `generation/runtime-bootstrap.md`
---
## 11. Health endpoint
- [ ] Backend exposes **GET /health** (or equivalent health route).
- [ ] **API responds to /health:** With backend running, `GET http://localhost:<port>/health` returns HTTP 200 and a body such as `{ "status": "ok" }`.
**Reference:** `backend/architecture.md` — Health Endpoint
---
# Summary Table
| Check | Required artifact / rule |
| ------------------- | ---------------------------------------------- |
| .env | File exists with DATABASE_URL |
| DATABASE_URL | Present in .env or .env.example |
| PrismaService | OnModuleInit + $connect(); no beforeExit |
| prisma generate | postinstall script or documented step |
| Migration | Documented step: prisma migrate dev |
| REST path params | Use entity PK name (:id or :code, etc.) |
| Decimal/Date in DTO | Map to string for serialization |
| API response `id` | Every record has `id`; if PK ≠ id, map PK → id |
| Update payload | Service strips `id`, PK, readonly from data before Prisma |
| docker-compose.yml | Exists at project root; PostgreSQL service |
| Database container | Starts with `docker compose up -d` |
| prisma migrate dev | Runs successfully from server/ |
| Seed script | Exists; prisma db seed runs |
| GET /health | Backend responds with 200 and status payload |
---
# Integration with generation pipeline
1. **Backend generation** (see `generation/backend-generation.md`) should produce artifacts that satisfy the above by default.
2. After generation, run this checklist manually or via a script that parses generated code and config.
3. If any check fails, the AI context or generator should be updated so that future runs pass.

View File

@@ -1,64 +0,0 @@
# Runtime Bootstrap
After project generation, the following commands must work in order so that the application runs without manual database provisioning or ad-hoc steps.
The generator must produce a **runnable development environment**: backend, frontend, and database must all be startable via a documented sequence.
---
# Bootstrap Sequence
## 1. Start the database
From the **project root**:
```bash
docker compose up -d
```
This starts the PostgreSQL container. The backend will connect to it using `DATABASE_URL` from `server/.env`.
---
## 2. 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` (e.g. `prisma generate`) if configured.
- `npx prisma generate` — ensures Prisma client is generated explicitly after install/schema changes.
- `npx prisma migrate dev` — creates/applies migrations and ensures the database schema exists.
- `npx prisma db seed` — populates minimal development data for immediate UI/API usage.
- `npm run start` — starts the NestJS server (default port e.g. 3000).
---
## 3. Frontend setup and start
In a separate terminal, from the **project root**:
```bash
cd client
npm install
npm run dev
```
- `npm run dev` — starts the Vite dev server (e.g. http://localhost:5173).
---
# Success Criteria
After running the above:
- Database container is running; Prisma can connect.
- Backend responds (e.g. `GET /health` returns `{ "status": "ok" }`).
- Frontend loads and can call the backend API.
The generator is responsible for producing all artifacts (docker-compose, schema, migrations, seed, env, health endpoint) so that this sequence succeeds without additional manual setup.

View File

@@ -1,78 +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 (e.g. by writing all config files and folder structure by hand). Using the CLI reduces errors and ensures compatibility with current tool versions.
---
# 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 (default for Nest CLI).
- **npm** must be the package manager (`--package-manager npm`).
- **Git** initialization must be skipped (`--skip-git`).
## After scaffolding — install required dependencies
Run from the `server` directory:
```bash
npm install @prisma/client
npm install prisma --save-dev
npm install @nestjs/config
```
---
# 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 (`--template react-ts`).
## 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
```
---
# Scaffolding Strategy
Generation pipeline order:
1. **Parse DSL** — Read domain, DTO, API, and UI DSL files.
2. **Run CLI scaffolding** — Create `server` with NestJS CLI and `client` with Vite CLI; install dependencies as above.
3. **Code generation** — Generate Prisma schema, NestJS modules/DTOs/PrismaService, and React Admin resources.
4. **Runtime infrastructure** — Generate `.env`, `.env.example`, package lifecycle scripts, and runtime config files.
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`.
Scaffolding (steps 12) must be done with the CLI; steps 38 are generated from the DSL and project docs.

View File

@@ -1,8 +0,0 @@
# Update Strategy
When DSL changes:
1. Regenerate prisma.schema
2. Run prisma migrate dev
3. Regenerate Nest modules
4. Regenerate React Admin resources