155 lines
3.5 KiB
Markdown
155 lines
3.5 KiB
Markdown
# 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
|
|
- **Technology:** Livewire Volt
|
|
- **Follows pattern:** Soft state change pattern
|
|
- **Touch points:** Timeline list views
|
|
|
|
## Acceptance Criteria
|
|
|
|
### Archive Timeline
|
|
- [ ] Archive button on timeline detail
|
|
- [ ] Status changes to 'archived'
|
|
- [ ] Timeline remains visible to client
|
|
- [ ] No further updates can be added (until unarchived)
|
|
- [ ] Visual indicator shows archived status
|
|
|
|
### Unarchive Timeline
|
|
- [ ] Unarchive button on archived timelines
|
|
- [ ] Status returns to 'active'
|
|
- [ ] Updates can be added again
|
|
|
|
### List Filtering
|
|
- [ ] Filter timelines by status (active/archived/all)
|
|
- [ ] Archived timelines sorted separately in client view
|
|
- [ ] Bulk archive option for multiple timelines
|
|
|
|
### Quality Requirements
|
|
- [ ] Audit log for status changes
|
|
- [ ] Bilingual labels
|
|
- [ ] Tests for archive/unarchive
|
|
|
|
## 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
|
|
|
|
- [ ] Can archive active timeline
|
|
- [ ] Can unarchive archived timeline
|
|
- [ ] Cannot add updates to archived timeline
|
|
- [ ] Filter by status works
|
|
- [ ] Bulk archive works
|
|
- [ ] Visual indicators correct
|
|
- [ ] Audit log created
|
|
- [ ] Tests pass
|
|
- [ ] Code formatted with Pint
|
|
|
|
## Dependencies
|
|
|
|
- **Story 4.1:** Timeline creation
|
|
- **Story 4.2:** Timeline updates
|
|
|
|
## Estimation
|
|
|
|
**Complexity:** Low
|
|
**Estimated Effort:** 2 hours
|