notifications

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

README

StuHelper Notifications

站内通知模块,采用 Handler → Service → Repository。业务规格与当前实现见 通知说明,HTTP 定义见 OpenAPI。

本地检查

使用 Go 1.27.3、Node.js 24.22.1、pnpm 10.33.4。安装锁定依赖并启用 hooks:

make setup
pnpm run hooks
make generate
bash scripts/check-with-postgres.sh

数据库脚本创建独立、仅 Unix socket 可访问的临时 PostgreSQL,退出时清理。可通过 STUHELPER_TEST_PG_BIN 指定 PostgreSQL 程序目录。make check 要求 STUHELPER_NOTIFICATIONS_TEST_DSN 指向隔离测试服务器,测试会创建和删除专属数据库与角色。

Backend 装配

  1. 仓库为 StuHelper/stuhelper-notifications,默认分支 develop。候选在 feat/backend-decisions 分支和 PR #1 维护,集成时登记候选提交与依赖组合。
  2. backend 引入模块,迁移身份调用 postgres.Migrate(ctx, db)。该迁移创建 notifications schema,已有通知不会被删除。
  3. 单独创建运行身份,授予 schema USAGE、items/preferences 的 SELECT、INSERT、UPDATE、DELETE,revisions 的 SELECT、INSERT、UPDATE,以及 inbox 的 SELECT、INSERT。运行身份不得拥有 schema 或提权能力,也不得更新删除 inbox 或删除 revisions。
  4. 使用运行连接构造 postgres.Repository,并调用 CheckRuntime。backend 管理连接池、请求超时、健康检查和连接关闭。迁移身份不进入业务进程。
  5. 调用 notifications.New(repo, resolver, config, clock)。Resolver 根据来源模块和目标引用调用所属模块公开接口,按接收人当前权限返回状态。依赖错误返回 error,禁止默认判定可访问。
  6. 将 httpapi.Handler 挂载至 /api/v1/notifications 及其子路径,Authenticate 回调复用平台认证,返回稳定用户标识。Cookie 认证由宿主同时执行 CSRF 防护。
  7. 标题键、参数和目标类型必须符合 标题目录。向 backend relay 注入 notifications.Consumer。relay 保留生产者的 source、id、type、subject、revision,将全部收件人放入 Event.Recipients 后调用 Consume。Consume 成功后才能调用提供方 ConfirmOutbox;超时重试沿用原事件和映射。
  8. 宿主按配置周期调用 Service.Cleanup(ctx),每次一个有上限的批次。关闭服务时取消任务并等待退出。宿主配置任务超时,保留可再次执行的进度。
  9. 负责人同步 stuhelper-next 规格的实现状态、模块登记和候选锁文件,并更新 Web 的 SDK 快照及实际通知页面。合并前验证真实候选组合。

配置

以下为 Go Config 字段,环境变量映射由 backend 负责。

配置 条件与用途
Retention 正时长,按创建时间保留通知
AggregationWindow 正时长且不超过 Retention,互动聚合窗口
CleanupBatch 1 至 10000,每次清理最大条数
ResolveTimeout 正时长,每次目标状态查询超时

backend 还须提供独立运行数据库连接、迁移连接、清理周期、清理超时和认证回调。模块没有内置凭据或隐含保留期限。

Resolver 顺序处理当前页目标,每页最多 100 次调用。宿主应设置整个请求的总超时,Resolver 必须响应 context 取消。profiles 缺失只影响未来外部渠道偏好,不影响当前能力。

当前 SDK 包含 Go HTTP 客户端和 TypeScript 类型,分别由 oapi-codegen 与 openapi-typescript 生成。Go Consumer 是内部模块接口,不开放网络投递入口。消费输入和 relay 处理约定见 事件消费。

Consume 每次接收 1–20 个收件人条目,去重排序后原子写入整批结果。Result.Recipients 返回逐人通知 ID 或抑制原因。若候选库已有单收件人 inbox 数据,迁移会明确报错并保留数据;恢复要求见事件消费说明。

Documentation

Index

Constants

View Source
const (
	SuppressionInteractionDisabled = "interaction_disabled"
	SuppressionStaleRevision       = "stale_revision"
)

Variables

View Source
var (
	ErrInput           = errors.New("invalid_input")
	ErrUnauthenticated = errors.New("unauthenticated")
	ErrNotFound        = errors.New("not_found")
	ErrConflict        = errors.New("idempotency_conflict")
	ErrUnavailable     = errors.New("unavailable")
)

Functions

func OpenAPI

func OpenAPI() []byte

OpenAPI returns the exact provider contract for consumer compatibility checks.

Types

type Config

type Config struct {
	Retention         time.Duration
	AggregationWindow time.Duration
	CleanupBatch      int
	ResolveTimeout    time.Duration
}

type Consumer

type Consumer interface {
	Consume(context.Context, Event) (Result, error)
}

type Cursor

type Cursor struct {
	CreatedAt time.Time
	ID        string
}

type Event

type Event struct {
	Source      string
	ID          string
	EventType   string
	Subject     string
	Revision    int64
	Recipients  []string
	Type        string
	Target      Target
	TitleKey    string
	TitleParams map[string]string
}

Event is a trusted, complete notification mapping of one source event. Source, ID, EventType, Subject and Revision retain the producer's identity. The relay validates the CloudEvents envelope and maps only supported results.

type Notification

type Notification struct {
	ID           string            `json:"id"`
	Type         string            `json:"type"`
	SourceModule string            `json:"source_module"`
	Target       Target            `json:"target"`
	TitleKey     string            `json:"title_key"`
	TitleParams  map[string]string `json:"title_params"`
	CreatedAt    time.Time         `json:"created_at"`
	ReadAt       *time.Time        `json:"read_at"`
	TargetStatus string            `json:"target_status"`
	Count        int64             `json:"count"`
}

type Page

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

type Preferences

type Preferences struct {
	InteractionEnabled bool `json:"interaction_enabled"`
}

type RecipientResult

type RecipientResult struct {
	Recipient         string `json:"recipient"`
	ID                string `json:"id"`
	SuppressionReason string `json:"suppression_reason"`
}

type Resolver

type Resolver interface {
	Resolve(context.Context, string, string, Target) (string, error)
}

Resolver enforces current target authorization for the recipient. Unknown targets must return inaccessible; dependency failures return an error.

type Result

type Result struct {
	Recipients []RecipientResult `json:"recipients"`
	Ignored    bool              `json:"ignored"`
}

type Service

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

func New

func New(repo Repository, resolver Resolver, config Config, now func() time.Time) (*Service, error)

func (*Service) Cleanup

func (s *Service) Cleanup(ctx context.Context) (int64, error)

Cleanup performs one bounded batch. The host schedules further batches.

func (*Service) Consume

func (s *Service) Consume(ctx context.Context, d Event) (Result, error)

func (*Service) List

func (s *Service) List(ctx context.Context, owner, after string, limit int) (Page, error)

func (*Service) MarkAllRead

func (s *Service) MarkAllRead(ctx context.Context, owner string) error

func (*Service) MarkRead

func (s *Service) MarkRead(ctx context.Context, owner, id string) error

func (*Service) Preferences

func (s *Service) Preferences(ctx context.Context, owner string, enabled *bool) (Preferences, error)

func (*Service) Unread

func (s *Service) Unread(ctx context.Context, owner string) (int64, error)

type Target

type Target struct {
	Kind string `json:"kind"`
	ID   string `json:"id"`
}

Directories

Path Synopsis
Package sdk provides primitives to interact with the openapi HTTP API.
Package sdk provides primitives to interact with the openapi HTTP API.

Jump to

Keyboard shortcuts

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