Notifications
Status: π’ Production (email + WhatsApp live; in-app + push low-volume) Β· Last validated: 2026-09-06
Multi-channel delivery: in-app, push (FCM + Web Push), email, SMS, WhatsApp. Validated against classs/PushNotificationModule.php, classs/KvMailService.php, classs/KvWhatsAppCloud.php + schema.
Channels & stores (2026-09-06)
| Channel | Class | Store | Rows |
|---|---|---|---|
| In-app | (notification writes) | notifications | 0 (live schema, low data) |
KvMailService (static) | email_queue (+ email_templates 35) | 1,673 (recounted; was 1,555) | |
KvWhatsAppCloud / KvWhatsAppFaqBot | wa_outbound | 155 | |
| Push (web) | PushNotificationModule | push_subscriptions | 0 |
| Push (Android) | PushNotificationModule (FCM) | FCM tokens | β |
| OTP | (auth) | notification_otp_codes | 25 |
Drift caught:fp_notify(referenced in some older notes) is not present in this DB β the in-app store isnotifications.notification_master/notification_queue/sms_logalso do not exist. Validate the channel table before writing to it.
Email (KvMailService, static API)
KvMailService::queue(to, subject, htmlBody, opts): int(:160) β enqueue toemail_queue.recipientDeliverable(email)(:44) β suppression/deliverability check.template(key)(:98) +render(tpl, vars)(:110) β templated mail fromemail_templates.userAllows(userId, category)(:139) β respects per-user notification preferences before
sending. Always honored.
htmlToText(html)(:127) β plain-text alt.- Delivery: the
cron/email_queue_processor.phpcron drainsemail_queue.
Push (PushNotificationModule)
saveWebPushSubscription(userId, subscription)(:72),saveFcmToken(userId, token, deviceType)
(:121) β register endpoints (push_subscriptions + FCM tokens).
sendToUser(userId, title, body, url, data)(:197),sendToUsers(userIds, β¦)(:470) β send.removeSubscription(:160),getUserSubscriptions(:179).
KvWhatsAppCloud (Cloud API) writes wa_outbound; inbound + FAQ via KvWhatsAppFaqBot (the "Rishi" bot). Outbound is gated to opted-in contacts (wa_optins) β see memory whatsapp-outbound-reality. Template sync via cron/wa_template_sync.php.
The event β notification pattern
Business event (order placed, KYC approved, new lead, refundβ¦)
β module decides channels + recipient
β KvMailService::userAllows(userId, category) (pref gate)
β per channel: notifications (in-app) Β· KvMailService::queue (email) Β· PushNotificationModule::sendToUser Β· KvWhatsAppCloud (WhatsApp)
β cron workers deliver (email_queue_processor, marketing_*_worker, social_media_publisher)
Representative events (fill per module)
Order created/accepted/dispatched/delivered; payment success/failure; refund initiated/completed; booking confirmed; KYC approved/rejected; new lead; new message; membership renewal reminder. Each module's page section J lists its own events.
Business rules
BR-NOTF-001β always gate onKvMailService::userAllows(userId, category)before user email.BR-NOTF-002β WhatsApp outbound only to opted-in contacts (wa_optins).BR-NOTF-003β email is queued (email_queue) and delivered by cron, never sent inline on the request.
Errors (prefix NOTF-E)
NOTF-E001email not delivered β checkemail_queuestatus +email_queue_processorcron +
recipientDeliverable suppression.
NOTF-E002push not received β nopush_subscriptions/FCM token for the user.NOTF-E003WhatsApp not sent β recipient not inwa_optins.
Change-impact
Every module fires notifications; changing the pref gate or a channel affects all of them. Re-test: pref gate honored, email queued+drained, push to a subscribed user, WhatsApp to an opted-in contact.