# M05 — Tasks & Workflow

Phase 2. Matter-linked task management, driven by reusable checklist templates
so common workflows (e.g. "New Suit Filing") don't get re-typed every time.

## Dependencies
M03 (matters).

## Database

### `task_templates` / `task_template_items`
```php
// task_templates
$table->id();
$table->foreignId('firm_id')->constrained()->restrictOnDelete();
$table->string('name');                    // "New Suit Filing", "Corporate Retainer Onboarding"
$table->string('applies_to')->nullable();  // MatterType filter, or null = any
$table->boolean('is_active')->default(true);
$table->timestamps();

// task_template_items
$table->id();
$table->foreignId('task_template_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->unsignedSmallInteger('sort_order')->default(0);
$table->unsignedSmallInteger('due_offset_days')->nullable(); // days from matter open
$table->string('default_assignee_role')->nullable();         // lead_counsel/paralegal…
```

### `tasks`
```php
$table->id(); $table->ulid('ulid')->unique();
$table->foreignId('firm_id')->constrained()->restrictOnDelete();
$table->foreignId('matter_id')->nullable()->constrained()->nullOnDelete();
$table->string('title'); $table->text('description')->nullable();
$table->foreignId('assigned_to')->nullable()->constrained('users')->nullOnDelete();
$table->foreignId('assigned_by')->constrained('users');
$table->date('due_date')->nullable();
$table->string('priority')->default('normal');
$table->string('status')->default('open');   // open/in_progress/done/cancelled
$table->dateTime('completed_at')->nullable();
$table->timestamps(); $table->softDeletes();
$table->index(['firm_id', 'status', 'due_date']);
```

### `task_comments`
```php
$table->id();
$table->foreignId('task_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->text('comment'); $table->timestamps();
```

## Behaviour

- `App\Actions\Tasks\GenerateTasksFromTemplate::handle(Matter $matter, TaskTemplate $template)`
  — creates one task per template item, `due_date = matter.date_opened +
  due_offset_days`, `assigned_to` resolved from `default_assignee_role` against
  `matter_team` (fallback: unassigned, flagged for the lead counsel to triage).
- Auto-invoked by `RegisterMatter` (M03) when a template matches the new
  matter's type.
- Task completion writes a `matter_events` row ("task_completed") when a task
  has a `matter_id`.
- Overdue tasks (due_date < today, status not done/cancelled) surface on the
  matter page banner and the user's "My Tasks" widget (M10 dashboard).

## Routes

RESTful `tasks` (global + nested under matters for creation), plus:
```
PATCH /tasks/{task}/status         tasks.status.update
POST  /tasks/{task}/comments       tasks.comments.store
RESTful /task-templates            (admin management)
```

## Views

`tasks/index` ("My Tasks" default filter + firm-wide view for those with
`tasks.viewAll`; KPI: open, due today, overdue, completed this week; Kanban-style
status columns OR a filterable list — pick whichever the chosen template
supports better per `05a-TEMPLATE-MAP.md`). Matter page Tasks tab: scoped list +
quick-add. `task-templates/index` for admin management of checklists.

## Acceptance criteria

- [ ] Task templates CRUD; applying one to a matter creates correctly-offset,
      correctly-assigned tasks
- [ ] Matter registration with a matching template auto-generates its checklist
- [ ] Task status changes reflected on matter timeline when matter-linked
- [ ] Overdue tasks surface correctly on matter page and dashboard widget
- [ ] Comments thread works per task
- [ ] Cross-firm isolation + permission tests green

## Claude Code kickoff prompt

> Read CLAUDE.md, docs/03-DATA-MODEL.md, and this file, plus the M03 Matter
> model's `team()` relation (task assignee resolution depends on it).
> Implement: migrations → models → GenerateTasksFromTemplate Action (test
> offset/assignee resolution) → wire into RegisterMatter → controllers/routes →
> views → Pest tests.
