LinkDesk/frontend/docs/permanent-delete-workflow-i...

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.