# Bulk Catalog Delete Endpoint Documentation ## Overview Generic bulk delete endpoint for catalog entities (makes, models, years, trims, engines) in the admin panel. ## Endpoint ``` DELETE /api/admin/catalog/{entity}/bulk-delete ``` ## Path Parameters - `entity`: Entity type - one of: `makes`, `models`, `years`, `trims`, `engines` ## Request Body ```json { "ids": [1, 2, 3, 4, 5] } ``` ### Validation Rules - IDs must be an array of positive integers - At least 1 ID required - Maximum 100 IDs per batch - All IDs must be valid integers (not strings or floats) ## Response Codes - `204 No Content`: All deletions succeeded (no response body) - `207 Multi-Status`: Some deletions failed (includes response body with details) - `400 Bad Request`: Invalid entity type or invalid request body - `401 Unauthorized`: Missing or invalid authentication - `500 Internal Server Error`: Unexpected server error ## Response Body (207 Multi-Status only) ```json { "deleted": [1, 3, 5], "failed": [ { "id": 2, "error": "Make 2 not found" }, { "id": 4, "error": "Cannot delete make with existing models" } ] } ``` ## Cascade Behavior The endpoint uses existing single-delete methods which have the following behavior: ### Makes - **Blocks deletion** if models exist under the make - Error: "Cannot delete make with existing models" - **Solution**: Delete all dependent models first ### Models - **Blocks deletion** if years exist under the model - Error: "Cannot delete model with existing years" - **Solution**: Delete all dependent years first ### Years - **Blocks deletion** if trims exist under the year - Error: "Cannot delete year with existing trims" - **Solution**: Delete all dependent trims first ### Trims - **Blocks deletion** if engines exist under the trim - Error: "Cannot delete trim with existing engines" - **Solution**: Delete all dependent engines first ### Engines - **No cascade restrictions** (leaf entity in hierarchy) ## Deletion Order for Hierarchy To delete an entire make and all its dependencies: 1. Delete engines first 2. Delete trims 3. Delete years 4. Delete models 5. Delete make last ## Examples ### Example 1: Delete Multiple Engines (Success) ```bash DELETE /api/admin/catalog/engines/bulk-delete { "ids": [101, 102, 103] } Response: 204 No Content ``` ### Example 2: Delete Multiple Makes (Partial Failure) ```bash DELETE /api/admin/catalog/makes/bulk-delete { "ids": [1, 2, 3] } Response: 207 Multi-Status { "deleted": [3], "failed": [ { "id": 1, "error": "Cannot delete make with existing models" }, { "id": 2, "error": "Make 2 not found" } ] } ``` ### Example 3: Invalid Entity Type ```bash DELETE /api/admin/catalog/invalid/bulk-delete { "ids": [1, 2, 3] } Response: 400 Bad Request { "error": "Invalid entity type", "message": "Entity must be one of: makes, models, years, trims, engines" } ``` ### Example 4: Invalid IDs ```bash DELETE /api/admin/catalog/makes/bulk-delete { "ids": ["abc", "def"] } Response: 400 Bad Request { "error": "Invalid IDs", "message": "All IDs must be positive integers" } ``` ## Implementation Details ### Files Modified 1. `/backend/src/features/admin/api/admin.routes.ts` (line 209-212) - Added route: `DELETE /admin/catalog/:entity/bulk-delete` - Requires admin authentication 2. `/backend/src/features/admin/api/catalog.controller.ts` (line 542-638) - Added method: `bulkDeleteCatalogEntity()` - Maps entity type to appropriate delete method - Processes deletions sequentially - Collects successes and failures 3. `/backend/src/features/admin/api/admin.validation.ts` (line 43-49, 57-58) - Added `catalogEntitySchema`: Validates entity type - Added `bulkDeleteCatalogSchema`: Validates request body - Exported types: `CatalogEntity`, `BulkDeleteCatalogInput` 4. `/backend/src/features/admin/domain/admin.types.ts` (line 97-103) - Added `BulkDeleteCatalogResponse` interface ### Continue-on-Failure Pattern The endpoint uses a continue-on-failure pattern: - One deletion failure does NOT stop the batch - All deletions are attempted - Successes and failures are tracked separately - Final response includes both lists ### Transaction Behavior - Each individual deletion runs in its own transaction (via service layer) - If one delete fails, it doesn't affect others - No rollback of previously successful deletions ## Testing ### Manual Testing with cURL ```bash # Test valid request (requires auth token) curl -X DELETE "http://localhost/api/admin/catalog/makes/bulk-delete" \ -H "Authorization: Bearer YOUR_TOKEN_HERE" \ -H "Content-Type: application/json" \ -d '{"ids": [1, 2, 3]}' # Test invalid entity type curl -X DELETE "http://localhost/api/admin/catalog/invalid/bulk-delete" \ -H "Content-Type: application/json" \ -d '{"ids": [1, 2, 3]}' # Test empty IDs curl -X DELETE "http://localhost/api/admin/catalog/makes/bulk-delete" \ -H "Content-Type: application/json" \ -d '{"ids": []}' ``` ### Expected Audit Log Behavior Each successful deletion creates a platform change log entry: - `changeType`: "DELETE" - `resourceType`: Entity type (makes, models, years, trims, engines) - `resourceId`: ID of deleted entity - `changedBy`: Actor's user ID - `oldValue`: Entity data before deletion - `newValue`: null ## Security - Endpoint requires admin authentication (via `fastify.requireAdmin`) - Actor ID is logged for all operations - All deletions are audited in platform_change_log table ## Performance Considerations - Deletions are processed sequentially (not in parallel) - Each deletion queries the database separately - Cache invalidation occurs after each successful deletion - For large batches (50+ items), consider breaking into smaller batches ## Future Enhancements Potential improvements: 1. Add cascade delete option to automatically delete dependent entities 2. Add dry-run mode to preview what would be deleted 3. Add batch size optimization for better performance 4. Add progress tracking for long-running batches