docs: design spec for admin purchase notifications (item 7)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user