Skip to main content

Notifications API

Planned

This module is not yet shipped. The shape below describes the intended endpoints on the new Hono + Supabase + Drizzle stack.

In-app notifications. Persisted as rows in notifications and fanned-out in real time via Supabase Realtime.

All endpoints require Authorization: Bearer <supabase-access-token>.

Endpoints

MethodPathDescription
GET/notificationsList notifications (paginated)
GET/notifications/countUnread count
POST/notifications/readMark a list of IDs as read
POST/notifications/read-allMark all as read
DELETE/notifications/:idDelete a notification

List

GET /notifications?unreadOnly=false&cursor=xxx&limit=20
Authorization: Bearer <token>
QueryTypeDescription
unreadOnlybooleanDefault false
cursor, limitPagination
{
"data": [
{
"id": "uuid",
"type": "group_approved",
"userId": "uuid",
"payload": { "eventId": "uuid", "groupId": "uuid" },
"readAt": null,
"createdAt": "2026-04-01T12:00:00Z"
}
],
"nextCursor": null
}

Notification types

TypeTrigger
friend_requestSomeone sent you a friend request
friend_acceptedA friend request you sent was accepted
author_inviteYou were invited as event author
group_likeA user liked your event
group_approvedYour like group was approved
group_rejectedYour like group was rejected
messageNew chat message (suppressed if chat is open)
event_reminderEvent starting soon

The payload shape is type-specific and validated server-side.

Unread count

GET /notifications/count
{ "count": 5 }

Mark as read

POST /notifications/read
{ "ids": ["uuid1", "uuid2"] }
POST /notifications/read-all

Both set read_at = now() for the matching rows owned by the caller.

Delete

DELETE /notifications/:id

Hard-deletes the row (small table, no audit need).

Realtime

Clients can subscribe to their own notification stream via Supabase Realtime:

supabase
.channel(`user:${userId}:notifications`)
.on(
"postgres_changes",
{ event: "INSERT", schema: "public", table: "notifications", filter: `user_id=eq.${userId}` },
(payload) => addToTray(payload.new),
)
.subscribe();

RLS ensures a user only sees their own rows on the stream.

Implementation notes

  • Notifications are written by the originating service (e.g. groups.service.ts writes group_approved inside the same Drizzle transaction that flips group status).
  • For higher-volume types (e.g. message), the API may batch or collapse notifications server-side rather than emit one per row.
  • Push (APNs / FCM) and email are out of scope for v1; only in-app notifications are tracked here.