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

notify

package
v1.39.0 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 8 Imported by: 0

README

AuthKit account inbox

github.com/open-rails/authkit/notify owns account notification types and the producer-facing Publisher interface. AuthKit provides the configured publisher; applications pass it to ContentKit, OpenRails or their own domain services.

Use Publish(ctx, []Publication, tx...) and Withdraw(ctx, []Withdrawal, tx...). The exact deterministic ID and positive producer revision identify source state. AuthKit binds the account tenant, source origin and application visibility. Neither operation requires an inbox read. Omit the transaction for independent durable acceptance, or supply one non-nil same-source-database transaction. Remote publishers always queue a durable source delivery job; only workers send HTTP. Local publication and withdrawal join the account database transaction.

The postgres subpackage contains the inbox persistence and explicit migration and adoption machinery. Its existing SQL bytes, ledger, namespace, advisory lock, receipt IDs and erasure fences are preserved from the earlier Helpers package. It is not another service or an application-owned inbox. Host-facing API and client behavior belong to AuthKit; producers use the small publisher contract.

Read/archive state remains separate from producer resolution. Withdrawals hide unread items and retain a revision tombstone; delayed old delivery cannot revive them. A newer explicit publication can reopen unread. Batches are atomic and bounded at100 exact identities; no ranges or prefix deletion are supported.

See the configuration, delivery and migration guide.

Documentation

Overview

Package notify defines AuthKit account inbox data and the scoped producer interface. AuthKit owns storage and authorization; producers own the domain action that remedies a problem. Reading never resolves that action. Legacy envelopes remain available for explicit data adoption and durable wire replay.

Index

Constants

View Source
const MaxMutations = 100

MaxMutations bounds one atomic publication/withdrawal batch.

Variables

View Source
var (
	ErrInvalid         = errors.New("notify: invalid input")
	ErrNotFound        = errors.New("notify: item not found")
	ErrConflict        = errors.New("notify: item changed")
	ErrRecipientErased = errors.New("notify: recipient erased")
)

Errors are stable outcomes of validation, scoped lookup and concurrent edits.

Functions

func ValidateRecipient

func ValidateRecipient(r Recipient) error

ValidateRecipient checks the scope-local identity; it grants no authority.

func ValidateWithdrawal

func ValidateWithdrawal(in Withdrawal) error

ValidateWithdrawal checks an exact producer identity and its durable revision.

Types

type Adoption

type Adoption struct {
	Previous []Origin `json:"previous"`
	Current  Mutation `json:"current"`
}

Adoption maps exact legacy origins for Current's recipient to one current producer identity during an explicit, stopped-writer migration. The host authorizes the mapping; it never means a prefix, range or inbox search.

type AppView

type AppView struct {
	AppID         string
	LegacyOrigins []OriginScope
}

AppView presents tenant-wide receipts and one exact application's receipts. LegacyOrigins is an explicit compatibility allowance for unclassified rows. A nil or empty allowance admits no legacy origins.

type Audience

type Audience string

Audience selects an authorization boundary, not a delivery channel.

const (
	AudienceUser     Audience = "user"
	AudienceOperator Audience = "operator"
)

type Input

type Input struct {
	Recipient  Recipient       `json:"recipient"`
	Origin     Origin          `json:"origin"`
	Kind       string          `json:"kind"`
	Data       json.RawMessage `json:"data"`
	CreatedAt  time.Time       `json:"created_at"`
	Visibility Visibility      `json:"visibility,omitempty"`
	AppID      string          `json:"app_id,omitempty"`
	Status     Status          `json:"status,omitempty"`
	// ActionRequested records the item's category at creation. With empty Status
	// it is historical information, not a claim that the issue is still open.
	ActionRequested bool   `json:"action_requested,omitempty"`
	Severity        string `json:"severity,omitempty"`
}

Input is trusted application-authored content. Kind is extensible. Data must contain only fields the recipient may see. CreatedAt is the source time. Publish accepts StatusNotice or StatusOpen; workflow transitions are separate.

func Validate

func Validate(in Input) (Input, error)

Validate checks a publish input and supplies an empty JSON object when omitted.

type Item

type Item struct {
	ID string `json:"id"`
	Input
	ReadAt *time.Time `json:"read_at"`
	// DismissedAt archives this recipient's receipt without resolving work.
	DismissedAt *time.Time `json:"dismissed_at"`
	ResolvedAt  *time.Time `json:"resolved_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
	Revision    int64      `json:"revision"`
	// ProducerRevision orders source mutations independently of receipt changes.
	ProducerRevision int64 `json:"producer_revision,omitempty"`
	// Withdrawn items are retained only to reject delayed producer mutations.
	Withdrawn bool `json:"withdrawn,omitempty"`
}

Item is an inbox record or a projection of an existing domain record. ReadAt and ResolvedAt describe different operations; neither implies the other. Revision is positive in the durable store and zero for unversioned projections.

type ListOptions

type ListOptions struct {
	Limit      int
	Cursor     string
	UnreadOnly bool
	Status     *Status
	// Dismissed selects archived receipts instead of the active inbox.
	Dismissed bool
}

ListOptions selects a bounded, newest-first page. Status nil includes notices and work items; a pointer to StatusNotice selects only general notices.

type Mutation

type Mutation struct {
	Input
	Revision  int64 `json:"revision"`
	Withdrawn bool  `json:"withdrawn,omitempty"`
}

Mutation is the current state of one exact producer identity. The producer durably assigns Revision before delivery; transport retries reuse it. A newer publication replaces the payload, while Withdrawn hides the item even if it has not arrived yet. Neither IDs nor withdrawals interpret wildcards.

func ValidateMutation

func ValidateMutation(in Mutation) (Mutation, error)

ValidateMutation validates and normalizes one producer mutation. Withdrawal needs only recipient, origin and visibility; payload fields are ignored.

type Origin

type Origin struct {
	System string `json:"system"`
	Scope  string `json:"scope"`
	ID     string `json:"id"`
	// Subject is the source recipient, when the destination maps it to a
	// different local identity. It grants no authority by itself.
	Subject string `json:"subject,omitempty"`
}

Origin preserves a producer's deployment, namespace and stable item ID. Scope can identify a merchant, project or account issuer. Each recipient receives at most one item for the same System, Scope and ID in one local store scope; Subject is optional provenance, not part of that identity.

type OriginScope

type OriginScope struct {
	System string `json:"system" yaml:"system"`
	Scope  string `json:"scope" yaml:"scope"`
}

OriginScope selects all items from one exact producer namespace. It is separate from recipient authorization and never grants access to an account.

type Page

type Page struct {
	Items      []Item `json:"items"`
	NextCursor string `json:"next_cursor,omitempty"`
}

Page is a bounded page; NextCursor is empty at the end of a current scan.

type Publication

type Publication struct {
	RecipientID     string
	ID              string
	Revision        int64
	Kind            string
	Data            json.RawMessage
	CreatedAt       time.Time
	ActionRequested bool
	Severity        string
}

Publication describes one user's current notification. ID is the exact deterministic producer ID, not a receipt ID or a wildcard pattern.

func ValidatePublication

func ValidatePublication(in Publication) (Publication, error)

ValidatePublication normalizes content before durable acceptance. The bound publisher supplies origin and visibility; recipients must be canonical account UUIDs, just as on the authenticated destination endpoint.

type Publisher

type Publisher interface {
	Publish(context.Context, []Publication, ...pgx.Tx) error
	Withdraw(context.Context, []Withdrawal, ...pgx.Tx) error
}

Publisher is the producer-facing account inbox channel. AuthKit binds its tenant, origin and application visibility when constructing the publisher. Each batch accepts at most MaxMutations exact identities. Retries reuse the producer's revision; older revisions never undo a newer publication or withdrawal. Producers do not read the inbox to decide what to publish.

Omit tx to durably accept the batch in a new transaction. Supplying one non-nil transaction joins the batch to the producer's database mutation. Remote publishers enqueue delivery in their source database in both cases; successful acceptance does not require the destination to be online.

type Reader

type Reader interface {
	List(context.Context, Recipient, ListOptions) (Page, error)
}

Reader is a recipient-scoped inbox. Callers supply an authorized recipient.

type Recipient

type Recipient struct {
	Audience Audience `json:"audience"`
	ID       string   `json:"id"`
}

Recipient names a user or an operator queue within the store's scope. Hosts authorize this pair; an email address is never an identity join.

type Status

type Status string

Status is independent of read state. A general notice has no workflow; actionable items begin open and are explicitly resolved or dismissed.

const (
	StatusNotice    Status = ""
	StatusOpen      Status = "open"
	StatusResolved  Status = "resolved"
	StatusDismissed Status = "dismissed"
)

type Visibility

type Visibility string

Visibility identifies where a receipt may be presented; Origin remains provenance and replay identity. Empty visibility means an unclassified legacy item, never an implicit tenant-wide grant in an AppView.

const (
	VisibilityTenant Visibility = "tenant"
	VisibilityApp    Visibility = "app"
)

type Withdrawal

type Withdrawal struct {
	RecipientID string
	ID          string
	Revision    int64
}

Withdrawal hides one exact producer identity, including one not yet delivered. The retained revision prevents an older queued publication from reviving it.

Directories

Path Synopsis
Package postgres implements notify's durable inbox on a host-owned PostgreSQL pool.
Package postgres implements notify's durable inbox on a host-owned PostgreSQL pool.

Jump to

Keyboard shortcuts

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