Documentation Updates
This commit is contained in:
227
docs/changes/BULK-DELETE-ENDPOINT-DOCS.md
Normal file
227
docs/changes/BULK-DELETE-ENDPOINT-DOCS.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user