FabrikFabrik
FabrikNotifications

Notifications

In-app notifications and optional email delivery — how Fabrik surfaces scheduled-task completions, AWX outcomes, drift alerts, approvals, and system events.

Notifications are the channel Fabrik uses to tell you something happened without you having to open the page where it happened. A scheduled task finished, an AWX job failed, an approval is waiting, Time Machine cleanup ran overnight — all of it converges on the same notification stream.

There are two delivery paths: in-app (the bell icon in the header plus a live WebSocket stream) and email (optional, opt-in, severity-gated). Every user controls their own preferences.

Where notifications come from

Any part of Fabrik can emit a notification by calling create_notification(). The sources that actually do so today:

SourceFires on
scheduled_task_successA scheduled query completed successfully
scheduled_task_failureA scheduled query failed
awx_execution_successAn AWX job finished successfully
awx_execution_failureAn AWX job failed
query_execution_failureAn interactive query execution errored
connection_healthAn APIC or AWX connection tested unhealthy
time_machine_cleanupRetention cleanup ran and deleted snapshots
system_maintenanceSystem-level events (migrations, escalations, admin actions)

The source identifier is used for per-user opt-out — you can turn off "scheduled task success pings" without muting everything else.

The anatomy of a notification

Every notification carries:

  • User — who sees it. Notifications are per-user; there is no shared inbox.
  • Type — severity: info, success, warning, error.
  • Title — short, displayed in the dropdown.
  • Message — fuller text, shown on expand.
  • Related IDs — optional related_task_id / related_execution_id for deep-linking into the thing that caused the notification.
  • Metadata — arbitrary JSON the frontend can render contextually (connection name, error snippet, row counts).
  • is_read + read_at — read state.
  • created_at — timestamp.

The bell, the center, the live stream

The bell

The main nav has a bell icon with an unread count badge. Clicking it opens a dropdown with the most recent notifications — title, message preview, severity icon, timestamp. A Mark all read button and a link to the full center.

The center

Notifications in the main nav opens the full center:

  • Filter by type (info / success / warning / error).
  • Filter by read / unread.
  • Search across title and message.
  • Bulk actions: mark read, mark unread, delete.
  • Pagination.

Clicking a notification:

  • Marks it read.
  • If it carries a related_task_id, navigates to the task detail.
  • If it carries a related_execution_id, navigates to the execution detail.
  • Otherwise stays on the center.

The live stream

When you're logged in, Fabrik opens a WebSocket to /ws/notifications/ scoped to your user ID. Any notification created for you pushes through the socket and the UI updates without a reload — unread count bumps, the dropdown gets the new entry, a toast optionally appears.

The socket also supports:

  • Ping/pong heartbeat so the client can detect a stale connection.
  • mark_read — sending the notification ID clears its unread state server-side.
  • get_recent — the client can request a recent-list refresh at any time.

If the WebSocket drops, the bell still works — the dropdown refetches via REST on open. The live stream is a progressive enhancement, not a requirement.

Severity semantics

The four types are not cosmetic; they drive filtering and delivery gates.

  • info — things you might want to know (cleanup summary, maintenance heads-up).
  • success — something completed as expected. Opt-out-friendly; most users disable success pings for noisy sources.
  • warning — something needs attention but isn't breaking.
  • error — something failed and you probably should look at it.

The email delivery gate is a severity threshold: only types at or above email_min_severity send email. Default warning → errors and warnings email, info and success don't. Raise to error to only ever get emailed about actual failures.

Retention

Notifications aren't kept forever. A nightly cleanup task (notifications.cleanup_old_notifications) purges:

  • Read notifications older than NOTIFICATION_RETENTION_READ_DAYS (default 90).
  • Unread notifications older than NOTIFICATION_RETENTION_UNREAD_DAYS (default 180).

Unread retention is deliberately longer than read — if someone hasn't acknowledged a notification, it's likely more important than the ones they have. The task logs deleted counts per category.

These thresholds are Django settings, not per-user; admins tune them for the whole deployment.

A notification that's relevant months after the fact is usually rehydratable from the underlying execution record — the task, the AWX job, the snapshot. Long notification retention doesn't preserve state; it just preserves the ping.

What notifications are not

A few things worth clarifying:

  • Not a broadcast. Notifications are per-user. A task failure doesn't notify a team Slack channel by default (you'd wire an email list or a webhook for that).
  • Not synchronous. Emitting a notification is best-effort — a user can have muted the source, disabled in-app, be in quiet hours, or have digest enabled, and the notification gets filtered or deferred accordingly.
  • Not a replacement for logs. Notifications are noticed; logs are searched. If you need a full audit record, that's the Audit Log system.

Continue reading


Notifications are the glue between async work (scheduled tasks, AWX jobs, Celery cleanups) and the user. Tune your preferences once and the stream stays useful instead of becoming noise.