Commit Graph

545 Commits

Author SHA1 Message Date
sdarbinyan
c91b75c036 docs: backend contracts for Phases 2-4 (orders/notifications, catalog/offer, connectors)
Continues the Phase 1 contract doc with the same wire-contract-only style.
All three build on Sprint 0.1's answered decisions - no further business
input needed to start implementation once backend ownership is confirmed:

- Phase 2: canonical Order/OrderLine/Fulfillment/OrderEvent per the unified
  multi-seller decision (one Order, per-seller Fulfillment groups), event
  bus, Notification Center contract.
- Phase 3: Product/Offer split, InventoryRecord, publish-time executability
  validation (the mechanism behind "no branch may distinguish an inspector
  from a normal buyer").
- Phase 4: generic config-driven connector framework per the "no fixed
  marketplace list" decision - onboarding a new partner is configuration
  against a fixed pipeline, not a bespoke integration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 23:02:52 +04:00
sdarbinyan
8d9eb97e9e docs: remove superseded super-admin Phase 1 design doc
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
superuser.md (already tracked from prior session) supersedes
2026-08-15-platform-super-admin-design.md. Committing the prior
session's uncommitted rename.
2026-08-17 22:43:09 +04:00
sdarbinyan
821fecf5d3 docs: record Sprint 0.1 decisions across delivery plan, gap analysis, backend contract
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
User answered 8 of 9 Sprint 0.1 blocking decisions (2026-08-17); backend
ownership stays open pending a clearer re-ask. Recorded and propagated:

- Payment chain unfrozen -> BACKEND-API-REFERENCE.md §7 and the Phase 1
  contract doc's status banner both updated; Phase 1/6/7 unblocked.
- No fixed external-marketplace list -> Phase 4's connector framework
  respecified as config-driven/generic; Sprint 4.2 retired as "per named
  marketplace," replaced with a generic onboarding runbook.
- FX rate source: ours, in-house, as the default (not just a fallback) ->
  Phase 1 contract's `source` field can read "internal" as the normal case.
- VK ID before OTP -> Phase 8 sprints resequenced (VK ID now 8.2, OTP 8.3).
- Multi-seller orders: unified -> Phase 3.3, Phase 5.2, and Z16 updated to
  the resolved model (one Order, per-seller Fulfillment groups).
- "Fixed 5-second payment" claim: confirmed non-issue, PAYMENT_POLL_INTERVAL_MS
  is already 5000 (real polling cadence, not an artificial delay).
- API namespace: new endpoints only (/api/v2/...), no forced migration of
  legacy endpoints.
- Document version: v3.1 is canonical.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 22:08:23 +04:00
sdarbinyan
54cd089e80 fix: WCAG AA contrast remediation on border/status colors (Z8, user-authorized)
Darkened --border-color and --success/--warning/--error/--info-color in
all three theme files, hue-preserving, computed against WCAG 2.1 formulas:
- border-color: 1.24-1.42:1 -> >=3.0:1 (non-text/UI-component minimum)
- status colors: 2.15-3.76:1 -> >=4.5:1 (plain-text minimum)
--primary-color/--secondary-color/--accent-color/gradients untouched -
only semantic feedback tokens changed. lavero's success-color now diverges
from primary-color (they only happened to share a hex before; semantic
status vs. brand identity are different concerns).

Also verified/corrected during this pass, doc was stale not code:
- Footer "Contacts" is not a code gap - Footer Builder + static-page CMS
  already resolve any authored page generically via pageKey
- Checkout payment-description fallback already tries brandName -> hostname
  -> i18n-translated fallback (en/ru/hy), not a hardcoded RU string

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 22:04:14 +04:00
sdarbinyan
634e3faf3d docs: correct Z6 finding - Product/Organization JSON-LD already shipped
SeoService.setJsonLd() already injects real application/ld+json for
Product (per-item) and Organization (site default) - the gap doc's
"confirmed absent" claim was stale. Noted the one real remaining gap
(BreadcrumbList/ItemList schema) as future net-new scope rather than
implementing it now. Sitemap generation remains backend-only, unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:50:59 +04:00
sdarbinyan
6ca672987e refactor: extract shared app-breadcrumb component (Z14)
Only breadcrumb logic anywhere in the storefront was a local signal +
inline markup inside catalog-container. Extracted a generic
shared/ui/breadcrumb component (rootLabel/items/ariaLabel inputs,
rootClick/itemClick outputs) and repointed catalog-container onto it,
removing the now-dead inline SCSS block. Future breadcrumb usages
(product detail, admin) have something to reuse instead of duplicating.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:49:54 +04:00
sdarbinyan
bf367fc5fe docs: correct search-model duplication finding - three shapes, not two
Re-verified GAPS-AND-IMPROVEMENTS.md's "duplicate search models" item:
core/search/models/search.model.ts was already a re-export shim (fine),
but core/search/models/search-state.model.ts is a real second copy, and
features/search/facade/search.facade.ts has a third, private
LegacySearchState interface with the same fields again. Documented as its
own scoped task rather than fixed here - reconciling three shapes on the
catalog rendering path needs full consumer tracing first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:38:53 +04:00
sdarbinyan
d24ba38479 docs: mark 7 GAPS-AND-IMPROVEMENTS.md items fixed, verified against current source
Doc was 4 days stale relative to source - each item below was independently
verified against the current file/line during this session's Track Z sweep,
not just marked off the todo list:
- Ed25519 auth-error body-code bug
- Dark mode selector (now actually fixed this session)
- Site Layout selector fallback
- setItemMeta() wiring
- og:locale dynamic locale
- stars.component.scss token usage
- AdminRole duplication
- PRODUCT_DATA_PROVIDER/CATEGORY_REPOSITORY dead mock branch
- sellerId UUID typing

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:37:04 +04:00
sdarbinyan
288c7ac33f fix: wire dark-mode theme tokens for all three tenant themes (Z1)
theme-engine.service.ts already sets [data-theme-mode] on the root, but
no CSS anywhere consumed it - picking Dark/System never changed anything
visually. Adds a structural dark override block per theme (dexar/lavero/
novo): bg/text/border/shadow tokens only. Brand colors (primary/secondary/
accent/gradients) are left untouched - a distinct dark-mode brand palette
is a design decision for the theme owner, not made here.

Also verified during this pass, no change needed (GAPS-AND-IMPROVEMENTS.md
was stale on these):
- og:locale already reads languageService.currentLanguage() dynamically
- SeoService.setItemMeta() is already called from product-details-container
- stars.component.scss already uses var(--border-color), no literal hex
- sellerId is already typed UUID, no bare-string field remains

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:35:13 +04:00
sdarbinyan
ffaa6d2a1c refactor: rename storefront CategoryApiModel; correct stale auth-error doc; add Phase 1 backend contract
- models/category.model.ts: Category -> CategoryApiModel, disambiguated
  from core/categories/models/category-domain.model.ts's Category (admin
  domain shape). Removes a dead unused import in item.utils.ts along the
  way. Only live consumer was services/api.service.ts, updated in place.
- BACKEND-API-REFERENCE.md §5: corrected two rows documenting the
  TOKEN_EXPIRED/INVALID_SIGNATURE auth-error bug as still open - the fix
  (reading error.error.code before falling back to HTTP status) is
  already in auth.service.ts. Doc was stale, not the code.
- Sprint 0.2 audit: AdminRole duplication and the
  PRODUCT_DATA_PROVIDER/CATEGORY_REPOSITORY dead mock branches were
  already resolved in a prior pass - verified, no code change needed.
- docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md: new wire contract
  for Money/FxQuote/PriceSnapshot/payment state machine, so backend can
  start Phase 1 the moment the frozen payment chain is unblocked.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 21:31:11 +04:00
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
687891cbaf docs: platform super-admin Phase 1 design spec
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 20:13:10 +04:00
sdarbinyan
e818dc6fc0 docs: add admin method toggle + error handling to email/phone login spec
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 18:52:52 +04:00
sdarbinyan
aedc05110c docs: design spec + backend ask for email/phone OTP login (item 4)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 17:51:15 +04:00
sdarbinyan
0d1d468307 feat: admin product views column (always 0 until backend tracks it)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 16:18:20 +04:00
sdarbinyan
3056be53db docs: implementation plan for admin product views column (item 1)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 16:11:09 +04:00
sdarbinyan
7f3a22abb8 docs: design spec for admin product views column (item 1)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 15:58:49 +04:00
sdarbinyan
fbc51c4866 merge: main into B2B (doc updates)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:37:52 +04:00
sdarbinyan
10b2ad9023 docs: backend FX/notifications gaps, add CHANGELOG for recent work
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:37:42 +04:00
sdarbinyan
7f9bb6aae6 merge: B2B into main
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:34:59 +04:00
sdarbinyan
1ab689e056 fix: unreadCount badge falls back to timestamp when ack pointer scrolls off page
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:33:25 +04:00
sdarbinyan
f1ee199d92 fix: AdminOrderWatcherService reacts to auth state, not component lifecycle
Previous fix (1032891) stopped polling via AdminLayoutComponent's
DestroyRef, but logout() never navigates or destroys the component -
the watcher kept polling and toasting indefinitely after logout.
Now polling starts/stops off AdminAuthService.isAuthenticated() directly,
following the same effect() pattern already used by AdminDashboardFacade.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:25:51 +04:00
sdarbinyan
1032891d26 fix: address final review findings (order-notification watcher robustness)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:18:20 +04:00
sdarbinyan
9ccd807a55 feat: editable new-order poll interval in admin settings
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 04:04:32 +04:00
sdarbinyan
35b1c7ed27 feat: wire order watcher into admin topbar bell (badge + panel)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:59:23 +04:00
sdarbinyan
28f39a31f6 feat: AdminOrderWatcherService polls for new orders and toasts
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:52:55 +04:00
sdarbinyan
5ed4936898 feat: UserNotificationService supports click-to-navigate toasts
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
2026-08-15 03:47:46 +04:00
sdarbinyan
55e4938a57 docs: spec update - reuse existing topbar bell instead of new sidebar badge
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:43:07 +04:00
sdarbinyan
cfee91355b docs: implementation plan for admin purchase notifications (item 7)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:20:32 +04:00
sdarbinyan
0d0f4e5f9c docs: design spec for admin purchase notifications (item 7)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 02:08:36 +04:00
sdarbinyan
0221c905f0 merge: B2B into main
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 02:01:18 +04:00
sdarbinyan
0cadc1a642 fix: delivery-selector price/currency not converting on currency switch
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Component read item.currency (source) as both the display label and the
conversion target, so amounts never actually converted - only the label
technically matched. Now converts deliveryPrice/selectedDeliveryTotal via
CurrencyRatesService and labels with the shopper's selected currency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 02:01:08 +04:00
sdarbinyan
8b01685b48 merge: B2B into main
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 01:46:08 +04:00
sdarbinyan
4510eb769a feat: client-side currency conversion with admin-configurable rates
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- CurrencyRatesService: RUB-based rates, persisted via localStorage
- CurrencyConvertPipe: impure pipe converting item price to selected currency
- Admin settings page: editable currency rates form
- Applied conversion to product-card, product-information, quick-view-dialog,
  delivery-information, compare-table, cart totals + payment payload

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 01:45:12 +04:00
sdarbinyan
414e86bfb5 Merge branch 'B2B'
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
2026-08-13 17:20:38 +04:00
sdarbinyan
d8c078ad5a fix: review findings from full-diff audit (7 fixed)
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- popularSearches sent translated display text as the actual search
  query instead of the canonical term - useSuggestion() now prefers
  target.query.q when present.
- CartService.addItem() dedup guard resolved immediately instead of
  awaiting the real in-flight add; now tracks the pending Promise per
  itemID so concurrent callers await the actual result.
- addItem()'s Promise never rejected on failure (resolve() in both
  next/error branches) - now rejects on error; buyNow() catches and
  shows an error toast instead of navigating on a failed add.
- Quick View had no stale-response guard - a slower earlier request
  could overwrite a faster later one. Added a request-generation
  counter.
- cart autoSubmitPurchase() set paymentStatus to null synchronously
  right after firing the async submit call, blanking the success
  screen while the request was still in flight. Removed the
  redundant/harmful line.
- Order terminal-status guard (cancelled/refunded can't be reopened)
  lived only in the page component. Moved enforcement into the
  gateway (single write path) via a shared TERMINAL_ORDER_STATUSES
  const, so no future caller can bypass it.
- TranslatePipe's per-instance memoization cache had no eviction,
  so bindings with volatile params (pagination counts) grew it
  unbounded for the component's lifetime. Capped at 50 entries.

Not changed: the dark-mode color override was flagged as clobbering
admin branding, but it's the exact palette explicitly requested this
session for the global dark default - not a bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 17:20:00 +04:00
sdarbinyan
07367d3183 Merge branch 'B2B'
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
2026-08-13 13:01:42 +04:00
sdarbinyan
357d346787 refactor: remove dead mock-mode branches in PRODUCT_DATA_PROVIDER/CATEGORY_REPOSITORY
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Both tokens switched on getProductProviderMode()/getCategoryProviderMode()
but every case (including 'mock') fell through to the same real API
provider - no mock implementation of either interface exists. Removed
the dead switch instead of leaving code that implies a mock mode which
was never built.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:18:14 +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
00e5ce6b20 perf: AdminAnalyticsFacade.load() - forkJoin instead of 4 nested subscriptions
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
orders/products/categories/reviews don't depend on each other but were
fetched serially, 4 levels deep. forkJoin runs them in parallel.

Also fixes a real race: a rapid setDateRange() double-call previously
had no cancellation, so a stale in-flight chain could resolve after
and overwrite a newer one. Added a cancelPreviousLoad$ subject with
takeUntil.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:08:47 +04:00
sdarbinyan
a339a1c64e perf: debounce price-range/slider filter inputs
updateRange()/updateSlider() emitted stateChange synchronously on
every keystroke/drag event, triggering a full catalog filter
recompute each time. Debounced both (350ms, per filterId+key timer,
cleared on destroy).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:07:03 +04:00
sdarbinyan
c9a80da7c3 perf: memoize TranslatePipe instead of re-walking translations every CD cycle
pure:false stays (needed so language switches propagate without
touching every | translate template call site), but repeat calls with
unchanged key/params/language now hit a Map lookup instead of
re-splitting the key and re-walking the translation object tree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:03:30 +04:00
sdarbinyan
bad3002006 fix: WCAG 2.2.2 hero autoplay pause control, invisible keyboard-focusable cart button, literal hex token
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- Hero widget autoplay had no pause control and ignored
  prefers-reduced-motion (WCAG 2.2.2 requires a way to pause
  auto-updating content lasting >5s). Added a pause/resume toggle
  button and skip autoplay entirely when the OS prefers reduced motion.
- Cart's swipe-reveal delete-btn-mobile was reachable by Tab even
  while invisible (opacity: 0, only the touch-swipe gesture could
  reveal it) - a confusing, unusable focus stop for keyboard users.
  Now tabindex=-1 + aria-hidden until swiped. Keyboard users already
  had a full removal path via the always-visible header remove button;
  this just stops the redundant hidden button from being a dead tab
  stop.
- stars.component.scss hardcoded #cdd6d5 for the unfilled-star color
  instead of the --border-color design token.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 10:12:41 +04:00
sdarbinyan
178b5f0dc7 fix: i18n gaps in popular searches and compare table
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
- SearchFacade.popularSearches hardcoded English titles regardless of
  active locale. Converted to a getter using translate.t() for the
  displayed title/text; the underlying search query stays the stable
  English canonical term the backend index matches against.
- Compare table and compare page rendered product.name raw instead of
  through getTranslatedField(), same pattern used everywhere else
  product titles are shown (catalog, product detail).
- SearchTrendingService.loadTrending() is a genuine backend gap (no
  trending-search endpoint exists) - already degrades gracefully,
  documented as a gap in BACKEND-API-REFERENCE.md \u00a712.6 rather than
  faked client-side.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 10:04:29 +04:00
sdarbinyan
6cc5d43a10 feat: build and wire the Quick View modal
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
The Quick View button (search results page only) emitted
quickViewPlaceholder with zero listeners anywhere up the chain - the
button did nothing. Built a minimal QuickViewDialogComponent (image,
name, price incl. discount, short description, Add to Cart, link to
full product page) and wired the event through product-grid ->
search-results -> catalog-container, which fetches the product via
ProductFacade and opens the dialog.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:45:03 +04:00
sdarbinyan
b04e3a67f5 feat: wire up dark mode selector with a real dark palette
theme.mode wrote data-theme-mode to the DOM but no CSS ever reacted to
it, and mapThemeConfigToCssVariables() never looked at mode at all -
selecting Dark had zero visible effect.

Added dark-mode neutral overrides (background/text/border axis only -
brand colors stay as configured) using the palette provided by the
user (colorhunt.co/palette/091413285a48408a71b0e4cc):
  --bg-primary: #091413   --bg-secondary: #285a48
  --text-primary: #b0e4cc --text-secondary: #408a71
  --border-color: #285a48

ThemeEngineService now resolves 'system' mode via
prefers-color-scheme and re-renders live on OS theme changes, and
sets data-theme-mode to the *effective* resolved mode instead of the
raw setting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:35:09 +04:00
sdarbinyan
0b08802996 feat: real back-in-stock subscription for Notify Me (API + localStorage fallback)
notifyMe() just called toggleWishlist() - no actual subscription
mechanism existed. Now calls a new subscribeToRestock() API method
(POST /items/{id}/notify-me, not yet built server-side - see
BACKEND-API-REFERENCE.md §12.5) and falls back to a local-only record
in localStorage on failure, so the request isn't silently dropped
while the backend catches up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:30:53 +04:00
sdarbinyan
1af337f005 fix: footer Contacts link resolved to nothing, add placeholder static page
The /contacts route had no bootstrap.staticPages entry at all (the old
hardcoded contacts page was intentionally removed per app.routes.ts's
comment, in favor of the generic staticPath -> CMS resolver). Added a
placeholder entry (route/title/html per locale) so the link resolves
instead of 404ing. Placeholder text explicitly says the real contact
details go through the admin panel - per user decision, real content
belongs to whoever runs a given marketplace, not something to fabricate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:26:32 +04:00
sdarbinyan
3feb806caa feat: add JSON-LD structured data for product and site pages
JSON-LD was absent entirely (sitemap generation is separate backend
work, out of scope here). Added Product schema (name/description/
image/offers with price+availability) on item pages via setItemMeta(),
and a site-wide Organization schema via resetToDefaults(), both
injected as a single #seo-json-ld <script type=application/ld+json>
tag that gets replaced on navigation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:16:37 +04:00
sdarbinyan
ec8ed8f6a8 fix: Site Layout builder setting saved but never read by page rendering
bootstrap.layout.type (the 'Site Layout' selector in the theme editor)
was only ever consulted by a validator checking it against the known
list - nothing used it to actually pick a layout. SectionEngineService
already resolves a per-page layout.type with a hardcoded 'default'
fallback; that fallback now reads the site-wide setting first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 09:14:56 +04:00