Version 3 of the kit: - Radix UI replaced with Base UI (using the Shadcn UI patterns) - next-intl replaces react-i18next - enhanceAction deprecated; usage moved to next-safe-action - main layout now wrapped with [locale] path segment - Teams only mode - Layout updates - Zod v4 - Next.js 16.2 - Typescript 6 - All other dependencies updated - Removed deprecated Edge CSRF - Dynamic Github Action runner
264 lines
7.3 KiB
Plaintext
264 lines
7.3 KiB
Plaintext
---
|
|
status: "published"
|
|
title: "Sending Notifications"
|
|
label: "Sending Notifications"
|
|
description: "Create in-app notifications from Server Actions, API routes, and background jobs using the notifications API."
|
|
order: 1
|
|
---
|
|
|
|
Notifications are created server-side using `createNotificationsApi`. This requires the Supabase admin client because only the `service_role` can insert into the notifications table.
|
|
|
|
## Basic usage
|
|
|
|
```typescript
|
|
import { createNotificationsApi } from '@kit/notifications/api';
|
|
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
|
|
|
async function sendNotification(accountId: string) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Your report is ready',
|
|
});
|
|
}
|
|
```
|
|
|
|
The `account_id` determines who sees the notification. Pass a user's personal account ID to notify just them, or a team account ID to notify all team members.
|
|
|
|
## Notification fields
|
|
|
|
| Field | Type | Required | Default | Description |
|
|
|-------|------|----------|---------|-------------|
|
|
| `account_id` | `uuid` | Yes | - | Personal or team account ID |
|
|
| `body` | `string` | Yes | - | Message text (max 5000 chars) |
|
|
| `type` | `'info' \| 'warning' \| 'error'` | No | `'info'` | Severity level |
|
|
| `link` | `string` | No | `null` | URL to navigate on click |
|
|
| `channel` | `'in_app' \| 'email'` | No | `'in_app'` | Delivery channel |
|
|
| `expires_at` | `Date` | No | 1 month | Auto-expiration timestamp |
|
|
|
|
## Notification types
|
|
|
|
Use types to indicate severity. Each type renders with a distinct icon color:
|
|
|
|
```typescript
|
|
// Info (blue) - General updates
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'New feature: Dark mode is now available',
|
|
type: 'info',
|
|
});
|
|
|
|
// Warning (yellow) - Attention needed
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Your trial expires in 3 days',
|
|
type: 'warning',
|
|
link: '/settings/billing',
|
|
});
|
|
|
|
// Error (red) - Action required
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Payment failed. Update your card to continue.',
|
|
type: 'error',
|
|
link: '/settings/billing',
|
|
});
|
|
```
|
|
|
|
## Adding links
|
|
|
|
Include a `link` to make notifications actionable. Users click the notification to navigate:
|
|
|
|
```typescript
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'John commented on your document',
|
|
link: '/documents/abc123#comment-456',
|
|
});
|
|
```
|
|
|
|
Links should be relative paths within your app. The UI renders the body as a clickable anchor.
|
|
|
|
## Setting expiration
|
|
|
|
By default, notifications expire after 1 month. Set a custom expiration for time-sensitive messages:
|
|
|
|
```typescript
|
|
// Expire in 24 hours
|
|
const tomorrow = new Date();
|
|
tomorrow.setHours(tomorrow.getHours() + 24);
|
|
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Flash sale ends tonight!',
|
|
link: '/pricing',
|
|
expires_at: tomorrow,
|
|
});
|
|
```
|
|
|
|
Expired notifications are filtered out on fetch. They remain in the database but won't appear in the UI.
|
|
|
|
## Team notifications
|
|
|
|
Send to a team account ID to notify all members:
|
|
|
|
```typescript
|
|
import { createNotificationsApi } from '@kit/notifications/api';
|
|
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
|
|
|
|
async function notifyTeam(teamAccountId: string, newMemberName: string) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
await api.createNotification({
|
|
account_id: teamAccountId,
|
|
body: `${newMemberName} joined the team`,
|
|
link: '/settings/members',
|
|
type: 'info',
|
|
});
|
|
}
|
|
```
|
|
|
|
Every user with a role on that team account will see this notification via the RLS policy.
|
|
|
|
## Common patterns
|
|
|
|
### Welcome notification on signup
|
|
|
|
```typescript
|
|
// In your post-signup hook or Server Action
|
|
export async function onUserCreated(userId: string) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
await api.createNotification({
|
|
account_id: userId,
|
|
body: 'Welcome! Start by creating your first project.',
|
|
link: '/projects/new',
|
|
type: 'info',
|
|
});
|
|
}
|
|
```
|
|
|
|
### Subscription renewal reminder
|
|
|
|
```typescript
|
|
export async function sendRenewalReminder(
|
|
accountId: string,
|
|
daysRemaining: number
|
|
) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
const expiresAt = new Date();
|
|
expiresAt.setDate(expiresAt.getDate() + daysRemaining);
|
|
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: `Your subscription renews in ${daysRemaining} days`,
|
|
link: '/settings/billing',
|
|
type: daysRemaining <= 3 ? 'warning' : 'info',
|
|
expires_at: expiresAt,
|
|
});
|
|
}
|
|
```
|
|
|
|
### Background job completion
|
|
|
|
```typescript
|
|
export async function onExportComplete(
|
|
accountId: string,
|
|
exportId: string
|
|
) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Your data export is ready to download',
|
|
link: `/exports/${exportId}`,
|
|
type: 'info',
|
|
});
|
|
}
|
|
```
|
|
|
|
### Payment failure
|
|
|
|
```typescript
|
|
export async function onPaymentFailed(accountId: string) {
|
|
const client = getSupabaseServerAdminClient();
|
|
const api = createNotificationsApi(client);
|
|
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Payment failed. Please update your payment method.',
|
|
link: '/settings/billing',
|
|
type: 'error',
|
|
});
|
|
}
|
|
```
|
|
|
|
## Using translation keys
|
|
|
|
For internationalized apps, store translation keys instead of plain text:
|
|
|
|
```typescript
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'notifications.exportReady', // Translation key
|
|
link: '/exports',
|
|
});
|
|
```
|
|
|
|
The UI component runs the body through `t()` from next-intl, falling back to the raw string if no translation exists.
|
|
|
|
Add the translation to your locale files:
|
|
|
|
```json
|
|
{
|
|
"notifications": {
|
|
"exportReady": "Your data export is ready to download"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Notification channels
|
|
|
|
The `channel` field supports `'in_app'` (default) and `'email'`. Currently, only `in_app` is implemented. The `email` channel is reserved for future use where a database trigger could send email notifications.
|
|
|
|
```typescript
|
|
// In-app only (default)
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'New message received',
|
|
channel: 'in_app',
|
|
});
|
|
```
|
|
|
|
## Error handling
|
|
|
|
The API throws on failure. Wrap calls in try-catch for production code:
|
|
|
|
```typescript
|
|
try {
|
|
await api.createNotification({
|
|
account_id: accountId,
|
|
body: 'Notification message',
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to send notification:', error);
|
|
// Don't throw - notification failure shouldn't break the main flow
|
|
}
|
|
```
|
|
|
|
Notifications are typically non-critical. Consider logging failures but not throwing, so the primary operation (signup, export, etc.) still succeeds.
|
|
|
|
## Related documentation
|
|
|
|
- [Notifications overview](/docs/next-supabase-turbo/notifications): Feature overview and when to use notifications
|
|
- [Configuration](/docs/next-supabase-turbo/notifications/notifications-configuration): Environment variables and feature flags
|
|
- [UI Components](/docs/next-supabase-turbo/notifications/notifications-components): How notifications appear in the UI
|
|
- [Database schema](/docs/next-supabase-turbo/notifications/notifications-schema): Table structure and security policies
|