# 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 ```typescript @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.ts` - `equipment-type.controller.ts` - `repair-order.controller.ts` ## Service naming - File: `{entity-kebab}.service.ts` - Class: `EquipmentService`, `EquipmentTypeService`, `RepairOrderService` Examples: - `equipment.service.ts` - `equipment-type.service.ts` - `repair-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.ts` or use entity name for list/detail response types --- # Resource Naming Rules API resource paths are derived from the entity name: 1. **PascalCase → kebab-case:** Replace camelCase with lowercase hyphenated segments. 2. **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 `/equipment` for 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`) with `DATABASE_URL` so 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 dev` after schema generation. See **backend/runtime-rules.md** and **generation/backend-generation.md**.