Add a new domain entity with full CRUD infrastructure to an existing project
Generate complete CRUD infrastructure for a new domain entity in your noop project. Creates types, database operations, HTTP handlers, migrations, and route registrations with organization-scoped security. Use when adding new entities like Products or Orders.
/plugin marketplace add HDeibler/noop/plugin install hdeibler-noop@HDeibler/noop<EntityName> [--fields=name:string,price:number]Generate complete CRUD infrastructure for a new domain entity in an existing noop-based project.
@docs/universal-framework/GENERATOR_INSTRUCTIONS.md
@docs/universal-framework/CONVENTIONS.md
@docs/universal-framework/ARCHITECTURE_SPEC.md
For a new entity (e.g., Product):
src/types/product.types.tssrc/db/pg/ProductOps.tssrc/handlers/productHandler.tssrc/routes.tssrc/db/pg/PgClientStore.tssrc/types/index.ts$ARGUMENTS format: <EntityName> [--fields=field1:type,field2:type]
Product, OrderItem)Examples:
/noop:entity-add Product
/noop:entity-add Product --fields=price:number,sku:string,inStock:boolean
/noop:entity-add OrderItem --fields=quantity:number,unitPrice:number,productId:string
| Input | Derived | Example |
|---|---|---|
| Entity name | PascalCase | Product |
| entityLower | camelCase | product |
| entityPlural | plural | products |
| tableName | snake_case plural | products |
| Type file | {entity}.types.ts | product.types.ts |
| Ops file | {Entity}Ops.ts | ProductOps.ts |
| Handler file | {entity}Handler.ts | productHandler.ts |
| Store property | camelCase plural | dbStore.products |
Verify this is a noop-based project by checking for:
src/db/pg/PgClientStore.tssrc/handlers/src/types/src/routes.tsIf missing, abort with: "This doesn't appear to be a noop project. Run /noop:make first."
From $ARGUMENTS, extract entity name and derive all naming variants.
Verify entity doesn't already exist. If exists, ask to overwrite.
Create src/types/{entity}.types.ts:
export interface {Entity}Info {
id: string
name: string
description?: string
// Custom fields from --fields
organizationId: string
createdAt: Date
updatedAt: Date
}
export type Create{Entity}Input = Omit<{Entity}Info, 'id' | 'organizationId' | 'createdAt' | 'updatedAt'>
export type Update{Entity}Input = Partial<Create{Entity}Input>
Create src/db/pg/{Entity}Ops.ts with:
create(data, organizationId) - MUST validate organizationIdgetById(id, organizationId) - MUST filter by organizationIdlist(organizationId, options) - MUST filter by organizationIdupdate(id, organizationId, data) - MUST filter by organizationIddelete(id, organizationId) - MUST filter by organizationIdmapRowTo{Entity}(row) methodCRITICAL: Every method MUST require and validate organizationId
Create src/handlers/{entity}Handler.ts with:
create - POST handlerget - GET /:id handlerlist - GET handler with paginationupdate - PUT /:id handlerremove - DELETE /:id handlerAll handlers MUST:
asyncHandler wrappercreateError factoriessendSuccess / sendPaginatedResponsegetDbStore()Find latest src/db/pg/migrations/sql/v*.sql and add:
CREATE TABLE {table_name} (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
description TEXT,
-- Custom fields
organization_id UUID NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_{table_name}_organization ON {table_name}(organization_id);
CREATE INDEX idx_{table_name}_created_at ON {table_name}(created_at DESC);
Update src/db/pg/PgClientStore.ts:
Update src/routes.ts:
Update src/types/index.ts:
npm run typecheck
npm run lint
Entity "{Entity}" created successfully!
Files created:
- src/types/{entity}.types.ts
- src/db/pg/{Entity}Ops.ts
- src/handlers/{entity}Handler.ts
Files updated:
- src/db/pg/PgClientStore.ts
- src/routes.ts
- src/types/index.ts
- src/db/pg/migrations/sql/v0.0.X.sql
New endpoints:
- GET /api/v1/{entities}
- POST /api/v1/{entities}
- GET /api/v1/{entities}/:id
- PUT /api/v1/{entities}/:id
- DELETE /api/v1/{entities}/:id