Skip to content

Notification System

import { Aside, Steps, Tabs, TabItem } from ‘@astrojs/starlight/components’;

VitaSync includes a modular notification system that delivers alerts to users through 7 configurable channel types. Notifications are routed by category and severity using user-defined rules. All configuration is stored per-user in the database — no environment variables needed.

The notification system is ready to use out of the box. There are two ways to configure it:

Navigate to Dashboard → Notifications at http://localhost:3000/dashboard/notifications. The UI provides:

  • Channels tab — Add, edit, test, enable/disable, and delete notification channels. Each channel type has a dedicated form with the required configuration fields.
  • Routing Rules tab — Create rules that match event categories and severity levels to one or more channels.
  • Test delivery — Send a test notification to verify your channel config before going live.

Use the API endpoints documented below to create channels and rules programmatically.

Navigate to Dashboard → Notification Logs at http://localhost:3000/dashboard/notification-logs to see:

  • Stats cards: total notifications, delivered, pending, failed
  • Filterable log table with status and channel type filters
  • Expandable rows showing the full payload and error details
  • Auto-refreshes every 10 seconds
Event occurs (anomaly detected, goal reached, sync completed…)
API / Worker enqueues notification job onto `notifications` BullMQ queue
Notification Processor (worker)
├─ loads user's notification rules from DB
├─ filters rules by category + severity
├─ resolves target channels from matching rules
├─ dispatches to all channels in parallel via NotificationManager
└─ logs delivery results to notification_logs table
ChannelPackageTransportConfig Keys
Discord@biosync-io/notification-discordWebhook with rich embedswebhookUrl
Slack@biosync-io/notification-slackBlock Kit messageswebhookUrl
Microsoft Teams@biosync-io/notification-teamsAdaptive Cards v1.4webhookUrl
Email@biosync-io/notification-emailSMTP via nodemailerhost, port, user, pass, from, to
Web Push@biosync-io/notification-pushVAPID-based pushendpoint, keys.p256dh, keys.auth
ntfy@biosync-io/notification-ntfyntfy.sh REST APIserverUrl, topic, token (optional)
Webhook@biosync-io/notification-webhookHTTP POST with HMAC-SHA256url, secret
1. In your Discord server, go to **Server Settings → Integrations → Webhooks → New Webhook** 2. Copy the webhook URL 3. In VitaSync, create a Discord channel with that URL: ```json { "channelType": "discord", "label": "Health Alerts", "config": { "webhookUrl": "https://discord.com/api/webhooks/123/abc..." } } ``` Optionally set `botUsername` and `avatarUrl` for custom branding. 1. Create a Slack app at [api.slack.com/apps](https://api.slack.com/apps) 2. Enable **Incoming Webhooks** and create one for your channel 3. Create a Slack channel: ```json { "channelType": "slack", "label": "Team Health Channel", "config": { "webhookUrl": "https://hooks.slack.com/services/T.../B.../..." } } ``` Provide your SMTP server credentials: ```json { "channelType": "email", "label": "Personal Email", "config": { "host": "smtp.gmail.com", "port": 587, "user": "you@gmail.com", "pass": "app-password", "from": "VitaSync ", "to": "you@gmail.com" } } ``` For Gmail, use an [App Password](https://support.google.com/accounts/answer/185833). [ntfy](https://ntfy.sh) is a simple push notification service. You can use the public server or self-host. ```json { "channelType": "ntfy", "label": "Phone Alerts", "config": { "serverUrl": "https://ntfy.sh", "topic": "vitasync-health", "token": "tk_optional_access_token" } } ``` Install the ntfy app on your phone and subscribe to the same topic. Send raw HTTP POST payloads to any URL with HMAC-SHA256 verification: ```json { "channelType": "webhook", "label": "Custom Integration", "config": { "url": "https://your-app.com/hooks/vitasync", "secret": "whsec_your_secret_key" } } ``` The `X-VitaSync-Signature` header contains the HMAC signature.

Every notification contains:

FieldTypeDescription
titlestringShort summary
bodystringDetailed message
severityinfo | warning | criticalUrgency level
categorystringEvent type (see below)
metadataobjectOptional structured data (metric values, thresholds, etc.)
urlstringOptional deep link
timestampISO 8601When the event occurred
CategoryTriggered by
anomalyAnomaly detector finds unusual health patterns
goalUser reaches a configured health goal
achievementPersonal record set or milestone reached
syncSync completed or failed
reportScheduled health report generated
systemSystem events (connection issues, token expiry)
insightAI-generated health insights

Rules specify a minimum severity. A rule with minSeverity: "warning" matches both warning and critical notifications, but not info.

LevelUse for
infoInformational — sync completed, daily report ready
warningAttention needed — unusual metric pattern, token expiring
criticalImmediate attention — clinical threshold breached, SpO₂ < 92%
MethodPathDescription
GET/v1/users/:userId/notifications/channelsList all channels
POST/v1/users/:userId/notifications/channelsCreate a channel
PUT/v1/users/:userId/notifications/channels/:channelIdUpdate a channel
DELETE/v1/users/:userId/notifications/channels/:channelIdDelete a channel
POST/v1/users/:userId/notifications/channels/:channelId/testSend a test notification
MethodPathDescription
GET/v1/users/:userId/notifications/rulesList all rules
POST/v1/users/:userId/notifications/rulesCreate a rule
PUT/v1/users/:userId/notifications/rules/:ruleIdUpdate a rule
DELETE/v1/users/:userId/notifications/rules/:ruleIdDelete a rule
MethodPathDescription
GET/v1/users/:userId/notifications/logsQuery delivery history
1. **Create a Discord channel**
Terminal window
curl -X POST http://localhost:3001/v1/users/$USER_ID/notifications/channels \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channelType": "discord",
"label": "Health Alerts",
"config": {
"webhookUrl": "https://discord.com/api/webhooks/123/abc..."
}
}'
  1. Create a rule for anomaly alerts

    Terminal window
    curl -X POST http://localhost:3001/v1/users/$USER_ID/notifications/rules \
    -H "Authorization: Bearer $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "name": "Critical anomalies to Discord",
    "categories": ["anomaly"],
    "minSeverity": "warning",
    "channelIds": ["<channel_id_from_step_1>"]
    }'
  2. Test the channel

    Terminal window
    curl -X POST http://localhost:3001/v1/users/$USER_ID/notifications/channels/<channel_id>/test \
    -H "Authorization: Bearer $API_KEY"
  3. Check delivery logs

    Terminal window
    curl http://localhost:3001/v1/users/$USER_ID/notifications/logs?limit=10 \
    -H "Authorization: Bearer $API_KEY"

To add a new channel type:

1. **Create the package**
packages/notifications/<name>/
├── package.json
├── tsconfig.json
└── src/
└── index.ts
  1. Implement the channel class

    import { NotificationChannel } from "@biosync-io/notification-core"
    import type { NotificationPayload, NotificationResult, ChannelConfig } from "@biosync-io/notification-core"
    export class MyChannel extends NotificationChannel {
    readonly type = "my-channel" as const
    async send(payload: NotificationPayload, config: ChannelConfig): Promise<NotificationResult> {
    // Deliver the notification using config settings
    // Return { success: true } or { success: false, error: "..." }
    }
    validateConfig(config: ChannelConfig): boolean {
    // Return true if config has all required fields
    return Boolean(config.requiredField)
    }
    }
  2. Register in the worker

    In apps/worker/src/index.ts:

    import { MyChannel } from "@biosync-io/notification-my-channel"
    channelRegistry.register("my-channel", new MyChannel())
  3. Add to workspace config

    Update pnpm-workspace.yaml if using a new glob, and add the dependency to apps/worker/package.json.

The notification system uses three tables:

  • notification_channels — User’s configured channel instances with channel-specific config (JSONB)
  • notification_rules — Routing rules that map categories + severity to channels
  • notification_logs — Delivery audit log with status, attempts, and error details

See the Data Model reference for full column definitions.

Notifications are processed by a dedicated BullMQ queue (notifications) with:

  • Concurrency: 8 parallel jobs
  • Retries: 3 attempts with exponential back-off
  • Delivery results are logged to notification_logs after each attempt