reviewed epic 4
This commit is contained in:
@@ -12,10 +12,31 @@ So that **I can keep clients informed about their case progress**.
|
||||
|
||||
### Existing System Integration
|
||||
- **Integrates with:** timeline_updates table, timelines table
|
||||
- **Technology:** Livewire Volt, rich text editor
|
||||
- **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
|
||||
@@ -43,9 +64,22 @@ So that **I can keep clients informed about their case progress**.
|
||||
- [ ] Visual timeline representation
|
||||
|
||||
### Quality Requirements
|
||||
- [ ] HTML sanitization for security
|
||||
- [ ] Audit log for edits
|
||||
- [ ] Tests for add/edit operations
|
||||
- [ ] 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
|
||||
|
||||
@@ -60,11 +94,48 @@ Schema::create('timeline_updates', function (Blueprint $table) {
|
||||
});
|
||||
```
|
||||
|
||||
### 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
|
||||
<?php
|
||||
|
||||
use App\Models\{Timeline, TimelineUpdate};
|
||||
use App\Models\{Timeline, TimelineUpdate, AdminLog};
|
||||
use App\Notifications\TimelineUpdateNotification;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
@@ -79,12 +150,13 @@ new class extends Component {
|
||||
'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), // Sanitize HTML
|
||||
'update_text' => clean($this->updateText),
|
||||
]);
|
||||
|
||||
// Notify client
|
||||
// Notify client (queued - works when Epic 8 email is ready)
|
||||
$this->timeline->user->notify(new TimelineUpdateNotification($update));
|
||||
|
||||
AdminLog::create([
|
||||
@@ -131,6 +203,12 @@ new class extends Component {
|
||||
$this->updateText = '';
|
||||
session()->flash('success', __('messages.update_edited'));
|
||||
}
|
||||
|
||||
public function cancelEdit(): void
|
||||
{
|
||||
$this->editingUpdate = null;
|
||||
$this->updateText = '';
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
@@ -148,8 +226,11 @@ new class extends Component {
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Story 4.1:** Timeline creation
|
||||
- **Epic 8:** Email notifications
|
||||
- **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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user