509 lines
9.2 KiB
Markdown
509 lines
9.2 KiB
Markdown
ROLE
|
|
|
|
You are a Staff-level Fullstack Platform Engineer.
|
|
|
|
Your task is to generate a fully runnable fullstack CRUD application from the DSL context of this repository.
|
|
|
|
Use context7.
|
|
|
|
Follow official best practices from:
|
|
|
|
NestJS documentation
|
|
|
|
Prisma documentation
|
|
|
|
React Admin documentation
|
|
|
|
Vite documentation
|
|
|
|
Keycloak documentation
|
|
|
|
Docker documentation
|
|
|
|
The generated application must run without manual fixes.
|
|
|
|
PROJECT CONTEXT
|
|
|
|
You must read the project documentation in the following strict order:
|
|
|
|
domain/dsl-spec.md
|
|
|
|
domain/*.dsl
|
|
|
|
If present, read optional overrides after the domain DSL:
|
|
|
|
overrides/api-overrides.dsl
|
|
overrides/ui-overrides.dsl
|
|
|
|
backend/architecture.md
|
|
|
|
backend/prisma-rules.md
|
|
|
|
backend/prisma-service.md
|
|
|
|
backend/service-rules.md
|
|
|
|
backend/runtime-rules.md
|
|
|
|
backend/database-runtime.md
|
|
|
|
backend/seed-rules.md
|
|
|
|
frontend/architecture.md
|
|
|
|
frontend/react-admin-rules.md
|
|
|
|
auth/keycloak-architecture.md
|
|
|
|
auth/frontend-auth-rules.md
|
|
|
|
auth/backend-auth-rules.md
|
|
|
|
auth/keycloak-realm-template-rules.md
|
|
|
|
generation/scaffolding-rules.md
|
|
|
|
generation/backend-generation.md
|
|
|
|
generation/frontend-generation.md
|
|
|
|
generation/runtime-bootstrap.md
|
|
|
|
generation/post-generation-validation.md
|
|
|
|
Do not ignore any rules defined in these documents.
|
|
|
|
INPUT CONTRACT
|
|
|
|
Required DSL input:
|
|
|
|
domain/*.dsl
|
|
|
|
Optional override inputs:
|
|
|
|
overrides/api-overrides.dsl
|
|
overrides/ui-overrides.dsl
|
|
|
|
Rules:
|
|
|
|
- Domain DSL is the single source of truth for entities, attributes, primary keys, foreign keys, and enums.
|
|
- DTO, API, and UI must be derived from the domain DSL.
|
|
- Optional overrides must not duplicate or redefine the domain model.
|
|
- Generation must work without override files.
|
|
- Ignore deprecated multi-DSL inputs if they are present in the repository; they are not authoritative generation inputs.
|
|
- Do not require standalone DTO, API, or UI DSL inputs.
|
|
|
|
GOAL
|
|
|
|
Generate a domain-DSL-driven fullstack CRUD system with default Keycloak authentication and authorization.
|
|
|
|
Repository-specific defaults and examples may use names such as `toir`, `toir-frontend`, `toir-backend`, `toir-realm.json`, and `*.greact.ru`, but the generator must parameterize realm name, client IDs, production URLs, and realm-artifact filename for other generated projects.
|
|
|
|
Stack:
|
|
|
|
Backend
|
|
|
|
Node.js
|
|
|
|
NestJS
|
|
|
|
Prisma ORM
|
|
|
|
PostgreSQL
|
|
|
|
jose
|
|
|
|
Frontend
|
|
|
|
React
|
|
|
|
Vite
|
|
|
|
React Admin
|
|
|
|
MUI
|
|
|
|
shadcn/ui
|
|
|
|
Keycloak JS
|
|
|
|
PROJECT STRUCTURE
|
|
|
|
Root
|
|
.gitignore
|
|
docker-compose.yml
|
|
root-level Keycloak realm import artifact (default example filename: `toir-realm.json`)
|
|
server/
|
|
client/
|
|
|
|
Backend
|
|
server/
|
|
src/
|
|
auth/
|
|
config/
|
|
modules/{entity}/
|
|
prisma/schema.prisma
|
|
prisma/seed.ts
|
|
.gitignore
|
|
.env
|
|
.env.example
|
|
|
|
Frontend
|
|
client/
|
|
.gitignore
|
|
src/
|
|
auth/
|
|
config/
|
|
resources/{entity}/
|
|
App.tsx
|
|
main.tsx
|
|
dataProvider.ts
|
|
.env.example
|
|
|
|
STEP 1 — Parse Domain DSL
|
|
|
|
Parse domain/*.dsl and extract:
|
|
|
|
Entities
|
|
Attributes
|
|
Primary keys
|
|
Foreign keys
|
|
Enums
|
|
|
|
If present, read optional override files only after the domain model has been parsed. Overrides may refine derived API or UI behavior but must never redefine entities, attributes, primary keys, foreign keys, or enums.
|
|
Do not consult any supplemental DTO/API/UI DSL source when deriving backend or frontend artifacts.
|
|
|
|
Respect the DSL specification.
|
|
|
|
STEP 2 — CLI scaffolding
|
|
|
|
Use official CLIs.
|
|
|
|
Backend
|
|
npx @nestjs/cli@10.3.2 new server --package-manager npm --skip-git
|
|
|
|
Frontend
|
|
npm create vite@5.2.0 client -- --template react-ts
|
|
|
|
STEP 3 — Install dependencies
|
|
|
|
Backend
|
|
|
|
@prisma/client
|
|
prisma
|
|
@nestjs/config
|
|
jose
|
|
|
|
Frontend
|
|
|
|
react-admin
|
|
ra-data-simple-rest
|
|
@mui/material
|
|
@emotion/react
|
|
@emotion/styled
|
|
keycloak-js
|
|
|
|
STEP 4 — Generate Prisma schema
|
|
|
|
From DSL domain generate:
|
|
|
|
models
|
|
|
|
enums
|
|
|
|
relations
|
|
|
|
primary keys
|
|
|
|
Type mapping
|
|
|
|
decimal → Decimal
|
|
date → DateTime
|
|
|
|
DTO mapping
|
|
|
|
decimal → string
|
|
date → ISO string
|
|
|
|
STEP 5 — Generate NestJS CRUD modules and derived DTOs
|
|
|
|
Per entity generate:
|
|
|
|
module
|
|
controller
|
|
service
|
|
dto
|
|
|
|
Controller routes
|
|
|
|
GET /resource
|
|
GET /resource/:pk
|
|
POST /resource
|
|
PATCH /resource/:pk
|
|
DELETE /resource/:pk
|
|
|
|
Path parameter must match the DSL primary key name.
|
|
|
|
Examples
|
|
|
|
/equipment/:id
|
|
/equipment-types/:code
|
|
/repair-orders/:id
|
|
|
|
STEP 6 — Generate backend auth infrastructure
|
|
|
|
Generate:
|
|
|
|
AuthModule
|
|
JWT guard
|
|
roles guard
|
|
@Public()
|
|
@Roles()
|
|
typed authenticated principal
|
|
typed env validation
|
|
|
|
Rules:
|
|
|
|
- `/health` must remain public
|
|
- CRUD routes must be protected by default
|
|
- RBAC source must be `realm_access.roles`
|
|
- JWT verification must use issuer + audience + JWKS
|
|
- JWKS resolution priority must be:
|
|
1. explicit `KEYCLOAK_JWKS_URL`
|
|
2. OIDC discovery
|
|
3. `${issuer}/protocol/openid-connect/certs`
|
|
- Do not use deprecated Keycloak-specific Node adapters
|
|
|
|
STEP 7 — Generate Service Layer
|
|
|
|
Service layer must follow backend/service-rules.md.
|
|
|
|
Important rule:
|
|
|
|
React Admin sends the id field in update payloads even when the primary key is not named id.
|
|
|
|
Therefore update payload must be sanitized before passing data to Prisma.
|
|
|
|
Services MUST NOT pass raw request DTO directly into Prisma.
|
|
|
|
Incorrect:
|
|
|
|
prisma.entity.update({
|
|
where,
|
|
data: dto
|
|
})
|
|
|
|
Correct pattern:
|
|
|
|
const { id, <primaryKey>, ...data } = dto
|
|
|
|
return prisma.entity.update({
|
|
where,
|
|
data
|
|
})
|
|
|
|
Example (PK = code)
|
|
|
|
const { id, code, ...data } = dto
|
|
|
|
return prisma.equipmentType.update({
|
|
where: { code },
|
|
data
|
|
})
|
|
|
|
Example (PK = id)
|
|
|
|
const { id: _pk, ...data } = dto
|
|
|
|
return prisma.entity.update({
|
|
where: { id },
|
|
data
|
|
})
|
|
|
|
Rules
|
|
|
|
Update payload passed to Prisma must not contain:
|
|
|
|
id
|
|
primary key attribute
|
|
readonly attributes
|
|
|
|
STEP 8 — Generate frontend auth integration
|
|
|
|
Generate:
|
|
|
|
client/src/config/env.ts
|
|
client/src/auth/keycloak.ts
|
|
client/src/auth/authProvider.ts
|
|
|
|
Rules:
|
|
|
|
- Keycloak login must be redirect-based only
|
|
- Use Authorization Code + PKCE (`S256`)
|
|
- Initialize Keycloak before rendering the SPA
|
|
- Attach `Authorization: Bearer <access_token>` through the shared request seam in `client/src/dataProvider.ts`
|
|
- `authProvider.getIdentity()` must derive identity from parsed token claims such as `sub`, `preferred_username`, `email`, and `name`
|
|
- 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
|
|
- `401` must force re-authentication
|
|
- `403` must surface access denied without forcing re-authentication
|
|
- Token refresh must be concurrency-safe
|
|
- Do not store tokens in `localStorage` or `sessionStorage`
|
|
- Frontend auth config must fail fast if required auth vars are missing
|
|
|
|
STEP 9 — Generate runtime infrastructure
|
|
|
|
Create:
|
|
|
|
server/.env
|
|
server/.env.example
|
|
client/.env.example
|
|
root/.gitignore
|
|
server/.gitignore
|
|
client/.gitignore
|
|
root-level Keycloak realm import artifact (default example filename: `toir-realm.json`)
|
|
|
|
Backend env examples must include:
|
|
|
|
PORT
|
|
DATABASE_URL
|
|
CORS_ALLOWED_ORIGINS
|
|
KEYCLOAK_ISSUER_URL
|
|
KEYCLOAK_AUDIENCE
|
|
KEYCLOAK_JWKS_URL (optional)
|
|
|
|
Frontend env examples must include:
|
|
|
|
VITE_API_URL
|
|
VITE_KEYCLOAK_URL
|
|
VITE_KEYCLOAK_REALM
|
|
VITE_KEYCLOAK_CLIENT_ID
|
|
|
|
Add to package.json:
|
|
|
|
postinstall: prisma generate
|
|
|
|
Generated `.gitignore` files must prevent local-only artifacts from entering git, including:
|
|
|
|
node_modules
|
|
dist
|
|
dist-ssr
|
|
coverage
|
|
*.tsbuildinfo
|
|
.env
|
|
.env.local
|
|
.env.*.local
|
|
|
|
STEP 10 — Database runtime
|
|
|
|
Generate root:
|
|
|
|
docker-compose.yml
|
|
|
|
PostgreSQL container
|
|
|
|
postgres:16
|
|
port 5432
|
|
|
|
STEP 11 — Generate seed
|
|
|
|
Create:
|
|
|
|
server/prisma/seed.ts
|
|
|
|
Seed minimal data for:
|
|
|
|
EquipmentType
|
|
Equipment
|
|
RepairOrder
|
|
|
|
Add to package.json:
|
|
|
|
prisma.seed
|
|
|
|
STEP 12 — Generate React Admin resources
|
|
|
|
Generate React Admin resources automatically from the domain DSL.
|
|
|
|
For each entity generate:
|
|
|
|
Field mapping
|
|
|
|
string → TextInput
|
|
number → NumberInput
|
|
date → DateInput
|
|
enum → SelectInput
|
|
FK → ReferenceInput
|
|
|
|
API responses MUST contain:
|
|
|
|
If PK ≠ id, map primary key to id.
|
|
|
|
If PK ≠ id, backend list/query logic must map React Admin `_sort=id` to the real primary key field before constructing ORM sorting.
|
|
|
|
Example
|
|
|
|
{
|
|
id: record.code,
|
|
code: record.code
|
|
}
|
|
|
|
STEP 13 — Validation
|
|
|
|
Verify:
|
|
|
|
docker-compose.yml exists
|
|
database container starts
|
|
prisma migrate dev works
|
|
prisma db seed works
|
|
API responds /health
|
|
React Admin receives id
|
|
update services sanitize payload before Prisma
|
|
frontend auth files exist
|
|
backend auth files exist
|
|
auth env examples exist
|
|
root/server/client .gitignore files exist
|
|
gitignore rules exclude local dependency, build, env, coverage, and tsbuildinfo artifacts
|
|
frontend auth code does not call `keycloak.loadUserProfile()`
|
|
frontend `getIdentity()` is token-claim based and does not rely on `/account`
|
|
public /health is preserved
|
|
unauthenticated protected route returns 401
|
|
insufficient role returns 403
|
|
natural-key entities map React Admin `_sort=id` to the real primary key field
|
|
generated realm import artifact is self-contained and guarantees `sub`, `aud`, and `realm_access.roles`
|
|
|
|
OUTPUT
|
|
|
|
Provide:
|
|
|
|
FULLSTACK GENERATION REPORT
|
|
|
|
Include:
|
|
|
|
1 Parsed DSL
|
|
2 Prisma models
|
|
3 Backend modules
|
|
4 API endpoints
|
|
5 React Admin resources
|
|
6 Authentication and authorization
|
|
7 Runtime configuration
|
|
8 Validation results
|
|
|
|
RUN INSTRUCTIONS
|
|
|
|
The generated application must run successfully with:
|
|
|
|
Import the generated root-level Keycloak realm artifact (for example `toir-realm.json`) into the external Keycloak server
|
|
|
|
docker compose up -d
|
|
|
|
cd server
|
|
npm install
|
|
npx prisma migrate dev
|
|
npm run start
|
|
|
|
cd client
|
|
npm install
|
|
npm run dev
|