Help us shape the future of Go! Take the 2026 Go Developer Survey

notify

package
v0.34.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package notify stores in-app notifications per user and fans them out to mail and real-time broadcast.

A notification is any value with a Kind; its JSON encoding is stored as the row's data. Send writes it through the channels you pass:

nf := notify.New(db, nil)
_, err := nf.Send(ctx, user.ID, CommentReplied{PostID: 7},
	notify.Database,
	notify.Mail(mailer, replyMail),
	notify.Broadcast(hub, func(id string) string { return "private-user." + id }))

SendTx does the same inside a transaction: the row is written with it, the mail is queued only if it commits and the broadcast is published after the commit. Unread, List, MarkRead and MarkAllRead serve the bell icon and the notification page; every query is scoped to the user id it receives.

Index

Constants

View Source
const MaxKind = 100

MaxKind is the longest Kind a notification may have.

View Source
const Table = "notifications"

Table is the table holding notifications.

Variables

View Source
var ErrNoChannels = errors.New("notify: no channel")

ErrNoChannels is returned by Send and SendTx without a channel.

Functions

func Database

func Database(ctx context.Context, ex database.Executor, s Stored, _ Notification) error

Database is the channel that writes the notification to Table, inside the transaction when SendTx is used.

func Migration

func Migration(id string) schema.Migration

Migration creates Table; register it with a timestamped id:

notify.Migration("20261029120000_create_notifications_table")

Types

type Channel

type Channel func(ctx context.Context, ex database.Executor, s Stored, n Notification) error

Channel delivers one notification. ex is the Executor Send or SendTx ran with (the transaction for SendTx); s is the stored form, n the original.

func Broadcast

func Broadcast(p Publisher, channelFor func(userID string) string) Channel

Broadcast returns a channel that publishes the Stored notification as event Kind on the channel named by channelFor (a private per-user channel). Inside SendTx it publishes after the commit, and a publish error then cannot fail the committed work: it is dropped, since the Database row stays the source of truth the client reloads.

func Mail

func Mail(
	m *mail.Mailer,
	build func(ctx context.Context, userID string, n Notification) (mail.Mailable, error),
) Channel

Mail returns a channel that queues the mailable build returns with Mailer.SendLaterTx, so it is sent only if the transaction commits. build returning a nil mailable skips the mail (a user without an address, or one who turned these mails off). The Mailer needs a queue (mail.ErrNoQueue otherwise).

type Notification

type Notification interface {
	Kind() string
}

Notification is something a user is told about. Kind names it ("comment.replied") so the front end can pick an icon and a text; the JSON encoding of the value is stored as Stored.Data.

type Notifier

type Notifier struct {
	// contains filtered or unexported fields
}

Notifier sends and reads notifications in Table.

func New

func New(db *database.DB, now func() time.Time) *Notifier

New returns a Notifier over db; now stamps created_at and read_at (time.Now when nil).

func (*Notifier) List

func (nf *Notifier) List(ctx context.Context, userID, cursor string, limit int) ([]Stored, string, error)

List returns up to limit of userID's notifications, newest first, after the cursor (empty for the first page), and the cursor of the next page ("" on the last one). limit is clamped to 1..100; 0 means 20. The cursor is the last id of the page: ids sort by creation time.

func (*Notifier) MarkAllRead

func (nf *Notifier) MarkAllRead(ctx context.Context, userID string) (int64, error)

MarkAllRead marks every unread notification of userID as read and returns how many changed.

func (*Notifier) MarkRead

func (nf *Notifier) MarkRead(ctx context.Context, userID string, ids ...string) (int64, error)

MarkRead marks userID's notifications with the given ids as read and returns how many changed. Ids of other users' notifications are ignored.

func (*Notifier) Prune

func (nf *Notifier) Prune(ctx context.Context, cutoff time.Time) (int64, error)

Prune deletes the notifications, read or not, created before cutoff and returns how many it deleted. Schedule it to bound the table.

func (*Notifier) Send

func (nf *Notifier) Send(ctx context.Context, userID string, n Notification, channels ...Channel) (Stored, error)

Send delivers n to userID through each channel in order and returns the stored form. It stops at the first channel error.

func (*Notifier) SendTx

func (nf *Notifier) SendTx(
	ctx context.Context,
	ex database.Executor,
	userID string,
	n Notification,
	channels ...Channel,
) (Stored, error)

SendTx is Send inside the transaction of ex (a *database.Tx from DB.Tx): a rollback discards the row, the queued mail and the broadcast.

func (*Notifier) Unread

func (nf *Notifier) Unread(ctx context.Context, userID string) (int64, error)

Unread counts userID's unread notifications.

type Publisher

type Publisher interface {
	Publish(ctx context.Context, channel, event string, data any) error
}

Publisher publishes an event on a channel; *broadcast.Server implements it.

type Stored

type Stored struct {
	ID        string          `json:"id"`
	UserID    string          `json:"user_id"`
	Kind      string          `json:"kind"`
	Data      json.RawMessage `json:"data"`
	ReadAt    *time.Time      `json:"read_at"`
	CreatedAt time.Time       `json:"created_at"`
}

Stored is a notification as written to Table and returned by List. It is also the data a Broadcast channel publishes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL