Skip to content

Notifications

Signed-in users get a notification bell in the app header (NotificationBell.jsx). It polls the Worker for the caller's notifications, shows an unread badge, and lets you open and mark them read. The browser never queries the table directly — everything goes through the Worker's /notifications endpoints, which scope every query to the signed-in caller.

What triggers one

  • comment — someone replied to your comment, or commented on a lesson you published. The Worker creates these inside its comment handler when a comment is posted (notifying the parent comment's author and the lesson's author). Comments are rich text, but the notification's body carries the comment flattened to plain text — the bell renders it as text, so markup would show up there as literal tags.
  • link — another signed-in user sent you a link via send link to user (an optional short message can ride along, and is profanity-checked server-side). Because the recipient may not have an account id yet, a link notification is addressed by email, so it's waiting for them the next time they sign in.
  • follow — someone started following you. The Worker creates this inside its follow handler (POST /profiles/:id/follow) when a new follow edge is added; re-following is a no-op and doesn't re-notify. Its link opens the follower's profile. See Following.
  • pull_request — someone proposed changes to a lesson you published, or the proposal you made was merged or closed. The three are one type because they're one conversation, and the title says which happened. The link follows what you'd want next: a proposal to review opens that proposal, while a merged or closed one opens the lesson, since the decision has already been made and what matters is where your changes ended up. Nothing is sent until a proposal actually has changes in it (an upload that never finished notifies nobody), and withdrawing your own never notifies you. A proposal opened from your own account — which is how an AI assistant working over MCP offers changes — reads "Changes are waiting for your review", because it's the only thing telling you there's something in the queue. See Pull requests.
  • lesson_update — a trusted collaborator saved a lesson you published. It changed under you and you didn't do it, so you're told. (Merging a proposal into your lesson also lands as one of these, from whoever merged it.)

How it's stored

Notifications live in the notifications table (defined in apps/api/schema.sql). A notification reaches its recipient either by their auth user id (user_id) or by their email (recipient_email, used by send-link before that person's id is known). Each row carries a type, title, body, optional link, a read flag, and a timestamp.

Worker endpoints

Method & pathAuthWhat it does
GET /notificationsBearer <Supabase JWT>The caller's notifications, newest first (by user id or email).
POST /notifications/readBearer <Supabase JWT>Marks the caller's notifications (or a given one) as read.
POST /notifications/send-linkBearer <Supabase JWT>Sends a link notification (URL + optional message) to a user by email.

The frontend wrapper is @spelling-creator/core/notifications.

Copyright © 2026 Spelling Creator.