# Template Variable Audit

Audit date: 2026-06-05

---

## Validation mechanism

`NotificationTemplate::render()`:

1. Substitutes scalar `data` keys into `{{key}}` placeholders  
2. Scans rendered subject/body for remaining `{{...}}`  
3. **Logs error** and throws `UnresolvedTemplatePlaceholderException` if any remain  
4. Notification send aborts — no broken email delivered

Test: `tests/Feature/Notifications/NotificationTemplateRenderTest.php`

---

## Agile / health templates

### `project_health_critical`

| Variable | Declared | Passed by listener | Status |
|----------|----------|-------------------|--------|
| `project_name` | ✓ | `NotifyOnHealthUpdated`, `AgileNotificationMonitorService` | ✓ |
| `project_id` | ✓ | Both | ✓ |
| `health_score` | ✓ | Both | ✓ |

### `project_health_at_risk`

| Variable | Declared | Passed | Status |
|----------|----------|--------|--------|
| `project_name` | ✓ | Both | ✓ |
| `project_id` | ✓ | Both | ✓ |

Note: Template body does not use `health_score`; no conflict.

### `sprint_health_at_risk` / `sprint_health_critical`

| Variable | Declared | Passed | Status |
|----------|----------|--------|--------|
| `sprint_name` | ✓ | `NotifyOnHealthUpdated`, `AgileNotificationMonitorService` | ✓ Fixed |
| `sprint_id` | ✓ | Both | ✓ |
| `project_id` | ✓ | Both | ✓ |

### `project_milestone_due` / `project_milestone_overdue`

| Variable | Declared | Passed | Status |
|----------|----------|--------|--------|
| `milestone_name` | ✓ | `AgileNotificationMonitorService` | ✓ Fixed |
| `milestone_id` | ✓ | Monitor | ✓ |
| `project_id` | ✓ | Monitor | ✓ |

### `project_risk_critical`

| Variable | Declared | Passed | Status |
|----------|----------|--------|--------|
| `risk_title` | ✓ | Risk event handlers | ✓ (existing) |
| `risk_id` | ✓ | Risk handlers | ✓ |
| `project_id` | ✓ | Risk handlers | ✓ |

---

## Before vs after examples

**Before (broken):**
```
Subject: Project {{project_name}} health critical
Body: Project health score is critical ({{health_score}}).
```

**After (rendered):**
```
Subject: Project Benefits Platform health critical
Body: Project health score is critical (39).
```

---

## Non-agile templates

All ticket/SLA templates in `NotificationTemplateSeeder` declare `variables[]` arrays. Ticket listeners pass `ticket_number`, `ticket_subject`, etc. via `NotificationService` — no unresolved placeholders detected in seeder definitions.

---

## Gaps / recommendations

| Template | Gap |
|----------|-----|
| `workload_overloaded` | Requires `user_name` — verify monitor passes it |
| Sprint start/end notifications | Templates use `sprint_name` — monitor now passes it |

Run `php artisan db:seed --class=NotificationTemplateSeeder` after template text changes.
