Getting started
Your first project · Docs — DomainCraft
Build a small store with entities, relations, a permission matrix and auth, then generate the full backend.
This guide builds a small store — User, Product, Category — to show relations, features, permissions and seed data in one model.
Entities and fields
Each entity declares its fields. Field definitions are strings: a type, plus inline traits in square brackets:
entities:
User:
fields:
id: uuid [primary]
email: string [required, unique, email]
password: string [required, hidden, min:8]
Fields you never want exposed over the API (like password) use the hidden trait — the generator keeps them out of JSON responses.
Relations
A relation is written on the owning (child) side with relation(Target). The inverse collection on the parent is created automatically.
Category:
fields:
id: uuid [primary]
name: string [required, unique]
products: relation(Product) [many] # many-to-many, join table auto-created
Product:
fields:
id: uuid [primary]
title: string [required, min:3, max:200]
price: decimal [required, gte:0]
categoryId: relation(Category) [required] # many-to-one
relation(Category)onProduct.categoryIdcreates aProductslist onCategory.relation(Product) [many]creates an automatic many-to-many join table with composite keys.relation(Profile) [unique]on a child field makes the relation one-to-one.
Foreign-key behaviour (on_delete)
Control what happens when a referenced row is deleted:
| Value | Behaviour |
|---|---|
cascade |
Deletes dependent rows |
set_null |
Keeps the row, resets the FK to NULL |
restrict |
Blocks deleting the parent |
no_action |
Leaves it to the database |
set_null is only valid on optional relations.
Features
Entity features auto-inject standard fields and behaviour:
Product:
features: [audit, soft_delete]
...
auditaddscreatedAt/updatedAt, updated on save.audit_logaddscreatedBy/updatedBy(IDs of the current user).soft_deleteaddsdeletedAt; DELETE marks rows and GET filters them out.optimistic_lockaddsversionand returns409 Conflicton stale writes.
Permissions
Product:
permissions:
read: ["*"] # public endpoint
create: [Admin]
update: ["@Owner", Admin]
read: [*]— public, no auth required.- A role name (
Admin) — RBAC check on the role claim. @Owner— ABAC: only the user whose ID matches the row’s foreign key.
Roles referenced here must be declared under auth.roles.
Seed data
Seed rows are inserted on first run:
Role:
fields:
id: int [primary]
name: string [unique]
seed:
- { id: 1, name: "Admin" }
- { id: 2, name: "Customer" }
Generate
domaincraft generate --domain domain.yaml --bridge csharp-restful --admin
Passing --admin additionally scaffolds an admin panel. The generated project includes entity summaries under docs/Entities/ and a docs/ProjectSummary.md.