Skip to content

Bizcom Portal — Notification Routing Audit ​

Author: Apolinario Ratio
Date: 2026-03-25
Status: implementation-ready
Target branch: bizcom/notification-routing-audit


Summary ​

Outbound email logs from the last 7 days indicate two likely defects in the Bizcom notification subsystem:

  1. Recipient targeting is too broad for some notification classes, especially feedback and digest/account-update emails.
  2. Duplicate or repeated sends are likely occurring for the same subject-recipient combinations over time.

This is a user-trust, privacy, and operational-noise issue. The routing logic should be made record-scoped and default-deny, and the send pipeline should be made idempotent and auditable.


Evidence reviewed ​

Source file analyzed from NAS:

  • nas:agents-shared/ventures/bizcom/Bizcom Portal/emails-sent-1774418369547.csv

Observed patterns:

FindingEvidenceImplication
Feedback notification sent to multiple recipientsNew Feedback: other from Alex Gari went to 7 recipients; same for Angelyn Portafeedback routing is broader than necessary
Digest/account-update subjects sent to many recipients[BIZCOM] 4 updates on your account reached 13 recipientsdigest grouping/routing likely not partitioned tightly enough
Same subject-recipient pair repeated many timese.g. [BIZCOM] 3 updates on your account sent 46 times to one recipient over the 7-day windowdedupe / send-state / replay issue likely exists
Some alerts are single-recipientoverdue alerts for specific tasks went to one recipient onlynot all notification paths are broken; issue appears concentrated in digest/feedback flows

Problem statement ​

The notification subsystem appears to be mixing two failure modes:

1. Over-broad routing ​

Some notifications are being sent to role groups or broad recipient sets instead of only the users directly relevant to the underlying record or event.

2. Duplicate delivery ​

Some notifications appear to be re-sent repeatedly to the same recipient for the same subject/event class over time, suggesting weak idempotency or incorrect digest rebuild behavior.


Desired behavior ​

Routing principle ​

Default deny, then include explicit recipients only.

The system must derive recipients from the record/event itself, not from a broad role group unless that is explicitly the intended behavior.

Allowed routing by notification type ​

Notification typeIntended recipients
Client-specific updateauthorized contact(s) for that client only
Staff task/activity updateassigned staff only
Admin oversight eventadmins only
Feedback submissionconfigured reviewers / admins only
Internal workflow eventonly users attached to that workflow record

Failure rule ​

If the system cannot confidently derive recipients:

  • do not broadcast
  • do not silently fallback to everyone
  • log a routing-resolution failure
  • optionally notify admins as a system exception only

Engineering goals ​

  1. Targeted delivery — only relevant users receive a given event.
  2. Idempotency — the same event-recipient pair should not be re-sent unintentionally.
  3. Auditability — every outbound email can be traced to an event, a resolver, and a recipient reason.
  4. Safe fallback behavior — unresolved routing should degrade safely, not noisily.

Likely root-cause areas to inspect ​

A. Recipient selection logic ​

Check whether current logic:

  • expands too early to all admins/staff
  • uses role buckets where record-scoped recipients should be used
  • merges unrelated recipients into a shared digest/send list
  • treats "account updates" as org-global rather than recipient-partitioned

B. Digest builder / aggregation ​

Check whether digest generation is incorrectly grouped by:

  • organization instead of recipient
  • client instead of authorized contact
  • event class without recipient partitioning

C. Queue replay / sent-state handling ​

Check whether repeated sends happen because:

  • sent status is not persisted reliably
  • retries lack idempotency protection
  • scheduler re-collects previously included events
  • digest windowing allows old events to be rebuilt into new sends repeatedly

D. Feedback notifications ​

Check whether feedback submission currently notifies a broad internal audience rather than an explicit configured reviewer set.


Phase 1 — Trace current behavior ​

Add structured internal logging around outbound notification resolution:

  • notification type
  • source record id / event id
  • resolved recipients
  • why each recipient was included
  • dedupe key / idempotency key
  • send vs skip decision

Goal: confirm the exact failure point before invasive changes.

Phase 2 — Isolate recipient resolution ​

Refactor recipient selection into explicit resolver functions/modules per notification type.

Requirements:

  • no broad fallback by default
  • record-scoped resolution where applicable
  • explicit admin-only and reviewer-only paths
  • deterministic output for the same input event

Phase 3 — Add idempotency protection ​

Introduce stable dedupe keys such as:

<notification_type>:<source_event_id>:<recipient_id>:<window>

Use them to prevent:

  • duplicate queue processing
  • digest rebuild duplicates
  • retry duplication after partial failure

Phase 4 — Add observability and tests ​

Create tests and/or fixtures covering:

  • one client, one staff, one admin
  • multiple clients in the same org
  • repeated scheduler runs
  • retry after transient provider failure
  • feedback notification reviewer scoping

Acceptance criteria ​

Routing correctness ​

  • Feedback submission notifies only configured reviewers/admins.
  • Client update notifications reach only that client's allowed contacts.
  • Staff task notifications reach only assigned staff.
  • Admin-only events do not reach clients or unrelated staff.

Deduplication correctness ​

  • Re-running the same queue job does not resend the same event-recipient pair.
  • Rebuilding a digest does not duplicate already-sent items.
  • Retries do not create multiple successful sends for the same recipient/event.

Auditability ​

For any sent email, engineering/admin should be able to answer:

  • what event triggered it
  • why this recipient was included
  • whether it was first-send or retry
  • which dedupe key applied

Proposed testing plan for staging ​

  1. Seed one client with one authorized contact.
  2. Seed one assigned staff user and one admin.
  3. Trigger each relevant notification class:
    • feedback submission
    • task/activity update
    • client-facing update
    • admin-only event
  4. Verify exact recipients.
  5. Re-run scheduler / queue job.
  6. Verify no duplicate sends.
  7. Inspect logs for recipient resolution trace and dedupe keys.

Suggested implementation ticket title ​

Fix over-broad notification routing and duplicate email sends


Codex task framing ​

Use this document as the implementation source of truth.

Primary objective:

  • audit current recipient resolution and dedupe behavior
  • implement targeted routing and idempotency protections
  • preserve existing intended single-recipient alert behavior
  • keep changes staging-safe and testable tomorrow

First-pass implementation notes ​

Current branch implementation now applies these staging-safe controls:

  • Feedback submission emails resolve to explicit reviewers: active admin / superadmin users plus staff explicitly granted feedback.manage.
  • Feedback email routing now default-denies when no reviewer recipients can be resolved, and logs the routing failure instead of broadcasting.
  • Queue insertion now supports optional dedupe keys and logs duplicate-skip decisions.
  • Queue insertion also suppresses exact duplicate pending/processing rows for the same recipient + content within the dedupe window.
  • Client-facing task/compliance digest contributors now enqueue with recipient-scoped dedupe keys over an 8-hour window:
    • task_waiting
    • task_completed
    • approval_needed
    • documents_needed
    • document_reviewed

Remaining gaps for a later pass:

  • Other notification producers still rely on their existing caller-side guards and have not yet been moved to dedicated resolver modules.
  • Queue idempotency is currently opt-in for sent-row replay prevention; broader event-id based coverage would require standardizing dedupe keys across all producers.

Bizcom Portal Guide