All updates
QABackend

Unified Notifications & Activity Log, Real-Time WebSocket Delivery, and Mail Status Cleanup

PR #87aisupport-datagainSep 15, 2025 · 20:17 UTC
QASep 15, 2025

Executive summary

This backend release consolidates notifications into the existing Activity Log, adds real-time delivery of notifications and comments over WebSockets (with email fallback), and enforces mutually-exclusive mail statuses (resolved/unresolved and read/unread). It also refactors the Comments data model and extends commenting to more record types. The change reached the QA environment for testing.

Why this was needed

Notifications previously lived in a separate notifications table that duplicated much of what the Activity Log already tracked, and they were not delivered in real time (email sending was an unimplemented TODO). Separately, mail records could end up tagged with contradictory statuses (both resolved and unresolved, or both read and unread), and the Comments model used legacy column and table structures that no longer matched how modules are referenced. This work unifies the data, makes alerts live, and removes those data-integrity gaps.

Client / user impact

  • Users see notifications and new comments update live in the UI through new WebSocket channels, rather than only on refresh.
  • Notification emails are now actually sent for relevant events instead of being skipped.
  • A single Activity Log feed now backs notifications, giving a consistent history and faster unread queries.
  • Mail statuses can no longer be both resolved and unresolved (or read and unread) at once; the most recent choice wins, and existing conflicting data is cleaned up.
  • Comments can now be attached to more record types (Folders, Document Types, Organizations, Departments, Contacts).

Technical scope

  • Notifications merged into ActivityLog: migration adds notify/event_type/notification_type/priority/is_internal_only/metainfo/status_id columns, backfills from notifications, repoints user_notifications to ActivityLog.id, drops the notifications table, and adds unread-feed indexes. The Notification model is removed and notification_service.py reads/writes Activity Log instead.
  • Real-time delivery: new WebSocket endpoints /api/v1/ws/notifications and /api/v1/ws/comments, a notification_websocket_manager, and a Redis pub/sub subscriber (channel notifications:events) that relays events to connected clients. Wired into app startup/shutdown in main.py, gated by ENABLE_NOTIFICATION_PUBSUB.
  • Email notifications: new send_generic_email in sendgrid_email_service.py; the notification service now sends emails (previously a no-op TODO).
  • Mail status exclusivity: mail_status_validation.py and mail_user_status_service.py enforce mutually-exclusive resolved/unresolved and read/unread groups (last choice wins); a data-cleanup migration removes existing conflicts in Mails.user_statuses and Mail_UserStatus.
  • Rule engine: status rule actions move from MailReadStatusLookup.id to the canonical Mails.user_statuses object {lookup_statuses, custom_statuses}; priority/status actions normalized via a data migration.
  • Comments refactor: module_entity_id renamed to module_id, new module_item_id column + composite index; obsolete CommentsModule table/view dropped; access checks extended to Folders, DocumentTypes, Organization/Department/Contacts; API accepts module_id.
  • Redis hardening: substantial rework of async_redis_client.py and upstash_rest_client.py to support pub/sub over both TCP and Upstash REST.
  • Minor: a stray empty file _ was committed, an example helper file was deleted, and AGENTS.md gained internal contributor notes.

Risk & mitigation

Risk is elevated: this includes multiple irreversible data migrations (dropping the notifications and CommentsModule tables, repointing foreign keys, renaming a Comments column, and normalizing rule-action and mail-status data). Several migration downgrade paths are intentionally no-ops, so rollback would not restore original data. Mitigations: migrations are written to be idempotent and use existence checks before each step; the notifications backfill maps legacy IDs before swapping; real-time pub/sub is feature-gated via ENABLE_NOTIFICATION_PUBSUB and wrapped in try/except so failures degrade gracefully rather than blocking startup. A full database backup before applying migrations and verification on QA before any production promotion are strongly recommended.

QA validation focus

  • Run all migrations on a production-like QA copy and confirm notifications/CommentsModule are dropped cleanly and user_notifications rows still resolve to Activity Log entries.
  • Verify notification list, unread counts, and filters (type, priority, date, read/unread) return correct data after the merge into Activity Log.
  • Open the /api/v1/ws/notifications and /api/v1/ws/comments WebSocket channels and confirm live events arrive (and ping/pong keepalive works); test with pub/sub enabled and disabled.
  • Trigger a notification event and confirm an email is sent to the correct recipients.
  • Apply contradictory statuses to a mail (resolved+unresolved, read+unread) and confirm only the last choice persists; spot-check that the cleanup migration resolved pre-existing conflicts.
  • Run priority and status assignment rules end-to-end and confirm the mail's priority and user_statuses update as expected.
  • Add and fetch comments on the newly supported types (Folders, Document Types, Organizations, Departments, Contacts) using module_id.
  • Confirm the stray empty _ file does not ship in production artifacts.