# Notification System Blueprint (Phase 10 + Realtime Extension)

Complete implementation guide for ERPFlow notifications so the team can ship in controlled steps.

**Audience:** Backend + Frontend developers, DevOps  
**Related:** [IMPLEMENTATION_PHASES.md](../IMPLEMENTATION_PHASES.md)

---

## 1) Objectives

Build a platform-level notification engine that is:

- Channel-based (database, email first)
- Template-driven (event key + placeholders)
- Queue-friendly (retry, delay, escalation)
- Company-aware and user-targeted
- Realtime-ready (initially optional, then extend)

---

## 2) Scope

## In Scope (Phase 10 Core)

- Database notifications (in-app bell + notifications page)
- Email notifications for critical workflow events
- Notification templates table + renderer
- Notification APIs (list, mark read, mark all read, unread count)
- Approval assignment reminder + escalation jobs (queued)
- Stub provider contracts for SMS/Push/Realtime

## Out of Scope (Phase 10 Core)

- Real SMS provider integration
- Real push provider integration (FCM/APNS)
- Full websocket live delivery (planned as extension)

---

## 3) High-Level Architecture

```mermaid
flowchart LR
    A[Domain Event<br/>approval.assigned] --> B[NotificationEngine]
    B --> C[Template Resolver]
    B --> D[Recipient Resolver]
    B --> E[Channel Router]

    E --> F[Database Channel]
    E --> G[Email Channel]
    E --> H[SMS Provider Stub]
    E --> I[Push Provider Stub]
    E --> J[Realtime Provider Stub]

    F --> K[(notifications)]
    G --> L[Mail Queue]
```

Core principle: **one business event** can fan out to **multiple channels** using policy rules.

---

## 4) Data Model

## 4.1 `notifications` (Laravel table, extended by usage)

Use Laravel's standard notifications table (`id`, `type`, `notifiable_type`, `notifiable_id`, `data`, `read_at`), with payload conventions:

- `event_key` (example: `approval.assigned`)
- `title`
- `message`
- `action_url`
- `module_slug`
- `company_id`
- `priority` (`low|normal|high|critical`)
- `meta` (JSON)

## 4.2 `notification_templates`

Suggested columns:

- `id` (uuid or bigint)
- `event_key` (unique per channel + locale)
- `channel` (`database|email|sms|push|realtime`)
- `locale` (default `en`)
- `subject` (nullable for database)
- `body` (template body with placeholders)
- `variables` (JSON schema of allowed placeholders)
- `is_active` (bool)
- `created_at`, `updated_at`

Example placeholders:

- `{{recipient_name}}`
- `{{request_code}}`
- `{{workflow_name}}`
- `{{action_url}}`

---

## 5) Backend Design (Laravel)

Follow ERPFlow Service/Repository/Contract conventions.

## 5.1 Contracts

- `NotificationEngineContract`
- `NotificationChannelContract`
- `TemplateRendererContract`
- `RecipientResolverContract`
- `SmsProviderInterface` (stub)
- `PushProviderInterface` (stub)
- `RealtimeProviderInterface` (stub)

## 5.2 Services

- `NotificationEngine`
  - entrypoint: `send(eventKey, recipients, context, options)`
  - resolves templates + channels + dispatch strategy
- `NotificationTemplateService`
  - fetch active templates
  - fallback locale logic
- `NotificationPreferenceService` (future-ready)
  - per-user channel toggle support
- `ApprovalReminderService`
  - schedules reminder/escalation jobs

## 5.3 Channel Implementations

- `DatabaseNotificationChannel`
  - writes to Laravel notifications table
- `EmailNotificationChannel`
  - sends queued mailable / notification mail
- `SmsNotificationChannel` (stub)
- `PushNotificationChannel` (stub)
- `RealtimeNotificationChannel` (stub for Phase 10)

## 5.4 Events to integrate first

- `approval.assigned` (mandatory)
- `approval.reminder` (mandatory)
- `approval.escalated` (mandatory)
- `approval.completed` (nice-to-have)
- `approval.rejected` (nice-to-have)

---

## 6) API Contract (v1)

Base: `/api/v1`

| Method | Endpoint | Purpose |
|---|---|---|
| GET | `/notifications` | paginated list |
| GET | `/notifications/unread-count` | unread badge count |
| POST | `/notifications/{id}/read` | mark single as read |
| POST | `/notifications/read-all` | mark all read |
| GET | `/notifications/preferences` | (optional future) |
| PUT | `/notifications/preferences` | (optional future) |

## Response shape (recommended)

```json
{
  "success": true,
  "message": "Notifications fetched successfully.",
  "data": {
    "items": [
      {
        "id": "uuid-or-ulid",
        "event_key": "approval.assigned",
        "title": "New approval request",
        "message": "Request APV-2026-001 needs your action",
        "action_url": "/approvals/requests/123",
        "is_read": false,
        "created_at": "2026-07-02T08:12:45Z",
        "priority": "high"
      }
    ],
    "pagination": {}
  }
}
```

---

## 7) Frontend Design (React + Query)

## 7.1 UI surfaces

- Header bell dropdown (latest N notifications)
- Unread badge counter
- Full notifications page (filters + pagination)
- Mark-read and mark-all-read actions

## 7.2 State approach

- TanStack Query as source of truth
- Shared notification query keys:
  - `notifications:list`
  - `notifications:unread-count`
- Optimistic updates for read actions
- Polling fallback every 30-60s in Phase 10 core

## 7.3 UX rules

- Clicking item marks it read then navigates `action_url`
- Critical notifications visually highlighted
- Empty state + loading skeleton + error retry

---

## 8) Queue, Scheduler, Reliability

## 8.1 Jobs

- `DispatchNotificationJob`
- `SendApprovalReminderJob`
- `SendApprovalEscalationJob`

## 8.2 Reliability policies

- Retry with backoff for email failures
- Dead-letter/error logging strategy
- Idempotency key: avoid duplicate send on retry race
- Database notification should be attempted before non-critical channels

## 8.3 Scheduler

- Cron-driven check for pending approvals needing reminder/escalation
- Configurable intervals per workflow/policy

---

## 9) Realtime Extension (Phase 10.1)

After core notifications are stable, add live delivery.

## 9.1 Infrastructure required

- Redis (queue + pub/sub)
- Reverb server (recommended) or Pusher-compatible gateway
- Queue worker service

## 9.2 Backend changes

- Broadcast notification-created event to private user channels
- Channel auth in `routes/channels.php`
- Guard compatibility with JWT

## 9.3 Frontend changes

- `laravel-echo` client bootstrap
- subscribe: `private-user.{userId}`
- update query cache on message receive
- reconnect handling + API resync

## 9.4 Realtime fallback

If socket disconnected, keep periodic polling active.

---

## 10) Docker/Infra Plan

## Phase 10 Core infra (minimum)

- Existing `mysql`, `backend`, `backend-nginx`, `frontend`
- Add/ensure:
  - `backend-worker` (queue worker)
  - `backend-scheduler` (schedule worker)

## Realtime extension infra

- `redis`
- `reverb`

Recommended dev topology:

```mermaid
flowchart TB
    FE[Frontend] --> NGINX[backend-nginx]
    NGINX --> API[backend]
    API --> DB[(mysql)]
    API --> Q[(redis)]
    WORKER[backend-worker] --> Q
    REVERB[reverb] --> Q
    FE --> REVERB
```

---

## 11) Security & Governance

- All notification APIs require auth
- Filter by current company scope
- Never expose sensitive raw payloads in UI
- Template variable whitelist validation
- Rate limit read/mark endpoints
- Audit log integration for notification dispatch failures and template changes

---

## 12) Testing Strategy

## Backend tests

- Unit: template render, channel routing, recipient resolve
- Feature: list/read/read-all APIs
- Integration: approval event triggers database + email dispatch
- Queue test: retry + failure path

## Frontend tests

- Bell badge count rendering
- Dropdown list rendering and click behavior
- Mark-read optimistic update
- Polling refresh behavior

## Manual UAT checklist

- Approval assignment creates notification row
- Email delivered (or queued) successfully
- Bell count increases/decreases correctly
- Mark-all-read updates all unread rows
- Pagination and filters work

---

## 13) Rollout Plan

## Milestone A — Foundation

- Migrations + contracts + basic engine skeleton

## Milestone B — Core Channels

- Database + email channels + template loader

## Milestone C — Approval Integration

- Assignment, reminder, escalation hooks + jobs

## Milestone D — UI/API

- Bell, page, unread badge, read APIs

## Milestone E — Hardening

- retries, logs, security review, test coverage

## Milestone F — Realtime Extension (optional)

- Redis + Reverb + Echo integration

---

## 14) Definition of Done

Phase 10 considered done when:

- Approval assignment sends database + email notifications
- Notifications are visible from bell dropdown + full page
- Unread badge + read/mark-all endpoints work
- Reminder + escalation jobs run from queue/scheduler
- Stub interfaces exist for SMS/Push/Realtime (without provider integration)

Realtime extension considered done when:

- New notifications appear live without page refresh
- Socket disconnect gracefully falls back to polling
- Private channel auth is secure and company-aware

---

## 15) Suggested Folder Targets

```text
backend/app/Platform/
├── Contracts/
│   ├── NotificationEngineContract.php
│   ├── NotificationChannelContract.php
│   └── ...
├── DTOs/
│   └── SendNotificationData.php
├── Services/
│   ├── NotificationEngine.php
│   ├── NotificationTemplateService.php
│   └── ApprovalReminderService.php
├── Channels/
│   ├── DatabaseNotificationChannel.php
│   ├── EmailNotificationChannel.php
│   └── ...
├── Http/
│   ├── Controllers/Api/NotificationController.php
│   ├── Requests/...
│   └── Resources/NotificationResource.php
└── Jobs/
    ├── DispatchNotificationJob.php
    ├── SendApprovalReminderJob.php
    └── SendApprovalEscalationJob.php
```

```text
frontend/src/modules/platform/notifications/
├── api/notificationsApi.ts
├── hooks/useNotifications.ts
├── components/NotificationBell.tsx
└── pages/NotificationListPage.tsx
```

---

## 16) Notes for Implementation Session

When the team starts coding:

1. Implement Phase 10 core first (no realtime dependency).
2. Keep API contract stable; frontend should not depend on channel internals.
3. Add realtime only after queue + API + UI are stable.
4. Keep SMS/Push/Realtime provider contracts minimal and testable.

---

*Document version: v1 (planning baseline before implementation).*
