# Proposal: Notification System Redesign ## Intent The current notification system has three critical limitations: (1) notifications are sent synchronously during appointment lifecycle operations, blocking the API response; (2) the notification-sender worker only handles today's appointments with a global delay (no per-company throttling for WhatsApp rate limits); and (3) there are no per-company or per-client notification preferences — notifications are either on or off for the entire company. This redesign decouples notification delivery from business operations into a job-based, multi-channel, policy-driven system. ## Scope ### In Scope - New `NotificationJob` model: per-notification job records with status, channel, payload, retry state - New `CompanyNotificationPolicy` model: org-level defaults for channels, scheduling windows, WhatsApp throttle config - New `ClientNotificationPreferences` model: per-client opt-in/out per channel - New `ClientCompanyNotificationOverride` model: per-client per-org overrides - Policy resolution engine: Plan limits → Org override → Client prefs → Org default → System default - Redesigned notification-sender worker: MongoDB polling, per-company WhatsApp throttle (8–16s), multi-channel dispatch - Server integration: replace inline notification calls in `Appointments` with job creation - Multi-channel support: WhatsApp (Baileys), Email (DonWeb), System (in-app + Socket.IO) ### Out of Scope - SMS channel (plan feature exists but not implemented today) - Notification templates / content builder - Client-facing notification preferences UI - Notification analytics / delivery reports - Push notifications (mobile) - Batch notification operations (e.g., "notify all clients about holiday") ## Capabilities ### New Capabilities - `notification-jobs`: Job creation, status tracking, retry logic, and lifecycle management for notification delivery - `notification-policies`: Company and client notification preferences, policy resolution hierarchy, channel configuration - `notification-worker`: Multi-channel job processor with per-company throttling and MongoDB polling - `notification-integration`: Server-side hooks that create notification jobs from appointment lifecycle events ### Modified Capabilities None — no existing specs in `openspec/specs/`. ## Approach **Server (job creation):** Replace inline `NotificationsManager.send*()` calls in `Appointments.ts` with `NotificationJobService.createJob()`. The service resolves the effective policy, checks plan limits, and persists a `NotificationJob` document. This makes API calls non-blocking. **notification-sender (worker):** Poll MongoDB for `status: "pending"` jobs. Process per-company with configurable WhatsApp throttle (default 8–16s between messages for same company). Email and System channels have no throttle. Failed jobs retry up to 3x with exponential backoff. **Policy resolution:** Resolve in order: Plan feature flags → `ClientCompanyNotificationOverride` (per-client per-org) → `ClientNotificationPreferences` (client global) → `CompanyNotificationPolicy` (org default) → System defaults (all channels on). **Migration:** No data migration needed — no pending notifications exist. New models are additive. ## Affected Areas | Area | Impact | Description | |------|--------|-------------| | `notification-sender/src/` | New | Complete rewrite: job polling, multi-channel dispatch, throttle | | `server/src/Models/Notifications/` | Modified | Add job creation service; existing adapters remain for direct sends | | `server/src/Models/Appointments/Appointments.ts` | Modified | Replace inline sends with job creation calls | | `server/src/Models/Plans/Plans.interface.ts` | Unchanged | Plan features already define channel support | | New: `server/src/Models/NotificationJobs/` | New | NotificationJob model + adapter | | New: `server/src/Models/NotificationPolicies/` | New | Company/Client policy models + resolution engine | | New: `notification-sender/src/Models/Jobs/` | New | Job polling model for worker | ## Risks | Risk | Likelihood | Mitigation | |------|------------|------------| | WhatsApp rate limit hit during high-volume periods | High | Per-company throttle (8–16s), exponential backoff on failures | | Job queue grows faster than worker processes | Medium | Monitor queue depth; add alerting on backlog threshold | | Policy resolution adds latency to appointment creation | Low | Resolution is a simple DB query cascade; cache per-request | | Breaking existing notification behavior during transition | Medium | Feature flag: keep inline sends as fallback during rollout | ## Rollback Plan 1. Disable job creation in server via feature flag (reverts to inline sends) 2. Stop notification-sender worker 3. Existing inline notification paths remain unchanged — no code removal needed until stable 4. Job collection can be truncated without data loss (jobs are ephemeral) ## Dependencies - MongoDB (shared across all modules) — already available - Baileys (txbot) — existing WhatsApp integration, no changes needed - DonWeb email API — existing integration, no changes needed - Socket.IO — existing in server, no changes needed ## Success Criteria - [ ] Appointment creation/update/delete returns within normal latency (< 200ms) - [ ] WhatsApp messages for same company spaced ≥ 8s apart - [ ] Failed notifications retry up to 3x with exponential backoff - [ ] Policy resolution correctly cascades through hierarchy - [ ] Zero missed notifications during 24h soak test - [ ] notification-sender processes backlog within 5 minutes under normal load