# IAP Status Notifications — Design Spec
**Date:** 2026-03-26
**Author:** Eric Dunn

---

## Overview

Add automated candidate-facing email notifications for IAP status changes (New, Processing,
Eligible, Ineligible). Centralize all notification logic — including the existing Leadership
Review flow — into a shared helper to keep templates auditable in one place.

---

## Trigger Points

| Status | Trigger File | When |
|---|---|---|
| New | `submit_application.php` | On form submission (insert) |
| Processing (`ReviewedProcessing` in DB) | `sync_application_status.php` | On status save from detail page |
| Eligible | `sync_application_status.php` | On status save from detail page |
| Ineligible | `sync_application_status.php` | On status save from detail page |
| Leadership Review | `sync_application_status.php` | On status save from detail page (existing) |

---

## Email Specs

| Status | To | CC | Subject |
|---|---|---|---|
| New | candidate | hr@whitewatercw.com, recruiting@whitewatercw.com | Next Steps Required to Complete Your Application |
| Processing | candidate | — | Application Status Update |
| Eligible | candidate | — | Application Update – Eligible for Consideration |
| Ineligible | candidate | hr@whitewatercw.com, recruiting@whitewatercw.com | Application Update |
| Leadership Review | recipients[] (from DB) | — | Leadership Review — [Name] (existing behavior) |

---

## Email Bodies

### New
> Hi [first_name],
>
> Thank you for your interest in the opportunity! You're just one step away from completing your application.
>
> Please be sure to apply directly to the specific position you would like to be considered for via JazzHR.
>
> Once completed, you can expect an update regarding next steps within 72 business hours.
>
> If you have any questions, please don't hesitate to reach out.
>
> Best regards,
> Human Resources

### Processing
> Hi [first_name],
>
> Thank you for your application. Our submission is currently under review to confirm eligibility for the role.
>
> We appreciate your patience and will provide an update as soon as the review is complete.
>
> Best regards,
> Human Resources

### Eligible
> Hi [first_name],
>
> Congratulations! Based on our review, you meet the minimum requirements to be considered for the [position_applying_for] at [desired_location].
>
> Your application has been shared with the hiring manager, who will review your information and determine next steps. You will be contacted soon with an update on the next stage of the process.
>
> Best of luck, and again, thank you for your interest!
>
> Best regards,
> Human Resources

### Ineligible
> Hi [first_name],
>
> Thank you for your interest in the role. We regret to inform you that you do not meet the minimum requirements for the position you applied for at this time.
>
> A member of the HR team will follow up with you within 72 business hours to provide additional details.
>
> If you believe this decision has been made in error, please feel free to discuss your concerns directly with HR.
>
> We appreciate your interest and encourage you to apply for future opportunities that align with your qualifications.
>
> Best regards,
> Human Resources

---

## Architecture

### New File: `app/HR/IAP/iap_notifications.php`

```php
// Constants
IAP_HR_EMAIL        = 'hr@whitewatercw.com'
IAP_RECRUITING_EMAIL = 'recruiting@whitewatercw.com'
IAP_FROM_EMAIL      = 'noreply@whitewatercw.com'
IAP_FROM_NAME       = 'Human Resources'

// Function
send_iap_notification(string $status, array $app, array $options = []): void
```

**`$app` keys required:**
- `first_name`, `last_name`, `email`
- `position_applying_for`, `desired_location`
- `application_id`

**`$options` keys (Leadership Review only):**
- `recipients[]` — pre-validated email array
- `custom_message` — optional string

**Behavior:**
- Switches on `$status`, builds subject/body/recipients per spec above
- Sends via SendGrid (`envv('SENDGRID_API_KEY')`)
- If `$app['email']` is empty: skip candidate send, `error_log` it; HR/Recruiting CC's still fire for New and Ineligible
- On SendGrid error (status >= 400): `error_log`, do not throw
- Wrapped in try/catch — notification failure must never break submission or status save

---

### Changes to `submit_application.php`

Replace lines 114–137 (broken SendGrid block, `$hr_email = 'recruiting'` placeholder) with:

```php
require_once __DIR__ . '/iap_notifications.php';
send_iap_notification('New', [
    'first_name'            => $first_name,
    'last_name'             => $last_name,
    'email'                 => $email,
    'position_applying_for' => $position,
    'desired_location'      => $desired_location,
    'application_id'        => $application_id,
]);
```

---

### Changes to `sync_application_status.php`

1. Expand the app data SELECT (currently inside the Leadership Review block) to also fetch `email`. Hoist it up to run for all notifiable statuses.
2. Merge `application_id` into the `$app_row` array (it's already in scope as a variable).
3. Replace the Leadership Review SendGrid block (lines 44–85) with a `send_iap_notification()` call.
4. Add notification calls for Processing, Eligible, Ineligible.

**Updated SELECT:**
```sql
SELECT first_name, last_name, email, position_applying_for, desired_location
FROM internal_applications WHERE application_id = ?
```

```php
require_once __DIR__ . '/iap_notifications.php';

$notifiable = ['ReviewedProcessing', 'Leadership Review', 'Eligible', 'Ineligible'];
if (in_array($new_status, $notifiable) && $app_row) {
    $app_row['application_id'] = (int)$application_id;
    $options = [];
    if ($new_status === 'Leadership Review') {
        $options = ['recipients' => $safe_recipients, 'custom_message' => $notify_message];
    }
    send_iap_notification($new_status, $app_row, $options);
}
```

> Note: The Leadership Review recipient validation (whitelist query against `iap_leadership_recipients`) stays in `sync_application_status.php` — it's request-handling logic, not notification logic.

---

## Edge Cases

| Case | Handling |
|---|---|
| Candidate has no email | Skip candidate send, error_log; HR/Recruiting CC's still fire (New, Ineligible) |
| SendGrid API error | error_log the status code + body; do not break the status save |
| SendGrid key missing | error_log and skip; same pattern as current code |
| Unknown status passed to helper | No-op (no matching case) |

---

## Out of Scope

- No UI changes — notifications are fully automatic, no opt-out for candidate emails
- Leadership Review recipient UI (checkbox panel) unchanged
- `submitted_by` not shown on detail page (post-UAT enhancement, previously decided)
