# 17 — Notification Settings

## Overview

A routing table that maps a vendor (or simply an email/phone) to outbound notification destinations. Used by an **external** notification dispatcher (email/SMS service) to know who to ping for events related to a given vendor. VisoAdmin only adds/deletes rows here — it does not itself dispatch mail or SMS based on these.

**Status:** Live (CRUD-on-row), but no sender code in this repo.

---

## User Stories

| ID | As a | I want to | So that |
|----|------|-----------|---------|
| NS-01 | Ops (perm 1) | Add an email + phone routing entry for a vendor | Outbound notifications reach the right inbox |
| NS-02 | Ops | See the existing routing list | Audit who's notified |
| NS-03 | Ops | Delete an outdated routing entry | Stop stale notifications |

---

## Screens & Flows

```
┌─────────────────────────────────┐
│ /setting/notification           │
│ notifications/setting.blade.php │
│  - Form: email, contact, vendor │
│  - Table of existing rows       │
└────────────┬────────────────────┘
             │
             ├── Add ──▶ POST /setting/addContact
             │              ▼
             │      INSERT INTO notification_setting
             │
             └── Delete ──▶ GET /setting/delete-email?id=N
                            ▼
                    DELETE FROM notification_setting WHERE id=N
```

### Routes & Actions

| Route | Method | Handler | Description |
|-------|--------|---------|-------------|
| `/setting/notification` | GET | `NotificationController::notification()` | List + add form |
| `/setting/addContact` | POST | `NotificationController::updateNotificationSetting()` | Insert a row |
| `/setting/delete-email` | GET | `NotificationController::deleteEmails()` | Delete a row by `?id=` |

The vendor dropdown is sourced from `/user/vendorListAjax` (Feature 05).

---

## Data Model

### `notification_setting`

```php
// App\Models\NotificationSetting
protected $table = 'notification_setting';
public $timestamps = true;

{
  id:           int,
  uuid:         string,        // generated by VisoAdmin on insert
  email:        string,        // required, valid email
  phone:        string,        // required (no format check)
  vendor_name:  string,        // free-text, copy of the dropdown label
  vendor_id:    int,           // FK users.id (the vendor)
  created_at,
  updated_at,
}
```

---

## Validations & Business Rules

| Rule | Detail |
|------|--------|
| `email_id` required + email | `required \| email` |
| `contact_number` required | `required` (no length/format check) |
| `vendor_id` required | `required` |
| Delete requires `id` | `required` |
| UUID server-set | `Str::uuid()->toString()` |
| Flash messages on success/failure | Session-flash pattern |
| No de-dupe check | Same vendor can have multiple rows (intentional — multiple destinations) |

---

## API Endpoints

| Method | Path | Auth | Request | Response | Consumer |
|--------|------|------|---------|----------|----------|
| GET | `/setting/notification` | session + permission 1 | — | HTML | Browser |
| POST | `/setting/addContact` | session + permission 1 | `email_id, contact_number, vendor_id, vendor_name` | redirect | Form |
| GET | `/setting/delete-email` | session + permission 1 | `?id=N` | redirect | List delete link |
| GET | `/user/vendorListAjax` | session (AJAX whitelisted) | — | Vendor dropdown source (see Feature 05) | Vendor dropdown |

---

## Upstream Impact

- **`users` (vendors)** — populates the vendor dropdown.

---

## Downstream Impact

- **External mail/SMS dispatcher** (not in this repo) — reads `notification_setting` rows to know whom to email/SMS when a vendor-specific event occurs.
- **Feature 05 (Vendor Mgmt) delete cascade** — removes `notification_setting` rows when a vendor is deleted.

---

## Impact of Changes

| If you change... | Risk to... | Level | Type |
|-----------------|------------|-------|------|
| Renaming `notification_setting.vendor_id` | Vendor delete cascade no longer cleans these rows | High | Data |
| Removing the unique `id` column | `delete-email?id=` deletes nothing | Critical | Data |
| Changing the format of `phone` | External dispatcher may reject SMS | Medium | Data |
| Adding `is_active` column | List & form must surface it; otherwise rows are silently active | Medium | UI |

---

## Known Issues

- **No de-dupe** — accidentally adding two rows for the same `(vendor_id, email)` is silent. Outbound emails may double up.
- **No phone format validation** — `+971...`, `00971...`, raw digits all accepted.
- **`vendor_name` is denormalised** — if a vendor renames themselves, the routing list shows the old name.
- **No bulk-import** — must add one row at a time.
- **`/setting/delete-email?id=N`** uses `where('id', $id)` with implicit cast — safe, but the GET-with-side-effect pattern is browser-prefetch dangerous (a hover-preview tool could trigger deletes).
