# Story 5.3: Post Deletion

## Epic Reference
**Epic 5:** Posts/Blog System

## User Story
As an **admin**,
I want **to permanently delete posts**,
So that **I can remove outdated or incorrect content from the website**.

## Story Context

### Existing System Integration
- **Integrates with:** posts table
- **Technology:** Livewire Volt
- **Follows pattern:** Permanent delete pattern
- **Touch points:** Post management dashboard
- **Files to modify:** Post management Volt component from Story 5.2

## Acceptance Criteria

### Delete Functionality
- [x] Delete button on post list (primary location)
- [x] Delete button on post edit page (secondary location)
- [x] Confirmation modal dialog before deletion
- [x] Permanent deletion (no soft delete per PRD)
- [x] Success message after deletion
- [x] Redirect to post list after deletion from edit page

### Restrictions
- [x] Admin-only access (middleware protection)

### Audit Trail
- [x] Audit log entry preserved
- [x] Old values stored in log

### Quality Requirements
- [x] Clear warning in confirmation
- [x] Bilingual messages
- [x] Tests for deletion

## Technical Notes

### Delete Confirmation Modal
```blade
<flux:modal wire:model="showDeleteModal">
    <flux:heading>{{ __('admin.delete_post') }}</flux:heading>

    <flux:callout variant="danger">
        {{ __('admin.delete_post_warning') }}
    </flux:callout>

    <p class="my-4">
        {{ __('admin.deleting_post', ['title' => $postToDelete?->title]) }}
    </p>

    <div class="flex gap-3">
        <flux:button wire:click="$set('showDeleteModal', false)">
            {{ __('common.cancel') }}
        </flux:button>
        <flux:button variant="danger" wire:click="confirmDelete">
            {{ __('admin.delete_permanently') }}
        </flux:button>
    </div>
</flux:modal>
```

### Delete Button on Edit Page
Add delete button to the post edit form (from Story 5.1) when editing an existing post:
```blade
@if($post?->exists)
    <flux:button variant="danger" wire:click="delete({{ $post->id }})">
        {{ __('admin.delete_post') }}
    </flux:button>
@endif
```

### Delete Logic
```php
public ?Post $postToDelete = null;
public bool $showDeleteModal = false;

public function delete(int $id): void
{
    $this->postToDelete = Post::findOrFail($id);
    $this->showDeleteModal = true;
}

public function confirmDelete(): void
{
    if (!$this->postToDelete) {
        return;
    }

    // Create audit log BEFORE deletion
    AdminLog::create([
        'admin_id' => auth()->id(),
        'action_type' => 'delete',
        'target_type' => 'post',
        'target_id' => $this->postToDelete->id,
        'old_values' => $this->postToDelete->toArray(),
        'ip_address' => request()->ip(),
    ]);

    // Permanently delete
    $this->postToDelete->delete();

    $this->showDeleteModal = false;
    $this->postToDelete = null;

    session()->flash('success', __('messages.post_deleted'));
}
```

### Testing
```php
use App\Models\Post;
use App\Models\AdminLog;
use App\Models\User;
use Livewire\Volt\Volt;

it('permanently deletes post', function () {
    $admin = User::factory()->create();
    $post = Post::factory()->create();

    Volt::test('admin.posts.index')
        ->actingAs($admin)
        ->call('delete', $post->id)
        ->call('confirmDelete');

    expect(Post::find($post->id))->toBeNull();
});

it('shows confirmation modal before deletion', function () {
    $admin = User::factory()->create();
    $post = Post::factory()->create();

    Volt::test('admin.posts.index')
        ->actingAs($admin)
        ->call('delete', $post->id)
        ->assertSet('showDeleteModal', true)
        ->assertSet('postToDelete.id', $post->id);
});

it('creates audit log on deletion with old values', function () {
    $admin = User::factory()->create();
    $post = Post::factory()->create(['title_en' => 'Test Title']);

    Volt::test('admin.posts.index')
        ->actingAs($admin)
        ->call('delete', $post->id)
        ->call('confirmDelete');

    $log = AdminLog::where('target_type', 'post')
        ->where('target_id', $post->id)
        ->where('action_type', 'delete')
        ->first();

    expect($log)->not->toBeNull()
        ->and($log->old_values)->toHaveKey('title_en', 'Test Title');
});

it('requires admin authentication to delete', function () {
    $post = Post::factory()->create();

    $this->delete(route('admin.posts.destroy', $post))
        ->assertRedirect(route('login'));
});
```

## Definition of Done

- [x] Delete button shows confirmation
- [x] Confirmation explains permanence
- [x] Post deleted from database
- [x] Audit log created with old values
- [x] Success message displayed
- [x] Tests pass
- [x] Code formatted with Pint

## Dependencies

- **Story 5.1:** Post creation
- **Story 5.2:** Post management dashboard

## Estimation

**Complexity:** Low
**Estimated Effort:** 1-2 hours

---

## Dev Agent Record

### Status
Ready for Review

### Agent Model Used
Claude Opus 4.5

### File List
**Modified:**
- `resources/views/livewire/admin/posts/index.blade.php` - Added confirmation modal with `postToDelete`, `showDeleteModal`, `confirmDelete()`, `cancelDelete()` methods
- `resources/views/livewire/admin/posts/edit.blade.php` - Added delete button and confirmation modal with `delete()`, `confirmDelete()`, `cancelDelete()` methods, redirect after deletion
- `lang/en/posts.php` - Added delete modal translations: `delete_post`, `delete_post_warning`, `deleting_post`, `delete_permanently`
- `lang/ar/posts.php` - Added Arabic delete modal translations
- `tests/Feature/Admin/PostManagementTest.php` - Updated and added 10 delete-related tests

### Debug Log References
None - no issues encountered

### Completion Notes
- Implemented proper confirmation modal pattern (replacing simple `wire:confirm`)
- Both index and edit pages now have delete functionality with confirmation modals
- Edit page redirects to index after successful deletion
- Audit log captures old_values before deletion for audit trail
- All 48 tests in PostManagementTest pass
- Full regression suite passes (392 tests)

### Change Log
| Change | Description |
|--------|-------------|
| Modal-based delete | Replaced browser confirm dialog with Flux UI modal for better UX |
| Edit page delete | Added delete button to edit page with redirect to index |
| Bilingual support | Added EN/AR translations for delete modal messages |
| Test coverage | Added 10 new tests covering modal flow, cancel, and audit log |

---

## QA Results

### Review Date: 2025-12-27

### Reviewed By: Quinn (Test Architect)

### Risk Assessment
**Risk Level: Low** - Simple delete functionality with well-contained scope
- No auth/payment/security files modified (admin middleware already exists)
- 10 delete-related tests added
- Diff < 500 lines
- Story has 6 acceptance criteria (near threshold but manageable)

### Code Quality Assessment

**Overall: Excellent** - The implementation follows Laravel/Livewire best practices with proper separation of concerns.

**Strengths:**
1. **Transaction Safety**: Index page uses `DB::transaction()` with `lockForUpdate()` for race condition prevention
2. **Audit Trail**: Proper `AdminLog` entries created BEFORE deletion with `old_values` captured
3. **Modal UX Pattern**: Flux UI modal with proper confirmation flow (delete → modal → confirmDelete)
4. **Bilingual Support**: Complete EN/AR translations for all delete-related messages
5. **Error Handling**: Graceful handling when post not found (both index and edit pages)
6. **Redirect Flow**: Edit page properly redirects to index after deletion

**Minor Observations:**
1. Edit page `confirmDelete()` doesn't use `DB::transaction()` - acceptable for single operation but inconsistent with index page pattern
2. Edit page doesn't use `lockForUpdate()` - lower risk since already viewing the specific post

### Requirements Traceability

| AC # | Acceptance Criteria | Test Coverage | Status |
|------|---------------------|---------------|--------|
| 1 | Delete button on post list | `admin can delete post from index with confirmation modal` | ✓ |
| 2 | Delete button on post edit page | `admin can delete post from edit page`, `edit page shows delete button` | ✓ |
| 3 | Confirmation modal dialog before deletion | `delete modal shows before deletion`, `edit page delete shows confirmation modal` | ✓ |
| 4 | Permanent deletion (no soft delete) | `expect(Post::find($postId))->toBeNull()` | ✓ |
| 5 | Success message after deletion | Session flash 'success' in both components | ✓ |
| 6 | Redirect to post list after deletion from edit page | `assertRedirect(route('admin.posts.index'))` | ✓ |
| 7 | Admin-only access (middleware) | `non-admin cannot access posts index`, `guest cannot access posts index` | ✓ |
| 8 | Audit log entry preserved with old values | `delete post creates audit log with old values`, `edit page delete creates audit log` | ✓ |
| 9 | Clear warning in confirmation | Flux callout with `delete_post_warning` translation | ✓ |
| 10 | Bilingual messages | EN + AR lang files both have delete modal translations | ✓ |

### Test Architecture Assessment

**Coverage: Complete** - All acceptance criteria have corresponding tests

**Test Distribution:**
- Index delete flow: 5 tests
- Edit page delete flow: 4 tests
- Authorization: 4 tests (shared with other story tests)

**Test Quality:**
- Uses `Volt::test()` pattern correctly
- Proper factory usage with `User::factory()->admin()`
- Tests both happy path and edge cases (cancel, not found)
- Audit log assertions verify `old_values` content

### Refactoring Performed

None required - code quality is good.

### Compliance Check

- Coding Standards: ✓ Class-based Volt components, Flux UI components used
- Project Structure: ✓ Files in correct locations
- Testing Strategy: ✓ Feature tests with Pest, proper Volt::test usage
- All ACs Met: ✓ All 10 acceptance criteria verified

### Improvements Checklist

- [x] Modal-based confirmation implemented (Flux UI)
- [x] Transaction safety on index page
- [x] Audit log with old_values before deletion
- [x] Bilingual translations complete
- [x] Edit page redirect after deletion
- [x] Cancel functionality restores state
- [ ] Consider: Add transaction wrapper to edit page `confirmDelete()` for consistency (optional, low priority)

### Security Review

- ✓ Admin middleware protects routes
- ✓ No SQL injection risk (using Eloquent)
- ✓ CSRF protection via Livewire
- ✓ No XSS concerns (user-generated content not involved in delete flow)

### Performance Considerations

- ✓ `lockForUpdate()` used on index page to prevent race conditions
- ✓ Single delete operation - no N+1 concerns
- ✓ Audit log creation is synchronous but appropriate for admin actions

### Files Modified During Review

None - no modifications required.

### Gate Status

Gate: **PASS** → `docs/qa/gates/5.3-post-deletion.yml`

### Recommended Status

**✓ Ready for Done** - All acceptance criteria met, comprehensive test coverage, proper audit trail, bilingual support complete. Implementation is clean and follows established patterns.
