peisear_notify/lib.rs
1//! Notification dispatch pipeline.
2//!
3//! ## Architecture
4//!
5//! Three stages connected by a tokio `mpsc::channel`:
6//!
7//! 1. **Detection** (callers, typically a snapshot/jobs loop in
8//! `peisear-web`). After observing a state change, the caller
9//! builds a [`DispatchEvent`] using helpers in [`edge`] and
10//! `tx.send`s it.
11//! 2. **Filtering + delivery** ([`dispatch::dispatch_loop`]).
12//! Receives events, resolves the user's
13//! [`peisear_core::notifications::Preference`] (or default),
14//! applies severity and cooldown filters, persists an audit
15//! row, fans out to channels.
16//! 3. **Channel send** (per-channel impls in [`channel`]).
17//! `in_app` is a no-op (the audit row is the artefact);
18//! `email` and `webhook` perform their own I/O.
19//!
20//! ## Cooperative shutdown
21//!
22//! The loop exits when its receiver returns `None`. The caller
23//! holds the [`DispatchTx`] and can drop it to drain and stop
24//! the loop, or send a oneshot for synchronous shutdown.
25//!
26//! ## Why a dedicated crate
27//!
28//! See `crates/peisear-notify/README.md`. Short answer: the
29//! transport dependencies (SMTP today, more later) shouldn't
30//! bleed into the web crate's compile graph, and a future
31//! `peisear-ai` summariser will want to produce events without
32//! depending on the web crate.
33
34pub mod channel;
35pub mod config;
36pub mod dispatch;
37pub mod edge;
38pub mod email;
39
40pub use dispatch::{DISPATCH_CHANNEL_BUFFER, DispatchEvent, DispatchRx, DispatchTx, dispatch_loop};
41pub use edge::{detect_burnout_overload_edge, detect_burnout_stalled_edge};