Commit Graph

14 Commits

Author SHA1 Message Date
sdarbinyan
3c72c37e31 docs: v3.1 gap analysis + delivery plan; add DI seams to 9 admin gateways
Adds InjectionToken + factory for Orders, Products, Users, Transactions,
Monitoring, Moderation (mirrors existing Categories/Dashboard pattern) and
repoints their facades plus the derived Analytics/Customers facades and
admin-order-watcher off the mock LocalGateway class directly. No behavior
change today - still resolves to the mock - but a real backend can now be
bound per domain with zero facade edits.

Docs: full gap analysis of Product Plan v3.1 against current repo state,
and a phased delivery plan (10 phases, 34 sprints, 5 tracks) breaking every
identified gap into scoped, sequenced work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:24:57 +04:00
sdarbinyan
23d9f2f66f refactor: rename duplicate AdminRole interface, type sellerId as UUID
AdminRole was defined twice with unrelated shapes (core/auth's real
JWT role union vs. the Users admin page's display interface), flagged
in BACKEND-API-REFERENCE.md \u00a72b as needing a rename. Renamed the
Users-page one to AdminUserRoleRecord.

sellerId was bare string in admin-order/admin-product/item models
while core/sellers/models/seller-scope.model.ts already used the
shared UUID alias. Aligned all three to UUID for consistency (UUID is
currently just = string, so this is a documentation-level type change,
not a behavior change).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:16:16 +04:00
sdarbinyan
000bb78112 fix: no error feedback on failed save/delete/role-change, editors navigated away before save result was known
Products/Categories saveDraft() and deleteOne(), and Users
setRole()/setStatus()/invite(), had no error handler at all - a
failed mutation was completely silent.

Also found and fixed the same premature-navigation bug as the Phase 1
cart fix: both product and category editor pages called
router.navigate() immediately after facade.saveDraft(), before the
save had resolved - so even after adding error feedback, the user
would already be gone from the page before it could show. saveDraft()
now takes an onSuccess callback and only the page navigates on actual
success; on failure it stays put and shows a themed error dialog.

Added a mutationError signal to all three facades and a themed
app-dialog error alert on the products/categories editor + list pages
and the users page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:53:12 +04:00
sdarbinyan
c461d9bd5f fix: kill remaining native confirm() in admin, standardize on themed dialog
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Order cancel/refund and user suspend used window.confirm(). Migrated
all three to app-confirm-dialog, matching products/categories/orders
delete gates from earlier in this phase.

Remaining window.confirm() usages are the three canDeactivate dirty
guards (categories/products/project-editor) - left as-is, since
CanDeactivate needs a synchronous or Observable/Promise return and
browser navigation guards conventionally use the native dialog there;
converting those is a separate, larger refactor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:34:18 +04:00
sdarbinyan
bac415d003 feat: UI-only permission gate for admin routes (cosmetic pending backend)
adminAuthGuard only checked isAuthenticated() - any signed-in admin
could reach any route. The live Telegram/QR auth (Mechanism A) carries
no role claim, so a real gate needs a backend change (tracked in
BACKEND-API-REFERENCE.md).

Added AdminPermissionsService + requireAdminPermission() guard factory
that derive a permission set locally by matching the Telegram username
against the mock Users domain's roleId - the same local-only stand-in
already used for the rest of that domain. Wired onto /backoffice/users
requiring 'users.manage'. Explicitly cosmetic: backend must
independently authorize every mutation regardless of what this guard
decides.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 07:22:01 +04:00
sdarbinyan
0646d587eb fix: record real admin identity in Users/Transactions audit trail
audit entries hardcoded actor: 'admin' regardless of who performed the
action. Both local gateways now pull the signed-in admin's displayName
from AdminAuthService, falling back to 'admin' only when unavailable.

Moderation's actor field is a role classifier ('admin' | 'customer'),
not an identity string, and is left unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 07:15:59 +04:00
sdarbinyan
e153a67ec0 fix(backoffice): add error+retry states to Users, Monitoring, Analytics, Reports
Phase 8 (RC-01): these 4 list/dashboard pages had no error-state handling
on their primary data-load subscriptions — on a gateway error, `loading`
was either never reset (Users, Monitoring, Analytics: genuine infinite-
spinner risk, nested subscribe chain in Analytics never resolved on
failure) or there was no loading/empty/error handling at all (Reports
queue: raw table with zero skeleton or fallback).

- admin-users.facade.ts, admin-monitoring.facade.ts: add `error` signal,
  error callback on the primary load subscribe so `loading` always
  resolves.
- admin-analytics.facade.ts: add `error` signal; every level of the
  4-deep nested gateway subscribe chain (orders -> products ->
  categories -> reviews) now has an error handler that resolves loading
  instead of leaving it stuck true.
- admin-moderation.facade.ts: add `reportsLoading`/`reportsError` signals
  (reports list had none previously).
- Templates: reuse existing `app-skeleton`/`app-empty-state`/`app-button`
  primitives for the new error branch, `common.retry` label, two new
  generic `common.errorTitle`/`common.errorDescription` i18n keys added
  to en/ru/hy (reused across all 4 fixes instead of one-off per-page
  copy).

Verified: tsc --noEmit clean, `npm run build` green (pre-existing bundle-
budget warning only, unrelated). Live-checked Home (375px) and Backoffice
Products (1024px) — no console errors, tables/cards render without
overflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:31:30 +04:00
sdarbinyan
b909a195f7 fix(backoffice): wording quality pass across orders, moderation, transactions, users, customers
- Replaced hardcoded English audit/timeline text (order status changes,
  review moderation events, user role/status changes) with proper
  adminXxx.timelineEvent.*/adminUsers.audit.* i18n keys, so Recent
  Activity/Timeline/Audit panels no longer mix English into ru/hy UI.
- Translated raw internal codes rendered directly to users: transaction
  payment method ('card'/'qr'/'cash_on_delivery' -> adminTransactions.methodValue.*)
  and user roles/permissions ('products.manage' etc -> adminUsers.roleValue.*/
  adminUsers.permission.*), replacing developer-facing enum leakage with
  real copy.
- Fixed wrong-noun list-footer counts: Orders/Transactions/Moderation
  list pages all reused adminProducts.items ("N товаров"/"N products")
  regardless of what was actually listed; each now has its own itemsCount
  key ("N заказов", "N транзакций", "N отзывов").
- Fixed customer detail page's "Back" button reusing adminOrders.back
  ("Back to orders") instead of a customers-specific label.
- Added translation keys to en/ru/hy + translations.ts interface for all
  of the above.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:20:37 +04:00
sdarbinyan
565fd9b3a8 fix(backoffice): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Backoffice (admin/*) area. Builds on 712a7b4/63c9cee's
composition pass (scope="col", skeletons, empty-states) without redoing that
work.

- Sidebar nav landmark: admin-layout's <nav aria-label> reused the
  "Dashboard" nav-item translation key as its landmark label, misleadingly
  announcing the whole sidebar as "Dashboard" - added a dedicated
  adminShell.sidebarLabel key ("Admin sidebar navigation") in en/ru/hy.
  Skip link, #admin-content main landmark, Escape handling, and mobile-drawer
  focus management were already correct - verified, not touched.

- Categories tree drag-and-drop keyboard fallback (WCAG 2.1.1): the category
  tree's native HTML5 DnD (draggable/dragstart/drop) reorders siblings with
  no keyboard equivalent - existing arrow-key tree navigation only expands/
  collapses/selects, never reorders. Added per-row move-up/move-down icon
  buttons (disabled at sibling boundaries), reusing the existing `reorder`
  output so the facade's reorder logic is untouched; new
  adminCategories.moveUp/moveDown keys in en/ru/hy.

- Screen-reader loading announcements: skeleton-row loading states across
  Products, Categories, Customers, Orders, Transactions, Users, Reviews,
  Monitoring (webhooks/events), and Analytics (summary cards + top products)
  were purely visual (app-skeleton is aria-hidden by design) with no
  accessible "loading" text, unlike the storefront/product-details pattern -
  added role="status"/aria-live="polite"/aria-busy + sr-only text using the
  existing common.loading key.

- Table row headers: added scope="row" to the primary identifying cell
  (product/category/customer name, order number, transaction order number,
  user name, review customer, report target, top-products/low-stock product
  name, webhook endpoint) on 9 tables that only had scope="col". Added
  matching `tbody th[scope='row'] { font-weight/color/text-align/
  vertical-align }` + last-row border resets in each component's own scss so
  the semantic change doesn't alter visuals (the shared app-table stylesheet
  styles all <th> as bold/muted by default).

Verified via `git show --stat` of fb1afb7/a03260e and `docs/UI-COMPOSITION-
REVIEW.md`'s Backoffice sections first, per instructions - confirmed
scope="col" coverage already complete, all admin modals already route
through the shared app-dialog (focus-trap/Escape/return-focus already
correct, nothing to fix), and the bare-<select> filters still carry
aria-label per the accepted Sprint 28 decision (not re-migrated to
app-select).

Flagged, not fixed:
- No toast/notification system exists anywhere in this codebase (product/
  category save and delete call the gateway with no success/error UI at
  all, not even a subscribe error handler) - there is nothing to wire
  aria-live onto without adding a new UI mechanism, which is out of scope
  for an a11y-only pass. A prerequisite feature-level fix, not an a11y
  regression.
- Dashboard's per-card metric/status-row/timeline skeletons (dashboard-
  metric, dashboard-status-row, dashboard-timeline) were left without
  aria-live wiring - wrapping each of the ~10 simultaneous mini-widgets in
  its own live region would fire a burst of redundant announcements; needs
  a single page-level "loading dashboard" region instead, a larger change
  than this surgical pass.
- Monitoring's events table and the notifications dropdown (role="menu"
  with a static empty-state message, aria-haspopup="true") were left as-is -
  matches the same partial-widget-pattern precedent already accepted for
  locale-tabs/product-tabs in the storefront and builder passes.
- Analytics `lowStockProducts` table's missing loading-skeleton branch
  (already flagged, not fixed, in the RC-Visual-02 pass) - untouched again
  here for the same reason.

Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
768.57 kB vs 700 kB initial-bundle budget warning, unrelated to this pass).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:18:09 +04:00
sdarbinyan
63c9ceeaa6 fix(backoffice): composition audit fixes for transactions, customers, moderation, users, monitoring, analytics
- Transactions list: hardcoded #fff background replaced with var(--bg-primary); missing th scope=col added on all 7 headers
- Customers list: hardcoded #fff background replaced with var(--bg-primary); missing th scope=col added on all 7 headers
- Customer detail: fake CSS vars --border-subtle/--brand-primary (never defined, silently falling back to hex) replaced with real --border-color/--primary-color
- Reviews list: hardcoded #fff card background and sticky-header background replaced with var(--bg-primary)/var(--bg-secondary); missing th scope=col added across dynamic column table header
- Reports list: hardcoded #fff background replaced with var(--bg-primary); fake --brand-primary var replaced with --primary-color; missing th scope=col added
- Review health widget: fake --surface-muted/--brand-primary vars replaced with real --bg-tertiary/--primary-color (matches product-health-widget precedent)
- Users page: hardcoded #fff background replaced with var(--bg-primary); missing th scope=col added on both tables
- Monitoring page: hardcoded #fff background replaced with var(--bg-primary); missing th scope=col added on webhooks and events tables
- Analytics page: fake --color-primary var (undefined anywhere in codebase) replaced with real --primary-color across tabs/chart/focus rings; fake --surface-muted/--brand-primary on health bar replaced with --bg-tertiary/--primary-color; hardcoded #fff card/summary-card backgrounds replaced with var(--bg-primary); missing th scope=col added across 4 tables

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:06:17 +04:00
sdarbinyan
7cb1c8c3c6 style(design-system): roll out font-size scale across storefront/builder/backoffice
Mechanical, value-preserving substitution: every literal font-size
declaration across src/app (89 files) that matched one of the 9
typography scale steps introduced earlier (--font-size-xs..4xl) was
replaced with var(--font-size-STEP, <same-or-nearest-step-value>).

Values within ~0.03rem/1px of a scale step were snapped to that step
(e.g. 0.85rem and 0.8rem both -> --font-size-sm/0.8125rem; 0.9rem and
0.875rem -> --font-size-base/0.875rem) to consolidate roughly 15
near-duplicate sizes down to the 9-step scale, per the RC design-system
finalization brief. This eliminates most of the font-size fragmentation
found across the app (previously: 0.7/0.72/0.75/0.78/0.8/0.8125/0.85/
0.875/0.9/0.9375/0.95/1/1.05/1.1/1.125/1.15/1.2/1.25/1.3/1.35/1.4/1.5/
1.75/2rem all in live use simultaneously).

Not touched (deliberately, see docs/UI-DESIGN-REVIEW.md): 3rem+ display
sizes (too large a jump to any existing step, would need a --font-size-5xl
addition), font-size values expressed via clamp()/calc(), and any
component listed as intentionally distinct (code-editor syntax tokens,
theme brand colors).
2026-07-20 03:26:17 +04:00
sdarbinyan
e2ec8dc632 refactor(admin): unify platform UX and consistency
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

- Tokenized every admin card/container radius to the design-system scale: raw 16px/12px/8px replaced with var(--radius-md)/var(--radius-sm) per DESIGN.md (cards 12px, fields keep 10px rounded.field)
- All 16 admin surfaces now share one card language: 1px --border-color border, --radius-md, white fill, 16px padding
- Normalized type-ramp outliers: 0.88rem -> 0.85rem (order timeline), 0.9em -> 0.9rem (category form breadcrumb)
- Visual-only pass: no markup, logic, or layout changes
2026-07-18 22:47:15 +04:00
sdarbinyan
576f2600a5 refactor: marketplace release polish
Sprint 28, scoped to admin/* (user decision — full marketplace audit
declined in favor of a bounded pass over the 8 admin features from
Sprints 20-27).

- a11y: aria-label added to every bare <select> not already inside a
  <label> across categories/products/orders/transactions/users/monitoring
- loading states: app-skeleton rows/cards added to list pages that
  previously rendered blank during the initial fetch (categories, orders,
  transactions, users, monitoring's event feed, analytics summary cards)
- admin-dashboard-card's custom shimmer CSS replaced with the shared
  SkeletonComponent (same visual result, one less duplicated animation)
- bundle-size budget warning (~198kB over) confirmed pre-existing —
  present at Sprint 20's first build before any admin/* code existed,
  and new admin pages are all lazy-loaded — documented as out of scope
  for this pass rather than chased

docs/ADMIN.md + docs/SPRINT-PLAN.md updated with the scope decision and
what was explicitly not done (Lighthouse, animations, SEO/sitemap,
storefront/editor a11y).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 00:14:46 +04:00
sdarbinyan
17adc9e9fd feat(admin): users and permissions
Sprint 25.

New features/admin/users/ module, net-new /:lang/backoffice/users route +
Dashboard Quick Action.

- users: name, Telegram username, scope (marketplace vs office admin),
  role (inline change), status (active/invited/suspended), last login
- 4 built-in roles (owner/admin/editor/viewer) with flat permission lists
- invitations: email + role + scope form, pending list + revoke (no email
  actually sends - local record only)
- passwordless login confirmed already real (AdminAuthService Telegram QR,
  docs/BACKEND.md item 1) - linked, not reimplemented
- per-user mock session list (device/IP/last-active, revoke) - flagged as
  mock since the real AdminAuthService only ever tracks the current
  browser's session
- per-user audit log dialog (role/status changes), same pattern as
  Sprint 24's per-transaction audit, intentionally separate from the
  system-wide log planned for Sprint 26

docs/ADMIN.md + docs/BACKEND.md (new item 14) updated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 11:05:21 +04:00