218 lines
6.1 KiB
Markdown
218 lines
6.1 KiB
Markdown
# DSL Language Specification
|
||
|
||
This document describes the single DSL (Domain Specific Language) used to specify fullstack CRUD applications. The only required DSL input is `domain/*.dsl`.
|
||
|
||
`domain-summary.json` is a derived artifact generated from this DSL to stabilize LLM-first generation and feed the lightweight validation gate. It must never replace the DSL as the source of truth. The active prompt corpus that consumes this contract lives in `prompts/`.
|
||
|
||
---
|
||
|
||
# DSL Responsibility
|
||
|
||
The domain DSL defines only:
|
||
|
||
- domain model
|
||
- relations
|
||
- enums
|
||
|
||
The domain DSL is the single source of truth for:
|
||
|
||
- entities
|
||
- attributes
|
||
- primary keys
|
||
- foreign keys
|
||
- enums
|
||
|
||
The following layers are always derived from the domain DSL and must not be authored as standalone authoritative DSL inputs:
|
||
|
||
- DTO
|
||
- API
|
||
- UI
|
||
|
||
Optional extension mechanism:
|
||
|
||
```text
|
||
overrides/
|
||
api-overrides.dsl
|
||
ui-overrides.dsl
|
||
```
|
||
|
||
Override rules:
|
||
|
||
- Overrides are optional.
|
||
- The generator must work without them.
|
||
- Overrides may refine derived API or UI behavior, but they must not duplicate or redefine entities, attributes, primary keys, foreign keys, relations, or enums.
|
||
|
||
---
|
||
|
||
# DSL Grammar Concepts
|
||
|
||
## entity
|
||
|
||
An **entity** is a domain object that becomes a database table and a first-class resource in the backend and frontend.
|
||
|
||
```
|
||
entity Equipment {
|
||
attribute id { type uuid; key primary; }
|
||
attribute name { type string; is required; }
|
||
}
|
||
```
|
||
|
||
- **Domain:** Defines the canonical model; one entity = one Prisma model, one NestJS module, one React Admin resource.
|
||
- **Naming:** PascalCase (e.g. `Equipment`, `EquipmentType`, `RepairOrder`).
|
||
|
||
---
|
||
|
||
## attribute
|
||
|
||
An **attribute** is a field of an entity. It has a type and optional modifiers.
|
||
|
||
```
|
||
attribute name {
|
||
description "Наименование";
|
||
type string;
|
||
is required;
|
||
is unique;
|
||
}
|
||
```
|
||
|
||
**Modifiers:**
|
||
|
||
- `type` — required; one of: `string`, `uuid`, `integer`, `decimal`, `date`, `text`, or an enum name.
|
||
- `key primary` — this attribute is the primary key.
|
||
- `key foreign { relates Entity.field }` — foreign key to another entity's field.
|
||
- `is required` — non-nullable.
|
||
- `is unique` — unique constraint.
|
||
- `default Value` — default value (for enums or literals).
|
||
- `description "..."` — human-readable description.
|
||
|
||
---
|
||
|
||
## enum
|
||
|
||
An **enum** defines a fixed set of values. Used for attributes that can only take one of these values.
|
||
|
||
```
|
||
enum EquipmentStatus {
|
||
value Active { label "В эксплуатации"; }
|
||
value Repair { label "В ремонте"; }
|
||
}
|
||
```
|
||
|
||
- **value** — identifier used in data and code.
|
||
- **label** — optional display label for UI.
|
||
|
||
---
|
||
|
||
## primary key
|
||
|
||
Exactly one attribute per entity must be marked as primary key.
|
||
|
||
```
|
||
attribute id {
|
||
type uuid;
|
||
key primary;
|
||
}
|
||
```
|
||
|
||
Or for a natural key:
|
||
|
||
```
|
||
attribute code {
|
||
type string;
|
||
key primary;
|
||
is required;
|
||
is unique;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## foreign key
|
||
|
||
A **foreign key** links to another entity's primary key. The attribute type must match the referenced primary key type.
|
||
|
||
```
|
||
attribute equipmentTypeCode {
|
||
type string;
|
||
key foreign {
|
||
relates EquipmentType.code;
|
||
}
|
||
is required;
|
||
}
|
||
```
|
||
|
||
- `relates Entity.attribute` — references `Entity`'s `attribute` (must be primary key).
|
||
- FK type must equal referenced PK type (e.g. `string` → `EquipmentType.code`, `uuid` → `Equipment.id`).
|
||
|
||
---
|
||
|
||
## required
|
||
|
||
- **is required** — attribute is non-nullable in the domain model and drives requiredness in derived DTO/API/UI artifacts.
|
||
- Absence of `is required` means the attribute is optional (nullable).
|
||
|
||
---
|
||
|
||
## default
|
||
|
||
- **default Value** — applied when no value is provided (e.g. enum defaults like `default Active`).
|
||
- Value must exist in the enum when the attribute type is an enum.
|
||
|
||
---
|
||
|
||
# DSL → System Component Mapping
|
||
|
||
## DSL → Prisma
|
||
|
||
| DSL Concept | Prisma Result |
|
||
| ------------ | --------------------------- |
|
||
| entity | model |
|
||
| attribute | field |
|
||
| enum | enum |
|
||
| key primary | @id or @id @default(uuid()) |
|
||
| key foreign | relation + references |
|
||
| type string | String |
|
||
| type uuid | String @id @default(uuid()) |
|
||
| type integer | Int |
|
||
| type decimal | Decimal |
|
||
| type date | DateTime |
|
||
| type text | String |
|
||
|
||
---
|
||
|
||
## DSL → NestJS
|
||
|
||
| DSL Concept | NestJS Result |
|
||
| -------------- | ------------------------------------- |
|
||
| entity | One module (e.g. equipment.module.ts) |
|
||
| entity | Controller with CRUD endpoints |
|
||
| entity | Service with Prisma CRUD |
|
||
| entity + attribute metadata | create-{entity}.dto.ts |
|
||
| entity + attribute metadata | update-{entity}.dto.ts |
|
||
| entity + attribute metadata | Response DTO / API shape |
|
||
|
||
API paths are derived from entity name: PascalCase → kebab-case, pluralized (e.g. `Equipment` → `/equipment`, `RepairOrder` → `/repair-orders`).
|
||
|
||
---
|
||
|
||
## DSL → React Admin
|
||
|
||
| DSL Concept | React Admin Result |
|
||
| --------------------- | ----------------------------------- |
|
||
| entity | Resource (name = kebab-case plural) |
|
||
| attribute | Form field / column |
|
||
| type string | TextInput, TextField |
|
||
| type integer/decimal | NumberInput, NumberField |
|
||
| type date | DateInput, DateField |
|
||
| enum | SelectInput with choices |
|
||
| foreign key | ReferenceInput, ReferenceField |
|
||
|
||
---
|
||
|
||
# Derived Layer Mapping
|
||
|
||
- **Create DTO** — derived from domain attributes and must not include generated primary keys (for example no `id` for uuid PKs).
|
||
- **Update DTO** — derived from the same domain attributes with all fields optional for partial updates.
|
||
- **API response shape** — derived from domain attributes and must expose React Admin-compatible identifiers when needed.
|
||
- **UI field mapping** — derived from attribute types, descriptions, enums, and foreign keys without a separate UI DSL.
|