# 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: - `Timeline` model with fields: `user_id`, `case_name`, `case_reference`, `status` - `updates()` hasMany relationship on Timeline model - `timelines` table with foreign key to users - Admin can create timelines for any client - Initial notes saved as first timeline update ### Prerequisites - `Timeline` model with `updates()` relationship (from Story 4.1) - `TimelineUpdate` model (create in this story) - `AdminLog` model for audit logging (from Epic 1) - HTML sanitization: use `mews/purifier` package with `clean()` 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/purifier` package - [ ] 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 ```php 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 ```php // 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) ```php // In app/Models/Timeline.php - add this relationship public function updates(): HasMany { return $this->hasMany(TimelineUpdate::class)->orderBy('created_at', 'asc'); } ``` ### Setup Requirements ```bash # 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 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 `TimelineUpdateNotification` class with queued email - Notification will work once Epic 8 email infrastructure is ready ## Estimation **Complexity:** Medium **Estimated Effort:** 3-4 hours