6.1 KiB
Backend Architecture
Backend stack:
- Node.js
- TypeScript
- NestJS
- Prisma ORM
- PostgreSQL
The backend is generated from the DSL specification.
Each DSL entity becomes:
- Prisma model
- NestJS module
- CRUD controller
- Service
- DTO definitions
Project Structure
server/ package.json
prisma/ schema.prisma
src/ main.ts app.module.ts
modules/
{entity}/
{entity}.module.ts
{entity}.controller.ts
{entity}.service.ts
dto/
create-{entity}.dto.ts
update-{entity}.dto.ts
{entity}.response.dto.ts
Module Rules
Each entity generates exactly one NestJS module.
Example:
Entity: Equipment
Module:
modules/ equipment/ equipment.module.ts equipment.controller.ts equipment.service.ts
Controller Rules
Each entity controller must expose these endpoints:
- GET /{resource} — list
- GET /{resource}/:pk — get one
- POST /{resource} — create
- PATCH /{resource}/:pk — update
- DELETE /{resource}/:pk — delete
The path parameter :pk must use the primary key attribute name from the DSL, not always :id.
Path parameter by primary key
| Entity | Primary key (DSL) | Path parameter | Example routes |
|---|---|---|---|
| Equipment | id | :id | GET /equipment/:id, PATCH /equipment/:id |
| EquipmentType | code | :code | GET /equipment-types/:code, PATCH /equipment-types/:code |
| RepairOrder | id | :id | GET /repair-orders/:id, PATCH /repair-orders/:id |
Rule: Use the actual primary key name. For example, EquipmentType has PK code, so routes must be:
- GET /equipment-types/:code
- PATCH /equipment-types/:code
- DELETE /equipment-types/:code
Do not use /equipment-types/:id when the entity primary key is code.
Health Endpoint
Every generated backend must expose a health endpoint so that runtime and orchestration can verify the API is up.
- Path:
GET /health - Response: JSON with a status indicator (e.g.
{ "status": "ok" }).
Controller example
@Controller("health")
export class HealthController {
@Get()
getHealth() {
return { status: "ok" };
}
}
Register the health controller in the root app module (or a dedicated health module). No authentication required for this endpoint.
List Endpoint
List endpoint must support pagination and filters via query parameters.
Example:
GET /equipment?page=0&size=10
Response format must follow React Admin requirements:
{ "data": [], "total": number }
Service Layer
Services implement CRUD operations using Prisma.
Example:
findAll() findOne(id) create(data) update(id, data) remove(id)
DTO Rules
Create DTO:
- contains required fields
- does NOT contain generated primary keys
Update DTO:
- all fields optional
Response DTO:
- mirrors domain entity attributes
Naming Conventions
Entity naming
DSL entities use PascalCase. Generated backend artifacts use the same base name in lowercase for folders and file prefixes.
- Equipment → equipment module
- EquipmentType → equipment-type module (or equipment-type as path segment)
- RepairOrder → repair-order module
Module naming
One entity = one module folder. Folder name = entity name in kebab-case (lowercase, hyphen-separated).
- Equipment →
modules/equipment/ - EquipmentType →
modules/equipment-type/ - RepairOrder →
modules/repair-order/
Controller naming
- File:
{entity-kebab}.controller.ts - Class:
EquipmentController,EquipmentTypeController,RepairOrderController
Examples:
equipment.controller.tsequipment-type.controller.tsrepair-order.controller.ts
Service naming
- File:
{entity-kebab}.service.ts - Class:
EquipmentService,EquipmentTypeService,RepairOrderService
Examples:
equipment.service.tsequipment-type.service.tsrepair-order.service.ts
DTO naming
- Create:
create-{entity-kebab}.dto.ts(e.g.create-equipment.dto.ts,create-repair-order.dto.ts) - Update:
update-{entity-kebab}.dto.ts(e.g.update-equipment.dto.ts) - Response:
{entity-kebab}.response.dto.tsor use entity name for list/detail response types
Resource Naming Rules
API resource paths are derived from the entity name:
- PascalCase → kebab-case: Replace camelCase with lowercase hyphenated segments.
- Pluralize: Use plural form for the resource path (list endpoint represents a collection).
| Entity (DSL) | API path (resource) |
|---|---|
| Equipment | /equipment |
| EquipmentType | /equipment-types |
| RepairOrder | /repair-orders |
Rules:
- Equipment →
equipment(already singular-looking; path is still/equipmentfor consistency with REST resource naming). - EquipmentType →
equipment-types(camelCase "EquipmentType" → "equipment-type", then plural → "equipment-types"). - RepairOrder →
repair-orders("RepairOrder" → "repair-order" → "repair-orders").
Standard endpoints per resource:
- GET /{resource} — list
- GET /{resource}/:pk — get one (pk = primary key name, e.g. :id or :code)
- POST /{resource} — create
- PATCH /{resource}/:pk — update
- DELETE /{resource}/:pk — delete
See Controller Rules above for the rule that :pk must match the entity's primary key attribute name.
Environment and runtime
- Environment variables: Backend requires at least
DATABASE_URL. See backend/runtime-rules.md. - .env: Generated project must include a
.env(and.env.example) withDATABASE_URLso the app starts without runtime errors. - PrismaService: Must follow backend/prisma-service.md (OnModuleInit, $connect; no beforeExit).
- Prisma client: Add
"postinstall": "prisma generate"(or equivalent) to package.json so the client is generated after install. - Migrations: Document or run
npx prisma migrate devafter schema generation. See backend/runtime-rules.md and generation/backend-generation.md.