Notification Subscription UI/UX Plan
Notification Subscription UI/UX Plan
Section titled “Notification Subscription UI/UX Plan”Reviewed: 2026-07-08
This is a rough product and implementation plan for the public outage alert subscription UI. It is intentionally practical: enough detail to guide the first Angular build without turning the UI into a large dashboard or a second backend design document.
Purpose
Section titled “Purpose”Create a simple authenticated UI that lets people subscribe to outage notifications without understanding the notification pipeline internals.
The UI should make the main task feel obvious:
- Choose what alerts they care about.
- Choose the places or keywords they care about.
- Create the subscription.
- Open the generated ntfy subscription link.
- Manage their saved alerts from their account.
This plan assumes the frontend will be built with current Angular using signals for local state, derived UI state, and async data boundaries. It was reviewed against Angular v22 docs on 2026-07-08. Spartan UI will provide the component system.
UX Goals
Section titled “UX Goals”- A first-time user can create an alert in under a minute.
- A signed-in user can create and manage their own alerts.
- The UI uses plain language: “alerts”, “areas”, “places”, and “notify me” instead of internal terms like “feed”, “destination”, or “filter”.
- Mobile is the primary layout. Desktop should feel roomier, not like a different product.
- The ntfy subscription step is explicit so users understand that creating an alert is not enough; they still need to open or copy the ntfy link.
- Advanced targeting is available without making the common path feel technical.
- The design leaves room for future email, maps, and analytics without forcing them into the MVP.
Design Principles
Section titled “Design Principles”- Start with the user’s question: “How do I get alerts for places I care about?”
- Prefer one clear decision per screen.
- Default to safe, broad choices, then let users narrow down.
- Keep technical concepts behind labels and summaries.
- Use progressive disclosure for feeders, keyword match mode, and other power-user filters.
- Make every destructive or high-friction action reversible or clearly confirmed.
- Treat subscription IDs as sensitive enough to avoid logging or sharing unnecessarily.
Target Users
Section titled “Target Users”Signed-In Resident
Section titled “Signed-In Resident”A resident wants outage alerts for the places they care about, such as a neighborhood, barangay, feeder, subdivision, or nearby landmark.
They should not need to know how notifications are stored, deduplicated, rendered, or delivered.
Returning User
Section titled “Returning User”A user comes back to the alerts area to edit areas, pause alerts, send a test notification, or delete the subscription.
Operations Or Support User
Section titled “Operations Or Support User”Someone helping another person should be able to walk through the screen and explain what each choice does without needing developer context.
Product Shape
Section titled “Product Shape”The first version should be a focused alert subscription tool, not a dashboard.
Recommended routes:
| Route | Purpose |
|---|---|
/alerts |
User’s alert list, empty state, and create entry point. |
/alerts/new |
Create subscription flow. |
/alerts/success/:publicId |
Success screen with ntfy subscribe link and test action. |
/alerts/:publicId |
Edit, test, pause, resume, or delete an owned subscription. |
/alerts/help |
Short help page for ntfy setup and troubleshooting. |
The UI can start as one Angular feature area. It does not need a new backend module, event bus, or admin shell.
Primary Workflow: Create An Alert
Section titled “Primary Workflow: Create An Alert”1. Start
Section titled “1. Start”The page headline should be direct:
Get outage alerts for your area
The first screen should show the task immediately, not a marketing page.
Recommended layout:
- Short headline.
- One sentence of support copy.
- Primary action:
Create alert. - Secondary link:
View my alerts.
2. Choose Alert Type
Section titled “2. Choose Alert Type”Use user-facing labels backed by the feed IDs returned by the API.
Recommended options:
| UI Label | API Meaning |
|---|---|
| Power outage alerts | Power outage notification feed. |
| Scheduled outage alerts | Scheduled outage notification feed. |
Avoid a broad “All alerts” option in the first pass unless the UI clearly explains that it may create more than one subscription behind the scenes. The current API creates one subscription per feed, so a “Both” option should either:
- create two subscriptions in sequence, or
- be deferred until the product intentionally supports bundled subscriptions.
Pragmatic MVP recommendation: start with one feed per subscription.
Recommended default:
- If the user entered from a power outage page, preselect power outage alerts.
- Otherwise, show both choices with neither selected until the user chooses.
3. Choose Areas Or Keywords
Section titled “3. Choose Areas Or Keywords”This is the most important UX step.
Use friendly copy:
Choose the places you care about
The UI should support entering location keywords such as barangay names, road names, neighborhoods, substations, or other feed text users recognize.
Use two clear choices:
| Choice | API Filter |
|---|---|
| All areas | Empty filter values. This matches all events for the selected feed. |
| Specific places | One or more locationKeywords, with optional advanced values. |
Do not force a location keyword for MVP. Some users may want the whole feed.
Recommended fields:
Area, barangay, road, or landmark- Add button or Enter-to-add behavior.
- Chips for selected keywords.
- Optional helper examples from common local language.
Advanced options can be hidden behind a disclosure:
- Feeder names or IDs.
- Exact event keywords.
- Match mode.
Do not make feeder IDs the primary path unless users commonly know them.
Validation rules to mirror the API:
- each filter list can contain up to 20 values,
- each filter value should be 100 characters or fewer,
- duplicate entries should collapse case-insensitively,
- blank chip values should be ignored before submit.
4. Choose Notification Events
Section titled “4. Choose Notification Events”Show plain labels. Map them to event types internally.
Examples:
| UI Label | Event Type | Meaning |
|---|---|---|
| New outage reported | NewOutage |
Notify when a new outage appears. |
| Outage restored | Restoration |
Notify when power is restored or the outage is removed. |
| Already restored outage announced | RestoredAnnouncement |
Notify when an outage first appears after it was already restored. |
| Scheduled outage added | NewEntry |
Notify when a scheduled outage is published. |
| Scheduled outage updated | Updated |
Notify when a scheduled outage changes. |
| Scheduled outage cancelled | Cancelled |
Notify when a scheduled outage is removed or cancelled. |
| Weekly scheduled outage summary | WeeklyDigest |
Notify when the weekly scheduled outage digest is sent. |
| Daily scheduled outage update | DailyUpdate |
Notify when daily schedule changes are summarized. |
| Tomorrow reminder | DayBeforeReminder |
Notify before scheduled outages happening tomorrow. |
The feed metadata endpoint should drive the available event types where possible, so the UI does not become stale when backend feed definitions change.
Recommended default:
- Preselect all event types for the chosen feed.
- Let users uncheck types only after they choose “Customize event types”.
- If all event types are selected, submit an empty
eventTypeslist so the backend treats it as “all supported events”.
5. Review
Section titled “5. Review”Before creating, show a compact summary:
- Alert type.
- Areas or keywords.
- Event types.
- Delivery method: ntfy.
The create button should be explicit:
Create alert
6. Success
Section titled “6. Success”After the API creates the subscription, the success screen should focus on the next required action.
Primary card:
Open in ntfyCopy subscribe linkSend test notification
Recommended success-state order:
- Open or copy ntfy subscribe link.
- Send test notification.
The user should leave the page knowing whether they subscribed successfully. A created subscription without an opened/copied ntfy link is only half done.
Manage Workflow
Section titled “Manage Workflow”The manage screen should load from the authenticated user’s subscription list or an owned public subscription ID.
Recommended sections:
- Status summary.
- Current alert type.
- Areas and filters.
- Event types.
- ntfy subscribe link.
- Test notification.
- Pause or resume.
- Delete alert.
Users should be able to update:
- area/location keywords,
- event types,
- active/inactive status,
- match mode if exposed.
The UI should show unsaved changes clearly and keep the save action sticky on small screens.
The test action should be obvious after creation and on the manage screen.
Recommended copy:
Send a test notification
Successful test:
Test sent. Check your ntfy app or browser subscription.
Failure:
The test could not be sent. Check that the ntfy topic is still available, then try again.
Delete
Section titled “Delete”Use a confirmation dialog.
Recommended copy:
Delete this alert?
Explain that deleting stops future notifications but does not delete outage history or analytics data.
Implementation note: the current API treats delete as deactivation. The UI can say “Delete alert” to the user, but the product behavior is “stop this alert from sending again.” Inactive subscriptions can be shown as stopped and may be resumed unless the API later introduces hard delete.
API Contract Used By The UI
Section titled “API Contract Used By The UI”The UI should use the authenticated notification subscription endpoints.
| Action | Endpoint |
|---|---|
| List available feeds | GET /api/notification-feeds |
| List my subscriptions | GET /api/notification-subscriptions |
| Create subscription | POST /api/notification-subscriptions |
| Get subscription | GET /api/notification-subscriptions/{publicId} |
| Update subscription | PUT /api/notification-subscriptions/{publicId} |
| Delete subscription | DELETE /api/notification-subscriptions/{publicId} |
| Send test notification | POST /api/notification-subscriptions/{publicId}/test |
The backend owns:
- generated public subscription IDs,
- generated ntfy topics,
- destination validation,
- per-user subscription limits,
- ownership checks,
- delivery provider details.
The frontend should not ask the user to enter an ntfy topic manually in the MVP.
Feed Metadata Shape
Section titled “Feed Metadata Shape”The create flow should start by loading feed metadata.
[ { "id": "beneco.power-outages", "displayName": "BENECO Power Outages", "eventTypes": ["NewOutage", "Restoration", "RestoredAnnouncement"], "filterableFields": [ { "name": "feeder", "displayName": "Feeder" }, { "name": "area", "displayName": "Area" }, { "name": "cause", "displayName": "Cause" }, { "name": "status", "displayName": "Status" }, { "name": "keywords", "displayName": "Keywords" } ], "allowsUserSubscriptions": true }]Use allowsUserSubscriptions to hide feeds that should not appear in the public create flow.
Create Request Shape
Section titled “Create Request Shape”The UI should send the smallest useful payload.
{ "displayName": "Home outage alerts", "feedId": "beneco.power-outages", "filter": { "locationKeywords": ["Bakakeng"], "eventTypes": ["NewOutage", "Restoration"], "matchMode": "Any" }, "provider": "Ntfy"}Do not send destination for public ntfy subscriptions. The backend rejects client-provided destinations and generates the topic itself.
Create Response Shape
Section titled “Create Response Shape”The created response includes everything needed for the success page.
{ "publicId": "ns_example1234", "displayName": "Home outage alerts", "feedId": "beneco.power-outages", "filter": { "feeders": [], "locationKeywords": ["Bakakeng"], "keywords": [], "eventTypes": ["NewOutage", "Restoration"], "matchMode": "Any" }, "provider": "Ntfy", "destination": "beneco-outages-alerts-example1234", "subscribeUrl": "https://ntfy.example.com/beneco-outages-alerts-example1234", "isActive": true, "createdAt": "2026-07-08T00:00:00+00:00", "lastSentAt": null}Error Code Mapping
Section titled “Error Code Mapping”Map backend error codes to user-facing text.
| Error Code | User Message |
|---|---|
NotificationSubscription.InvalidFeed |
This alert type is no longer available. Refresh and try again. |
NotificationSubscription.FeedNotAllowed |
This alert type is not available for public subscriptions yet. |
NotificationSubscription.UnsupportedProvider |
Public alerts currently support ntfy only. |
NotificationSubscription.DestinationNotAllowed |
The app creates the ntfy topic for you. Refresh and try again. |
NotificationSubscription.InvalidFilter |
One of the alert filters is invalid. |
NotificationSubscription.InvalidEventType |
One selected event type is not available for this alert. |
NotificationSubscription.FilterTooLarge |
Too many filter values were added. |
NotificationSubscription.FilterValueTooLong |
One filter value is too long. |
NotificationSubscription.LimitExceeded |
Your account already has the maximum number of active alerts. |
NotificationSubscription.NotFound |
This alert was not found. |
NotificationSubscription.Inactive |
This alert is paused or deleted. Reactivate it before sending a test. |
NotificationSubscription.TestDeliveryFailed |
The test notification could not be delivered. |
Suggested Angular Structure
Section titled “Suggested Angular Structure”Use standalone components and signal-first local state.
Recommended folders:
src/app/alerts/ data-access/ notification-subscription-api.ts notification-subscription.models.ts notification-subscription-errors.ts state/ subscription-form.store.ts subscription-manage.store.ts pages/ alerts-entry.page.ts create-subscription.page.ts subscription-success.page.ts manage-subscription.page.ts alerts-help.page.ts ui/ feed-picker.ts location-keyword-editor.ts event-type-picker.ts filter-summary.ts subscribe-ntfy-card.ts manage-link-card.ts subscription-status-banner.ts api-error-alert.tsKeep business rules on the backend. The Angular feature should validate for fast feedback, but the API remains the source of truth for allowed feeds, event types, topic generation, and subscription limits.
State Pattern
Section titled “State Pattern”Use signals for form state:
- selected feed,
- location keywords,
- event types,
- advanced filters,
- active status,
- request state.
Use computed signals for derived UI:
- whether the form can submit,
- human-readable filter summary,
- selected event labels,
- whether advanced filters are active,
- request payload.
Use Angular resource-style async state where it fits naturally:
- feed metadata loading,
- existing subscription loading,
- test notification status.
Keep RxJS mostly inside the API service or HTTP boundary unless the application already has an established RxJS pattern.
Recommended signal boundaries:
- private writable signals inside the store,
- read-only signal accessors exposed to components,
- computed request payloads instead of manual object rebuilding in templates,
- explicit submit methods for create, update, delete, and test actions,
- no async work hidden inside computed signals.
When an async action needs signal values, read the needed values before the await boundary and pass plain values to the API method.
Angular Template Style
Section titled “Angular Template Style”Use the current Angular control flow syntax:
@iffor loading, empty, and error states,@forfor lists of feeds, event types, and keyword chips,@switchif different feed types need different copy.
Prefer ChangeDetectionStrategy.OnPush for page and UI components.
Spartan UI Component Mapping
Section titled “Spartan UI Component Mapping”Use Spartan components to keep the UI accessible and consistent.
| UX Need | Spartan Component Direction |
|---|---|
| Main page sections | Card only where framing helps a single task or result. |
| Primary actions | Button. |
| Form layout | Field, Label, Input, Textarea where needed. |
| Feed choice | Radio Group for two choices; Select only if the list grows. |
| Event type choices | Checkbox list. |
| Location keyword entry | Input Group plus Badge chips; Autocomplete or Combobox later if suggestions exist. |
| Advanced filters | Accordion, Sheet, or Drawer on mobile. |
| Status messages | Alert. |
| Empty states | Empty. |
| Loading | Skeleton for page load; Spinner for button-local actions. |
| Copy/open actions | Button with Tooltip for icon-only variants. |
| Delete confirmation | Alert Dialog or Dialog. |
| Success/failure feedback | Sonner Toast plus inline confirmation. |
| Summary chips | Badge. |
| Pause/resume | Switch plus plain status text. |
Prefer Spartan Signal Forms for the create/edit form if it fits cleanly. Use the form root pattern so submit marks fields touched, runs validation, and reveals errors consistently. If it adds friction for dynamic chip lists, keep the first version with Angular signals and straightforward component inputs/outputs.
Visual Design Direction
Section titled “Visual Design Direction”The UI should feel calm, direct, and trustworthy.
Recommended style:
- Mobile-first single-column flow.
- One primary action per step.
- Clear spacing between decision groups.
- Small summaries after each step so users know what they selected.
- Plain icons only where they improve scanning.
- Avoid decorative hero sections, abstract graphics, and overly large cards.
The first viewport should show the actual alert creation task.
Interaction Details
Section titled “Interaction Details”Wizard Behavior
Section titled “Wizard Behavior”- Use a short stepper only if it reduces confusion. Do not make users click through empty ceremony.
- On mobile, keep the current step title, summary, and primary action visible.
- On desktop, use a two-column layout only if the right column is a live summary, not another card stack.
- Preserve in-progress selections if the user goes back to a previous step.
- Disable submit only for truly incomplete forms; otherwise let validation explain what is wrong.
Live Summary
Section titled “Live Summary”Show a compact summary after each major selection:
Power outage alertsSpecific places: Bakakeng, Camp 7Events: New outage, Power restoredDelivery: ntfyThis reduces anxiety before the final create action.
Subscription Link Handling
Section titled “Subscription Link Handling”- Show the ntfy subscribe URL after creation.
- Add a copy button with visible success feedback.
- Do not send subscription IDs, ntfy topics, or subscribe URLs to a third party analytics tool.
Accessibility And Usability
Section titled “Accessibility And Usability”Required behaviors:
- Every input has a visible label.
- Error messages are tied to fields.
- Keyboard users can complete the whole flow.
- Tap targets are comfortable on mobile.
- Copy buttons announce success.
- Color is not the only indicator for active, inactive, success, or error states.
- Loading states do not shift layout heavily.
- Delete and pause actions require clear confirmation or recovery.
- Icon-only buttons have accessible names.
- Form errors are announced when submit fails.
- Motion is subtle and not required to understand state.
Empty, Error, And Limit States
Section titled “Empty, Error, And Limit States”Feed Metadata Fails
Section titled “Feed Metadata Fails”Show:
Alert options could not be loaded. Please try again.
Action:
- Retry.
Subscription Not Found
Section titled “Subscription Not Found”Show:
This alert was not found.
Actions:
- Create a new alert.
- Check the link.
Per-IP Limit Reached
Section titled “Per-IP Limit Reached”Show:
You already have the maximum number of active alerts from this network.
Actions:
- Delete an alert no longer needed.
Test Notification Fails
Section titled “Test Notification Fails”Show:
The test notification could not be sent.
Actions:
- Retry.
- Copy subscribe link.
- Open help.
Inactive Subscription
Section titled “Inactive Subscription”Show:
This alert is paused.
Actions:
- Resume alert.
- Send test after resuming.
- Delete alert.
Invalid Filter
Section titled “Invalid Filter”Show:
One of the alert filters needs attention.
Actions:
- Highlight the exact field when possible.
- Keep the user’s entered values so they can fix them.
MVP Scope
Section titled “MVP Scope”Include:
- Create one ntfy subscription for one notification feed.
- List feed/event options from the backend.
- Let users choose all areas or specific place keywords.
- Location keyword filters.
- Event type selection.
- Success page with subscribe URL.
- Test notification.
- Manage page.
- Pause/resume through active status.
- Delete subscription.
- Mobile-first responsive layout.
Do not include yet:
- Email subscriptions.
- SMS subscriptions.
- Map selection.
- QR codes.
- Multiple feeds bundled into one wizard result.
- Admin dashboards.
- Historical analytics views.
Later Enhancements
Section titled “Later Enhancements”Good follow-up improvements:
- “Both power and scheduled outage alerts” as a bundled create flow.
- QR code for the ntfy subscribe link.
- Email delivery once verified addresses are supported.
- Suggested locations from known outage data.
- Map-assisted area selection.
- Saved presets for common barangays or feeders.
- User accounts for managing multiple alerts.
- Delivery channel choices once more providers exist.
- Lightweight analytics for create started, create completed, test sent, and manage updated.
Implementation Phases
Section titled “Implementation Phases”Phase 1: API Client And Models
Section titled “Phase 1: API Client And Models”- Add typed frontend models for feeds, subscriptions, filters, and delivery results.
- Add
NotificationSubscriptionApi. - Wire feed metadata loading.
- Add basic error handling.
- Add error-code-to-message mapping.
Phase 2: Create Flow
Section titled “Phase 2: Create Flow”- Build the create page using signal state.
- Add feed selection.
- Add all areas vs specific places selection.
- Add location keyword editor.
- Add event type picker.
- Add review summary.
- Submit to the create endpoint.
Phase 3: Success And ntfy Setup
Section titled “Phase 3: Success And ntfy Setup”- Build the success page.
- Show subscribe URL.
- Add copy and open actions.
- Add send test action.
- Show the ntfy subscribe URL clearly.
Phase 4: Manage Flow
Section titled “Phase 4: Manage Flow”- Load the user’s owned subscriptions.
- Edit filters.
- Save changes.
- Pause/resume.
- Delete with confirmation.
- Send test notification.
Phase 5: UX Polish
Section titled “Phase 5: UX Polish”- Add loading skeletons.
- Improve empty/error states.
- Verify mobile layout.
- Verify keyboard navigation.
- Verify copy buttons and screen reader labels.
- Add basic analytics events if the app already has an analytics pattern.
Acceptance Checklist
Section titled “Acceptance Checklist”- A signed-in user can create a power outage alert from a mobile viewport.
- A signed-in user can create a scheduled outage alert from a mobile viewport.
- A user can create an all-areas alert with an empty filter.
- A user can create a specific-places alert with location keyword chips.
- A user can copy and open the ntfy subscribe URL from the success page.
- A user can see their subscriptions in the alert list.
- A user can load an owned subscription from the alert list.
- A user can update filters and event types.
- A user can pause and resume an alert.
- A user can send a test notification only when the alert is active.
- A user can delete an alert, which deactivates it.
- API errors show plain user-facing text.
- Keyboard-only users can complete create, manage, test, and delete flows.
- The UI never asks the user to type an ntfy topic.
- The UI never sends a client-provided destination for public ntfy subscriptions.
Open Product Decisions
Section titled “Open Product Decisions”- Should “Both alert types” be exposed immediately, creating two subscriptions, or deferred?
- Should feeder targeting be visible by default or advanced-only?
- Should the user see the raw ntfy topic, or only the subscribe URL?
- Should paused subscriptions count toward the per-user maximum?
- Should digest and reminder event types be selected by default for scheduled outage alerts?
- Should the success page offer QR codes in MVP or keep them as a later enhancement?
Mental Model For Users
Section titled “Mental Model For Users”The UI should make the system feel like this:
Outage data changes -> Obaki checks what changed -> Obaki matches the change against my alert choices -> Obaki sends a notification to my generated ntfy link -> I can update or delete the alert later from my accountThe UI does not need to explain deduplication, event persistence, renderer classes, delivery attempts, or internal subscription records unless this becomes an admin experience.
References
Section titled “References”- Angular Signals: https://angular.dev/guide/signals
- Angular Template Control Flow: https://angular.dev/guide/templates/control-flow
- Spartan Components: https://www.spartan.ng/components
- Spartan Signal Forms: https://www.spartan.ng/forms/signal-forms
