Files
huly-platform/services/notification/pod-notification
cc16352be9 Sync with foundations packages (#10703)
* fix: redesign and compact

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* fix: comments

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* fix: correctly dropping connections in timeout

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* feature: loglevel in config

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* fix: loglevel in config

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* features lopt: direct personal messages between websockets by username

Signed-off-by: Leonid Kaganov <lleo@lleo.me>

* fix collaborator security query

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>

* Fix svelte warnings

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Change log

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Add workspace permissions enum

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Add changelog

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Permission methods

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update core and account versions

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix  predicate

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Add changelog

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix object clone

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Bump and add changelog

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix exception in getTypeOf

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Disable changelog check

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix failed to fetch errors in account client

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Clean up

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Support in-memory mode for hulypulse

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update platform-rig

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Comment change log verification

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update pnpm lock

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Sync with foundation

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update platform-rig

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Sync with foundation and bump versions

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Sync with foundations

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update and increment versions

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Skip change log verification

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix hulypulse connections

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix formatting and ci

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix validation warnings

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix formatting

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix validation

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Fix pnpm lock

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update versions

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Update hulypulse version

Signed-off-by: Artem Savchenko <armisav@gmail.com>

---------

Signed-off-by: Leonid Kaganov <lleo@lleo.me>
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
Signed-off-by: Artem Savchenko <armisav@gmail.com>
Co-authored-by: Leonid Kaganov <lleo@lleo.me>
Co-authored-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
2026-03-31 10:23:56 +07:00
..
2025-09-16 23:18:12 +07:00

Notification Service

A microservice for sending push notifications via web push protocol.

Overview

The notification service provides endpoints for sending web push notifications to subscribed clients. It uses the Web Push Protocol with VAPID (Voluntary Application Server Identification) for secure delivery of notifications.

Features

  • Web Push Notifications: Send push notifications to web browsers
  • VAPID Support: Secure authentication using VAPID keys
  • Subscription Management: Handles expired and invalid subscriptions
  • Token Authentication: Optional bearer token authentication
  • Error Handling: Automatic cleanup of invalid subscriptions

Prerequisites

  • Node.js (version specified in package.json)
  • VAPID key pair for web push authentication
  • Valid push subscriptions from client applications

Configuration

The service is configured via environment variables:

Variable Required Default Description
PORT Yes 8091 Port number for the service
SOURCE Yes - Source identifier for the service
AUTH_TOKEN No - Bearer token for API authentication
PUSH_PUBLIC_KEY No - VAPID public key for web push
PUSH_PRIVATE_KEY No - VAPID private key for web push
PUSH_SUBJECT No mailto:hey@huly.io VAPID subject (email or URL)

VAPID Keys

To generate VAPID keys, you can use the web-push library:

npx web-push generate-vapid-keys

This will output a public and private key pair that should be set in the environment variables.

Installation

npm install

Running the Service

Development

rushx run-local

Docker

docker build -t notification-service .
docker run -p 8091:8091 \
  -e SOURCE=notification \
  -e PUSH_PUBLIC_KEY=your_public_key \
  -e PUSH_PRIVATE_KEY=your_private_key \
  notification-service

API Endpoints

POST /web-push

Sends web push notifications to subscribed clients.

Authentication

  • Header: Authorization: Bearer <token> (if AUTH_TOKEN is configured)

Request Body

{
  "data": {
    "title": "Notification Title",
    "body": "Notification message",
    "icon": "/icon.png",
    "badge": "/badge.png",
    "tag": "notification-tag",
    "url": "/target-url"
  },
  "subscriptions": [
    {
      "_id": "subscription-id",
      "endpoint": "https://fcm.googleapis.com/fcm/send/...",
      "keys": {
        "p256dh": "client-public-key",
        "auth": "client-auth-secret"
      }
    }
  ]
}

Response

{
  "result": ["subscription-id-1", "subscription-id-2"]
}

The result array contains IDs of subscriptions that failed due to:

  • Expired subscriptions
  • Unregistered subscriptions
  • Invalid subscriptions

These subscription IDs should be removed from your database.

Error Responses

  • 400 Bad Request: Missing data or subscriptions in request body
  • 401 Unauthorized: Invalid or missing auth token (when auth is enabled)
  • 500 Internal Server Error: Server error during processing

Push Data Format

The data object supports the following properties:

Property Type Required Description
title string Yes Notification title
body string No Notification body text
icon string No URL to notification icon
badge string No URL to notification badge
tag string No Tag for grouping notifications
url string No URL to open when notification is clicked
data object No Custom data payload

Client Integration

Subscribing to Push Notifications

// Register service worker
const registration = await navigator.serviceWorker.register('/sw.js');

// Subscribe to push notifications
const subscription = await registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: 'your-vapid-public-key'
});

// Send subscription to your server
await fetch('/api/subscribe', {
  method: 'POST',
  body: JSON.stringify(subscription),
  headers: { 'Content-Type': 'application/json' }
});

Service Worker (sw.js)

self.addEventListener('push', event => {
  const data = event.data ? event.data.json() : {};
  
  const options = {
    body: data.body,
    icon: data.icon,
    badge: data.badge,
    tag: data.tag,
    data: { url: data.url }
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

self.addEventListener('notificationclick', event => {
  event.notification.close();
  
  if (event.notification.data?.url) {
    event.waitUntil(
      clients.openWindow(event.notification.data.url)
    );
  }
});

Error Handling

The service automatically handles common web push errors:

  • Expired subscriptions: Automatically identified and returned in response
  • Invalid endpoints: Subscriptions with invalid endpoints are flagged
  • Unregistered subscriptions: Previously valid subscriptions that are no longer active

Applications should monitor the response and remove failed subscription IDs from their database.

Monitoring

The service logs the following events:

  • Service startup and VAPID configuration
  • Authentication failures
  • Push notification errors
  • Subscription cleanup events

Security

  • VAPID Authentication: All push messages are signed with VAPID keys
  • Token Authentication: Optional bearer token authentication for API access
  • HTTPS Required: Web Push Protocol requires HTTPS in production
  • Origin Validation: Push subscriptions are tied to specific origins

Development

Project Structure

src/
├── main.ts          # Main application entry point
├── config.ts        # Configuration management
├── server.ts        # Express server setup
└── types.ts         # TypeScript type definitions

Troubleshooting

Common Issues

  1. "No VAPID keys configured"

    • Ensure PUSH_PUBLIC_KEY and PUSH_PRIVATE_KEY are set
    • Verify keys are valid VAPID keys
  2. "Invalid auth token"

    • Check AUTH_TOKEN environment variable
    • Verify bearer token in Authorization header
  3. Push notifications not delivered

    • Verify subscription is still valid
    • Check browser developer tools for service worker errors
    • Ensure HTTPS is used in production
  4. High subscription failure rate

    • Check if users are unsubscribing
    • Verify subscription objects are properly formatted
    • Monitor browser console for push registration errors