Files
marketplaces/docs/superpowers/specs/2026-08-15-admin-purchase-notifications-design.md
2026-08-15 02:08:36 +04:00

78 lines
2.9 KiB
Markdown

# Admin purchase notifications — design
**Status:** Approved
**Date:** 2026-08-15
**Related backlog item:** #7 (marked ВАЖНО — important)
## Problem
Admin has no signal when a purchase happens on the marketplace. Orders only surface if
someone manually opens the Orders list and refreshes. Backend exposes no WebSocket/SSE
(confirmed in `BACKEND-API-REFERENCE.md:20` — every "live" feature today, e.g. payment
status, is plain polling), so this has to be poll-based like the rest of the app.
## Architecture
**`AdminOrderWatcherService`** (new, `providedIn: root`, admin-scoped)
- Polls `AdminOrdersLocalGateway.loadOrders()` (sorted `createdAt` desc, already the
default sort) on an interval.
- Diffs the newest order's `id`/`createdAt` against the last-seen value, kept in memory
and persisted via `LocalStorageService` (survives page reload, same pattern as
`AdminPreferencesService`).
- On finding order(s) newer than last-seen: fires one toast per new order and
increments an `unreadCount` signal.
- Started once at the admin shell root, so it keeps polling regardless of which admin
page is open.
**Poll interval**
- Editable by admin, default 15s.
- Setting lives in the same admin-settings page as currency rates
(`admin-settings-page.component.ts`), persisted via `LocalStorageService`.
**Toast delivery**
- Reuses the existing `UserNotificationService` / `FloatingNotificationsComponent`
(already global — `providedIn: root`, mounted once in `app.html`). No new toast UI.
- `UserNotification` gains an optional `route: string[]` field.
- `FloatingNotificationsComponent` gets a click handler: navigate to `route` (if set)
then dismiss.
**Badge**
- `unreadCount` signal (from `AdminOrderWatcherService`) rendered on the admin
sidebar's "Orders" nav item.
- Visiting the orders list marks all currently-known orders as seen → badge resets to 0.
**Click behavior**
- Toast click → `/admin/orders/:id` (the new order's detail page).
- Badge click → orders list.
## Data flow
```
AdminOrderWatcherService (interval timer)
-> AdminOrdersLocalGateway.loadOrders()
-> diff against last-seen order id/createdAt (LocalStorageService)
-> new order(s) found?
-> UserNotificationService.show(message, 'info', { route: ['/admin/orders', id] })
-> unreadCount.update(n => n + 1)
-> admin clicks toast/badge -> router navigate -> orders-list visit resets unreadCount
```
## Error handling
Poll failures are silent/logged only (`console.error`), consistent with existing
polling code (payment status polling in `cart.component.ts`). No toast spam on
transient network errors — watcher just retries on the next interval.
## Out of scope
- Native OS push notifications (tab not focused) — user explicitly chose in-app
toast/badge only, not browser Notification API.
- Sound alerts — not selected.
- Telegram/email alerts to staff — not selected, would need backend bot/mail
integration.