Skill v1.0.1
currentAutomated scan100/100+2 new
version: "1.0.1" name: add-entity description: Scaffold a new Spiderly entity end-to-end (entity class, Angular pages, routes, menu, migration)
Add Entity Workflow
Follow these steps in order. Do not skip ahead.
Step 1 — Gather Requirements
Ask the user:
- Entity name (PascalCase, singular — e.g.,
Product,BlogPost) - Properties — for each: name, C# type, required?, string max length, any special attributes
- Relationships — many-to-one (required/optional?), many-to-many, ordered one-to-many
- Base class —
BusinessObject<long>(CRUD, default) orReadonlyObject<long>(lookup table) - File uploads? — which properties, storage type (S3 public, Cloudinary, or default file manager)
- List page format — data table (default) or data view (card grid)?
Do NOT proceed until the user confirms the entity design.
Step 2 — Run the CLI scaffold
Note: This command prompts interactively for the entity name. Tell the user to run it themselves in a terminal, then continue with Step 3 once it completes.
spiderly add-new-entity
If the user chose data view format:
spiderly add-new-entity --data-view
This creates:
Backend/{App}.Business/Entities/{Entity}.cs(empty entity with[DoNotAuthorize])Frontend/src/app/pages/{kebab-name}/{kebab-name}-list.component.ts+.htmlFrontend/src/app/pages/{kebab-name}/{kebab-name}-details.component.ts+.html- Inserts routes into
Frontend/src/app/app.routes.ts - Inserts menu item into
Frontend/src/app/business/layout/layout.component.ts
Step 3 — Write the entity class
Use the entity-design skill to write the entity with correct attributes. Replace the CLI-generated empty entity.
Checklist:
- [ ]
[DisplayName]on the name/title property - [ ]
[Required]on mandatory fields - [ ]
[StringLength(max, MinimumLength = min)]on ALL strings (never omit — avoids NVARCHAR(MAX)) - [ ]
virtualon navigation properties - [ ]
List<T>with{ get; } = new()on collections - [ ]
[WithMany]on M2O child side,[CascadeDelete]or[SetNull]for delete behavior - [ ]
[UIOrderedOneToMany]on parent collection +OrderNumberon child (if ordered) - [ ]
[M2M]on junction entities with exactly 2[M2MWithMany]properties - [ ] File properties: a
StorageAttributesubclass ([DiskStorage]/[S3PublicStorage]/[S3PrivateStorage]/ custom) +[AcceptedFileTypes]+[MaxFileSize]+[StringLength] - [ ] Remove
[DoNotAuthorize]if the entity needs authorization
Also add the collection property to related parent entities (e.g., public virtual List<Product> Products { get; } = new(); on Category).
Step 4 — Build the backend
dotnet build
Run from the Backend/ directory. This triggers Spiderly source generators which produce:
- DTOs, services, controllers, validators, mappers, TypeScript classes
Fix any build errors before continuing.
Step 5 — Create and apply the migration
spiderly add-migration Add{EntityName}Tablespiderly update-database
Use PascalCase for migration names. If the migration looks wrong, spiderly remove-migration and fix the entity first.
Step 6 — Customize Angular components
List component ({kebab-name}-list.component.ts)
Update both the filter store (the create{EntityName}Filters function the scaffold declares above the component) and the cols array in ngOnInit() with actual entity columns. The store is the table's whole filter surface — a column without a matching store entry renders fine but cannot be filtered:
function createProductFilters(t: (key: string) => string) {return createFilterStore({name: textFilter({ label: t("Name") }),price: numberFilter({ label: t("Price") }),});}
this.cols = [{name: this.translocoService.translate("Name"),filterType: "text",field: "name",},{name: this.translocoService.translate("Price"),filterType: "numeric",field: "price",},{actions: [{ name: this.translocoService.translate("Details"), field: "Details" },{ name: this.translocoService.translate("Delete"), field: "Delete" },],},];
Store ids are backend property names (they go straight into the paginated request), so they normally repeat the column's field. Factories: textFilter, numberFilter (accepts options for a pick-list), booleanFilter, dateFilter — all imported from spiderly.
Translation keys
Add keys to Frontend/src/assets/i18n/en.json (and to any other language files your app uses):
{"{EntityName}": "...","{EntityName}List": "..."// property name keys as needed}
Menu icon (optional)
In layout.component.ts, change 'pi pi-fw pi-list' to an appropriate PrimeNG icon.
Step 7 — Build frontend
ng build
From Frontend/. Fix any build errors.
Step 8 — Add backend hooks (if needed)
If the entity requires custom business logic (validation, computed fields, side effects), override hooks in {Entity}Service (which extends {Entity}ServiceGenerated):
protected override async Task OnBeforeSave{Entity}AndReturnMainUIFormDTO({Entity}SaveBodyDTO saveBodyDTO) { }protected override async Task OnAfterSave{Entity}AndReturnMainUIFormDTO({Entity}SaveBodyDTO saveBodyDTO,{Entity}MainUIFormDTO mainUIFormDTO) { }
See the backend-hooks skill for the full hook reference.
Step 9 — Verify
- Start the app (F5 or
dotnet run) - Navigate to the new entity's list page
- Create a record, verify all fields save correctly
- Edit the record, verify update works
- Delete the record, verify cascade/set-null behavior
- Check file uploads if applicable