Skip to main content

Notification Service — Jira Epics & User Stories

Status: populated Owner: Product + Platform Engineering Last updated: 2026-04-18


Epic EP-NOTIF-01: Event Consumption & Routing

Goal: Consume platform lifecycle events from NATS and route to the appropriate notification handler.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-001Consume auth.user.registered.v1 eventsGiven a auth.user.registered.v1 event on auth.events, when consumed, then SendUserRegisteredNotificationUseCase is invoked and NATS message ACKed2
US-NOTIF-002Consume billing.invoice.generated.v1 eventsGiven a billing.invoice.generated.v1 event on billing.events, when consumed, then SendInvoiceGeneratedNotificationUseCase is invoked2
US-NOTIF-003Consume operator.health.status_changed.v1 (DOWN)Given an operator status change to DOWN, when consumed, then SendOperatorDownNotificationUseCase is invoked2
US-NOTIF-004Consume operator.health.status_changed.v1 (UP)Given an operator recovery event (newStatus=UP), when consumed, then SendOperatorRecoveredNotificationUseCase is invoked1
US-NOTIF-005Consume system.alerts.raised.v1 eventsGiven a system alert event, when consumed, then SendSystemAlertNotificationUseCase is invoked with severity routing2
US-NOTIF-006Deduplicate NATS redeliveriesGiven a NATS event with a sourceEventId already in notification_log with status=SENT, when redelivered, then the notification is SUPPRESSED and NATS ACKed3
US-NOTIF-007Per-subject durable consumersGiven 4 NATS subjects, then each has its own independently-manageable durable consumer with a named consumer group2
US-NOTIF-008Per-consumer feature flagGiven NOTIF_CONSUMERS_ENABLED env vars per subject, then individual consumers can be enabled/disabled without restart2

Epic EP-NOTIF-02: Preference Management & Suppression

Goal: Respect per-account notification opt-outs while ensuring mandatory notifications are always delivered.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-009Preference lookup before dispatchGiven an account with optedOut=true for OPERATOR_ALERT × EMAIL, when an OPERATOR_DOWN notification is dispatched, then status=SUPPRESSED is logged and no email is sent2
US-NOTIF-010SYSTEM_SECURITY ignores opt-outGiven an account with optedOut=true for SYSTEM_SECURITY × EMAIL, when a CRITICAL system alert fires, then email is delivered regardless (opt-out bypassed)3
US-NOTIF-011BILLING and ACCOUNT categories non-optionalGiven any opt-out for BILLING or ACCOUNT category, then invoice and registration emails are always sent2
US-NOTIF-012Default opted-in behaviorGiven a new account with no notification_preferences rows, then all notifications are dispatched (opted-in by default)1
US-NOTIF-013Update preference via internal endpointGiven a PUT /internal/preferences with valid body from admin-dashboard, then the preference is upserted and takes effect on next dispatch2
US-NOTIF-014List preferences for accountGiven GET /internal/preferences?accountId=..., then all category × channel preferences for that account are returned1

Epic EP-NOTIF-03: Template Engine

Goal: Provide a DB-backed, versioned template system with Handlebars + Mjml rendering and admin management.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-015Render Handlebars + Mjml email templateGiven a template with Mjml body and Handlebars variables, when rendered with a valid variable map, then valid HTML is returned with all variables substituted3
US-NOTIF-016Plain-text fallback on Mjml errorGiven a template where Mjml compilation fails, when rendering, then bodyText is returned and a NotifTemplateRenderError metric is incremented2
US-NOTIF-017Variables schema validation at save timeGiven a template with variablesSchema defining required fields, when saving with POST /internal/templates, then the schema is validated and 400 returned for invalid JSON Schema2
US-NOTIF-018Variables schema validation at render timeGiven a render call missing a required variable, then TemplateRenderError is thrown, delivery is FAILED, and the error is logged2
US-NOTIF-019Unique active template per type × channelGiven an existing active template for INVOICE_GENERATED × EMAIL, when creating a second active template for the same type × channel, then 409 conflict is returned2
US-NOTIF-020Versioned template updateGiven a PATCH /internal/templates/{id}, then version increments, is_active remains true, and the old version is readable via the notification_log reference2
US-NOTIF-021Template preview endpointGiven POST /internal/templates/{id}/preview with sample variables, then rendered HTML and plain text are returned without triggering a delivery2
US-NOTIF-022List and get templatesGiven GET /internal/templates and GET /internal/templates/{id}, then active templates are returned with full bodyHtml, bodyText, and variablesSchema1

Epic EP-NOTIF-04: Delivery Channels

Goal: Deliver notifications via email (SendGrid) and SMS (Ghasi platform) with retry and audit.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-023Email delivery via SendGridGiven a rendered email notification, when delivered, then SendGrid POST /v3/mail/send is called with correct from, to, subject, html, text; providerMessageId stored in log3
US-NOTIF-024SMS delivery via sms-orchestratorGiven an SMS notification, when delivered, then POST /v1/sms/send is called with metadata.priority=low and notificationId; messageId stored as providerMessageId3
US-NOTIF-025Retry on transient delivery failure (3 attempts)Given a transient SendGrid 5xx, when retrying with backoff (5s, 30s, 2min), then up to 3 attempts are made before logging FAILED3
US-NOTIF-026No NATS NAK on permanent delivery failureGiven all 3 retry attempts fail with a permanent error (e.g. invalid email), then the NATS message is ACKed, status=FAILED logged, and NotifEmailDeliveryFailed alert fires2
US-NOTIF-027Dual channel for OPERATOR_DOWNGiven an OPERATOR_DOWN event and an opted-in admin, then both an EMAIL and an SMS notification are dispatched; both logged independently2
US-NOTIF-028CRITICAL alert dual channelGiven a system.alerts.raised.v1 with severity=CRITICAL, then EMAIL + SMS dispatched to all platform.admin users, ignoring opt-out2
US-NOTIF-029Platform admin recipient resolutionGiven a platform alert, then auth-service is queried for all platform.admin users; result cached 5 min in Redis2

Epic EP-NOTIF-05: Notification Audit Log

Goal: Every delivery attempt is traceable, including suppressions and failures.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-030Log every delivery attemptGiven any dispatch path (SENT, FAILED, or SUPPRESSED), then a notification_log row is created with status, channel, category, sourceEventType, sourceEventId, attemptCount2
US-NOTIF-031PII masking in logGiven a delivery to user@example.com, then notification_log.recipient_address stores ***@example.com2
US-NOTIF-032Query notification log via admin endpointGiven GET /internal/notifications?accountId=...&status=FAILED, then filtered log entries are returned in reverse chronological order2
US-NOTIF-03390-day log retentionGiven notification_log rows older than 90 days, then they are dropped with the monthly partition; financial data not affected1

Epic EP-NOTIF-06: Observability & Reliability

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-034Prometheus metrics endpointGiven /metrics, then all notification metric families exposed in Prometheus format2
US-NOTIF-035NotifEmailDeliveryFailed alertGiven email FAILED rate > 5% for 5 min, then alert fires1
US-NOTIF-036NotifSystemAlertFailed alertGiven a CRITICAL system alert with status=FAILED, then alert fires immediately2
US-NOTIF-037NotifNatsLag alertGiven consumer lag > 5000 on any subject, then alert fires1
US-NOTIF-038Readiness probeGiven /health/ready, then 200 only when PG, NATS, and SendGrid are reachable1

Epic EP-NOTIF-07: National Incident Broadcasts to All Platform Stakeholders

Goal: During a national-scale incident (regional outage, MNO-wide outage, regulator advisory) the platform must reach all relevant stakeholders (tenants, NOC, on-call, regulator-portal) over multiple channels in seconds.

Story IDTitleAcceptance CriteriaPoints
US-NOTIF-039Incident broadcast trigger from NOCPOST /v1/internal/notifications/broadcast accepts severity (CRITICAL/HIGH/MEDIUM), audience (all-tenants, by-tier, by-affected-mno, by-region), channels (in-portal, email, SMS, webhook), and pre-approved templateId; mTLS-only, NOC role required5
US-NOTIF-040Multi-channel fan-out within 60 sFan-out engine writes to in-portal, email, SMS via channel-router, and tenant webhooks within 60 s P95; per-channel delivery status tracked in notif.broadcast_deliveries5
US-NOTIF-041Tenant unsubscribe protectionsTenants cannot unsubscribe from CRITICAL severity (regulator/safety); HIGH allows opt-out only with explicit signed acknowledgement; MEDIUM is fully opt-out-able per channel3
US-NOTIF-042Broadcast reach reporting and auditAfter broadcast: notif.broadcast.report.v1 emitted with reached/failed/opted-out counts per channel; archived 7 y in notif.broadcast_audit3