MODULES / ENGAGEMENT
Notifications
Free · MITv0.1.3In-app inbox with a live bell, per-category email and in-app preferences, and email delivery through Resend with a delivery log.
terminalnpx ajolla add notificationsWhat you get
- In-app inbox with unread-first ordering, mark one or all read, and pagination
- NotificationBell header component with a live unread count over Supabase Realtime
- Per-category in-app and email preferences plus a global email opt-out
- Email via Resend with idempotency keys, or a console log provider in development
- Accessible HTML and plain-text emails with escaped content and safe links
- Delivers notifications.requested from any module, idempotent and retried on provider outages
- Admin delivery log with status filter and a send-a-test button
Routes it adds
/account/notifications/admin/notifications/notifications
Plus 1 Supabase migration with row-level security, and an AGENTS.md your coding agent reads after install.
Installs with
Configuration
- RESEND_API_KEY
- Resend API key. When unset, emails are printed to the server console instead of sent.
- NOTIFICATIONS_FROM_EMAIL
- Verified sender, e.g. "Acme <notifications@acme.com>". Required when RESEND_API_KEY is set.
- NOTIFICATIONS_APP_NAME
- App name shown in notification emails (default "Notifications").
- NEXT_PUBLIC_SITE_URL
- Your site's origin (https://example.com), used for absolute links in emails.
- NOTIFICATIONS_LOGO_URL
- https URL of a PNG/JPG logo shown at the top of every email.
- NOTIFICATIONS_BRAND_COLOR
- Hex colour for email buttons and the accent bar, e.g. #4f46e5 (default #131316).
Events
Other modules (and your own code) can react to these:
notifications.deliverednotifications.failed
Use it from any stack
Ajolla Hosted runs the same code as a multi-tenant API. Create an app in your dashboard, enable Notifications, and call /api/m/notifications/v1 with your app key.
OpenAPI document — feed it to Ajolla to generate SDKs in 7 languages and an MCP server.
AGENTS.md
Read the instructions installed with this module
markdown# Ajolla Notifications
In-app inbox, per-user preferences and email delivery. Any module (or your own code) sends a notification by emitting `notifications.requested`; this module delivers it according to the recipient's preferences.
## Installed
- **Routes**
- `/notifications` — inbox: unread first, open (marks read and follows the link), mark one or all read, pagination.
- `/account/notifications` — preferences: in-app and email per category, plus "no notification emails".
- `/admin/notifications` — delivery log with a status filter, and "Send test notification to me" (permission `notifications.manage`).
- **Components** — `components/ajolla/notifications/notification-bell.tsx`: `<NotificationBell />` (Server Component) shows the unread count and links to `/notifications`; it updates live over Supabase Realtime and re-counts when the tab regains focus.
- **Library** — `lib/ajolla/notifications/`
- `core.ts` — `notify(scope, input, deps)`, `listNotifications`, `countUnread`, `markRead`, `getPreferences`, `setPreferences`, `listDeliveries`, zod schemas and pure helpers (`planChannels`, `isChannelEnabled`, `isSafeNotificationUrl`).
- `email.ts` — `EmailProvider` interface, `createResendProvider` (fetch, `Idempotency-Key`), `createLogProvider`, `renderNotificationEmail`.
- `config.ts` — builds the provider from env. `categories.ts` — the categories (and labels) your app sends.
- **Subscriber** — `lib/ajolla/subscribers/notifications.ts` consumes `notifications.requested`.
- **Tables** — `ajolla_notifications_notifications` (inbox, in the `supabase_realtime` publication), `ajolla_notifications_preferences`, `ajolla_notifications_user_settings`, `ajolla_notifications_deliveries` (email log).
- **Events** — emits `notifications.delivered` and `notifications.failed` (email), consumes `notifications.requested`.
- **Env** — `RESEND_API_KEY`, `NOTIFICATIONS_FROM_EMAIL` (required with the key), `NOTIFICATIONS_APP_NAME`, `NEXT_PUBLIC_SITE_URL`.
## Setup
1. Apply migrations: `supabase db push`.
2. Email: create a Resend API key, verify your sending domain, then set `RESEND_API_KEY` and `NOTIFICATIONS_FROM_EMAIL`. Without a key, emails are printed to the server console (marked DEVELOPMENT EMAIL).
3. Set `NEXT_PUBLIC_SITE_URL` so links in emails are absolute.
4. Put `<NotificationBell />` in your header (e.g. `app/layout.tsx`).
5. Make sure the kernel's `/api/ajolla/events` cron is scheduled: failed email attempts are retried from there.
6. Open `/admin/notifications` as an admin and send yourself a test.
## Sending notifications
```ts
import { emitEvent } from "@/lib/ajolla/events";
await emitEvent("notifications.requested", {
userId: user.id, // or email: "someone@example.com"
category: "billing", // lowercase key; users can turn categories off
title: "Your invoice is ready",
body: "Invoice #1042 for $49.00 is available.",
url: "/billing", // a path or an https:// URL
channels: ["in_app", "email"], // optional; default is every channel the user allows
});
```
Delivery is idempotent per event id: redelivered events never duplicate inbox rows or emails (the event id is also Resend's idempotency key). Provider outages (429/5xx/network) throw so the kernel retries with backoff; permanent rejections (other 4xx) are recorded as `failed`. To send directly from server code, call `notify()` with a secret-key scope (`selfHostedScope(createAjollaAdminClient())`); signed-in users cannot write inbox or log rows.
## Security
- Users read only their own notifications and may change only `read_at` (column privilege + RLS). They manage only their own preferences.
- The delivery log is readable only with `notifications.manage`. Anonymous visitors see nothing.
- Links are restricted to same-site paths and https URLs, both in the core and by a database check.
## Customise
- **Branding:** set `NOTIFICATIONS_LOGO_URL` (an https PNG/JPG; SVG doesn't render in most mail apps) and `NOTIFICATIONS_BRAND_COLOR` (hex) to put your logo above every email and colour its button and accent bar. Without a logo the header shows `NOTIFICATIONS_APP_NAME`.
- Add your categories, labels and descriptions to `lib/ajolla/notifications/categories.ts`.
- Restyle via the kit's `--aj-*` variables, or edit `notifications.module.css` / `notification-bell.module.css`.
- Use another email provider by implementing `EmailProvider` in `email.ts` and returning it from `config.ts`.