git init
This commit is contained in:
254
backend/architecture.md
Normal file
254
backend/architecture.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# 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**.
|
||||
Reference in New Issue
Block a user