Admin Notifications Integration

Admin Notifications Integration

This project now contains a standalone admin notification mechanism, but it is not wired into any business flow by default.

That means:

  • The infrastructure is ready.
  • No payment/auth/AI route will automatically send notifications.
  • You decide where and when to call it.

What Is Included

The current implementation includes:

  • A database-backed outbox for admin notification events and deliveries
  • A dispatcher with retry support
  • A Telegram channel implementation
  • Admin settings for Telegram credentials and notification switches
  • A protected dispatch route for cron or manual retry

Core files:

  • src/admin-notification/outbox.ts
  • src/admin-notification/dispatcher.ts
  • src/admin-notification/notifier.ts
  • src/admin-notification/channels/telegram.ts
  • src/app/api/admin-notifications/dispatch/route.ts

How It Works

The mechanism is designed to avoid slowing down your main business flow:

  1. Your code creates an admin notification event.
  2. The event is stored in the database outbox.
  3. Deliveries are created for enabled channels, such as Telegram.
  4. The dispatcher sends pending deliveries asynchronously.
  5. Failed deliveries are retried with backoff.

The intended model is:

  • Main flow only enqueues
  • Sending happens asynchronously
  • Notification failure must not break the main business logic

Database Setup

This feature adds two new tables to the schema:

  • admin_notification_event
  • admin_notification_delivery

Schema files:

  • src/config/db/schema.sqlite.ts
  • src/config/db/schema.postgres.ts
  • src/config/db/schema.mysql.ts

Apply the schema before using the feature:

pnpm run db:push

If you use a migration-based workflow instead:

pnpm run db:generate
pnpm run db:migrate

Admin Settings

New settings are available in the admin panel under the Notifications tab.

Important keys:

  • admin_notification_enabled
  • admin_notification_order_enabled
  • admin_notification_alert_enabled
  • admin_notification_telegram_enabled
  • admin_notification_telegram_bot_token
  • admin_notification_telegram_chat_ids
  • admin_notification_telegram_thread_id

Recommended minimum configuration for Telegram:

  • enable admin notifications
  • enable Telegram channel
  • provide bot token
  • provide one or more chat IDs

admin_notification_telegram_chat_ids supports:

  • one chat ID per line
  • or comma-separated chat IDs

Manual Integration

Option 1: Use The Ready-Made Helper Methods

Import from:

import {
  notifyAdminOrderPaid,
  notifyAdminPaymentWebhookFailed,
  notifyAdminSubscriptionCanceled,
  notifyAdminSubscriptionRenewed,
} from '@/admin-notification';

Example:

import { notifyAdminOrderPaid } from '@/admin-notification';

async function notifyOrder(order: {
  orderNo: string;
  amount?: number | null;
  currency?: string | null;
  paymentAmount?: number | null;
  paymentCurrency?: string | null;
  paymentProvider?: string | null;
  paymentEmail?: string | null;
  userEmail?: string | null;
  productName?: string | null;
}) {
  try {
    await notifyAdminOrderPaid({
      orderNo: order.orderNo,
      amount: order.amount,
      currency: order.currency,
      paymentAmount: order.paymentAmount,
      paymentCurrency: order.paymentCurrency,
      paymentProvider: order.paymentProvider,
      userEmail: order.paymentEmail || order.userEmail,
      productName: order.productName,
    });
  } catch (error) {
    console.log('enqueue admin notification failed', error);
  }
}

Use the same pattern for renew/cancel/alert helpers:

  • notifyAdminSubscriptionRenewed
  • notifyAdminSubscriptionCanceled
  • notifyAdminPaymentWebhookFailed

Option 2: Enqueue A Custom Admin Event

If your event does not match the built-in helpers, use the lower-level API:

import {
  AdminNotificationEventType,
  AdminNotificationLevel,
  AdminNotificationSource,
  enqueueAdminNotification,
} from '@/admin-notification';

Example:

await enqueueAdminNotification({
  eventType: AdminNotificationEventType.PAYMENT_WEBHOOK_FAILED,
  level: AdminNotificationLevel.CRITICAL,
  source: AdminNotificationSource.PAYMENT,
  title: 'Custom webhook alert',
  entityType: 'webhook',
  entityId: 'stripe',
  dedupeKey: `custom_webhook_alert:${Date.now()}`,
  payload: {
    provider: 'stripe',
    error: 'custom error',
    route: '/api/example',
    occurredAt: new Date().toISOString(),
  },
});

If you need new event names, add them in:

src / admin - notification / types.ts;

If you need a custom Telegram message layout, update:

src / admin - notification / templates / telegram.ts;

Make Dispatch Near Real-Time

The built-in helper methods already call scheduleAdminNotificationDispatch().

If you use enqueueAdminNotification() directly and want immediate best-effort dispatch, call:

import {
  enqueueAdminNotification,
  scheduleAdminNotificationDispatch,
} from '@/admin-notification';

const result = await enqueueAdminNotification(...);

if (result.queued) {
  scheduleAdminNotificationDispatch();
}

This gives you:

  • fast best-effort sending after the request lifecycle
  • without blocking the main flow on Telegram API latency

Fallback Dispatch Route

There is a protected internal route:

/api/admin-notifications/dispatch

It requires:

  • Authorization: Bearer <AUTH_SECRET>

Example:

curl -X POST \
  -H "Authorization: Bearer $AUTH_SECRET" \
  "http://localhost:3000/api/admin-notifications/dispatch?limit=20"

Use this route for:

  • cron dispatch
  • recovery after a failed async attempt
  • manual operations

Cron Recommendation

Recommended fallback frequency:

  • critical admin alerts: every 15s to 30s
  • general admin notifications: every 30s

Suggested strategy:

  • immediate best-effort dispatch from application code
  • fallback cron for retry and recovery

Do not rely on high-frequency database polling alone unless you really need it.

Retry Rules

Current retry behavior is implemented in src/admin-notification/dispatcher.ts.

Backoff:

  • 1st retry: 10s
  • 2nd retry: 30s
  • 3rd retry: 120s
  • later retries: 600s

Non-retryable cases should be treated as dead deliveries, for example:

  • invalid credentials
  • invalid chat ID
  • unsupported channel

Telegram Setup

You need:

  1. A Telegram bot token from BotFather
  2. A destination chat ID
  3. Optionally a forum topic thread ID

Notes:

  • group and channel chat IDs are usually negative numbers
  • forum topics require message_thread_id

If Telegram credentials are configured incorrectly, the main business flow should still continue, and only the delivery record should fail.

Use this structure whenever you wire notifications into business logic:

try {
  await notifyAdminOrderPaid(...);
} catch (error) {
  console.log('enqueue admin notification failed', error);
}

Rules:

  • do not let notification errors break the main business flow
  • enqueue after your main business write succeeds
  • do not await Telegram API calls directly in business code
  • use the notifier or outbox layer only

Where To Integrate

Common integration points:

  • payment success
  • subscription renewal
  • subscription cancellation
  • webhook error handling
  • AI callback failure
  • storage provider failure
  • signup / new user registration alerts

Keep the integration close to business success or failure boundaries, not inside UI code.

How To Test

  1. Configure Telegram settings in admin panel
  2. Ensure the database schema is applied
  3. Add one temporary manual call to a built-in notifier helper
  4. Trigger the corresponding flow
  5. Check the Telegram chat
  6. Check database rows in:
    • admin_notification_event
    • admin_notification_delivery
  7. Trigger the dispatch route manually if needed

Current Limitations

Current V1 scope:

  • admin notifications only
  • Telegram channel only
  • no built-in business auto-wiring
  • no admin UI yet for listing deliveries

This is intentional. The current goal is to provide a stable mechanism that you can wire in selectively.

Suggested Next Steps

If you continue building this feature, the most useful next steps are:

  • add an admin page for delivery status and dead-letter inspection
  • move important event enqueue into the same DB transaction as the business write
  • add more channels such as Slack, Email, or generic Webhook
  • add more built-in notifier helpers for AI and system alerts