Skip to content
Mohammed edited this page Apr 17, 2026 · 132 revisions

NotifyEngine


NotifyEngine Logo

NotifyEngine

ML-Powered Notification Delivery Service with Adaptive Channel Routing

Website


Project Description

NotifyEngine is an intelligent notification routing service that learns from user behavior to automatically choose the best delivery channel (email, SMS, push, or in‑app) for every message. Designed for developers and product teams sending high‑volume notifications, it replaces static routing rules with an XGBoost ML model that adapts per‑user in real time.

Project Description as PDF | Download Project Description as DOCX


Team Members


Zeeya Ramani
Data Analyst / Developer

Salvatore Ardisi
AI Engineer / Developer

Rhythm Patel
AI Engineer / Developer

Dhawalshree Mengane
Data Analyst / Developer

Mohammed Nazir Yusif
Security Engineer / Project Manager

Krish Dhorajiya
AI Engineer / Tester

Project Design

Architecture at a Glance

                                         ┌───────────────────┐
                                         │   React Dashboard │
                                         │  (Vite + Tailwind)│
                                         └────────┬──────────┘
                                                  │ HTTP + WebSocket
                                                  ▼
┌──────────┐    POST notifications       ┌──────────────────┐     ┌──────────────┐
│ Developer│ ──────────────────────────► │  API Server      │────►│ PostgreSQL   │
│  Client  │ ◄── 202 Accepted            │  Express + TS    │     │ (Multi-tenant│
└──────────┘                             └────────┬─────────┘     │  + RLS)      │
                                                  │ Enqueue       └──────────────┘
                                                  ▼                      ▲
                                         ┌─────────────────┐             │
                                         │  Redis + BullMQ │             │
                                         │  (Job Queue)    │             │
                                         └────────┬────────┘             │
                                                  │ Dequeue              │
                                                  ▼                      │
                                         ┌────────────────┐              │
                                         │   Worker       │──────────────┘
                                         │  (Delivery +   │
                                         │ Feature Ext.)  │
                                         └───┬────────┬───┘
                                             │        │
                              ┌──────────────┘        └──────────────────┐
                              ▼                                          ▼
                     ┌───────────────────┐                    ┌─────────────────────┐
                     │  ML Service       │                    │  Delivery Channels  │
                     │  FastAPI + XGBoost│                    │  Email              │
                     │  Epsilon-Greedy   │                    │  Push               │
                     └───────────────────┘                    │  SMS                │
                                                              │  In-App             │
                                                              └─────────────────────┘
Component Technology Purpose
API Server Node.js, Express, TypeScript Request handling, auth, validation, enqueuing
Worker Node.js, BullMQ, TypeScript Feature extraction, ML routing, delivery execution
ML Service Python, FastAPI, XGBoost Engagement prediction, epsilon-greedy exploration
Database PostgreSQL 16 Multi-tenant storage with row-level security
Cache/Queue Redis + BullMQ Async job processing, rate limiting, caching
Dashboard React, Vite, Tailwind, shadcn/ui Real-time analytics, routing intelligence, notification explorer
Real-time Socket.IO In-app delivery channel + live dashboard updates
Observability Prometheus, Grafana, Pino Metrics, dashboards, structured JSON logging
CI/CD Docker, GitHub Actions Containerized deployment, automated testing, secret scanning

Core Algorithms

Algorithm Role How It Works
XGBoost Channel Prediction Decision trees trained on delivery outcomes. Each tree corrects the previous tree's errors. Outputs per-channel engagement probability-highest wins.
Epsilon-Greedy Exploration Strategy 90% exploit (use model's best prediction), 10% explore (try alternative channels). Prevents the model from getting stuck on old data.
Circuit Breaker Reliability Monitors provider failure rates in real-time. Opens on threshold -> reroutes to next-best channel -> auto-recovers utilizing a half-open test after cooldown.

Diagrams

Architecture Diagram

graph LR
    CLIENT["Developer / Client App"]
    DASHUSER["Dashboard User<br/>(Tenant Admin)"]

    subgraph HOST["Host Machine - Node.js Services"]
        direction TB
        DASH["Dashboard<br/>React + Vite<br/>Port 5173"]
        API["API Server<br/>Express + TypeScript<br/>Port 3000<br/>Socket.IO /dashboard"]
        WORKER["Delivery Worker<br/>BullMQ + TypeScript<br/>4 Priority Queues<br/>Feature Extraction"]
    end

    subgraph DOCKER["Docker Compose - Infrastructure"]
        direction TB
        REDIS["Redis 7<br/>Port 6379<br/>BullMQ + Pub/Sub"]
        PG["PostgreSQL 16<br/>Port 5432<br/>Multi-tenant RLS"]
        ML["ML Service<br/>Python FastAPI<br/>Port 8000<br/>XGBoost"]
        MAILPIT["Mailpit<br/>SMTP 1025<br/>UI 8025"]
    end

    CLIENT -->|"POST /v1/notifications"| API
    CLIENT -->|"GET /v1/notifications/:id"| API
    DASHUSER --> DASH
    DASH -->|"REST API"| API
    DASH -.->|"Socket.IO /dashboard"| API

    API -->|"SHA-256 auth<br/>RLS context"| PG
    API -->|"Enqueue jobs"| REDIS
    API -.->|"SUBSCRIBE<br/>dashboard:events"| REDIS

    WORKER -->|"Pick up jobs"| REDIS
    WORKER -->|"Record attempts<br/>Update status"| PG
    WORKER -->|"POST /predict"| ML
    WORKER -->|"SMTP send"| MAILPIT
    WORKER -.->|"PUBLISH<br/>dashboard:events"| REDIS

    ML -->|"Training data<br/>Model metadata"| PG

    style DOCKER fill:#1a1a2e,color:#e0e0e0
    style HOST fill:#16213e,color:#e0e0e0
    style CLIENT fill:#0f3460,color:#e0e0e0
    style DASHUSER fill:#0f3460,color:#e0e0e0
Loading

Service Boundaries

Service Technology Responsibility Does NOT
API Server Express + TypeScript Auth, validation, rate limiting, enqueue, REST endpoints, Socket.IO dashboard events Deliver notifications, call ML service, process BullMQ jobs
Worker Node.js + BullMQ Job processing, feature extraction, ML routing calls, delivery execution, outcome recording Serve HTTP endpoints, train ML models
ML Service Python + FastAPI XGBoost prediction, model training, synthetic data generation Serve notifications, connect to queue
Dashboard React + Vite Admin UI, real-time feed, routing intelligence visualization Connect to DB directly, call ML service
PostgreSQL PostgreSQL 16 All persistent data with Row-Level Security per tenant -
Redis Redis 7 + BullMQ Job queuing, rate limiting, usage counters, pub/sub events -

ER Diagram

erDiagram
    TENANTS ||--o{ API_KEYS : "authenticates via"
    TENANTS ||--o{ CHANNELS : "delivers through"
    TENANTS ||--o{ NOTIFICATIONS : "sends"
    TENANTS ||--o{ RECIPIENT_CHANNEL_STATS : "tracks engagement for"
    TENANTS ||--o{ MODEL_METADATA : "trains models for"
    TENANTS ||--o{ USAGE_RECORDS : "meters usage for"
    NOTIFICATIONS ||--o{ DELIVERY_ATTEMPTS : "attempted via"
    CHANNELS ||--o{ DELIVERY_ATTEMPTS : "delivered through"

    TENANTS {
        uuid id PK
        string name
        string slug UK
        string plan
        boolean adaptive_routing_enabled
        float exploration_rate
    }

    API_KEYS {
        uuid id PK
        uuid tenant_id FK
        string key_hash UK
        string key_prefix
        string scopes
    }

    CHANNELS {
        uuid id PK
        uuid tenant_id FK
        string type
        string label
        int priority
        boolean is_enabled
        string circuit_state
    }

    NOTIFICATIONS {
        uuid id PK
        uuid tenant_id FK
        string recipient
        string routing_mode
        string priority
        string status
        jsonb routing_decision
    }

    DELIVERY_ATTEMPTS {
        uuid id PK
        uuid tenant_id FK
        uuid notification_id FK
        uuid channel_id FK
        string status
        boolean engaged
        jsonb feature_vector
    }

    RECIPIENT_CHANNEL_STATS {
        uuid id PK
        uuid tenant_id FK
        string recipient
        string channel_type
        int attempts_30d
        int engagements_30d
    }

    MODEL_METADATA {
        uuid id PK
        uuid tenant_id FK
        string version
        float auc_roc
        boolean is_active
        jsonb feature_importance
    }

    USAGE_RECORDS {
        uuid id PK
        uuid tenant_id FK
        date period_start
        int notifications_sent
    }
Loading

Context Diagram

graph TB
    DEV["Developer / Client Application<br/>(Tenant)"]
    ADMIN["Dashboard User<br/>(Tenant Admin)"]

    subgraph SYSTEM["NotifyEngine"]
        CORE["Notification Delivery Service<br/>with ML-Powered Adaptive Routing"]
    end

    EMAIL_PROV["Email Provider<br/>(Mailpit / SES)"]
    SMS_PROV["SMS Provider<br/>(Webhook-based)"]
    RECIPIENT["Notification Recipient<br/>(End User)"]

    DEV -->|"POST /v1/notifications<br/>API Key Authentication<br/>JSON payload"| SYSTEM
    DEV -->|"GET /v1/notifications/:id<br/>Check delivery status"| SYSTEM
    DEV -->|"POST /v1/tenants/register<br/>Create account + API key"| SYSTEM

    ADMIN -->|"View dashboard<br/>Monitor notifications<br/>Check delivery stats"| SYSTEM

    SYSTEM -->|"SMTP email delivery<br/>HTML + plain text"| EMAIL_PROV
    SYSTEM -->|"HTTP POST webhook<br/>HMAC-signed payload"| SMS_PROV
    SYSTEM -.->|"WebSocket push<br/>Socket.IO real-time<br/>(Sprint 2)"| RECIPIENT

    EMAIL_PROV -->|"Email arrives<br/>in inbox"| RECIPIENT
    SMS_PROV -->|"SMS delivered<br/>to phone"| RECIPIENT

    RECIPIENT -.->|"Opens email<br/>(tracking pixel)"| SYSTEM
    RECIPIENT -.->|"Acknowledges WebSocket<br/>(ws_ack event)<br/>(Sprint 2)"| SYSTEM

    style SYSTEM fill:#1a1a2e,stroke:#334155,color:#e0e0e0
    style DEV fill:#0f3460,stroke:#1e3a5f,color:#e0e0e0
    style ADMIN fill:#0f3460,stroke:#1e3a5f,color:#e0e0e0
    style EMAIL_PROV fill:#4a1d6a,stroke:#5b2d7a,color:#e0e0e0
    style SMS_PROV fill:#4a1d6a,stroke:#5b2d7a,color:#e0e0e0
    style RECIPIENT fill:#1b4332,stroke:#2d6a4f,color:#e0e0e0
    style CORE fill:#16213e,stroke:#1e3a5f,color:#e0e0e0
Loading

Sequence Diagram

sequenceDiagram
    autonumber
    participant Client as Developer
    participant API as API Server
    participant PG as PostgreSQL
    participant Redis as Redis / BullMQ
    participant Worker as Delivery Worker
    participant Email as Mailpit (SMTP)

    Note over Client,Email: Phase 1 - Send Notification

    Client->>API: POST /v1/notifications<br/>Authorization: Bearer ne_test_...
    API->>PG: SELECT from api_keys<br/>WHERE key_hash = SHA-256(token)
    PG-->>API: tenant_id, scopes
    API->>PG: SET tenant context (set_config)
    API->>PG: Validate with Zod, then<br/>INSERT notification (status: pending)
    PG-->>API: notification id
    API->>Redis: Enqueue to notifications-{priority}
    API->>PG: UPDATE status = 'queued'
    API-->>Client: 202 Accepted<br/>{ id, status: queued, status_url }

    Note over Client,Email: Phase 2 - Delivery

    Redis->>Worker: Job picked up
    Worker->>PG: SET tenant context (set_config)
    Worker->>PG: UPDATE status = 'processing'
    Worker->>PG: SELECT channels<br/>WHERE is_enabled AND circuit_state = closed<br/>ORDER BY priority DESC

    alt Sprint 1 - Static Routing
        Note over Worker: Try channels in priority order
    else Sprint 2 - Adaptive Routing
        Worker->>Worker: Call ML Service /predict<br/>Epsilon-greedy channel selection
    end

    Worker->>Email: SMTP send to recipient
    Email-->>Worker: 250 OK

    Worker->>PG: INSERT delivery_attempt<br/>(status: success, duration_ms, tenant_id)
    Worker->>PG: UPDATE notification<br/>status = delivered, delivered_via = email
    Worker->>PG: RESET tenant context

    Note over Client,Email: Phase 3 - Status Check

    Client->>API: GET /v1/notifications/:id<br/>Authorization: Bearer ne_test_...
    API->>PG: SELECT notification + delivery_attempts
    PG-->>API: Full notification with attempts array
    API-->>Client: 200 OK<br/>{ status: delivered, delivered_via: email,<br/>delivery_attempts: [...] }

    Note over Client,Email: Phase 4 - Failure Path (if all channels fail)

    Worker->>PG: UPDATE status = 'failed'
    Note over Worker,Redis: BullMQ retries with exponential backoff
    Worker->>Redis: After max retries: move to DLQ
    Worker->>PG: UPDATE status = 'dlq'
Loading

Worker Lifecycle Diagram

flowchart LR
    START(["Job arrives"]) --> STEP1

    subgraph WORKER["Delivery Worker - per-job lifecycle"]
        direction LR
        STEP1["1 - Pick job<br/>from BullMQ"]
        STEP2["2 - SET tenant context<br/>in Postgres"]
        STEP3["3 - Query channels<br/>from Postgres"]
        STEP4["4 - Extract features<br/>14 per channel"]
        STEP5{"Routing mode?"}
        STEP6A["6a - Static fallback<br/>priority order"]
        STEP6B["6b - Call ML /predict<br/>epsilon-greedy"]
        STEP7["7 - Deliver<br/>Email / WebSocket / Webhook"]
        STEP8["8 - INSERT delivery_attempt<br/>with feature_vector"]
        STEP9["9 - UPDATE notification status<br/>delivered / failed"]
        STEP10["10 - PUBLISH dashboard:events<br/>to Redis"]
        STEP11["11 - RESET tenant context<br/>release DB client"]

        STEP1 --> STEP2 --> STEP3 --> STEP4 --> STEP5
        STEP5 -->|Sprint 2 adaptive| STEP6B
        STEP5 -->|Sprint 1 static| STEP6A
        STEP6A --> STEP7
        STEP6B --> STEP7
        STEP7 --> STEP8 --> STEP9 --> STEP10 --> STEP11
    end

    STEP11 --> FINISH(["Job complete"])

    style WORKER fill:#16213e,color:#e0e0e0
    style START fill:#0f3460,color:#e0e0e0
    style FINISH fill:#0f3460,color:#e0e0e0
    style STEP5 fill:#4a3a1a,color:#e0e0e0
Loading

Languages and Tools

Languages & Frameworks

TypeScript Node.js Express React Vite Python FastAPI

ML & Data Science

XGBoost scikit--learn pandas

Databases & Infrastructure

PostgreSQL Redis Socket.IO BullMQ

UI

Tailwind CSS shadcn/ui

Validation

Zod Pydantic

Observability

Prometheus Grafana Pino

Testing

Jest pytest

DevOps & CI/CD

Docker GitHub Actions

Tools

GitHub Jira Slack VS Code Claude ChatGPT


NotifyEngine Final Artifacts


Application Manuals

NotifyEngine Technical Paper


CS691 - Spring 2026 Deliverables


Presentations (Sprint Reviews)

Sprint 0

Watch Sprint 0 Presentation Video | Click here to download mp4 File
1a. View Sprint 0 Presentation Slides as PDF
1b. Download Sprint 0 Presentation Slides as PowerPoint

Sprint 1

Watch Sprint 1 Presentation Video | Click here to download mp4 File
2a. View Sprint 1 Presentation Slides as PDF
2b. Download Sprint 1 Presentation Slides as PowerPoint
2c. Prototype
2d. Watch Sprint 1 Demo Video | Click here to download mp4 File
2e. [Sprint 1 Source Code]

Sprint 2

Watch Sprint 2 Presentation Video | Click here to download mp4 File
3a. View Sprint 2 Presentation Slides as PDF
3b. Download Sprint 2 Presentation Slides as PowerPoint
3c. Watch Sprint 2 Demo Video | Click here to download mp4 File
3d. [Sprint 2 Source Code]


Sprint Burndown Charts and Completed Tasks

  1. Sprint 0 Completed Tasks
  2. Sprint 1 Burndown Chart and Completed Tasks
  3. Sprint 2 Burndown Chart and Completed Tasks

Sprint Planning

  1. Watch Sprint 1 Planning Recording
  2. Watch Sprint 2 Planning Recording

Retrospectives

  1. Watch Sprint 0 Retrospective Video | Click here to download mp4 File
  2. Watch Sprint 1 Retrospective Video | Click here to download mp4 File
  3. Watch Sprint 2 Retrospective Video | Click here to download mp4 File

Team Working Agreement

Team Working Agreement as PDF | Download Team Working Agreement as DOCX


Architecture Diagrams


Additional Project Artifacts


Product Personas

Sarah Kim Daniel Ross Amanda Lopez
Backend Developer Persona PDF Product Manager Persona PDF Growth Lead Persona PDF

User Stories w/ Acceptance Criteria


Application Test Cases


Monorepo Structure

notifyengine/
├── apps/
│   ├── api/              # Node.js Express API server (TypeScript)
│   ├── worker/           # BullMQ queue workers (TypeScript)
│   ├── ml-service/       # Python FastAPI ML prediction + training
│   └── dashboard/        # React admin dashboard (Vite + Tailwind)
├── packages/
│   └── shared/           # Shared TypeScript types + constants
├── infra/
│   ├── migrations/       # PostgreSQL migrations (numbered, sequential)
│   ├── seed/             # Database seed scripts
│   └── migrate.ts        # Migration runner
├── scripts/              # Dev setup and utility scripts
├── .github/workflows/    # CI/CD + TruffleHog secret scanning
├── docker-compose.yml    # Dev infrastructure (Postgres, Redis, Mailpit, ML)
├── turbo.json            # Turborepo pipeline config
├── .env.example          # Environment variable template
├── package.json          # Root workspace config
├── README.md
└── CLAUDE.md             # Project config with coding standards + security rules

Clone this wiki locally