7.1 KiB
7.1 KiB
Story 4.2: Timeline Updates Management
Epic Reference
Epic 4: Case Timeline System
User Story
As an admin, I want to add and edit updates within a timeline, So that I can keep clients informed about their case progress.
Story Context
Existing System Integration
- Integrates with: timeline_updates table, timelines table
- Technology: Livewire Volt, rich text editor (Trix recommended)
- Follows pattern: Nested CRUD pattern
- Touch points: Client notifications, timeline view
Previous Story Context (Story 4.1)
Story 4.1 established:
Timelinemodel with fields:user_id,case_name,case_reference,statusupdates()hasMany relationship on Timeline modeltimelinestable with foreign key to users- Admin can create timelines for any client
- Initial notes saved as first timeline update
Prerequisites
Timelinemodel withupdates()relationship (from Story 4.1)TimelineUpdatemodel (create in this story)AdminLogmodel for audit logging (from Epic 1)- HTML sanitization: use
mews/purifierpackage withclean()helper - Rich text editor: Trix (ships with Laravel) or similar
Implementation Files
- Volt Component:
resources/views/livewire/pages/admin/timelines/updates.blade.php - Model:
app/Models/TimelineUpdate.php - Notification:
app/Notifications/TimelineUpdateNotification.php - Route:
admin.timelines.show(timeline detail page with updates section)
Acceptance Criteria
Add Update
- Add new update to timeline
- Update text content (required)
- Rich text formatting supported:
- Bold, italic, underline
- Bullet/numbered lists
- Links
- Timestamp automatically recorded
- Admin name automatically recorded
- Client notified via email on new update
Edit Update
- Edit existing update text
- Edit history preserved (updated_at changes)
- Cannot change timestamp or admin
Display
- Updates displayed in chronological order
- Each update shows:
- Date/timestamp
- Admin name
- Update content
- Visual timeline representation
Quality Requirements
- HTML sanitization using
mews/purifierpackage - Audit log for add/edit operations via AdminLog
- Feature tests for all operations
Test Scenarios
- Can add update with valid text (min 10 chars)
- Cannot add update with empty text - validation error
- Cannot add update with text < 10 chars - validation error
- HTML is sanitized (script tags, XSS vectors removed)
- Client receives notification email on new update
- Audit log created when update is added
- Audit log created when update is edited (includes old/new values)
- Updates display in chronological order (oldest first)
- Admin name and timestamp automatically recorded
- Edit preserves original created_at, updates updated_at
- Cannot change timestamp or admin on edit
Technical Notes
Database Schema
Schema::create('timeline_updates', function (Blueprint $table) {
$table->id();
$table->foreignId('timeline_id')->constrained()->cascadeOnDelete();
$table->foreignId('admin_id')->constrained('users');
$table->text('update_text');
$table->timestamps();
});
TimelineUpdate Model
// app/Models/TimelineUpdate.php
class TimelineUpdate extends Model
{
protected $fillable = ['timeline_id', 'admin_id', 'update_text'];
public function timeline(): BelongsTo
{
return $this->belongsTo(Timeline::class);
}
public function admin(): BelongsTo
{
return $this->belongsTo(User::class, 'admin_id');
}
}
Timeline Model Relationship (add to existing model)
// In app/Models/Timeline.php - add this relationship
public function updates(): HasMany
{
return $this->hasMany(TimelineUpdate::class)->orderBy('created_at', 'asc');
}
Setup Requirements
# Install HTML Purifier for sanitization
composer require mews/purifier
# Publish config (optional, defaults are secure)
php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"
Volt Component
<?php
use App\Models\{Timeline, TimelineUpdate, AdminLog};
use App\Notifications\TimelineUpdateNotification;
use Livewire\Volt\Component;
new class extends Component {
public Timeline $timeline;
public string $updateText = '';
public ?TimelineUpdate $editingUpdate = null;
public function addUpdate(): void
{
$this->validate([
'updateText' => ['required', 'string', 'min:10'],
]);
// clean() is from mews/purifier - sanitizes HTML, removes XSS vectors
$update = $this->timeline->updates()->create([
'admin_id' => auth()->id(),
'update_text' => clean($this->updateText),
]);
// Notify client (queued - works when Epic 8 email is ready)
$this->timeline->user->notify(new TimelineUpdateNotification($update));
AdminLog::create([
'admin_id' => auth()->id(),
'action_type' => 'create',
'target_type' => 'timeline_update',
'target_id' => $update->id,
'ip_address' => request()->ip(),
]);
$this->updateText = '';
session()->flash('success', __('messages.update_added'));
}
public function editUpdate(TimelineUpdate $update): void
{
$this->editingUpdate = $update;
$this->updateText = $update->update_text;
}
public function saveEdit(): void
{
$this->validate([
'updateText' => ['required', 'string', 'min:10'],
]);
$oldText = $this->editingUpdate->update_text;
$this->editingUpdate->update([
'update_text' => clean($this->updateText),
]);
AdminLog::create([
'admin_id' => auth()->id(),
'action_type' => 'update',
'target_type' => 'timeline_update',
'target_id' => $this->editingUpdate->id,
'old_values' => ['update_text' => $oldText],
'new_values' => ['update_text' => $this->updateText],
'ip_address' => request()->ip(),
]);
$this->editingUpdate = null;
$this->updateText = '';
session()->flash('success', __('messages.update_edited'));
}
public function cancelEdit(): void
{
$this->editingUpdate = null;
$this->updateText = '';
}
};
Definition of Done
- Can add new updates with rich text
- Can edit existing updates
- Updates display chronologically
- Admin name and timestamp shown
- Client notification sent
- HTML properly sanitized
- Audit log created
- Tests pass
- Code formatted with Pint
Dependencies
- Story 4.1: Timeline creation (REQUIRED - must be complete)
- Epic 8: Email notifications (SOFT DEPENDENCY)
- If Epic 8 is not complete, implement notification dispatch but skip email tests
- Create
TimelineUpdateNotificationclass with queued email - Notification will work once Epic 8 email infrastructure is ready
Estimation
Complexity: Medium Estimated Effort: 3-4 hours