8.9 KiB
Permanent Delete Workflow Implementation
Overview
This document describes the implementation of the permanent delete confirmation workflow for the Recovery Management feature (Task 9).
Requirements
Task 9 requires the following functionality:
- Wire up confirmation dialog to permanent delete actions
- Implement confirmation token validation
- Add loading states during permanent deletion
- Handle success and error responses appropriately
- Update UI state after successful permanent deletion
Implementation Details
1. Confirmation Dialog Integration
The permanent delete workflow is initiated from the DeletedItemsManagementView.vue component:
Single Item Deletion
const handlePermanentDelete = (type: 'shot' | 'asset', item: DeletedShot | DeletedAsset) => {
const deleteItem = {
id: item.id,
name: item.name,
type,
project_name: item.project_name,
episode_name: 'episode_name' in item ? item.episode_name : undefined,
task_count: item.task_count,
submission_count: item.submission_count,
attachment_count: item.attachment_count,
note_count: item.note_count,
review_count: item.review_count
}
itemsToDelete.value = [deleteItem]
permanentDeleteType.value = 'single'
showPermanentDeleteDialog.value = true
}
Bulk Deletion
const handleBulkPermanentDelete = () => {
const deleteItems = selectedItems.value.map(item => {
// Maps selected items to the required format
}).filter((item): item is NonNullable<typeof item> => item !== null)
itemsToDelete.value = deleteItems
permanentDeleteType.value = 'bulk'
showPermanentDeleteDialog.value = true
}
2. Confirmation Token Validation
The PermanentDeleteConfirmDialog.vue component implements a secure confirmation workflow:
Token Generation
const generateConfirmationToken = (): string => {
if (isBulkOperation.value) {
const shotCount = props.items.filter(item => item.type === 'shot').length
const assetCount = props.items.filter(item => item.type === 'asset').length
if (shotCount > 0 && assetCount > 0) {
return 'CONFIRM_MIXED_BULK_PERMANENT_DELETE'
} else if (shotCount > 0) {
return 'CONFIRM_BULK_SHOTS_PERMANENT_DELETE'
} else {
return 'CONFIRM_BULK_ASSETS_PERMANENT_DELETE'
}
} else {
const item = props.items[0]
if (item.type === 'shot') {
return 'CONFIRM_SHOT_PERMANENT_DELETE'
} else {
return 'CONFIRM_ASSET_PERMANENT_DELETE'
}
}
}
User Confirmation
- User must type the exact confirmation phrase (e.g., "DELETE Shot_001" or "DELETE 5 ITEMS")
- Paste is disabled to prevent accidental confirmations
- Delete button is disabled until confirmation phrase matches exactly
3. Loading States
Loading states are managed throughout the deletion process:
// State management
const isPermanentDeleting = ref(false)
// In the dialog component
<Button
variant="destructive"
@click="handleDelete"
:disabled="!isConfirmed || isDeleting || isLoadingInfo || !!loadError"
>
<Loader2 v-if="isDeleting" class="mr-2 h-4 w-4 animate-spin" />
<Trash2 v-else class="mr-2 h-4 w-4" />
{{ isDeleting ? 'Deleting...' : 'Permanently Delete' }}
</Button>
4. Success and Error Response Handling
The executePermanentDelete function handles all response scenarios:
const executePermanentDelete = async (confirmationToken: string) => {
try {
isPermanentDeleting.value = true
if (permanentDeleteType.value === 'single') {
const item = itemsToDelete.value[0]
let result
if (item.type === 'shot') {
result = await recoveryService.permanentDeleteShot(item.id, confirmationToken)
} else {
result = await recoveryService.permanentDeleteAsset(item.id, confirmationToken)
}
toast({
title: 'Permanent Deletion Successful',
description: `${result.name} and all related data have been permanently deleted`,
})
// Update UI state (see section 5)
} else {
// Handle bulk deletion with detailed feedback
// Shows success count and any errors
}
showPermanentDeleteDialog.value = false
itemsToDelete.value = []
} catch (err: any) {
toast({
title: 'Permanent Deletion Failed',
description: err.response?.data?.detail || 'Failed to permanently delete items',
variant: 'destructive'
})
} finally {
isPermanentDeleting.value = false
}
}
5. UI State Updates
After successful deletion, the UI is updated to reflect the changes:
// Remove from lists
if (item.type === 'shot') {
deletedShots.value = deletedShots.value.filter(s => s.id !== item.id)
selectedItems.value = selectedItems.value.filter(selected =>
!(selected.type === 'shot' && selected.id === item.id))
} else {
deletedAssets.value = deletedAssets.value.filter(a => a.id !== item.id)
selectedItems.value = selectedItems.value.filter(selected =>
!(selected.type === 'asset' && selected.id === item.id))
}
// Close dialog and clear state
showPermanentDeleteDialog.value = false
itemsToDelete.value = []
Backend Implementation
API Endpoints
The backend provides the following endpoints:
- Single Shot Deletion:
DELETE /admin/shots/{shot_id}/permanent - Single Asset Deletion:
DELETE /admin/assets/{asset_id}/permanent - Bulk Shot Deletion:
DELETE /admin/shots/bulk-permanent - Bulk Asset Deletion:
DELETE /admin/assets/bulk-permanent
Security Features
- Rate Limiting: Maximum 10 permanent delete operations per minute per user
- Token Validation: Backend validates confirmation tokens before proceeding
- Transaction Safety: All deletions are performed within database transactions
- Rollback on Failure: If any part of the deletion fails, all changes are rolled back
- Audit Logging: All permanent deletions are logged for audit purposes
Cascading Deletion
The backend ensures complete data removal:
- Tasks associated with the shot/asset
- Submissions and their files
- Attachments and their files
- Production notes
- Reviews
- Activity records
- File system cleanup
Frontend Service Layer
The recovery.ts service provides type-safe methods:
async permanentDeleteShot(shotId: number, confirmationToken: string): Promise<PermanentDeleteResult>
async permanentDeleteAsset(assetId: number, confirmationToken: string): Promise<PermanentDeleteResult>
async bulkPermanentDeleteShots(shotIds: number[], confirmationToken: string): Promise<BulkPermanentDeleteResult>
async bulkPermanentDeleteAssets(assetIds: number[], confirmationToken: string): Promise<BulkPermanentDeleteResult>
User Experience Flow
- User navigates to Recovery Management page
- User selects item(s) to permanently delete
- User clicks "Permanent Delete" button
- Confirmation dialog appears with:
- Warning about irreversible action
- List of items to be deleted
- Impact summary (tasks, files, etc.)
- Confirmation phrase requirement
- User types exact confirmation phrase
- Delete button becomes enabled
- User clicks "Permanently Delete"
- Loading state shows during deletion
- Success/error toast notification appears
- UI updates to remove deleted items
- Dialog closes automatically
Testing Recommendations
To verify the implementation:
-
Single Item Deletion
- Test shot deletion with correct confirmation
- Test asset deletion with correct confirmation
- Verify UI updates after deletion
-
Bulk Deletion
- Test bulk deletion of shots only
- Test bulk deletion of assets only
- Test bulk deletion of mixed items
-
Error Scenarios
- Test with invalid confirmation phrase
- Test network error handling
- Test rate limit enforcement
-
UI States
- Verify loading states during deletion
- Verify disabled states during operation
- Verify toast notifications
Compliance with Requirements
✅ Requirement 6.3: Confirmation dialog with data loss warnings - Implemented ✅ Requirement 6.5: Success messages and UI updates - Implemented ✅ Requirement 8.1: Immediate data removal - Implemented ✅ Requirement 8.4: Rollback on failure - Implemented
Files Modified
Frontend
frontend/src/views/admin/DeletedItemsManagementView.vue- Main view with workflow handlersfrontend/src/components/admin/PermanentDeleteConfirmDialog.vue- Confirmation dialogfrontend/src/services/recovery.ts- Service layer methods
Backend
backend/routers/admin.py- API endpointsbackend/services/recovery_service.py- Business logic
Conclusion
Task 9 has been successfully implemented with all required functionality:
- ✅ Confirmation dialog integration
- ✅ Token validation
- ✅ Loading states
- ✅ Success/error handling
- ✅ UI state updates
The implementation provides a secure, user-friendly workflow for permanent deletion with proper safeguards and feedback mechanisms.