Skip to content

Notifications

Purpose

The notifications app exists to provide a unified system for user-facing notifications across the backend.

It supports:

  • in-app notifications shown in the user inbox
  • asynchronous external delivery such as push notifications
  • scheduled notification creation
  • delivery tracking and retry handling
  • provider-specific receipt reconciliation
  • frontend-friendly notification metadata via the registry

Its main goal is to ensure that all apps send notifications in a consistent, scalable, and user-preference-aware way.


Key concepts

  • Notification
  • The canonical in-app inbox record for one user in one organization.

  • NotificationDelivery

  • A channel-specific delivery attempt for a notification, such as push.

  • Registry

  • The single source of truth for notification types, channels, preferences, routing metadata, and templates.

  • Providers

  • External delivery adapters such as Expo.

  • Tasks

  • Async execution layer for delivery processing, receipt checks, scheduled sends, and cleanup.

  • Preferences

  • User-level controls that determine whether a notification should be created unless explicitly forced.

  • Deduplication

  • Prevents repeated creation of the same notification for the same user.

  • Grouping

  • Allows notifications to be collapsed in the client UI using group_key.

Entry points

URLs

The app exposes endpoints for:

  • reading notifications
  • unread counts
  • grouped and ungrouped inbox feeds
  • marking notifications read
  • clearing notifications
  • bulk actions
  • push device registration and deactivation
  • notification registry metadata

Admin

Admin can be used to inspect:

  • notifications
  • delivery rows
  • push devices
  • scheduled notifications
  • Expo push tickets

This is useful for debugging delivery issues, stale devices, and queued work.


Tasks

The app includes async and scheduled tasks for:

  • processing pending deliveries
  • checking Expo push receipts
  • running scheduled notifications
  • cleaning up cleared notifications
  • cleaning up stale push devices

These tasks should remain thin wrappers around services.


Signals

There are currently no core notification signals that define app behavior.

Notification creation should happen explicitly through service calls rather than hidden signal side effects.


Dependencies

Depends on:

  • orgs
  • org scoping for notifications, devices, and schedules
  • accounts
  • recipient users and optional actor users
  • Celery
  • async delivery and scheduled processing
  • provider integrations
  • currently Expo push delivery / receipts
  • DRF
  • serializers and API views

Used by:

The notifications app is intended to be used by any domain app that needs to inform users of important events, including for example:

  • timesheets
  • planning
  • approvals
  • inventory
  • service reports
  • future workflow or customer-facing apps

Any app that wants to emit notifications should do so through the notifications service layer and registry.


Operational notes

Known pitfalls

  • Do not create Notification rows directly
  • Always go through notify() or a service wrapper.

  • Registry keys are contracts

  • Once clients depend on a key, renaming it becomes a compatibility concern.

  • Templates require matching payload fields

  • If a template uses {report_number}, callers must provide it or normalization must derive it.

  • Push delivery is asynchronous

  • A created notification does not mean push was delivered yet.

  • Expo acceptance is not final delivery

  • Ticket IDs must later be reconciled through receipt checks.

  • Soft deletion is not hard deletion

  • Cleared notifications remain in the database until cleanup tasks remove them.

  • Dedupe must be used intentionally

  • Retries and repeated business events can otherwise create duplicate notifications.

  • Push tokens can move

  • Upsert logic keyed by (provider, token) may reassign a token to a different user/org if the same token is registered again.

Performance considerations

  • Notification inbox queries are user- and org-scoped
  • Proper indexing is important for feed performance.

  • Collapsed/grouped feeds are more expensive than flat feeds

  • They require aggregation, merge logic, and latest-item resolution.

  • Delivery processing should run in batches

  • Avoids long-running locks and improves worker throughput.

  • Receipt reconciliation should remain bounded

  • Missing receipts must not cause infinite polling loops.

  • Push device cleanup matters

  • Stale or invalid tokens increase noise and delivery cost.

  • Retention cleanup is necessary

  • Soft-deleted notifications will grow indefinitely without cleanup.

Summary

The notifications app is the system-wide notification backbone.

It provides:

  • a canonical inbox model
  • multi-channel delivery support
  • async processing
  • provider abstraction
  • registry-driven notification definitions
  • a consistent integration path for other apps

This makes it possible for the rest of the backend to send notifications in a way that is:

  • consistent
  • scalable
  • preference-aware
  • testable
  • extensible