# Story 4.3: Timeline Archiving ## Epic Reference **Epic 4:** Case Timeline System ## User Story As an **admin**, I want **to archive completed cases and unarchive if needed**, So that **I can organize active and completed case timelines**. ## Story Context ### Existing System Integration - **Integrates with:** timelines table (status field from Story 4.1) - **Technology:** Livewire Volt - **Follows pattern:** Soft state change pattern - **Touch points:** Timeline list views, timeline detail view ### Prerequisites (from Story 4.1) The `timelines` table includes: ```php $table->enum('status', ['active', 'archived'])->default('active'); ``` ### Files to Modify - `app/Models/Timeline.php` - add archive/unarchive methods and scopes - `resources/views/livewire/admin/timelines/show.blade.php` - add archive/unarchive button - `resources/views/livewire/admin/timelines/index.blade.php` - add status filter dropdown - `resources/views/livewire/client/timelines/index.blade.php` - separate archived timelines display ## Acceptance Criteria ### Archive Timeline - [ ] Archive button on timeline detail view (admin only) - [ ] Confirmation modal before archiving ("Are you sure?") - [ ] Status changes to 'archived' - [ ] Timeline remains visible to client (read-only as always) - [ ] No further updates can be added (show disabled state with tooltip) - [ ] Visual indicator shows archived status (badge + muted styling) ### Unarchive Timeline - [ ] Unarchive button on archived timelines - [ ] Status returns to 'active' - [ ] Updates can be added again ### List Filtering - [ ] Filter dropdown with options: Active (default), Archived, All - [ ] Archived timelines shown in separate section in client view (below active) - [ ] Bulk archive via checkbox selection + "Archive Selected" button - [ ] Bulk archive shows count confirmation ("Archive 3 timelines?") ### Edge Cases - [ ] Archiving already-archived timeline: No-op, no error shown - [ ] Unarchiving already-active timeline: No-op, no error shown - [ ] Adding update to archived timeline: Prevented with error message - [ ] Bulk archive mixed selection: Skip already-archived, archive only active ones - [ ] Empty bulk selection: "Archive Selected" button disabled ### Quality Requirements - [ ] Audit log for status changes (action_type: 'archive' or 'unarchive') - [ ] Bilingual labels (AR/EN for buttons, messages, filters) - [ ] Feature tests covering all scenarios below ### Test Scenarios ``` tests/Feature/Timeline/TimelineArchivingTest.php - test_admin_can_archive_active_timeline - test_admin_can_unarchive_archived_timeline - test_archiving_archived_timeline_is_noop - test_unarchiving_active_timeline_is_noop - test_cannot_add_update_to_archived_timeline - test_client_can_view_archived_timeline - test_admin_can_filter_by_active_status - test_admin_can_filter_by_archived_status - test_admin_can_filter_all_statuses - test_bulk_archive_updates_multiple_timelines - test_bulk_archive_skips_already_archived - test_audit_log_created_on_archive - test_audit_log_created_on_unarchive - test_guest_cannot_archive_timeline ``` ## Technical Notes ### Timeline Model Methods ```php class Timeline extends Model { public function archive(): void { $this->update(['status' => 'archived']); } public function unarchive(): void { $this->update(['status' => 'active']); } public function isArchived(): bool { return $this->status === 'archived'; } public function scopeActive($query) { return $query->where('status', 'active'); } public function scopeArchived($query) { return $query->where('status', 'archived'); } } ``` ### Volt Component Actions ```php public function archive(): void { if ($this->timeline->isArchived()) { return; } $this->timeline->archive(); AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'archive', 'target_type' => 'timeline', 'target_id' => $this->timeline->id, 'ip_address' => request()->ip(), ]); session()->flash('success', __('messages.timeline_archived')); } public function unarchive(): void { if (!$this->timeline->isArchived()) { return; } $this->timeline->unarchive(); AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'unarchive', 'target_type' => 'timeline', 'target_id' => $this->timeline->id, 'ip_address' => request()->ip(), ]); session()->flash('success', __('messages.timeline_unarchived')); } public function bulkArchive(array $ids): void { Timeline::whereIn('id', $ids)->update(['status' => 'archived']); foreach ($ids as $id) { AdminLog::create([ 'admin_id' => auth()->id(), 'action_type' => 'archive', 'target_type' => 'timeline', 'target_id' => $id, 'ip_address' => request()->ip(), ]); } session()->flash('success', __('messages.timelines_archived', ['count' => count($ids)])); } ``` ## Definition of Done - [ ] Archive button on timeline detail view works with confirmation modal - [ ] Unarchive button on archived timelines works - [ ] Update form disabled/hidden on archived timelines with clear messaging - [ ] Status filter dropdown functional (Active/Archived/All) - [ ] Bulk archive with checkbox selection works - [ ] Visual indicators (badge + muted styling) display correctly - [ ] Client can still view archived timelines in separate section - [ ] Audit log entries created for all archive/unarchive actions - [ ] All test scenarios in `tests/Feature/Timeline/TimelineArchivingTest.php` pass - [ ] Code formatted with Pint ## Dependencies - **Story 4.1:** Timeline creation (`docs/stories/story-4.1-timeline-creation.md`) - provides Timeline model and schema - **Story 4.2:** Timeline updates (`docs/stories/story-4.2-timeline-updates-management.md`) - provides update blocking context ## Estimation **Complexity:** Low **Estimated Effort:** 2 hours