feat: implement comprehensive notification engine with policies, preferences, and automated dispatching services
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# Tasks: Notification Preferences UI
|
||||
|
||||
## Review Workload Forecast
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Estimated changed lines | 1000-1200 |
|
||||
| 400-line budget risk | High |
|
||||
| Chained PRs recommended | Yes |
|
||||
| Suggested split | PR 1 → PR 2 → PR 3 → PR 4 |
|
||||
| Delivery strategy | ask-on-risk |
|
||||
| Chain strategy | pending |
|
||||
|
||||
Decision needed before apply: Yes
|
||||
Chained PRs recommended: Yes
|
||||
Chain strategy: pending
|
||||
400-line budget risk: High
|
||||
|
||||
### Suggested Work Units
|
||||
|
||||
| Unit | Goal | Likely PR | Focused test command | Runtime harness | Rollback boundary |
|
||||
|------|------|-----------|----------------------|-----------------|-------------------|
|
||||
| 1 | Foundation: models, API service, store, validation | PR 1 | `npm run typecheck` | N/A — types only | Remove service, store, model files |
|
||||
| 2 | Org policy page + navigation | PR 2 | Navigate to `/admin/org/profile/[id]/notifications` | Org profile page loads, toggles render | Remove org notifications page and layout |
|
||||
| 3 | Client override page + navigation | PR 3 | Navigate to `/admin/org/[oid]/client/[clientId]/notifications` | Client profile page loads, toggles render | Remove client notifications page and layout |
|
||||
| 4 | Client-facing page + tests | PR 4 | Navigate to `/user/profile/notifications` | Landing profile page loads, toggles render | Remove landing notifications page and tests |
|
||||
|
||||
## Phase 1: Foundation
|
||||
|
||||
- [x] 1.1 Create `txclient/src/Models/NotificationPreferences.model.ts` — TypeScript interfaces: NotificationChannel, QuietHours, ReminderRule, CompanyNotificationPolicy, ClientNotificationPreferences, ClientCompanyNotificationOverride, upsert params
|
||||
- [x] 1.2 Create `txclient/src/services/Notifications.Service.ts` — 6 API functions using `ApiRequest.post<T>()`: getCompanyPolicy, upsertCompanyPolicy, getClientPreferences, upsertClientPreferences, getClientCompanyOverride, upsertClientCompanyOverride
|
||||
- [x] 1.3 Create `txclient/src/Store/NotificationPreferences.Store.ts` — Zustand store with mode, form data, dirty flag; actions: setMode, updateFormData, resetForm
|
||||
- [x] 1.4 Create `txclient/src/Models/NotificationPreferences.validation.ts` — Yup schemas: companyPolicySchema (channels min 1, timezone required, quietHours optional HH:mm, reminderRules max 5), clientPrefsSchema (preferredChannels, mutedChannels)
|
||||
|
||||
## Phase 2: Org Policy Page
|
||||
|
||||
- [x] 2.1 Create `txclient/src/app/admin/(organization-profile)/org/profile/[id]/notifications/layout.tsx` — Saveable wrapper loading company policy on mount, dispatching NEED_SAVE/SAVE events
|
||||
- [x] 2.2 Create `txclient/src/app/admin/(organization-profile)/org/profile/[id]/notifications/page.tsx` — Org policy form: channel toggles (3x Switch), quiet hours (2x input time), timezone Textbox, reminder rules dynamic list (max 5) with add/remove buttons
|
||||
- [x] 2.3 Modify `txclient/src/app/components/OrganizationHeader/OrganizationHeader.tsx` — Add "Notificaciones" menu item linking to `/admin/org/profile/[id]/notifications` with NotificationsIcon
|
||||
|
||||
## Phase 3: Client Override Page
|
||||
|
||||
- [x] 3.1 Create `txclient/src/app/admin/(client-profile)/org/[oid]/client/[clientId]/notifications/layout.tsx` — Saveable wrapper loading client company override on mount
|
||||
- [x] 3.2 Create `txclient/src/app/admin/(client-profile)/org/[oid]/client/[clientId]/notifications/page.tsx` — Client override form: preferred channels (3x Switch), muted channels (3x Switch)
|
||||
- [x] 3.3 Modify `txclient/src/app/admin/(client-profile)/org/[oid]/client/[clientId]/layout.tsx` — Add "Notificaciones" navigation link to client profile menu
|
||||
|
||||
## Phase 4: Client-Facing Page
|
||||
|
||||
- [x] 4.1 Create `txclient/src/app/user/profile/notifications-preferences/page.tsx` — Client preferences form: preferred channels (3x Switch), muted channels (3x Switch); wrapped in Secure component for auth gate
|
||||
- [x] 4.2 Modify `txclient/src/app/user/profile/page.tsx` — Add "Preferencias de notificación" navigation link to user profile menu
|
||||
|
||||
## Phase 5: Testing
|
||||
|
||||
- [ ] 5.1 Create `txclient/src/Models/__tests__/NotificationPreferences.validation.test.ts` — Test Yup schemas: valid inputs pass, invalid channels rejected, timezone required, quietHours format validated, reminderRules max 5 enforced (BLOCKED: no test runner in txclient)
|
||||
- [ ] 5.2 Create `txclient/src/services/__tests__/Notifications.Service.test.ts` — Mock ApiRequest.post, verify 6 functions call correct endpoints with correct params (BLOCKED: no test runner in txclient)
|
||||
- [ ] 5.3 Create `txclient/src/Store/__tests__/NotificationPreferences.Store.test.ts` — Test store actions: setMode, updateFormData, resetForm, dirty flag transitions (BLOCKED: no test runner in txclient)
|
||||
|
||||
## Phase 6: Cleanup (if needed)
|
||||
|
||||
- [x] 6.1 Remove any temporary console.log statements added during development
|
||||
- [x] 6.2 Verify all TypeScript types compile without errors
|
||||
- [x] 6.3 Confirm navigation links work in all three contexts (org, client, landing)
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user