# Story 4.3: Timeline Archiving

## Status
**Ready for Review**

## 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, `isArchived()` helper, and scopes
- `resources/views/livewire/admin/timelines/show.blade.php` - add archive/unarchive buttons, confirmation modal, disable update form when archived

> **Note:** List filtering (admin/timelines/index.blade.php) and client view separation (client/timelines/index.blade.php) are implemented in Stories 4.4 and 4.5 respectively. This story focuses on the core archive/unarchive functionality and updating the existing show page.

## 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 (Deferred to Story 4.4/4.5)
> The following filtering features require the admin dashboard (4.4) and client view (4.5):
> - 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?")

**This story provides the model methods and scopes that Stories 4.4/4.5 will use.**

### 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 edge cases deferred to Story 4.4:**
> - 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: 'archive' or 'unarchive') - uses AdminLog `action` field
- [ ] Bilingual labels (AR/EN for buttons, messages)
- [ ] Feature tests covering all scenarios below

### Test Scenarios
```
tests/Feature/Admin/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_audit_log_created_on_archive
- test_audit_log_created_on_unarchive
- test_guest_cannot_archive_timeline
- test_client_cannot_archive_timeline
- test_archived_timeline_shows_visual_indicator
- test_update_form_disabled_on_archived_timeline
```

> **Deferred to Story 4.4/4.5:**
> - 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_client_can_view_archived_timeline (4.5)

## Technical Notes

### Timeline Model Methods
Add these methods to `app/Models/Timeline.php`:
```php
use App\Enums\TimelineStatus;

class Timeline extends Model
{
    // ... existing code ...

    public function archive(): void
    {
        $this->update(['status' => TimelineStatus::Archived]);
    }

    public function unarchive(): void
    {
        $this->update(['status' => TimelineStatus::Active]);
    }

    public function isArchived(): bool
    {
        return $this->status === TimelineStatus::Archived;
    }

    public function isActive(): bool
    {
        return $this->status === TimelineStatus::Active;
    }

    public function scopeActive($query)
    {
        return $query->where('status', TimelineStatus::Active);
    }

    public function scopeArchived($query)
    {
        return $query->where('status', TimelineStatus::Archived);
    }
}
```

> **Note:** The Timeline model already casts `status` to `TimelineStatus::class` enum. Always use enum values, not strings.

### Volt Component Actions
Add these methods to `resources/views/livewire/admin/timelines/show.blade.php`:
```php
use App\Models\AdminLog;

public function archive(): void
{
    if ($this->timeline->isArchived()) {
        return; // No-op for already archived
    }

    $this->timeline->archive();

    AdminLog::create([
        'admin_id' => auth()->id(),
        'action' => 'archive',  // Note: field is 'action', not 'action_type'
        'target_type' => 'timeline',
        'target_id' => $this->timeline->id,
        'ip_address' => request()->ip(),
        'created_at' => now(),
    ]);

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

public function unarchive(): void
{
    if ($this->timeline->isActive()) {
        return; // No-op for already active
    }

    $this->timeline->unarchive();

    AdminLog::create([
        'admin_id' => auth()->id(),
        'action' => 'unarchive',  // Note: field is 'action', not 'action_type'
        'target_type' => 'timeline',
        'target_id' => $this->timeline->id,
        'ip_address' => request()->ip(),
        'created_at' => now(),
    ]);

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

> **Note:** The AdminLog model uses `action` field (not `action_type`). Also requires `created_at` since `$timestamps = false` on the model.

### Bulk Archive (Deferred to Story 4.4)
The `bulkArchive()` method will be implemented in Story 4.4 when the admin timeline index view is created.

## Tasks / Subtasks

- [x] **Task 1: Add Timeline model methods** (AC: Archive/Unarchive)
  - [x] Add `archive()` method using `TimelineStatus::Archived` enum
  - [x] Add `unarchive()` method using `TimelineStatus::Active` enum
  - [x] Add `isArchived()` helper method
  - [x] Add `isActive()` helper method
  - [x] Add `scopeActive()` query scope
  - [x] Add `scopeArchived()` query scope

- [x] **Task 2: Update show.blade.php component** (AC: Archive/Unarchive buttons)
  - [x] Add `archive()` action method with AdminLog
  - [x] Add `unarchive()` action method with AdminLog
  - [x] Add archive button (visible when timeline is active)
  - [x] Add unarchive button (visible when timeline is archived)
  - [x] Add confirmation modal using `<flux:modal>` for archive action
  - [x] Show archived status badge using `<flux:badge>`

- [x] **Task 3: Disable updates on archived timelines** (AC: No updates on archived)
  - [x] Conditionally disable/hide update form when `$timeline->isArchived()`
  - [x] Show tooltip or message explaining why updates are disabled
  - [x] Apply muted styling to archived timeline view

- [x] **Task 4: Add translation keys** (AC: Bilingual)
  - [x] Add EN/AR keys to `lang/*/messages.php`
  - [x] Add EN/AR keys to `lang/*/timelines.php`

- [x] **Task 5: Write feature tests** (AC: Quality Requirements)
  - [x] Create `tests/Feature/Admin/TimelineArchivingTest.php`
  - [x] Implement all test scenarios listed above
  - [x] Verify all tests pass

- [x] **Task 6: Code quality**
  - [x] Run `vendor/bin/pint --dirty`
  - [x] Verify no regressions in existing tests

## Definition of Done

- [x] Archive button on timeline detail view works with confirmation modal
- [x] Unarchive button on archived timelines works
- [x] Update form disabled/hidden on archived timelines with clear messaging
- [x] Visual indicators (badge + muted styling) display correctly
- [x] Audit log entries created for all archive/unarchive actions
- [x] All test scenarios in `tests/Feature/Admin/TimelineArchivingTest.php` pass
- [x] Code formatted with Pint

> **Deferred to Story 4.4/4.5:**
> - Status filter dropdown functional (Admin Dashboard)
> - Bulk archive with checkbox selection (Admin Dashboard)
> - Client can still view archived timelines in separate section (Client View)

## 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

## Dev Notes

### Source Tree Reference
```
app/
├── Models/
│   └── Timeline.php          # Add archive/unarchive methods and scopes
├── Enums/
│   └── TimelineStatus.php    # Already exists with Active/Archived values
resources/
└── views/
    └── livewire/
        └── admin/
            └── timelines/
                └── show.blade.php  # Add archive/unarchive UI and actions
tests/
└── Feature/
    └── Admin/
        └── TimelineArchivingTest.php  # New test file
```

### Required Translation Keys

**lang/en/messages.php:**
```php
'timeline_archived' => 'Timeline has been archived.',
'timeline_unarchived' => 'Timeline has been unarchived.',
'cannot_update_archived_timeline' => 'Updates cannot be added to archived timelines.',
```

**lang/ar/messages.php:**
```php
'timeline_archived' => 'تم أرشفة الجدول الزمني.',
'timeline_unarchived' => 'تم إلغاء أرشفة الجدول الزمني.',
'cannot_update_archived_timeline' => 'لا يمكن إضافة تحديثات إلى الجداول الزمنية المؤرشفة.',
```

**lang/en/timelines.php:**
```php
'archive' => 'Archive',
'unarchive' => 'Unarchive',
'archive_confirm_title' => 'Archive Timeline',
'archive_confirm_message' => 'Are you sure you want to archive this timeline? No further updates can be added until it is unarchived.',
'archived_notice' => 'This timeline is archived. Updates are disabled.',
```

**lang/ar/timelines.php:**
```php
'archive' => 'أرشفة',
'unarchive' => 'إلغاء الأرشفة',
'archive_confirm_title' => 'أرشفة الجدول الزمني',
'archive_confirm_message' => 'هل أنت متأكد من أرشفة هذا الجدول الزمني؟ لن يمكن إضافة تحديثات حتى يتم إلغاء الأرشفة.',
'archived_notice' => 'هذا الجدول الزمني مؤرشف. التحديثات معطلة.',
```

### Flux UI Components to Use
- `<flux:button variant="danger">` - Archive button
- `<flux:button variant="primary">` - Unarchive button
- `<flux:modal>` - Confirmation dialog
- `<flux:badge color="amber">` - Archived status indicator
- `<flux:tooltip>` - Disabled update form explanation

### Testing

**Test File:** `tests/Feature/Admin/TimelineArchivingTest.php`

**Testing Pattern:** Use Pest with `Volt::test()` for component testing (matches Stories 4.1/4.2)

**Required Factories:**
- `Timeline::factory()` with default active status
- `Timeline::factory()->archived()` state (may need to add)
- `User::factory()->admin()` for admin user
- `User::factory()->client()` for authorization tests

**Example Test Structure:**
```php
use App\Models\Timeline;
use App\Models\User;
use App\Models\AdminLog;
use Livewire\Volt\Volt;

beforeEach(function () {
    $this->admin = User::factory()->admin()->create();
    $this->client = User::factory()->individual()->create();
    $this->timeline = Timeline::factory()->for($this->client)->create();
});

test('admin can archive active timeline', function () {
    Volt::test('admin.timelines.show', ['timeline' => $this->timeline])
        ->actingAs($this->admin)
        ->call('archive')
        ->assertHasNoErrors();

    expect($this->timeline->fresh()->isArchived())->toBeTrue();
});
```

## Dev Agent Record

### Agent Model Used
Claude Opus 4.5

### File List
| File | Action |
|------|--------|
| `app/Models/Timeline.php` | Modified - Added archive/unarchive methods and scopes |
| `resources/views/livewire/admin/timelines/show.blade.php` | Modified - Added archive/unarchive actions, buttons, modal, visual indicators |
| `lang/en/messages.php` | Modified - Added archive-related translation keys |
| `lang/ar/messages.php` | Modified - Added archive-related translation keys |
| `lang/en/timelines.php` | Modified - Added archive UI translation keys |
| `lang/ar/timelines.php` | Modified - Added archive UI translation keys |
| `tests/Feature/Admin/TimelineArchivingTest.php` | Created - 17 test scenarios for archiving functionality |

### Debug Log References
None - Implementation completed without errors.

### Completion Notes
- All 17 archiving tests pass
- All 312 Admin feature tests pass (no regressions)
- Code formatted with Pint
- Bilingual support complete (AR/EN)
- Archive confirmation modal uses Flux UI components
- Muted styling applied to archived timelines
- Update form hidden with callout notice on archived timelines

## Change Log

| Date | Version | Description | Author |
|------|---------|-------------|--------|
| 2025-12-27 | 1.0 | Initial story draft | PM |
| 2025-12-27 | 1.1 | Validation fixes: re-scoped to exclude deferred features (filtering, bulk, client view), fixed AdminLog field name, fixed enum comparisons, added Tasks/Subtasks section, added translation keys, corrected test file path | Claude Opus 4.5 |
| 2025-12-27 | 1.2 | Implementation complete: Added Timeline model methods, archive/unarchive UI, translations, 17 passing tests | Claude Opus 4.5 |

## QA Results

### Review Date: 2025-12-27

### Reviewed By: Quinn (Test Architect)

### Code Quality Assessment

Excellent implementation following Laravel/Livewire best practices. The code is clean, well-organized, and follows the established patterns in the codebase. Key strengths:

- **Model Methods**: Proper use of TimelineStatus enum throughout, idempotent archive/unarchive operations
- **Volt Component**: Clean separation of archive/unarchive actions with proper AdminLog audit entries
- **UI Implementation**: Good UX with confirmation modal, visual indicators (badge + muted styling), and clear archived state messaging
- **Tests**: Comprehensive coverage with 17 tests covering all acceptance criteria including edge cases

### Refactoring Performed

None required. The implementation is clean and follows project conventions.

### Compliance Check

- Coding Standards: ✓ Pint passes with no issues
- Project Structure: ✓ Follows existing Volt component patterns
- Testing Strategy: ✓ Pest with Volt::test() as per codebase conventions
- All ACs Met: ✓ All acceptance criteria verified

### Improvements Checklist

All items addressed by developer:

- [x] Model methods (archive, unarchive, isArchived, isActive, scopes) implemented correctly
- [x] Archive button with confirmation modal implemented
- [x] Unarchive button implemented
- [x] Visual indicator (amber badge) for archived status
- [x] Muted styling (opacity-75/60) applied to archived timeline sections
- [x] Update form hidden with callout notice when archived
- [x] Edit buttons hidden on archived timeline updates
- [x] AdminLog audit entries created for archive/unarchive actions
- [x] Bilingual translations (EN/AR) complete
- [x] Factory state `archived()` available for testing
- [x] All 17 test scenarios pass

### Security Review

No security concerns. Authorization is properly handled:
- Admin middleware protects the route
- Guest and client access correctly returns 401/403
- Archive/unarchive actions only available to authenticated admins

### Performance Considerations

No performance concerns. Simple status updates with minimal database operations.

### Files Modified During Review

None - no modifications required.

### Gate Status

Gate: PASS → docs/qa/gates/4.3-timeline-archiving.yml

### Recommended Status

✓ Ready for Done

All acceptance criteria met, comprehensive test coverage, no security or performance concerns.
