{"id":28390525,"url":"https://github.com/solid-nestjs/framework","last_synced_at":"2025-06-28T03:30:55.449Z","repository":{"id":295874661,"uuid":"991355119","full_name":"solid-nestjs/framework","owner":"solid-nestjs","description":"using solid principles in nodejs to craft powerful apps","archived":false,"fork":false,"pushed_at":"2025-06-17T22:59:49.000Z","size":1049,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-18T09:19:14.835Z","etag":null,"topics":["crud-generator","crud-gerenator","framework","graphql","graphql-api","nestjs","nestjs-backend","nestjs-boilerplate","nestjs-graphql","repository-pattern","rest-api","restful-api","typeorm"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solid-nestjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-27T13:54:59.000Z","updated_at":"2025-06-11T18:31:56.000Z","dependencies_parsed_at":"2025-06-01T06:00:33.229Z","dependency_job_id":null,"html_url":"https://github.com/solid-nestjs/framework","commit_stats":null,"previous_names":["solid-nestjs/framework"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/solid-nestjs/framework","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid-nestjs%2Fframework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid-nestjs%2Fframework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid-nestjs%2Fframework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid-nestjs%2Fframework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solid-nestjs","download_url":"https://codeload.github.com/solid-nestjs/framework/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid-nestjs%2Fframework/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260523890,"owners_count":23022025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crud-generator","crud-gerenator","framework","graphql","graphql-api","nestjs","nestjs-backend","nestjs-boilerplate","nestjs-graphql","repository-pattern","rest-api","restful-api","typeorm"],"created_at":"2025-05-31T05:12:37.678Z","updated_at":"2025-06-28T03:30:55.441Z","avatar_url":"https://github.com/solid-nestjs.png","language":"TypeScript","readme":"# SOLID NestJS Framework\n\nA powerful, modular, and type-safe framework for building scalable NestJS applications with automatic CRUD generation, advanced query capabilities, and extensible architecture.\n\n## 🚀 Overview\n\nThe SOLID NestJS Framework is a collection of utilities and mixins that accelerate the development of robust REST APIs with TypeORM. It follows SOLID principles and provides a clean, maintainable architecture for enterprise-grade applications.\n\n### Core Packages\n\n- **`@solid-nestjs/common`** - Common utilities, interfaces, and decorators\n- **`@solid-nestjs/typeorm`** - TypeORM service mixins for data access\n- **`@solid-nestjs/rest-api`** - REST API controller mixins with Swagger integration\n\n### 🌟 Key Features\n\n- **🔧 Auto-generated CRUD Operations** - Instantly create controllers and services with full CRUD functionality\n- **🔍 Advanced Query System** - Powerful filtering, pagination, sorting, and relation handling\n- **🔒 Transaction Support** - Built-in transaction management with isolation levels\n- **📝 Type Safety** - Full TypeScript support with comprehensive type definitions\n- **🎯 OpenAPI Integration** - Automatic Swagger documentation generation\n- **🔄 Flexible Relations** - Easy configuration of entity relationships and eager loading\n- **🛡️ Input Validation** - Integrated class-validator support\n- **📦 Modular Architecture** - Clean separation of concerns following SOLID principles\n- **🎨 Extensible Design** - Easy to extend and customize for specific needs\n- **🔄 Soft Delete Support** - Built-in soft delete functionality with recovery operations\n- **🔄 Bulk Operations** - Efficient bulk insert, update, delete, and remove operations\n- **♻️ Recovery Operations** - Restore soft-deleted entities with cascade support\n- **📊 Audit Trail** - Optional audit logging for data changes\n- **🚀 Future-Ready** - Designed for GraphQL and Prisma integration\n\n## 🗺️ What's Coming in v0.3.0\n\nWe're excited to share a preview of upcoming features in version 0.3.0:\n\n#### 🛠️ Enhanced CLI Tools\n\n- 🔲 **Framework CLI Generator** - Scaffold controllers, services, and modules with interactive prompts\n\n#### 🎨 Custom Decorators \u0026 Boilerplate Reduction\n\n- 🔲 **Composite Field Decorators** - Create unified decorators that combine common patterns like `@ApiProperty`, `@IsString`, `@IsNotEmpty`, etc.\n- 🔲 **Smart Type Inference Decorators** - Automatically generate validation and API documentation based on TypeScript types\n- 🔲 **Entity-to-DTO Code Generation** - Generate DTOs automatically from entity definitions with configurable validation rules\n- 🔲 **Hybrid API Decorators** - Single decorators that work for both REST (`@ApiProperty`) and GraphQL (`@Field`) simultaneously\n- 🔲 **Validation Preset Decorators** - Pre-configured decorator combinations for common patterns (email, UUID, positive numbers, etc.)\n\n#### 🔐 Advanced Authentication \u0026 Authorization\n\n- 🔲 **Role-Based Access Control (RBAC)** - Built-in decorators for fine-grained permissions\n- 🔲 **JWT Integration** - Seamless authentication middleware\n- 🔲 **Resource-Level Security** - Per-endpoint authorization with custom guards\n- 🔲 **Audit Trail Enhancement** - User tracking and action logging\n\n#### 📊 Performance \u0026 Monitoring\n\n- 🔲 **Caching Layer** - Redis integration for improved performance\n\n#### 🔄 Advanced Relations \u0026 Data Management\n\n- ✅ **Soft Deletion \u0026 Recovery Operations** - Built-in soft delete functionality with recovery operations\n- ✅ **Bulk Operations** - Efficient bulk insert, update, delete, and remove operations\n- 🔲 **Custom Operation Definitions** - Framework for defining custom business operations beyond CRUD\n\n#### 🎨 Enhanced GraphQL Features\n\n- 🔲 **Subscription Support** - Real-time data updates via GraphQL subscriptions\n- 🔲 **DataLoader Integration** - Optimized N+1 query resolution\n- 🔲 **Custom Scalar Types** - Extended type system for complex data types\n\n### 🧪 Experimental Features\n\n- 🔲 **Prisma Integration** - Alternative ORM support alongside TypeORM\n- 🔲 **Event Sourcing** - Built-in event-driven architecture patterns\n- 🔲 **Microservices Support** - Framework for distributed system development\n- 🔲 **MCP Support** - Model Context Protocol integration for AI applications\n\n_Want to influence the roadmap? Check out our [full roadmap](ROADMAP.md) and join the discussion!_\n\n## 🚀 Try It Now\n\nGet started immediately with our working examples:\n\n### 🎯 REST API Example\n\n```bash\n# Clone and run the REST API example\ngit clone https://github.com/solid-nestjs/framework.git\ncd framework/apps-examples/simple-crud-app\nnpm install \u0026\u0026 npm run start:dev\n# Visit http://localhost:3000/api for Swagger docs\n```\n\n### 🎮 GraphQL Example\n\n```bash\n# Run the GraphQL example\ncd framework/apps-examples/simple-graphql-crud-app\nnpm install \u0026\u0026 npm run start:dev\n# Visit http://localhost:3000/graphql for GraphQL Playground\n```\n\n### 🔄 Advanced Example with Soft Deletion \u0026 Bulk Operations\n\n```bash\n# Run the advanced example with soft deletion and bulk operations\ncd framework/apps-examples/advanced-crud-app\nnpm install \u0026\u0026 npm run start:dev\n# Visit http://localhost:3000/api for comprehensive Swagger docs\n```\n\n### 🔄 Hybrid Example with GraphQL Soft Deletion\n\n```bash\n# Run the hybrid example with GraphQL soft deletion support\ncd framework/apps-examples/advanced-hybrid-crud-app\nnpm install \u0026\u0026 npm run start:dev\n# Visit http://localhost:3000/api (REST) or http://localhost:3000/graphql\n```\n\n## 📦 Installation\n\n```bash\n# Install all packages\nnpm install @solid-nestjs/common @solid-nestjs/typeorm @solid-nestjs/rest-api\n\n# Or install individually\nnpm install @solid-nestjs/typeorm-crud\n```\n\n## 🏗️ Quick Start\n\n### 1. Define Your Entity\n\n```typescript\nimport { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';\nimport { ApiProperty } from '@nestjs/swagger';\n\n@Entity()\nexport class Product {\n  @ApiProperty({ description: 'The unique identifier of the product' })\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @ApiProperty({ description: 'The name of the product' })\n  @Column()\n  name: string;\n\n  @ApiProperty({ description: 'The description of the product' })\n  @Column()\n  description: string;\n\n  @ApiProperty({ description: 'The price of the product' })\n  @Column('decimal', { precision: 10, scale: 2 })\n  price: number;\n\n  @ApiProperty({ description: 'The stock quantity of the product' })\n  @Column()\n  stock: number;\n\n  @ApiProperty({ description: 'Product Supplier', type: () =\u003e Supplier })\n  @ManyToOne(() =\u003e Supplier, supplier =\u003e supplier.products)\n  supplier: Supplier;\n}\n```\n\n### 2. Create DTOs\n\n```typescript\n// create-product.dto.ts\nimport { IsString, IsNumber, IsUUID, IsOptional } from 'class-validator';\nimport { ApiProperty } from '@nestjs/swagger';\n\nexport class CreateProductDto {\n  @ApiProperty()\n  @IsString()\n  name: string;\n\n  @ApiProperty()\n  @IsString()\n  description: string;\n\n  @ApiProperty()\n  @IsNumber()\n  price: number;\n\n  @ApiProperty()\n  @IsNumber()\n  stock: number;\n\n  @ApiProperty({ required: false })\n  @IsOptional()\n  @IsUUID()\n  supplierId?: string;\n}\n\n// update-product.dto.ts\nimport { PartialType } from '@nestjs/swagger';\nimport { CreateProductDto } from './create-product.dto';\n\nexport class UpdateProductDto extends PartialType(CreateProductDto) {}\n\n// find-product-args.ts\nimport { FindArgsMixin } from '@solid-nestjs/rest-api';\nimport { Product } from '../entities/product.entity';\n\nexport class FindProductArgs extends FindArgsMixin(Product) {}\n```\n\n### 3. Create Service with CRUD Operations\n\n```typescript\nimport { CrudServiceFrom, CrudServiceStructure } from '@solid-nestjs/typeorm';\nimport { Product } from './entities/product.entity';\nimport { CreateProductDto, FindProductArgs, UpdateProductDto } from './dto';\n\n// Define service structure\nexport const serviceStructure = CrudServiceStructure({\n  entityType: Product,\n  createInputType: CreateProductDto,\n  updateInputType: UpdateProductDto,\n  findArgsType: FindProductArgs,\n  relationsConfig: {\n    relations: {\n      supplier: true,\n    },\n  },\n});\n\n// Create service extending CRUD functionality\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  // Add custom methods here if needed\n}\n```\n\n### 4. Create Controller with REST Endpoints\n\n```typescript\nimport {\n  CrudControllerFrom,\n  CrudControllerStructure,\n} from '@solid-nestjs/rest-api';\nimport { ProductsService, serviceStructure } from './products.service';\n\n// Define controller structure\nconst controllerStructure = CrudControllerStructure({\n  ...serviceStructure,\n  serviceType: ProductsService,\n});\n\nexport class ProductsController extends CrudControllerFrom(\n  controllerStructure,\n) {\n  // Add custom endpoints here if needed\n}\n```\n\n### 5. Register in Module\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { ProductsController } from './products.controller';\nimport { ProductsService } from './products.service';\nimport { Product } from './entities/product.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Product])],\n  controllers: [ProductsController],\n  providers: [ProductsService],\n  exports: [ProductsService],\n})\nexport class ProductsModule {}\n```\n\n## 🎯 Generated API Endpoints\n\nThe framework automatically generates the following REST endpoints:\n\n- `GET /products` - List all products with filtering, pagination, and sorting\n- `GET /products/:id` - Get a specific product by ID\n- `POST /products` - Create a new product\n- `PUT /products/:id` - Update an existing product\n- `DELETE /products/:id` - Soft delete a product\n- `DELETE /products/soft/:id` - Explicit soft delete a product\n- `DELETE /products/hard/:id` - Hard delete a product (if enabled)\n- `PATCH /products/recover/:id` - Recover a soft-deleted product\n\n### 🔄 Soft Deletion \u0026 Recovery Operations\n\nThe framework provides comprehensive soft deletion capabilities that allow you to mark entities as deleted without permanently removing them from the database. Soft-deleted entities can be recovered later, making this feature ideal for data protection and audit requirements.\n\n#### Key Features\n\n- **Automatic Soft Delete** - Default `DELETE` operations perform soft deletion when entity has `@DeleteDateColumn()`\n- **Explicit Operations** - Separate endpoints for soft delete (`/soft/:id`) and hard delete (`/hard/:id`)\n- **Recovery Support** - Restore soft-deleted entities with `PATCH /recover/:id`\n- **Cascade Behavior** - Soft deletion and recovery cascade to related entities\n- **Query Filtering** - Soft-deleted entities are automatically excluded from queries\n- **GraphQL Support** - Full soft deletion support in GraphQL mutations\n\n#### Configuration\n\nEnable soft deletion by adding a `@DeleteDateColumn()` to your entity:\n\n```typescript\n@Entity()\nexport class Product {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  name: string;\n\n  // Enable soft deletion\n  @DeleteDateColumn()\n  deletedAt?: Date;\n\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n}\n```\n\nConfigure soft deletion operations in your controller structure:\n\n```typescript\nconst controllerStructure = CrudControllerStructure({\n  entityType: Product,\n  serviceType: ProductsService,\n  operations: {\n    // Standard CRUD operations\n    findAll: true,\n    findOne: true,\n    create: true,\n    update: true,\n    remove: true, // Default soft delete\n\n    // Explicit soft deletion operations\n    softRemove: true, // DELETE /products/soft/:id\n    recover: true, // PATCH /products/recover/:id\n    hardRemove: true, // DELETE /products/hard/:id (permanent)\n  },\n});\n```\n\n#### REST API Examples\n\n```bash\n# Soft delete a product (default behavior)\nDELETE http://localhost:3000/products/123\n\n# Explicit soft delete\nDELETE http://localhost:3000/products/soft/123\n\n# Recover a soft-deleted product\nPATCH http://localhost:3000/products/recover/123\n\n# Permanently delete a product\nDELETE http://localhost:3000/products/hard/123\n\n# List products (excludes soft-deleted)\nGET http://localhost:3000/products\n\n# Get a specific product (returns 404 if soft-deleted)\nGET http://localhost:3000/products/123\n```\n\n#### GraphQL Examples\n\n```graphql\n# Soft delete a product\nmutation {\n  softRemoveProduct(id: \"123\") {\n    id\n    name\n    deletedAt\n  }\n}\n\n# Recover a soft-deleted product\nmutation {\n  recoverProduct(id: \"123\") {\n    id\n    name\n    deletedAt # Will be null after recovery\n  }\n}\n\n# Hard delete a product (permanent)\nmutation {\n  hardRemoveProduct(id: \"123\") {\n    id\n    name\n  }\n}\n\n# Query products (automatically excludes soft-deleted)\nquery {\n  products {\n    id\n    name\n    deletedAt\n  }\n}\n```\n\n### 📦 Bulk Operations\n\nThe framework provides efficient bulk operations for handling multiple entities in a single database transaction, significantly improving performance for batch operations.\n\n#### Available Bulk Operations\n\n- **`bulkInsert`** - Create multiple entities in one operation\n- **`bulkUpdate`** - Update multiple entities matching criteria\n- **`bulkDelete`** - Permanently delete multiple entities\n- **`bulkRemove`** - Soft delete multiple entities (when soft deletion is enabled)\n- **`bulkRecover`** - Recover multiple soft-deleted entities\n\n#### Service-Level Bulk Operations\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  // Bulk insert multiple products\n  async createBulkProducts(\n    context: Context,\n    products: CreateProductDto[],\n  ): Promise\u003cstring[]\u003e {\n    const result = await this.bulkInsert(context, products);\n    return result.ids;\n  }\n\n  // Bulk update products by criteria\n  async updatePricesBySupplier(\n    context: Context,\n    supplierId: string,\n    priceMultiplier: number,\n  ): Promise\u003cnumber\u003e {\n    const result = await this.bulkUpdate(\n      context,\n      { price: () =\u003e `price * ${priceMultiplier}` },\n      { supplier: { id: supplierId } },\n    );\n    return result.affected || 0;\n  }\n\n  // Bulk soft delete products\n  async removeProductsByCategory(\n    context: Context,\n    categoryId: string,\n  ): Promise\u003cnumber\u003e {\n    const result = await this.bulkRemove(context, {\n      category: { id: categoryId },\n    });\n    return result.affected || 0;\n  }\n\n  // Bulk recover products\n  async recoverProductsBySupplier(\n    context: Context,\n    supplierId: string,\n  ): Promise\u003cnumber\u003e {\n    const result = await this.bulkRecover(context, {\n      supplier: { id: supplierId },\n    });\n    return result.affected || 0;\n  }\n}\n```\n\n#### Controller-Level Bulk Endpoints\n\nAdd custom bulk endpoints to your controllers:\n\n```typescript\nexport class ProductsController extends CrudControllerFrom(\n  controllerStructure,\n) {\n  @Post('bulk')\n  @ApiOperation({ summary: 'Bulk create products' })\n  async bulkCreate(\n    @CurrentContext() context: Context,\n    @Body() products: CreateProductDto[],\n  ): Promise\u003c{ ids: string[] }\u003e {\n    const result = await this.service.bulkInsert(context, products);\n    return { ids: result.ids };\n  }\n\n  @Put('bulk/update-by-supplier')\n  @ApiOperation({ summary: 'Bulk update products by supplier' })\n  async bulkUpdateBySupplier(\n    @CurrentContext() context: Context,\n    @Body() updateDto: { supplierId: string; updates: Partial\u003cProduct\u003e },\n  ): Promise\u003c{ affected: number }\u003e {\n    const result = await this.service.bulkUpdate(context, updateDto.updates, {\n      supplier: { id: updateDto.supplierId },\n    });\n    return { affected: result.affected || 0 };\n  }\n\n  @Delete('bulk/remove-by-category')\n  @ApiOperation({ summary: 'Bulk soft delete products by category' })\n  async bulkRemoveByCategory(\n    @CurrentContext() context: Context,\n    @Body() removeDto: { categoryId: string },\n  ): Promise\u003c{ affected: number }\u003e {\n    const result = await this.service.bulkRemove(context, {\n      category: { id: removeDto.categoryId },\n    });\n    return { affected: result.affected || 0 };\n  }\n\n  @Patch('bulk/recover-by-supplier')\n  @ApiOperation({ summary: 'Bulk recover products by supplier' })\n  async bulkRecoverBySupplier(\n    @CurrentContext() context: Context,\n    @Body() recoverDto: { supplierId: string },\n  ): Promise\u003c{ affected: number }\u003e {\n    const result = await this.service.bulkRecover(context, {\n      supplier: { id: recoverDto.supplierId },\n    });\n    return { affected: result.affected || 0 };\n  }\n}\n```\n\n#### Bulk Operations Examples\n\n```bash\n# Bulk create products\nPOST http://localhost:3000/products/bulk\nContent-Type: application/json\n\n[\n  { \"name\": \"Product 1\", \"price\": 99.99, \"supplierId\": \"supplier-1\" },\n  { \"name\": \"Product 2\", \"price\": 149.99, \"supplierId\": \"supplier-1\" },\n  { \"name\": \"Product 3\", \"price\": 199.99, \"supplierId\": \"supplier-2\" }\n]\n\n# Bulk update products by supplier\nPUT http://localhost:3000/products/bulk/update-by-supplier\nContent-Type: application/json\n\n{\n  \"supplierId\": \"supplier-1\",\n  \"updates\": {\n    \"price\": 89.99,\n    \"status\": \"discounted\"\n  }\n}\n\n# Bulk soft delete products by category\nDELETE http://localhost:3000/products/bulk/remove-by-category\nContent-Type: application/json\n\n{\n  \"categoryId\": \"category-1\"\n}\n\n# Bulk recover products by supplier\nPATCH http://localhost:3000/products/bulk/recover-by-supplier\nContent-Type: application/json\n\n{\n  \"supplierId\": \"supplier-1\"\n}\n```\n\n#### Event Hooks for Bulk Operations\n\nThe framework provides event hooks for bulk operations:\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  // Before bulk update hook\n  async beforeBulkUpdate(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    updateInput: Partial\u003cProduct\u003e,\n    where: Where\u003cProduct\u003e,\n  ): Promise\u003cvoid\u003e {\n    // Custom validation before bulk update\n    if (updateInput.price \u0026\u0026 updateInput.price \u003c 0) {\n      throw new BadRequestException('Price cannot be negative');\n    }\n  }\n\n  // After bulk remove hook\n  async afterBulkRemove(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    affectedCount: number,\n    where: Where\u003cProduct\u003e,\n  ): Promise\u003cvoid\u003e {\n    // Log bulk operation\n    console.log(`Soft deleted ${affectedCount} products`);\n\n    // Notify external systems\n    await this.notifyInventorySystem(where, 'bulk_removed');\n  }\n\n  // After bulk recover hook\n  async afterBulkRecover(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    affectedCount: number,\n    where: Where\u003cProduct\u003e,\n  ): Promise\u003cvoid\u003e {\n    console.log(`Recovered ${affectedCount} products`);\n    await this.notifyInventorySystem(where, 'bulk_recovered');\n  }\n}\n```\n\n## 🔧 Advanced Configuration\n\n### Service Structure Options\n\n```typescript\nexport const serviceStructure = CrudServiceStructure({\n  entityType: Product,\n  createInputType: CreateProductDto,\n  updateInputType: UpdateProductDto,\n  findArgsType: FindProductArgs,\n\n  // Relations configuration\n  relationsConfig: {\n    mainAlias: 'product',\n    relations: {\n      supplier: true,\n      category: {\n        relations: {\n          parentCategory: true,\n        },\n      },\n    },\n  },\n\n  // Lock mode for database operations\n  lockMode: 'pessimistic_read',\n\n  // Function-specific configurations\n  functions: {\n    findAll: {\n      relationsConfig: {\n        relations: { supplier: true },\n      },\n      decorators: [() =\u003e CacheInterceptor()],\n    },\n    findOne: {\n      lockMode: 'optimistic',\n      relationsConfig: {\n        relations: { supplier: true, category: true },\n      },\n    },\n    create: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n      decorators: [() =\u003e UseGuards(AdminGuard)],\n    },\n    update: {\n      transactional: true,\n      isolationLevel: 'REPEATABLE_READ',\n    },\n    remove: {\n      transactional: true,\n    },\n    // Soft deletion operations\n    softRemove: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n    recover: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n    hardRemove: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n      decorators: [() =\u003e UseGuards(AdminGuard)], // Restrict hard delete\n    },\n    // Bulk operations\n    bulkInsert: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n    bulkUpdate: {\n      transactional: true,\n      isolationLevel: 'REPEATABLE_READ',\n    },\n    bulkDelete: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n      decorators: [() =\u003e UseGuards(AdminGuard)],\n    },\n    bulkRemove: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n    bulkRecover: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n  },\n});\n```\n\n### Controller Structure Options\n\n```typescript\nconst controllerStructure = CrudControllerStructure({\n  ...serviceStructure,\n  serviceType: ProductsService,\n\n  // Custom route configuration\n  route: 'products',\n\n  // API documentation\n  apiTags: ['Products'],\n\n  // Operation configurations\n  operations: {\n    findAll: {\n      summary: 'Get all products',\n      description:\n        'Retrieve a list of all products with filtering and pagination',\n      decorators: [() =\u003e UseGuards(JwtAuthGuard)],\n    },\n    findOne: {\n      summary: 'Get product by ID',\n      description: 'Retrieve a specific product by its ID',\n    },\n    create: {\n      summary: 'Create new product',\n      description: 'Create a new product in the system',\n      decorators: [() =\u003e UseGuards(AdminGuard)],\n    },\n    update: {\n      summary: 'Update product',\n      description: 'Update an existing product',\n    },\n    remove: {\n      summary: 'Delete product',\n      description: 'Soft delete a product (default behavior)',\n    },\n    // Soft deletion operations\n    softRemove: {\n      summary: 'Soft delete product',\n      description: 'Mark a product as deleted without removing from database',\n    },\n    recover: {\n      summary: 'Recover product',\n      description: 'Restore a soft-deleted product',\n    },\n    hardRemove: {\n      summary: 'Hard delete product',\n      description: 'Permanently remove a product from the database',\n      decorators: [() =\u003e UseGuards(AdminGuard)], // Restrict access\n    },\n    pagination: true, // Enable pagination endpoint\n  },\n\n  // Custom decorators\n  classDecorators: [() =\u003e UseGuards(JwtAuthGuard)],\n\n  // Parameter decorators\n  parameterDecorators: {\n    context: CurrentUser,\n  },\n});\n```\n\n## 🔍 Query Features\n\n### Filtering\n\n```typescript\n// GET /products?filter={\"name\": {\"_contains\": \"laptop\"}, \"price\": {\"_gte\": 500}}\n// GET /products?filter={\"supplier\":{\"name\": \"TechCorp\"}}\n```\n\n### Pagination\n\n```typescript\n// GET /products?pagination={\"take\": 10, \"skip\": 20}\n// GET /products?pagination={\"page\": 3, \"limit\": 10}\n```\n\n### Sorting\n\n```typescript\n// GET /products?orderBy={\"name\": \"ASC\", \"price\": \"DESC\"}\n// GET /products?orderBy={\"supplier\":{\"name\": \"ASC\"}}\n```\n\n### Relations\n\n```typescript\n// GET /products?relations=[\"supplier\", \"category\"]\n// Automatic relation loading based on configuration\n```\n\n## 🛠️ Customization\n\n### Custom Service Methods\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  async findBySupplier(\n    context: Context,\n    supplierId: string,\n  ): Promise\u003cProduct[]\u003e {\n    return this.findAll(context, {\n      where: { supplier: { id: supplierId } },\n    });\n  }\n\n  async updateStock(\n    context: Context,\n    id: string,\n    quantity: number,\n  ): Promise\u003cProduct\u003e {\n    return this.runInTransaction(context, async transactionContext =\u003e {\n      const product = await this.findOne(transactionContext, id, true);\n      product.stock += quantity;\n      return this.getRepository(transactionContext).save(product);\n    });\n  }\n\n  // Bulk operations examples\n  async bulkUpdatePrices(\n    context: Context,\n    categoryId: string,\n    priceIncrease: number,\n  ): Promise\u003cnumber\u003e {\n    const result = await this.bulkUpdate(\n      context,\n      { price: () =\u003e `price + ${priceIncrease}` },\n      { category: { id: categoryId } },\n    );\n    return result.affected || 0;\n  }\n\n  async softDeleteExpiredProducts(\n    context: Context,\n    expirationDate: Date,\n  ): Promise\u003cnumber\u003e {\n    const result = await this.bulkRemove(context, {\n      expiresAt: { _lt: expirationDate },\n    });\n    return result.affected || 0;\n  }\n\n  async recoverRecentlyDeleted(\n    context: Context,\n    days: number = 7,\n  ): Promise\u003cnumber\u003e {\n    const cutoffDate = new Date();\n    cutoffDate.setDate(cutoffDate.getDate() - days);\n\n    const result = await this.bulkRecover(context, {\n      deletedAt: { _gte: cutoffDate },\n    });\n    return result.affected || 0;\n  }\n\n  // Override lifecycle hooks\n  async beforeCreate(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    entity: Product,\n    createInput: CreateProductDto,\n  ): Promise\u003cvoid\u003e {\n    // Custom logic before creating\n    entity.slug = this.generateSlug(entity.name);\n  }\n\n  async afterUpdate(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    entity: Product,\n    updateInput: UpdateProductDto,\n  ): Promise\u003cvoid\u003e {\n    // Custom logic after updating\n    await this.notifyStockChange(entity);\n  }\n\n  // Soft deletion hooks\n  async beforeSoftRemove(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    entity: Product,\n  ): Promise\u003cvoid\u003e {\n    // Custom logic before soft deletion\n    await this.notifySupplierOfDeletion(entity.supplier.id, entity.id);\n  }\n\n  async afterRecover(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    entity: Product,\n  ): Promise\u003cvoid\u003e {\n    // Custom logic after recovery\n    await this.notifySupplierOfRecovery(entity.supplier.id, entity.id);\n  }\n\n  // Bulk operation hooks\n  async beforeBulkRemove(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    where: Where\u003cProduct\u003e,\n  ): Promise\u003cvoid\u003e {\n    // Log bulk soft deletion\n    console.log(`About to soft delete products matching:`, where);\n  }\n\n  async afterBulkRecover(\n    context: Context,\n    repository: Repository\u003cProduct\u003e,\n    affectedCount: number,\n    where: Where\u003cProduct\u003e,\n  ): Promise\u003cvoid\u003e {\n    // Notify about bulk recovery\n    console.log(`Recovered ${affectedCount} products`);\n    await this.notifyInventorySystem('bulk_recovery', affectedCount);\n  }\n}\n```\n\n### Custom Controller Endpoints\n\n```typescript\nexport class ProductsController extends CrudControllerFrom(\n  controllerStructure,\n) {\n  @Get('by-supplier/:supplierId')\n  @ApiOperation({ summary: 'Get products by supplier' })\n  async findBySupplier(\n    @CurrentContext() context: Context,\n    @Param('supplierId') supplierId: string,\n  ): Promise\u003cProduct[]\u003e {\n    return this.service.findBySupplier(context, supplierId);\n  }\n\n  @Patch(':id/stock')\n  @ApiOperation({ summary: 'Update product stock' })\n  async updateStock(\n    @CurrentContext() context: Context,\n    @Param('id') id: string,\n    @Body() stockUpdate: { quantity: number },\n  ): Promise\u003cProduct\u003e {\n    return this.service.updateStock(context, id, stockUpdate.quantity);\n  }\n\n  // Bulk operations endpoints\n  @Post('bulk')\n  @ApiOperation({ summary: 'Bulk create products' })\n  async bulkCreate(\n    @CurrentContext() context: Context,\n    @Body() products: CreateProductDto[],\n  ): Promise\u003c{ ids: string[] }\u003e {\n    const result = await this.service.bulkInsert(context, products);\n    return { ids: result.ids };\n  }\n\n  @Put('bulk/update-prices/:categoryId')\n  @ApiOperation({ summary: 'Bulk update prices by category' })\n  async bulkUpdatePrices(\n    @CurrentContext() context: Context,\n    @Param('categoryId') categoryId: string,\n    @Body() priceUpdate: { increase: number },\n  ): Promise\u003c{ affected: number }\u003e {\n    const affected = await this.service.bulkUpdatePrices(\n      context,\n      categoryId,\n      priceUpdate.increase,\n    );\n    return { affected };\n  }\n\n  @Delete('bulk/expired')\n  @ApiOperation({ summary: 'Soft delete expired products' })\n  async bulkRemoveExpired(\n    @CurrentContext() context: Context,\n    @Body() expirationFilter: { expirationDate: string },\n  ): Promise\u003c{ affected: number }\u003e {\n    const affected = await this.service.softDeleteExpiredProducts(\n      context,\n      new Date(expirationFilter.expirationDate),\n    );\n    return { affected };\n  }\n\n  @Patch('bulk/recover-recent')\n  @ApiOperation({ summary: 'Recover recently deleted products' })\n  async bulkRecoverRecent(\n    @CurrentContext() context: Context,\n    @Body() recoveryFilter: { days?: number },\n  ): Promise\u003c{ affected: number }\u003e {\n    const affected = await this.service.recoverRecentlyDeleted(\n      context,\n      recoveryFilter.days,\n    );\n    return { affected };\n  }\n}\n```\n\n## 🔐 Security \u0026 Validation\n\n### Input Validation\n\n```typescript\nimport {\n  IsString,\n  IsNumber,\n  IsOptional,\n  Min,\n  Max,\n  Length,\n} from 'class-validator';\nimport { Transform } from 'class-transformer';\n\nexport class CreateProductDto {\n  @ApiProperty({ minLength: 3, maxLength: 100 })\n  @IsString()\n  @Length(3, 100)\n  name: string;\n\n  @ApiProperty({ minimum: 0 })\n  @IsNumber()\n  @Min(0)\n  price: number;\n\n  @ApiProperty({ minimum: 0, maximum: 10000 })\n  @IsNumber()\n  @Min(0)\n  @Max(10000)\n  stock: number;\n\n  @ApiProperty({ required: false })\n  @IsOptional()\n  @IsString()\n  @Transform(({ value }) =\u003e value?.trim())\n  description?: string;\n}\n```\n\n### Authentication \u0026 Authorization\n\n```typescript\nconst controllerStructure = CrudControllerStructure({\n  ...serviceStructure,\n  serviceType: ProductsService,\n\n  // Apply guards to all operations\n  classDecorators: [() =\u003e UseGuards(JwtAuthGuard)],\n\n  operations: {\n    findAll: true, // Public access\n    findOne: true, // Public access\n    create: {\n      decorators: [() =\u003e UseGuards(AdminGuard)], // Admin only\n    },\n    update: {\n      decorators: [() =\u003e UseGuards(OwnerOrAdminGuard)], // Owner or Admin\n    },\n    remove: {\n      decorators: [() =\u003e UseGuards(AdminGuard)], // Admin only\n    },\n  },\n});\n```\n\n## 📊 Transaction Management\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  async transferStock(\n    context: Context,\n    fromProductId: string,\n    toProductId: string,\n    quantity: number,\n  ): Promise\u003c{ from: Product; to: Product }\u003e {\n    return this.runInTransaction(\n      context,\n      async transactionContext =\u003e {\n        const fromProduct = await this.findOne(\n          transactionContext,\n          fromProductId,\n          true,\n        );\n        const toProduct = await this.findOne(\n          transactionContext,\n          toProductId,\n          true,\n        );\n\n        if (fromProduct.stock \u003c quantity) {\n          throw new BadRequestException('Insufficient stock');\n        }\n\n        fromProduct.stock -= quantity;\n        toProduct.stock += quantity;\n\n        const repository = this.getRepository(transactionContext);\n\n        const from = await repository.save(fromProduct);\n        const to = await repository.save(toProduct);\n\n        return { from, to };\n      },\n      'REPEATABLE_READ',\n    );\n  }\n}\n```\n\n## 📈 Performance Optimization\n\n### Query Optimization\n\n```typescript\n// Optimized relations loading\nexport const serviceStructure = CrudServiceStructure({\n  entityType: Product,\n  createInputType: CreateProductDto,\n  updateInputType: UpdateProductDto,\n  findArgsType: FindProductArgs,\n\n  functions: {\n    findAll: {\n      relationsConfig: {\n        // Only load essential relations for list view\n        relations: { supplier: true },\n      },\n    },\n    findOne: {\n      relationsConfig: {\n        // Load all relations for detail view\n        relations: {\n          supplier: true,\n          category: true,\n          reviews: true,\n        },\n      },\n    },\n  },\n});\n```\n\n### Pagination with Complex Relations\n\n```typescript\n// The framework automatically handles complex pagination scenarios\n// It prevents the N+1 problem and optimizes query performance for relations\nexport class ProductsController extends CrudControllerFrom(\n  controllerStructure,\n) {\n  // This endpoint automatically handles pagination optimization\n  // even with complex relations\n  async findAll() {\n    // Framework handles:\n    // 1. Initial query to get IDs with pagination\n    // 2. Separate query to load entities with relations\n    // 3. Proper count query for pagination metadata\n  }\n}\n```\n\n## 🧪 Testing\n\n### Test Commands\n\nThe framework includes comprehensive testing support for both unit and end-to-end (E2E) tests:\n\n```bash\n# Run all unit tests\nnpm run test\n\n# Run end-to-end tests\nnpm run test:e2e\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Generate test coverage report\nnpm run test:coverage\n\n# Run tests in debug mode\nnpm run test:debug\n```\n\n### Service Testing\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { ProductsService } from './products.service';\nimport { Product } from './entities/product.entity';\n\ndescribe('ProductsService', () =\u003e {\n  let service: ProductsService;\n  let repository: Repository\u003cProduct\u003e;\n\n  beforeEach(async () =\u003e {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        ProductsService,\n        {\n          provide: getRepositoryToken(Product),\n          useClass: Repository,\n        },\n      ],\n    }).compile();\n\n    service = module.get\u003cProductsService\u003e(ProductsService);\n    repository = module.get\u003cRepository\u003cProduct\u003e\u003e(getRepositoryToken(Product));\n  });\n\n  it('should create a product', async () =\u003e {\n    const createDto = { name: 'Test Product', price: 100, stock: 10 };\n    const context = { user: { id: '1' } };\n\n    jest.spyOn(repository, 'create').mockReturnValue(createDto as Product);\n    jest.spyOn(repository, 'save').mockResolvedValue(createDto as Product);\n\n    const result = await service.create(context, createDto);\n    expect(result).toEqual(createDto);\n  });\n});\n```\n\n### Controller Testing\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { ProductsController } from './products.controller';\nimport { ProductsService } from './products.service';\n\ndescribe('ProductsController', () =\u003e {\n  let controller: ProductsController;\n  let service: ProductsService;\n\n  beforeEach(async () =\u003e {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ProductsController],\n      providers: [\n        {\n          provide: ProductsService,\n          useValue: {\n            findAll: jest.fn(),\n            findOne: jest.fn(),\n            create: jest.fn(),\n            update: jest.fn(),\n            remove: jest.fn(),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get\u003cProductsController\u003e(ProductsController);\n    service = module.get\u003cProductsService\u003e(ProductsService);\n  });\n\n  it('should return an array of products', async () =\u003e {\n    const products = [{ id: '1', name: 'Test Product' }];\n    jest.spyOn(service, 'findAll').mockResolvedValue(products as any);\n\n    const context = { user: { id: '1' } };\n    const result = await controller.findAll(context, {});\n    expect(result).toEqual(products);\n  });\n});\n```\n\n## 🚀 Deployment \u0026 Production\n\n### Environment Configuration\n\n```typescript\n// app.module.ts\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true,\n      envFilePath: `.env.${process.env.NODE_ENV}`,\n    }),\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (configService: ConfigService) =\u003e ({\n        type: 'postgres',\n        host: configService.get('DB_HOST'),\n        port: configService.get('DB_PORT'),\n        username: configService.get('DB_USERNAME'),\n        password: configService.get('DB_PASSWORD'),\n        database: configService.get('DB_DATABASE'),\n        entities: [Product, Supplier],\n        synchronize: configService.get('NODE_ENV') !== 'production',\n        logging: configService.get('NODE_ENV') === 'development',\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Production Considerations\n\n```typescript\n// Use specific configurations for production\nexport const serviceStructure = CrudServiceStructure({\n  entityType: Product,\n  createInputType: CreateProductDto,\n  updateInputType: UpdateProductDto,\n  findArgsType: FindProductArgs,\n\n  // Production-optimized settings\n  lockMode:\n    process.env.NODE_ENV === 'production' ? 'pessimistic_read' : undefined,\n\n  functions: {\n    findAll: {\n      // Add caching in production\n      decorators:\n        process.env.NODE_ENV === 'production' ? [() =\u003e CacheInterceptor()] : [],\n    },\n    create: {\n      transactional: true,\n      isolationLevel: 'READ_COMMITTED',\n    },\n  },\n});\n```\n\n## 🎯 Best Practices\n\n### 1. Entity Design\n\n```typescript\n@Entity()\nexport class Product {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  // Always add created/updated timestamps\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n\n  // Add soft delete support (enables soft deletion operations)\n  @DeleteDateColumn()\n  deletedAt?: Date;\n\n  // Index frequently queried fields\n  @Index()\n  @Column()\n  name: string;\n\n  // Use appropriate column types\n  @Column('decimal', { precision: 10, scale: 2 })\n  price: number;\n\n  // Configure cascade behavior for soft deletion\n  @ManyToOne(() =\u003e Supplier, supplier =\u003e supplier.products, {\n    cascade: ['soft-remove', 'recover'], // Enable cascade operations\n  })\n  supplier: Supplier;\n}\n```\n\n### 2. DTO Validation\n\n```typescript\nexport class CreateProductDto {\n  @ApiProperty({\n    description: 'Product name',\n    minLength: 1,\n    maxLength: 100,\n    example: 'MacBook Pro',\n  })\n  @IsString()\n  @Length(1, 100)\n  @Transform(({ value }) =\u003e value?.trim())\n  name: string;\n\n  @ApiProperty({\n    description: 'Product price in USD',\n    minimum: 0,\n    example: 999.99,\n  })\n  @IsNumber({ maxDecimalPlaces: 2 })\n  @Min(0)\n  @Type(() =\u003e Number)\n  price: number;\n}\n```\n\n### 3. Error Handling\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  async findOne(\n    context: Context,\n    id: string,\n    orFail = false,\n  ): Promise\u003cProduct\u003e {\n    try {\n      return await super.findOne(context, id, orFail);\n    } catch (error) {\n      if (error instanceof NotFoundException) {\n        throw new NotFoundException(`Product with ID ${id} not found`);\n      }\n      throw error;\n    }\n  }\n}\n```\n\n### 4. Logging \u0026 Monitoring\n\n```typescript\nexport class ProductsService extends CrudServiceFrom(serviceStructure) {\n  private readonly logger = new Logger(ProductsService.name);\n\n  async create(\n    context: Context,\n    createInput: CreateProductDto,\n  ): Promise\u003cProduct\u003e {\n    this.logger.log(`Creating product: ${createInput.name}`);\n\n    try {\n      const result = await super.create(context, createInput);\n      this.logger.log(`Product created successfully: ${result.id}`);\n      return result;\n    } catch (error) {\n      this.logger.error(\n        `Failed to create product: ${error.message}`,\n        error.stack,\n      );\n      throw error;\n    }\n  }\n}\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/solid-nestjs/framework.git\ncd framework\n\n# Install dependencies\nnpm install\n\n# Build all packages\nnpm run build\n\n# Run the typeorm \u0026 rest-api example\nnpm run start:dev -w apps-examples/simple-crud-app\n\n# Run the typeorm \u0026 graphql example\nnpm run start:dev -w apps-examples/simple-graphql-crud-app\n\n# Run the typeorm \u0026 rest-api + graphql example\nnpm run start:dev -w apps-examples/simple-hybrid-crud-app\n\n# Run the advanced examples with soft deletion \u0026 bulk operations\nnpm run start:dev -w apps-examples/advanced-crud-app\nnpm run start:dev -w apps-examples/advanced-hybrid-crud-app\n```\n\n### 🔄 Exploring Advanced Features\n\nThe advanced examples (`advanced-crud-app` and `advanced-hybrid-crud-app`) demonstrate comprehensive implementations of soft deletion, recovery, and bulk operations:\n\n#### Advanced CRUD App Features:\n\n- **Soft Deletion**: Suppliers and Products with cascade soft delete\n- **Recovery Operations**: Restore soft-deleted entities\n- **Bulk Operations**: Bulk insert, update, delete, and remove\n- **Custom Bulk Endpoints**: Service-level bulk operations by criteria\n- **Event Hooks**: Complete lifecycle hooks for all operations\n- **Transaction Management**: All operations properly wrapped in transactions\n\n#### Advanced Hybrid App Features:\n\n- **GraphQL Soft Deletion**: Complete GraphQL mutation support\n- **REST + GraphQL**: Both API types with soft deletion support\n- **Cascade Operations**: Related entity cascade for soft delete/recover\n- **Bulk Recovery**: GraphQL and REST bulk recovery operations\n\n#### Example Endpoints from Advanced Apps:\n\n```bash\n# Advanced CRUD App (REST only)\nPOST   /suppliers/bulk                    # Bulk create suppliers\nPUT    /suppliers/bulk/update-email-by-name  # Bulk update by criteria\nDELETE /suppliers/bulk/delete-by-email    # Bulk hard delete by criteria\n\n# Advanced Hybrid App (REST + GraphQL)\nDELETE /suppliers/bulk/remove-by-email    # Bulk soft delete by criteria\nPATCH  /suppliers/bulk/recover-by-email   # Bulk recover by criteria\nDELETE /suppliers/soft/:id               # Individual soft delete\nPATCH  /suppliers/recover/:id            # Individual recovery\nDELETE /suppliers/hard/:id               # Individual hard delete\n\n# GraphQL mutations (Hybrid App)\nmutation { softRemoveSupplier(id: \"123\") { id name deletedAt } }\nmutation { recoverSupplier(id: \"123\") { id name deletedAt } }\nmutation { hardRemoveSupplier(id: \"123\") { id name } }\n```\n\nFor complete implementation details, see:\n\n- `apps-examples/advanced-crud-app/src/suppliers/suppliers.controller.ts`\n- `apps-examples/advanced-hybrid-crud-app/src/suppliers/suppliers.controller.ts`\n- Test files in each example's `test/` directory for comprehensive usage examples\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.\n\n## 👨‍💻 Author\n\n**Andres De la Ossa**\n\n- Email: adelaossa0129@gmail.com\n- GitHub: [@solid-nestjs](https://github.com/solid-nestjs)\n\n## 🙏 Acknowledgments\n\nThis framework wouldn't have been possible without the inspiration and guidance from several sources:\n\n### 🎓 Educational Inspiration\n\n- **[Fernando Herrera](https://fernando-herrera.com/)** - Special thanks for his exceptional NestJS and design patterns courses that provided fundamental inspiration and architectural guidance for this framework\n- **Claude Sonnet 4.0 (agent)** - Invaluable assistance with documentation, testing strategies, and architectural guidance throughout the development process\n\n### 🛠️ Technology Stack\n\n- Built with [NestJS](https://nestjs.com/) - The progressive Node.js framework\n- Powered by [TypeORM](https://typeorm.io/) - Amazing TypeScript ORM\n- Inspired by the SOLID principles and Clean Architecture\n- GraphQL support via [Apollo Server](https://www.apollographql.com/)\n\n### 🌟 Community\n\n- Community feedback and contributions that help shape the framework\n- The open-source ecosystem that makes projects like this possible\n- All developers who test, use, and provide feedback on the framework\n\n---\n\n_Made with ❤️ for the NestJS community_\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolid-nestjs%2Fframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolid-nestjs%2Fframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolid-nestjs%2Fframework/lists"}