Push Outbox and Suppression Audit

An audit trail from source changes through suppression decisions, outbox claims, and APNs results

Hangangjari creates notification candidates from source changes, applies delivery rules, and places only passing items in the outbox. APNs results and suppression reasons are both stored in the audit trail.

Operators need to distinguish no candidate, no matching subscription, policy suppression, and APNs delivery failure. Successful-send records alone cannot separate those states.

From Source Change to Notification Candidate

The push worker normalizes source events into canonical facts. A parking lot falling below a remaining-space threshold, a park crowding change, and an event cancellation each become a fact.

Then each fact is matched with subscriptions. The system checks which parks or lots the user cares about, which notification types are enabled, and whether quiet hours apply.

flowchart LR
  Source["Source change"] --> Fact["Notification fact"]
  Fact --> Match["Candidate matching"]
  Subscription["Subscriptions/settings"] --> Match
  Match --> Policy["Send decision"]
  Policy --> Decision["push_now or suppress"]
  Decision --> Outbox["Push outbox"]

Suppression Rules Applied First

Hangangjari has explicit suppression rules.

ExampleReason
Suppress broad parking-lot state-change notificationsUsers are closer to wanting remaining-space threshold alerts
Suppress threshold alerts for lots without remaining-space valuesThere is no actionable number
Suppress broad park state-change notificationsToo broad, with unclear user action
Suppress unclear crowding changesA safe message body cannot be made

Candidates that pass these rules receive user-setting and impact checks.

User Settings and Impact

After a candidate passes the suppression rules, the system evaluates the user’s notification mode and the fact’s priority.

The checks run in this order:

  • Did the user turn notifications off?
  • Is this change high urgency?
  • In parking-first mode, is this an important parking signal?
  • In outing-brief mode, is this an important park/event signal?
  • Otherwise, is it important enough for smart mode?

The result is push_now or suppress, and it must leave a reason code.

flowchart TD
  Candidate["Matched candidate"] --> Off{"Notifications off?"}
  Off -->|Yes| Suppress["Record suppression reason"]
  Off -->|No| Rule{"Stop rule applies?"}
  Rule -->|Yes| SuppressRule["Suppress with reason"]
  Rule -->|No| Tier{"Important or T0?"}
  Tier -->|Yes| Push["push_now"]
  Tier -->|No| Mode["Mode-specific decision"]

Non-Delivery Recorded in the Delivery Decision

Non-delivery is recorded as no candidate, subscription mismatch, policy suppression, or delivery failure.

The delivery-decision record stores subscription, fact, target, decision, reason code, policy mode, and policy version. It also prevents the same fact/subscription pair from being processed twice.

When reason-code distribution changes abruptly, fact generation and subscription matching are checked separately. Suppression records a candidate that intentionally did not proceed to delivery.

APNs Delivery from the Outbox

The outbox stores delivery work transactionally and lets a separate dispatcher send it to APNs.

sequenceDiagram
  autonumber
  participant Worker as Push worker
  participant Outbox as Outbox table
  participant Dispatcher as Push dispatcher
  participant APNs as APNs
  participant Repo as Delivery repository

  Worker->>Outbox: Enqueue notification for delivery
  Dispatcher->>Outbox: Fetch notification ready to send
  Dispatcher->>APNs: Send message to APNs
  alt Success
    Dispatcher->>Repo: Record delivery success
  else Invalid device token
    Dispatcher->>Repo: Record terminal failure and token-cleanup candidate
  else APNs auth error
    Dispatcher->>Repo: Defer remaining work
  else Retryable failure
    Dispatcher->>Repo: Store next attempt time and backoff
  end

When sending from the outbox, the system distinguishes:

  • Expired items are not sent.
  • Messages without prepared translations become terminal failures.
  • Invalid device tokens become cleanup candidates.
  • When APNs authentication fails, remaining items are deferred instead of being forced through.
  • Retryable failures reflect attempt count and backoff.

A Dashboard for Decision Reasons

The dashboard shows sends, suppressions, retries, invalid device tokens, long-waiting outbox items, and backlog by priority. An increase in suppression reasons leads to checks of fact generation and subscription rules; APNs errors are separated by retry and token-cleanup actions.

Reason Codes and Delivery Attempts

Delivery decisions record both sends and suppressions with reason codes. The outbox and delivery attempts connect missing translations, invalid device tokens, APNs authentication errors, and retryable failures to different follow-up actions.

Comments

Comments

    Image preview