Epic 10 — Notifications & Preferences

Covers in-app and external (email/Slack) notifications on PR-created and run-failed events, per-project subscription management, quiet hours, and user-level theme and locale preferences.

Personas: BU (primary subscriber) AP (approval notifications) OP

Shared modules: CorrelationChip EnvProvenance

Story 10.1 — Receive In-App Notifications

As a
BU
I want
to receive in-app notifications when a run completes or fails
So that
I know immediately when my pipeline needs attention without watching the timeline
Scenario: In-app notification on run failure
Giventhe user has an active in-app notification subscription for the project and a run transitions to failed Whenthe notification arrives (via polling or WebSocket push) Thena notification badge increments in the global navigation; the notification panel shows: project name, run_id (truncated), status badge Failed, timestamp, and a deep-link to the run timeline
Scenario: In-app notification on PR created
Whenthe notification arrives for a completed PR delivery Thenthe notification panel shows: project name, run_id, PR created, PR URL (external link), and timestamp
Endpoint / DBPurpose
GET /notificationsPoll or WebSocket push for notification list
POST /notifications/{id}/readMark notification as read

Story 10.2 — Per-Project Subscription Management

As a
BU
I want
to subscribe or unsubscribe to notifications for specific projects
So that
I only receive notifications for the repositories I care about
Scenario: Subscribe to a project's notifications
Whenthe user toggles the subscription on in the project settings ThenPOST /subscriptions is issued with { "project_id": "...", "events": ["run_failed", "pr_created"] }; the toggle reflects the subscribed state
Scenario: Unsubscribe from a project's notifications
Whenthe user toggles the subscription off ThenDELETE /subscriptions/{subscription_id} is issued; the toggle reflects the unsubscribed state; no further notifications arrive from that project
Endpoint / DBPurpose
POST /subscriptionsCreate subscription; events array selects event types
DELETE /subscriptions/{subscription_id}Remove subscription
GET /subscriptionsList active subscriptions

Story 10.3 — External Delivery Channels (Email and Slack)

As a
BU
I want
to receive run-failed and PR-created notifications via email or Slack
So that
I am alerted even when I am not actively using the AMTP app
Scenario: Email and Slack delivery on subscribed event
Giventhe user has set a delivery email address and/or Slack incoming webhook URL in notification preferences and has an active subscription for a project Whena subscribed event fires (e.g. run failed) Thenan email/Slack message is sent containing the project name, run_id, status, and a deep-link to the run timeline
Scenario: No delivery channel configured — in-app only
Giventhe user has no email address and no Slack webhook in preferences Thenonly the in-app notification (Story 10.1) is generated; no external delivery is attempted
Endpoint / DBPurpose
PATCH /preferences/notificationsSet delivery channels (email, slack_webhook_url)

Story 10.4 — Quiet Hours

As a
BU
I want
to set quiet hours during which external notification delivery is suppressed
So that
overnight runs do not send alerts while I am unavailable
Scenario: Quiet hours suppress external delivery
Giventhe user has configured quiet hours 22:00–08:00 in their locale timezone and a run_failed event fires at 23:30 Whenthe notification system evaluates delivery Thenthe in-app notification is still created immediately; email and Slack delivery are deferred until 08:00
Endpoint / DBPurpose
PATCH /preferences/notificationsIncludes quiet_hours: { start, end, timezone }

Story 10.5 — Theme and Locale Preferences

As a
BU
I want
to set my preferred colour theme (light / dark / auto) and locale
So that
the interface matches my working environment and language
Scenario: User sets dark theme
Whenthe user selects Dark in preferences ThenPATCH /preferences/display is issued with { "theme": "dark" }; document.documentElement receives data-theme="dark"; the preference persists across sessions
Scenario: Locale change updates date formatting and RTL layout
WhenPATCH /preferences/display is issued with { "locale": "ar-AE" } Thenall date/time values are reformatted using the ar-AE locale; text directionality follows RTL conventions (logical properties enforce the correct layout per the i18n NFR)
Endpoint / DBPurpose
PATCH /preferences/displaySet theme, locale
GET /preferencesLoad persisted display preferences on app boot