Skip to content

Signals & Notifications — Overview

Audience: Business stakeholders, product owners, analysts, new team members.


What This Module Does

The Signals & Notifications module is Swisper's outbound communication system. While the main chat interface requires users to open the app, Signals pushes messages to them proactively — through Telegram or Threema — when something important happens. This includes daily morning briefings, urgent email alerts, upcoming meeting preparations, commitment reminders, and follow-ups on emails awaiting a response.

The system does not decide what to send — that logic lives in the background jobs. Signals is the delivery layer: it takes a NotificationMessage (title + content + target user), determines which channels the user has enabled, formats the message for each channel, and delivers it.


Who It Serves

Persona Need
End users Receive timely, relevant notifications on their preferred messaging platform without opening Swisper
Product owners Understanding which channels are supported, what controls users have, and how notifications are delivered
Backend developers Sending notifications from new jobs or features using the SignalsService API

Key Capabilities

  • Multi-channel delivery — Messages are sent in parallel to all of a user's enabled notification channels. Currently supported: Telegram (Markdown v1) and Threema (plain text).
  • Two-level preference model — A global signals_enabled toggle (stored in user_preferences) controls whether the user receives any notifications at all. Per-channel notifications_enabled flags (on UserIntegration) let users selectively enable or disable individual channels.
  • Channel-specific formatting — Each channel implementation formats the NotificationMessage appropriately: Telegram uses Markdown with bold titles and character escaping; Threema uses plain text with emoji prefixes.
  • Retry and rate-limit handling — The Threema channel uses exponential backoff (3 attempts) for timeout and server errors, and gracefully handles HTTP 429 rate-limit responses without retrying.
  • Convenience methodssend_email_notification() provides a preformatted notification for new email alerts, which is the most common notification type.

How It Fits in the Platform

  • Background Jobs — Daily briefing, pre-meeting prep, important email, commitment reminder, and awaiting-response jobs all call SignalsService.send_notification() as their delivery mechanism.
  • Integrations — Telegram and Threema channels read their delivery address (chat_id, threema_id) from the UserIntegration records managed by the Integrations module.
  • Notification Preferences API — The frontend settings page reads and writes preferences through dedicated endpoints that the SignalsService respects at delivery time.
  • Greeting System — Operates independently; the greeting system uses the chat interface, not the signals pipeline.

Limits and Edge Cases

  • Two channels only. The system currently supports Telegram and Threema. Adding a new channel requires implementing the NotificationChannel ABC and registering it in the SignalsService.
  • No delivery receipts. The system logs success or failure of the API call but does not track whether the user actually read the notification.
  • Threema is one-way. Users cannot reply to Swisper via Threema. Threema Gateway only supports outbound messages.
  • Global toggle is workspace-scoped. The signals_enabled flag is stored in user_preferences.standard_rules, which is a workspace-level setting.

FAQ

Q: What happens if a user has no notification channels connected? A: get_user_channels() returns an empty list, and the notification is silently skipped. The background job logs that no channels were available.

Q: Can I add a new notification channel (e.g., email, SMS)? A: Yes. Implement the NotificationChannel ABC (from notification_channels/base_channel.py), adding send(), get_user_id(), and is_notifications_enabled() methods. Then register the channel instance in SignalsService.__init__().

Q: Does disabling signals_enabled affect all channels? A: Yes. When signals_enabled is False, no notifications are sent regardless of per-channel settings.

Q: Are notifications batched or sent individually? A: Each notification is sent individually. If a background job generates multiple notifications (e.g., for multiple users), each is a separate send_notification() call.