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:
Option A: Web Dashboard UI (recommended)
Section titled “Option A: Web Dashboard UI (recommended)”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.
Option B: REST API
Section titled “Option B: REST API”Use the API endpoints documented below to create channels and rules programmatically.
Viewing Delivery Logs
Section titled “Viewing Delivery Logs”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
Architecture
Section titled “Architecture”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 tableSupported Channels
Section titled “Supported Channels”| Channel | Package | Transport | Config Keys |
|---|---|---|---|
| Discord | @biosync-io/notification-discord | Webhook with rich embeds | webhookUrl |
| Slack | @biosync-io/notification-slack | Block Kit messages | webhookUrl |
| Microsoft Teams | @biosync-io/notification-teams | Adaptive Cards v1.4 | webhookUrl |
@biosync-io/notification-email | SMTP via nodemailer | host, port, user, pass, from, to | |
| Web Push | @biosync-io/notification-push | VAPID-based push | endpoint, keys.p256dh, keys.auth |
| ntfy | @biosync-io/notification-ntfy | ntfy.sh REST API | serverUrl, topic, token (optional) |
| Webhook | @biosync-io/notification-webhook | HTTP POST with HMAC-SHA256 | url, secret |
Channel Configuration Examples
Section titled “Channel Configuration Examples”Concepts
Section titled “Concepts”Notification Payload
Section titled “Notification Payload”Every notification contains:
| Field | Type | Description |
|---|---|---|
title | string | Short summary |
body | string | Detailed message |
severity | info | warning | critical | Urgency level |
category | string | Event type (see below) |
metadata | object | Optional structured data (metric values, thresholds, etc.) |
url | string | Optional deep link |
timestamp | ISO 8601 | When the event occurred |
Categories
Section titled “Categories”| Category | Triggered by |
|---|---|
anomaly | Anomaly detector finds unusual health patterns |
goal | User reaches a configured health goal |
achievement | Personal record set or milestone reached |
sync | Sync completed or failed |
report | Scheduled health report generated |
system | System events (connection issues, token expiry) |
insight | AI-generated health insights |
Severity Levels
Section titled “Severity Levels”Rules specify a minimum severity. A rule with minSeverity: "warning" matches both warning and critical notifications, but not info.
| Level | Use for |
|---|---|
info | Informational — sync completed, daily report ready |
warning | Attention needed — unusual metric pattern, token expiring |
critical | Immediate attention — clinical threshold breached, SpO₂ < 92% |
API Endpoints
Section titled “API Endpoints”Channels
Section titled “Channels”| Method | Path | Description |
|---|---|---|
GET | /v1/users/:userId/notifications/channels | List all channels |
POST | /v1/users/:userId/notifications/channels | Create a channel |
PUT | /v1/users/:userId/notifications/channels/:channelId | Update a channel |
DELETE | /v1/users/:userId/notifications/channels/:channelId | Delete a channel |
POST | /v1/users/:userId/notifications/channels/:channelId/test | Send a test notification |
| Method | Path | Description |
|---|---|---|
GET | /v1/users/:userId/notifications/rules | List all rules |
POST | /v1/users/:userId/notifications/rules | Create a rule |
PUT | /v1/users/:userId/notifications/rules/:ruleId | Update a rule |
DELETE | /v1/users/:userId/notifications/rules/:ruleId | Delete a rule |
Delivery Logs
Section titled “Delivery Logs”| Method | Path | Description |
|---|---|---|
GET | /v1/users/:userId/notifications/logs | Query delivery history |
Quick Start
Section titled “Quick Start”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..." } }'-
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>"]}' -
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" -
Check delivery logs
Terminal window curl http://localhost:3001/v1/users/$USER_ID/notifications/logs?limit=10 \-H "Authorization: Bearer $API_KEY"
Adding a Notification Channel
Section titled “Adding a Notification Channel”To add a new channel type:
packages/notifications/<name>/├── package.json├── tsconfig.json└── src/ └── index.ts-
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 constasync 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 fieldsreturn Boolean(config.requiredField)}} -
Register in the worker
In
apps/worker/src/index.ts:import { MyChannel } from "@biosync-io/notification-my-channel"channelRegistry.register("my-channel", new MyChannel()) -
Add to workspace config
Update
pnpm-workspace.yamlif using a new glob, and add the dependency toapps/worker/package.json.
Database Tables
Section titled “Database Tables”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 channelsnotification_logs— Delivery audit log with status, attempts, and error details
See the Data Model reference for full column definitions.
Worker Queue
Section titled “Worker Queue”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_logsafter each attempt