feat: order total-formula panel, dashboard metrics, revision-API core (F53/F55/F56)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

Checked F49-F56 against current source before writing anything; three
resolved to "already done, nothing to build":

  F49 (ed25519 admin auth flip) - lives entirely in the external
      @marketplaces/auth package plus a live backend; nothing in this repo.
  F50 (HttpOnly session cookie) - HttpOnly can only be set via a
      Set-Cookie response header. No frontend code can ever set one via
      document.cookie. 100% backend, always was.
  F51 (route permission guards) - already deliberately paused by prior
      work with a stated reason ("could lock an admin out without warning"
      across 27 routes, no live backend to verify against). Respected that
      judgment rather than overriding it blind.
  F54 (wire mock requestRefund) - already resolved by the Block 3 gateway
      swap; the facade calls gateway.requestRefund(), which now hits the
      real endpoint. No mock left to wire.

Built:

- AdminOrder gains optional per-line pricing fields (unitPriceMinor,
  lineTotalMinor, priceSnapshotId, discountMinor) plus fxQuoteId and
  routing, per PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §5.3/§6.5. All
  optional - most orders today have none of it, and absence must render
  as "not available", never a fabricated 0.
- OrderTotalFormulaComponent: pure presentational panel reconstructing
  total = sum(unitPrice*qty) - discounts + delivery, wired into order
  detail. Refuses to show a partial breakdown - every line must carry
  unitPriceMinor or the panel says so plainly instead of half-computing.
- AdminDashboardMetrics gains 8 optional fields per
  PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md §7's target list (GMV, paid
  orders, conversion, payment failure rate, moderation queue, low stock,
  unmatched events, integration health). Status is 'unknown' when a field
  is absent, not 'healthy' - a successful fetch with no field present is
  not the same as a confirmed-healthy metric, same pattern the existing
  'images-without-alt' check already used.
- Marketplace revision gateway core (F52/F55's shared dependency):
  models/marketplace-revision.model.ts, interface, api+local gateways,
  token. Additive only - the 724-line project-editor facade's actual
  localStorage-to-API rewire is NOT done here; that is a separate,
  larger, stateful change (autosave/undo/redo all currently synchronous)
  that deserves its own verified pass, not a rushed retrofit.

One real contract ambiguity surfaced and resolved with a stated
assumption, not silently: §5 describes 4 pipeline stages
(draft/validated/preview/published) but only 3 write endpoints
(validate/publish/rollback). Modeled validate() as moving straight to
'preview' - the state publish() actually requires - treating 'validated'
as a value the caller may never observe. Documented in the model's own
comment for backend to confirm.

Local gateway enforces the pipeline order rather than being a permissive
stub: can't publish a draft, can't re-validate a previewed revision,
rollback only from published, rollback creates a new revision rather
than mutating the old one.

Verified: 152/152 unit tests (13 new), arch:check clean, production
build succeeds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-08-18 21:23:43 +04:00
parent 9134a7ff63
commit ec949b5a19
19 changed files with 655 additions and 1 deletions

View File

@@ -995,6 +995,14 @@ export const hy: Translations = {
draftDiscard: 'Չեղարկել սևագիրը',
healthProductsCount: 'Ապրանքներ',
healthCategoriesCount: 'Կատեգորիաներ',
healthGmv: 'GMV',
healthPaidOrders: 'Վճարված պատվերներ',
healthConversionRate: 'Փոխարկման տոկոս',
healthPaymentFailureRate: 'Անհաջող վճարումների տոկոս',
healthModerationQueue: 'Մոդերացիայի հերթ',
healthLowStock: 'Ցածր պահուստ',
healthUnmatchedEvents: 'Չհամապատասխանեցված իրադարձություններ',
healthIntegrationHealth: 'Ինտեգրումների վիճակ',
healthDraftExists: 'Սևագիր',
healthImagesWithoutAlt: 'Alt տեքստ չունեցող պատկերներ',
healthStaticPagesUnpublished: 'Չհրապարակված ստատիկ էջեր',