255 lines
6.1 KiB
Markdown
255 lines
6.1 KiB
Markdown
# 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**.
|