287 lines
8.9 KiB
Markdown
287 lines
8.9 KiB
Markdown
# 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:
|
|
1. Wire up confirmation dialog to permanent delete actions
|
|
2. Implement confirmation token validation
|
|
3. Add loading states during permanent deletion
|
|
4. Handle success and error responses appropriately
|
|
5. 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
|
|
```typescript
|
|
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
|
|
```typescript
|
|
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
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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:
|
|
|
|
1. **Single Shot Deletion**: `DELETE /admin/shots/{shot_id}/permanent`
|
|
2. **Single Asset Deletion**: `DELETE /admin/assets/{asset_id}/permanent`
|
|
3. **Bulk Shot Deletion**: `DELETE /admin/shots/bulk-permanent`
|
|
4. **Bulk Asset Deletion**: `DELETE /admin/assets/bulk-permanent`
|
|
|
|
### Security Features
|
|
|
|
1. **Rate Limiting**: Maximum 10 permanent delete operations per minute per user
|
|
2. **Token Validation**: Backend validates confirmation tokens before proceeding
|
|
3. **Transaction Safety**: All deletions are performed within database transactions
|
|
4. **Rollback on Failure**: If any part of the deletion fails, all changes are rolled back
|
|
5. **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:
|
|
|
|
```typescript
|
|
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
|
|
|
|
1. User navigates to Recovery Management page
|
|
2. User selects item(s) to permanently delete
|
|
3. User clicks "Permanent Delete" button
|
|
4. Confirmation dialog appears with:
|
|
- Warning about irreversible action
|
|
- List of items to be deleted
|
|
- Impact summary (tasks, files, etc.)
|
|
- Confirmation phrase requirement
|
|
5. User types exact confirmation phrase
|
|
6. Delete button becomes enabled
|
|
7. User clicks "Permanently Delete"
|
|
8. Loading state shows during deletion
|
|
9. Success/error toast notification appears
|
|
10. UI updates to remove deleted items
|
|
11. Dialog closes automatically
|
|
|
|
## Testing Recommendations
|
|
|
|
To verify the implementation:
|
|
|
|
1. **Single Item Deletion**
|
|
- Test shot deletion with correct confirmation
|
|
- Test asset deletion with correct confirmation
|
|
- Verify UI updates after deletion
|
|
|
|
2. **Bulk Deletion**
|
|
- Test bulk deletion of shots only
|
|
- Test bulk deletion of assets only
|
|
- Test bulk deletion of mixed items
|
|
|
|
3. **Error Scenarios**
|
|
- Test with invalid confirmation phrase
|
|
- Test network error handling
|
|
- Test rate limit enforcement
|
|
|
|
4. **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 handlers
|
|
- `frontend/src/components/admin/PermanentDeleteConfirmDialog.vue` - Confirmation dialog
|
|
- `frontend/src/services/recovery.ts` - Service layer methods
|
|
|
|
### Backend
|
|
- `backend/routers/admin.py` - API endpoints
|
|
- `backend/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.
|