docs/BACKEND_API.md no longer exists as a live file (merged into
BACKEND.md in an earlier consolidation pass, per that doc's own intro
- only docs/archive/BACKEND_API.md remains, historical only). This
mission's "update BACKEND_API.md" instruction is fulfilled by
extending the doc that actually supersedes it: new §11 "Seller
Management (Optional Capability)", added to the top-of-file table of
contents, no existing section renumbered or altered.
Every subsection explicitly tagged Implemented / Planned / Future,
matching the same legend used in docs/architecture/foundation/
Seller-Management.md (the frontend-side capability doc this section
is the backend counterpart to):
- 11.2 Future entities: Marketplace (Implemented, existing
TenantConfig unchanged), Seller/SellerBranding (Planned - frontend
types exist, no backend schema), SellerUser/SellerSettings/
SellerInvitation (Future - no type, no concept, named for roadmap
completeness only).
- 11.3 Future endpoints: Seller CRUD/Activation/Invitations/Branding/
Analytics/Dashboard - all Future, none designed, each noted as
following the existing mock-to-API-gateway pattern (SS8) once built.
- 11.4 Authentication: SellerPermissionRole (4 roles) explicitly
flagged as a separate vocabulary from the existing, live AdminRole -
not merged, no guard wired, zero auth change.
- 11.5 Domain resolution: market.com -> Marketplace is Implemented
today (ADR-001, backend-Host-resolved); nike.market.com -> Marketplace
-> Seller is Future, no backend resolves it - and per the storefront
audit, needs no frontend routing change once it does.
- 11.6 Bootstrap additions: modules/modules.sellerManagement documented
as Implemented-as-contract (typed, always false/absent today);
sellerScope/sellerBranding as Planned with an explicitly flagged open
question (SellerConfig vs SellerBranding nesting not reconciled);
permissions noted as existing/unrelated today.
- 11.7 Checkout modes: Unified Order vs Split Orders - Future, not
designed, flagged as the single most consequential undecided item
for backend design given payments/refunds/reporting all depend on it.
- 11.8 Product ownership: sellerId? on Item/AdminProduct/AdminOrder -
Implemented as schema only (optional, absent = marketplace-owned,
verified backward-compatible via tsc staying clean). Existing
products remain valid with no migration required - NULL/absent
ownership documented as a permanent state, not transitional.
No backend implemented. No frontend code touched. Documentation only.
Audit only, no code changed - facts gathered by reading current
source (routes, containers, header/footer, SeoService), not assumed.
Covers Homepage, Categories, Products, Search, Favorites, Cart,
Checkout, Reviews, SEO, Breadcrumbs, Header, Footer.
Core finding: tenant resolution is already entirely backend-side by
request Host (ADR-001) - the frontend just consumes whatever bootstrap
comes back for whatever hostname it's running on. A seller subdomain
is architecturally closer to already working than any part of the
Backoffice audit found; the real gaps are all about whether the
*data* rendered carries a seller-aware value, not about routing/
hosting.
Key findings:
- Canonical URLs already correct today - SeoService.siteUrl derives
from location.origin dynamically, not hardcoded. Nothing to change.
- Header/Footer/SEO branding all read through one shared facade
(UiRuntimeFacade.reloadFromBootstrap()) - a single future injection
point that would cascade to all three for free, rather than three
separate fixes.
- SeoService.setItemMeta() (per-product OG/canonical tags) is defined
but never called anywhere in the codebase today - a pre-existing
dead hook, unrelated to seller-scoping but blocking any future
per-product/per-seller SEO work until wired.
- No dedicated breadcrumb component/service exists anywhere in the
storefront - the only breadcrumb logic in the app is one local
signal in catalog-container.component.ts.
- Checkout is not a separate route - it's an inline popup flow in
cart.component.ts, with no multi-vendor/multi-seller cart concept
at all. This is where Checkout Modes and Unified/Split Orders (both
marked Future in Seller-Management.md) would actually need to land.
- Structured data (JSON-LD) and sitemap generation don't exist for
anyone today, marketplace or seller - net-new work either way, not
seller-specific gaps.
- One pre-existing, unrelated issue noted in passing: og:locale is
hardcoded 'ru_RU' in SeoService - flagged, not fixed (out of scope).
Linked from docs/architecture/foundation/README.md alongside the
other Seller Management docs.
Audit only, no code changed - every fact gathered by reading current
facades/gateways/components on this branch, not assumed. Covers all
13 admin modules (Dashboard, Products, Categories, Orders, Customers,
Users, Analytics, Reviews/Moderation, Media, CMS, Builder, Settings,
Monitoring, Transactions).
Per module: answers the 3 readiness questions (does Marketplace Owner
see everything / would Seller see only their own / would Seller Staff
be limited), documents where a future scope would be injected (an
existing method/interface parameter to extend - no "if seller" checks
introduced anywhere), lists components that currently assume global
ownership, and classifies Ready / Needs scope / Needs permissions /
Needs API change.
Key findings:
- Only 3 of 13 gateways (Categories, Dashboard-metrics, Media) are
DI-token-swappable today; everything else needs that seam added
first, independent of seller scoping.
- Orders is the load-bearing blocker: Customers, Transactions, and
half of Analytics all derive from its same unscoped full-fetch order
list, and AdminOrderItem has no per-item seller attribution at all -
the concrete gap behind Seller-Management.md's open Unified-vs-Split-
Orders question.
- Users already carries an AdminUserScope/AdminRole concept (label-
only today) - the natural future home for the Marketplace Owner/
Seller/Seller Staff/Platform Admin role vocabulary.
- CMS/Static Pages and Builder/Project Editor are structurally not
about data scoping at all (marketplace-wide content, single global
config document respectively) - seller-level work there is new
product surface, not an extension.
- No admin module anywhere does role-based hiding of buttons or data
today - confirmed, not assumed.
Linked from docs/architecture/foundation/README.md alongside the
other Seller Management docs.
Master entry-point doc (Seller-Management.md) consolidating everything
built across the prior 4 commits (ADR-011, domain models, Phase 1 UI,
UX review) plus the full roadmap, with every section explicitly
tagged Implemented / Planned / Future so nothing reads as built that
isn't.
Covers: Overview, Architecture & Hierarchy, Marketplace, Seller,
Roles & Permissions, Feature Flags, Bootstrap, Future API, Seller
Storefronts, Seller Branding, Seller Ownership, Checkout Modes,
Unified/Split Orders, Migration & Compatibility (why existing
marketplaces stay unchanged, with the concrete verification evidence
for each claim), Developer Notes, Builder Notes, Backend Notes.
Explicitly marked Future (not designed, no shape decided) rather than
documented as if real: the API surface, seller storefronts, checkout
modes, and the unified-vs-split-order decision - none of these have
any code or ADR behind them yet, unlike the typed models/feature flag/
Phase 1 UI which are genuinely Implemented.
Added a rollout-stage diagram (types+flag -> Phase 1 UI -> backend
decisions -> CRUD -> branding/storefronts -> checkout modes) showing
work stops after "Phase 1 UI" today. Linked as the entry point from
docs/architecture/foundation/README.md and docs/PROJECT_INDEX.md,
ahead of ADR-011/diagrams/domain-models/UX-review which stay as
detail references.
No code changed.
Reviewed the Phase 1 UI against every other Backoffice page. Found and
fixed 2 real issues; everything else verified already consistent
(built entirely from shared components, so hover/focus/dialog-a11y/
dark-readiness/contrast come from those components, not reinvented).
Fixed:
- Message textarea had no id/aria-describedby wiring (app-input
self-wires this via injected FormFieldContext; the raw textarea -
no dedicated textarea component exists yet - never got it, so the
visible label's `for` pointed nowhere). Added explicit aria-label
bound to the same translation key as the visible label.
- Learn More dialog's feature list would render native browser
bullets (no global list-style reset exists outside details>summary
in styles.scss). Replaced with checkCircle icon + text rows,
consistent with how the rest of the app pairs icons with list/status
meaning.
Added docs/architecture/foundation/Seller-Management-UX-Review.md
documenting both fixes plus everything checked and confirmed already
consistent (empty-state usage, icon reuse, translations completeness
across en/ru/hy, responsive at 1280px/375px, dialog a11y verified via
accessibility tree not assumed).
tsc --noEmit clean, arch:check (boundaries + cycles) clean. Live-
verified: Learn More dialog shows all 6 items each with an icon
(confirmed via DOM query), textarea aria-label confirmed
"Сообщение", no console errors.
Typed models only, per mission. Nothing outside the new files reads
or writes any of this yet.
New core/sellers/models/ (mirrors core/products/models,
core/auth/models convention):
- MarketplaceRef - minimal {id,slug,name} reference from a seller
back to its marketplace, distinct from bootstrap's TenantConfig.
- SellerStatus - 'pending'|'active'|'suspended'|'disabled', no
transition logic.
- SellerScope - {sellerId, marketplaceId}, domain-level counterpart
to BootstrapConfig.seller (SellerConfig from the ADR-011 pass).
- SellerBranding (+SellerContact/SellerAddress/SellerThemeOverrides)
- logo/banner/description/contacts/address/theme overrides, every
field optional. Marketplace branding/theme remain default;
nothing consumes this yet.
- SellerPermissionRole/SellerPermissions - marketplaceOwner/seller/
sellerStaff/platformAdmin. Separate vocabulary from the existing
AdminRole (core/auth/models/permission.model.ts) - not merged, not
wired into any guard, zero auth behavior change.
- Seller - the eventual entity, composed from the above.
Changed (optional-only, verified backward compatible):
- Item (models/item.model.ts) gained sellerId?: string
- AdminProduct (features/admin/products/models/) gained
sellerId?: string
- AdminOrder (features/admin/orders/models/) gained sellerId?: string
Absent means marketplace-owned in every case, exactly like every
existing product/order today. No consumer of any of these three
models needed updating. AdminOrderItem (per-line-item ownership) and
the existing PermissionsConfig/AdminRole system were deliberately not
touched - out of scope for this pass.
Added docs/architecture/foundation/Seller-Management-Domain-Models.md
documenting every new type, every changed field, and the explicit
non-goals list. Linked from the foundation README alongside ADR-011
and the diagrams doc.
tsc --noEmit clean, arch:check (boundaries + cycles) clean.
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.
New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
pages/) - renders the specified empty state (title/description/
Request Access + Learn More buttons) using existing shared/ui
primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
app-form-field + app-input + a plain textarea (no dedicated
textarea component exists yet, styled to match app-input's own
tokens exactly). Submission is mocked (setTimeout), no API call.
On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
storefronts, permissions, analytics, product ownership, marketplace
administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
(admin-nav.model.ts), new route /backoffice/partners/seller-management
(app.routes.ts), using the same loadComponent/breadcrumb pattern as
every other admin route.
Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.
Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.
Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.
Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
Pointer-only updates, no rewrite: added ADR-011 to both docs' existing
ADR lists/counts, plus a one-line Seller Management entry in
PROJECT_INDEX.md's capability summary noting it's typed-foundation-
only, disabled by default, not implemented.
Documents the decision behind the typed contracts added in the
previous commit: Seller Management is an optional platform capability
module (Platform -> Marketplace -> Seller, 0..N per marketplace), not
a second tenancy tier. Backend resolves seller scope the same way it
already resolves tenant (ADR-001); frontend never resolves it itself.
Gated by one typed flag (modules.sellerManagement.enabled), same
capability-guard discipline as ADR-009, defaulting to disabled/absent
so existing marketplaces are byte-identical.
Explicitly scopes out UI, backend, and business logic as future work
requiring its own ADR/implementation pass once the module is actually
built out.
Added companion diagrams (Seller-Management-Diagrams.md): hierarchy,
bootstrap module-gate flow, and the type-contract class diagram.
Registered ADR-011 in the foundation README's ADR index.
Architectural foundation only - no UI, no backend, no business logic.
Per ADR-001 (Platform -> Marketplace -> Seller hierarchy) and ADR-009
(feature flags / capability guards): Seller is an optional child scope
beneath a marketplace, not another tenant.
New:
- PlatformModulesConfig / SellerManagementModuleConfig
(shared/models/config/platform-modules.model.ts) - the
modules.sellerManagement.enabled contract, defaults to disabled
(DEFAULT_PLATFORM_MODULES_CONFIG).
- SellerConfig (shared/models/config/seller.model.ts) - typed shape for
the resolved seller scope, mirroring TenantConfig's fields at the
subset a seller needs. Frontend never resolves this itself; it only
reads what the backend already decided (same convention as tenant
resolution, ADR-001).
Changed:
- BootstrapConfig gained two optional fields: modules?, seller?. Both
absent by default - every existing marketplace's bootstrap response
is untouched, TypeScript-checked backward compatible (all new fields
optional, no existing field types changed).
tsc --noEmit clean. No component, facade, service, or route touched -
this commit is pure type contracts.
Ran via ng update @angular/cdk@22 - no code migrations required.
Verified after full upgrade (core/cli/animations/common/compiler/
forms/platform-browser/router/service-worker/cdk all now 22.0.8/
22.0.6): tsc --noEmit clean, ng build --configuration=production
clean (same pre-existing bundle-budget warning, size unchanged),
arch:check:boundaries and arch:check:cycles both pass. Live-verified
in browser: storefront home renders correctly (categories/products/
i18n all working), /backoffice/dashboard (admin shell, lazy-loaded
per the earlier routing fix) renders correctly, no console errors on
either.
Required a Node.js upgrade on the dev machine first (Angular 22 CLI
needs Node >=22.22.3 or >=24.15; machine had v22.16.0) - done by the
user before this update ran.
Ran via ng update @angular/core@22 @angular/cli@22 (schematics applied
automatically). TypeScript bumped 5.9.3 -> 6.0.3 as a required peer.
Migrations applied:
- provideHttpClient() calls gained withXhr() where HttpXhrBackend is used
(app.config.ts)
- optional-chaining expressions wrapped in $safeNavigationMigration()
(language-selector.component.html)
- nullishCoalescingNotNullable/optionalChainNotNullable extended
diagnostics disabled in tsconfig.app.json/tsconfig.spec.json (matches
the new stricter default the migration works around)
Next: ng update @angular/cdk@22, then verify tsc/build/tests.
Goal: this document alone, pasted into a fresh Claude session, should
be enough for a backend dev to implement against without getting
stuck or inventing conventions the frontend doesn't actually need.
Fixed a real bug: ~65 cross-references throughout the document pointed
to docs/AUTHENTICATION.md, docs/ERROR_CONTRACT.md, docs/MAINTENANCE_MODE.md
- three sibling docs that were deleted and fully merged into this
document's own §4/§6/§10 during the earlier doc-consolidation pass, but
the in-text references were never updated. A fresh agent following
those links would hit dead ends repeatedly. Bulk-replaced with in-
document section references; hand-fixed ~4 sentences that framed §6/
§10 as "sibling task, in progress" (stale - both are complete, this
document's §6/§10 already are the settled contract, nothing to wait on).
Added "Recommended default" to every item across the document's 5
consolidated "Requires backend decision" registers (§2.12 framework,
§3.21 CRUD cross-cutting - 18 items, §4 §12 auth open items - 9 items,
§6 error-model summary - 9 items, §10 maintenance-mode list - 5 items).
Each default is derived from what the frontend already implies or
standard REST/security convention - no invented APIs or business
rules. ~6 items are explicitly flagged as real business/security
decisions instead (order state-machine rules, Ed25519 cutover
strategy, refresh-token reuse-detection posture) since those carry
consequences no amount of frontend-code-reading can resolve.
Added a "How to use this document" preamble up front: work in §9's
dependency order not document order, apply recommended defaults and
keep moving, only stop for the explicitly-flagged business/security
items, don't invent beyond what's written or directly implied.
Frontend side: confirmed nothing else is left. docs/TODO.md already
has zero blockers; docs/KNOWN-ISSUES.md's one open item (unreachable
Ed25519 error-code UI) is correctly left open and documented rather
than faked closed - fixing it needs a real backend emitting real
distinguishable error codes, which doesn't exist yet and can't be
fabricated without inventing an API contract.
No frontend code touched. No architecture changed. No APIs invented.
Reviewed BACKEND.md top to bottom (4775 lines, 10 sections) against
the full backend-handoff checklist (auth, bootstrap, every endpoint,
media, all domains, pagination/filter/sort/search, error contract,
maintenance mode, status codes, versioning, rate limits, CORS,
security, websocket/events, mock-to-api migration).
Confirmed already covered, no action: Authentication (§4, all
sub-items), Bootstrap (§1, full), every domain's CRUD contract (§3.1-
3.20, includes Moderation under 3.17.b), Media (§7), SEO (bootstrap
SeoConfig + per-page seo + sitemap tracked as remaining work), Error
Model (§6), Maintenance Mode (§10), Migration guide (§8).
Added (genuine gaps, not covered anywhere in the doc):
- §2.10 API path versioning - no endpoint has a version segment/header
anywhere; only BootstrapConfig.schemaVersion exists and that only
versions the bootstrap payload shape, not the API surface. Flagged
as a backend/infra decision with zero frontend impact either way.
- §2.11 Real-time/WebSocket - confirmed no WebSocket/SSE exists
anywhere in the frontend; consolidated the 5 places that look "live"
(QR/Telegram login, payment status, session validity, maintenance
notice, admin monitoring) into one table, all client-side polling.
Flagged push-vs-poll as a backend decision, most relevant to payment
latency and the session-revocation propagation delay.
- Renumbered the section's "Consolidated requires-backend-decision"
list 2.9 -> 2.12 (moved after the two new subsections, no other
content changed) and added both new items to it. No other §2.x
cross-references existed elsewhere in the doc to update.
No duplication found requiring merge; docs/archive/BACKEND_API.md
cross-references are intentional (superseded-but-kept historical
detail, per the doc's own stated design), not obsolete/duplicate
content.
Phase 3 (Performance). Bundle-stats analysis (esbuild metafile) found
AdminLayoutComponent statically imported and used as component: in
app.routes.ts, the only route in the file not using loadComponent -
pulled the whole backoffice shell into the initial bundle even for
storefront-only visitors, even though every child route under it was
already lazy.
Fixed: component: AdminLayoutComponent -> loadComponent(). Verified
live at /backoffice/dashboard - admin-layout-component now its own
21.86kB lazy chunk, no console errors, dashboard renders correctly.
Initial bundle over-budget shrank from 438.68kB to 417.53kB.
Investigated and deliberately left as-is (not bugs, documented/
legitimate):
- src/app/i18n/ru.ts (272kB) eagerly bundled - explicit, commented
tradeoff in translate.service.ts (ru is platform default language,
avoids extra round-trip for majority of users; en/hy already
code-split). Changing this trades bundle size for default-language
UX regression - a product call, not a cleanup item.
- @lucide/angular (182kB) - verified tree-shaking works correctly
(1750 icons in the package, ~85 actually imported by name in
icon-registry.ts, sideEffects:false). Cost is genuine icon usage,
not dead weight. A further win exists (splitting the icon registry
into storefront-critical vs admin-only sets so backoffice-only
icons don't ride the eager header/footer import chain) but touches
every icon consumer across the app - flagging as a scoped follow-up
rather than attempting blind in this pass.
Remaining bundle-budget warning after this fix: 1.12MB vs 700kB
budget. Given ~350kB is unavoidable Angular framework/router/zone.js
floor, +272kB deliberate ru.ts, +182kB legitimate icon usage, the
700kB budget itself looks stale/unrealistic for this app's actual
floor - flagging for a business decision on raising it rather than
chasing further cuts.
tsc --noEmit clean, ng build clean (warning only, no errors), live
browser-verified.
Ran knip to find unused exports/dependencies (deps already clean, no
unused packages/files found).
Removed genuinely dead code (verified zero references anywhere,
including templates):
- 4 unused constants in config/constants.ts (scroll/pagination/search
thresholds never consumed)
- isAdminRole(), toSearchResult(), createInitialSearchState(),
getTranslatedCategoryName() - unused utility functions
- DEFAULT_EDITOR_HEADER_CONFIG - unused constant
- TelegramService - entire file deleted; cart.component.ts/
cart.service.ts already implement the same window.Telegram.WebApp
access directly, this was an unused duplicate
Real bug fix found during the sweep: SeoService has providedIn:'root'
with a live effect() meant to sync <title>/OG/canonical tags to
tenant bootstrap config, but nothing in the app ever injected it, so
Angular never instantiated it and the effect never ran - the SEO sync
a prior sprint reported as "done and verified" was actually dead on
arrival. Fixed by injecting SeoService in the root App component.
Left alone: ~125 knip-flagged "unused exported types" - overwhelmingly
config/schema interfaces for the widget/theme/admin domain models,
high false-positive rate for this kind of interface-heavy Angular app,
deleting blind risks breaking structural type contracts. Also left
locally-used-but-over-exported helpers (toCssColor/toBackendColor,
HTML_EDITOR_TOOLBAR*, HISTORY_LIMIT, DEFAULT_CATALOG_PAGE_SIZE) - real
code, not dead, just exported wider than needed.
tsc --noEmit and ng build --configuration=production both clean (only
pre-existing bundle-budget warning, unrelated).
Files changed: src/app/app.ts, src/app/config/constants.ts,
src/app/core/auth/models/permission.model.ts,
src/app/core/products/models/catalog-experience.model.ts,
src/app/core/search/models/search-state.model.ts,
src/app/features/project-editor/models/project-editor.model.ts,
src/app/services/index.ts, src/app/utils/item.utils.ts,
src/app/services/telegram.service.ts (deleted)
Audited every *.md in docs/ and root. Merged five overlapping backend
docs (BACKEND_INTEGRATION.md + AUTHENTICATION.md + ERROR_CONTRACT.md +
MAINTENANCE_MODE.md + the already-archived BACKEND_API.md/
BACKEND_API_REMAINING_WORK.md) into one canonical docs/BACKEND.md
(4775 lines, 10 numbered sections) - deleted the four standalone
files outright now that their content is fully inlined.
Archived (not deleted - real historical value): ADMIN.md (Sprint
19-28 build log, sprint-report-shaped, not a living reference) and
FRONTEND-ROADMAP.md (despite its name, a shipped-history changelog
with detail no other doc has - not a forward roadmap, so keeping it
in root alongside NEXT_PHASE.md was exactly the "10 roadmaps"
confusion being cleaned up).
Deleted outright (zero value): SPRINTS.md - a leftover copy-pasted
sprint-kickoff prompt saved as a file, not documentation.
Rewrote docs/PROJECT_STATUS.md with completion-percentage estimates
per area (frontend/backend/UI/admin/storefront) and an explicit
first-customer-readiness call. Rewrote docs/NEXT_PHASE.md to the
strict 5-phase structure (backend integration -> production testing
-> performance -> monitoring -> v2 ideas), pointing to PRODUCT_BACKLOG
.md/FUTURE_FEATURES.md for phase 5 detail instead of duplicating it.
Rewrote root README.md - was stale (referenced deleted pages/info,
pages/legal folders from a prior RC pass), now covers architecture,
frontend/backend status, how to run, mock<->API switch mechanism
(useMockData in environment.ts), current folder structure, and a
documentation map.
Updated docs/PROJECT_INDEX.md (the stated entry point) to link only
the surviving doc set - every remaining document is reachable from it.
Fixed every broken/stale cross-reference to the deleted/renamed
backend docs across ARCHITECTURE.md, EDITOR.md, FRONTEND.md,
PROJECT-STRUCTURE.md, StaticPages.md, KNOWN-ISSUES.md (10 individual
link fixes, verified by repo-wide grep before and after). Left
CHANGELOG.md's two historical entries untouched - changelogs are
append-only history, not live navigation, editing past entries would
misrepresent what was true at the time.
Not touched (explicitly out of scope): docs/architecture/foundation/**
(enforced ADRs/governance, permanent not sprint-shaped),
docs/context/** (Barry Cache infrastructure, "do not edit by hand"
per CLAUDE.md), .claude/worktrees/** (separate git worktrees
containing an unrelated project's docs, not this repo's documentation).
docs/ root: 22 files -> 16. Plus 5 in docs/archive/ (was 3).
Classified every TODO.md item into one of DONE/BACKEND/PRODUCT
DECISION/FUTURE VERSION/BUG, verified against source, not against
prior docs:
- BACKEND items (bootstrap content, builder draft/publish, 6 admin
CRUD domains, media pipeline) confirmed already covered by
BACKEND_INTEGRATION.md; appended a mapping appendix rather than
duplicating raw bullets. Fixed 22 stale internal BACKEND_API.md
cross-references left over from before that file was archived.
- PRODUCT DECISION items (dark mode, brand-color WCAG contrast,
stars.component token gap, footer Contacts content, advanced
analytics, payment providers) moved to new docs/PRODUCT_BACKLOG.md.
- FUTURE VERSION items (Angular 22, bundle splitting, cart-modal
composition cleanup, hero-spacing investigation) moved to new
docs/FUTURE_FEATURES.md.
- BUG: rewrote docs/KNOWN-ISSUES.md down to the one real, verified,
currently-reproducible frontend bug (Ed25519 admin-auth error codes
session-expired/invalid-signature are unreachable -
toAuthErrorShape() never reads a body error code, only maps HTTP
status, and no status ever produces those two codes - confirmed by
reading auth.service.ts + auth-error.model.ts). Condensed the
"Fixed" history instead of carrying full verbose repro text forward.
- DONE items removed outright (dead-code deletion, dashboard false
positive, RC-02 fixes, stale "dynamic-renderer unwired"/"178 missing
keys" claims already disproven by source).
docs/TODO.md rewritten to the exact "no blockers" template - nothing
left qualifies as a release blocker.
New docs/PROJECT_STATUS.md: honest per-area status (frontend/backend/
docs/auth/builder/storefront/admin), known limitations, and explicit
production/backend/demo readiness calls - including correcting an
initial draft's unpushed-commit count (53, not 10, per git log
origin/B2B..HEAD).
New docs/NEXT_PHASE.md: work that can only start once a real backend
exists (gateway swap-in, mock removal, dormant-auth activation, role
enforcement, integration/E2E tests, perf profiling, monitoring,
maintenance-mode UI).
docs/PROJECT_INDEX.md (the stated entry point) updated to link the new
doc set and stop pointing at the now-archived BACKEND_API.md/AUTH.md.
docs/FRONTEND-ROADMAP.md's "Known open items" replaced with pointers
to the new category-split docs instead of a duplicated mixed list.
Not swept: a handful of low-traffic docs (architecture ADRs,
FRONTEND.md, EDITOR.md, ARCHITECTURE.md, PROJECT-STRUCTURE.md,
StaticPages.md, ADMIN.md) still reference the old BACKEND_API.md/
AUTH.md filenames - noted as a known gap in PROJECT_STATUS.md rather
than touched blindly, since they're historical-context docs, not the
navigation entry point.
4349 lines, 9 numbered sections per the Backend Finalization Sprint
spec: Bootstrap, Endpoint Framework, CRUD Contracts (~102 endpoints
across 20 domains), Authentication (spliced from AUTHENTICATION.md),
Security, Error Model (spliced from ERROR_CONTRACT.md), Uploads, Real
Backend Implementation Guide, Backend Checklist (34 items).
Everything traced to docs/context/BACKEND-AUDIT.md and actual current
source - proposed (unverified) paths explicitly marked as such,
everything the frontend has no opinion on marked "Requires backend
decision" rather than invented.
Archived the three docs this supersedes (BACKEND_API.md, AUTH.md,
BACKEND_API_REMAINING_WORK.md) to docs/archive/ with pointers back to
this file. AUTHENTICATION.md, ERROR_CONTRACT.md, MAINTENANCE_MODE.md
kept in place as standalone companion references (their content is
also inlined/cross-referenced here). ADMIN.md left untouched - it's a
frontend admin-UI sprint doc, not a backend spec, no overlap.
Verified via repo-wide search: no other backend/API spec docs remain
outside archive/ and this canonical file.
Unified API error envelope + full HTTP status catalogue (401/403/404/
409/422/429/500/503, maintenance, validation, tenant-disabled,
rate-limit, expired-token, invalid-signature) with JSON examples and
current frontend reaction behavior, including two flagged pre-existing
frontend bugs (expired-token/invalid-signature body-code handling is
currently dead code - toAuthErrorShape() ignores fallbackCode for real
HTTP errors).
Maintenance-mode contract (global/per-tenant/per-module/read-only/
scheduled/feature-disable) with proposed 503 response shapes and an
explicit split between "requires backend decision" and "no frontend UI
exists yet, requires a future frontend task."
These two agents wrote their files before hitting a session usage
limit that killed the process before final report-back; content
verified complete on disk before committing.
bootstrap.json's footer.paymentIcons referenced /assets/images/
mir-logo.svg, visa-logo.svg, mastercard-logo.svg - none of that
directory's files existed until the RC-02 placeholder fix, and these
three were still missing. Site-wide broken-image icons in every page
footer. Added neutral labeled-badge SVGs (not reproductions of the
actual trademarked logo artwork) at the exact referenced paths, plus
an onerror fallback on the footer <img> for defense in depth.
Exhaustive inventory of every HTTP call, gateway (interface + mock +
real impl), facade, and model/DTO the frontend defines or expects,
grouped by domain. Primary input for the remaining Backend
Finalization Sprint docs.
Key findings:
- Only AdminCategoriesGateway and AdminDashboardMetricsGateway are
DI-token-bound; every other admin domain (orders, products, users,
transactions, monitoring, moderation) injects its *LocalGateway
class directly - a real backend swap needs a token added first, not
just a rebind.
- Only one real admin API impl exists (AdminCategoriesApiGateway);
everything else admin is in-memory/localStorage mock.
- Content-management/project-editor have no save/publish HTTP call at
all - builder writes are in-memory + localStorage draft only.
- No literal /admin|/builder|/backoffice CRUD paths exist in source;
concrete admin paths are proposals, not verified literals.
Analytics, Reports, and Diagnostics were already clean (no raw
HTTP/queue-worker strings found on audit). Monitoring had three spots
speaking developer language by default:
- Background queue names ("order-notifications") -> friendly labels
("Order notifications").
- Webhook event keys ("order.created") -> friendly labels ("New order
placed").
- Activity log's "api" category showed the raw HTTP line
("GET /api/products responded 200 in 84ms") as the primary message.
Now shows a plain-language summary by default ("Product data
refreshed successfully"), with the raw string moved to a collapsed
"Technical details" <details> per event (api/error/warning rows).
getMainImage() referenced /assets/images/placeholder.svg as the no-image
fallback, but src/assets/images/ never existed - any item with zero
photos rendered a browser broken-image icon instead of a placeholder.
Added the asset.
Also added an (error) handler (onImageError) on every dynamic <img> that
renders a user/admin-supplied URL (product card, cart line item, cart
payment QR code, product gallery main + thumbnails) so a 404'd/broken
image URL swaps to the shared placeholder instead of shipping broken.
pages/category, pages/search, pages/item-detail, pages/info/**,
pages/legal/** (40+ files) were entirely unrouted dead code:
- category/:id, category/:id/items, search all redirect/route to
CatalogContainerComponent
- product/:id routes to ProductDetailsContainerComponent, not item-detail
- cmsContentRoutes (meant to route info/legal) is a literal empty array;
static/legal content is served by the CMS-driven :staticPath ->
StaticPageComponent route instead
dynamic-renderer/ is unrelated and stays - confirmed active, it's the
live homepage rendering pipeline (HomeComponent -> WebsiteRuntimeFacade
-> PageRendererService/PageResolverService -> DynamicPageLayoutComponent).
Updated docs/TODO.md, docs/KNOWN-ISSUES.md, docs/FRONTEND-ROADMAP.md,
docs/PROJECT_INDEX.md to reflect the resolution.
- Route aria-label/alt/title strings (rating, discount, carousel arrows,
hero slides, dialog close, toast dismiss, QR code, bank payment iframe,
guest checkout fallback) through the translate pipe/service instead of
literal English.
- Drop the "Oops!"/"Упс!" apology framing from category/subcategory empty
states (en/ru/hy) - zero results is not an error.
Builder static-page editor marked done (Phase 6). Added 4 new items
found during RC-01 Phase 12 final walkthrough, not fixed this pass:
hardcoded 'Featured Products' heading, dashboard false-Problem status
on empty stores, Monitoring's raw developer text, category image 404s.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
- 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>
- KNOWN-ISSUES item 11: the WYSIWYG page content editor was buried inside
a collapsed Advanced <details>, labeled 'Raw HTML (advanced)'. Moved it
to the top of the Content tab, unwrapped, relabeled 'Page Content' /
'Содержимое страницы' / 'Эջի բովանդակություն' with a plain-language
description. Advanced tab keeps genuinely technical fields (id, slug,
route, custom template).
- Publish (save-bar) and Remove language (languages-section) had no
confirmation despite being destructive/high-impact — added
window.confirm guards using the existing builder.confirm* i18n pattern
(matches resetDraft/resetSection/dirty-guard precedent), all 3 locales.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- product-carousel-widget: implicit CSS grid track had no min-width:0,
so the flex scroller's intrinsic content width (fixed 220px product
cards) overflowed the grid item and pushed body width to ~2187px on
a 1440px viewport, squeezing the entire homepage into a ~340px column.
Added min-width:0 to the track and scroller (standard grid/flex
overflow fix).
- bootstrap.json mock fixture: about-us/privacy-policy/terms-of-service
static pages (the real CMS pages served via bootstrap.staticPages,
per docs/PROJECT_INDEX.md) used a 'content' field, but
content-page.service.ts's normalizePage() only reads 'html' -
ContentPageBootstrapInput has no 'content' field. Title rendered,
body was always empty. Renamed the 3 fixture entries' field from
content to html to match the schema; content now renders.
- compare-table: colour row rendered raw hex/name values as plain text
(e.g. '#fCfCfC') with no swatch, inconsistent with variant-selector's
established colour-swatch pattern used on the product page. Added a
small circular swatch (reusing the same border-radius:50% pattern)
next to the value.
Verified live via ng serve: overflow gone (body/viewport width match
at 1440/1280/375), static pages render real content, compare swatch
displays. tsc --noEmit and ng build both clean (pre-existing bundle-
budget warning only, already tracked in KNOWN-ISSUES item 12).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/search routes to CatalogContainerComponent + CatalogSearchResultsComponent
(app.routes.ts:45-47) - confirmed the live search surface (pages/search/* is
unrouted dead code per KNOWN-ISSUES.md item 13, not touched here).
- search-results.component: hand-rolled `.skeleton-card` shimmer (hardcoded
hex gradient colors, duplicate keyframes) replaced with the shared
app-skeleton primitive the dead pages/search copy already used, but the
live component never got. Bare `<div class="empty-state"><h3>/<p></div>`
replaced with app-empty-state + app-icon, matching CatalogEmptyStateComponent's
established pattern elsewhere in the same feature.
- Added distinct empty-state messaging: a too-short query (<3 chars, mirrors
the existing minSearchLength/isQueryTooShort convention from the dead
pages/search/search.component.ts) now shows "Enter at least N characters"
instead of being indistinguishable from a genuine no-results-for-X state,
which now shows the query and a retry hint (search.noResults/noResultsFor/
noResultsHint/minLength i18n keys already existed, just unused on this path).
- catalog-container.component.html: icon-only close/remove buttons (filter
drawer, sort sheet, grid sheet, saved-search chip) rendered a literal "x"
text character with no app-icon - now use app-icon name="x".
Debounce (220ms, search.facade.ts), URL query-param sync, keyboard
arrow-key suggestion navigation (role=combobox/aria-activedescendant), and
filter/sort discoverability were all verified already correct on this path,
no changes needed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Search suggestions/popular-searches (search-autocomplete.service.ts,
search.facade.ts) set icon values like 'inventory_2', 'category', 'sell',
'auto_awesome', 'trending_up' - Material Symbols ligature names rendered as
raw {{ item.icon }} text in search-bar.component.html. No Material Icons
font is loaded anywhere in this Lucide/app-icon-based app, so these
rendered as literal garbled text ("inventory_2", etc.) instead of icons.
- SearchSuggestion.icon retyped from string to AppIconName (search.model.ts)
- Suggestion icon values mapped to registered app-icon names: product->package,
category->folder, brand->tag, ai->zap, popular/trending->trendingUp (new
registry entry, LucideTrendingUp)
- search-bar.component now renders <app-icon [name]="item.icon" /> instead of
the raw ligature string, and its icon-only clear ("x") button now renders
app-icon name="x" instead of a bare literal "x" character glyph
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
canDeactivate guard, primeng/primeicons+barry-cache cleanup checked
off. HeaderConfig.showProfile corrected - was already fixed
previously, TODO.md was stale on that one.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RC-01 Phase 1 mechanical fixes (verified against current repo state,
not blindly reapplied from TODO.md):
- admin/products create/edit/duplicate now protected by an unsaved-
changes guard (adminProductDirtyGuard), mirroring the existing
categories pattern. AdminProductsFacade had zero dirty-tracking
before this - added a dirty signal, set true on updateDraft(),
cleared on load/create/successful save. Added confirmLeaveUnsaved
to the adminProducts i18n section (en/ru/hy) - categories already
had its own copy of this key, products didn't.
- barry-cache bumped ^0.1.0 -> ^0.9.3 (the pinned range no longer
resolved on the registry - ETARGET - which had been silently
blocking every npm install/uninstall all cycle).
- Removed primeng/primeicons (npm uninstall, now unblocked) - the
only consumer (items-carousel) was already deleted in RC PERF-01.
- Removed core/search/services/search-history.service.ts, a dead
1-line re-export with zero importers (verified: the real
implementation is features/search/services/search-history.service.ts,
used by search.facade.ts). Left core/search/models/* alone - those
ARE live, imported by catalog components.
Verified before touching: HeaderConfig.showProfile toggle is already
removed from the header-section editor template (TODO.md was stale on
this one) - no change needed, will correct the tracking doc separately.
tsc --noEmit clean, npm run build green (bundle unchanged, primeng
was already tree-shaken out, this just removes the dead dependency
declaration itself).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- docs/TODO.md: checklist of every open item from KNOWN-ISSUES.md/
FRONTEND-ROADMAP.md/BACKEND_API_REMAINING_WORK.md/ANGULAR22_PLAN.md,
re-verified against current repo state (git ahead count, package.json,
app.routes.ts) rather than copied blind. Backend items kept but
marked skipped per user request (doing together separately).
- Deleted docs/archive/ (19 files) now that every open finding was
confirmed already merged into KNOWN-ISSUES.md/FRONTEND-ROADMAP.md.
Full original text recoverable via git history
(git log --diff-filter=D -- docs/archive).
- Fixed the resulting dangling docs/archive/* references in
PROJECT_INDEX.md/KNOWN-ISSUES.md/FRONTEND-ROADMAP.md.
Verification: tsc --noEmit clean, npm run build green, 0 broken
markdown links across 49 files (checked programmatically). No
application code touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Step 1-2 (audit + plan): classified 35 project markdown files into
Core/Architecture/ADR/Temporary-audit/Sprint-report/Generated-review/
Duplicate/Obsolete/Historical. Agent-tooling files (.agents/skills/**,
.superpowers/**, docs/context/**, CLAUDE.md/GEMINI.md/AGENTS.md/
.github/copilot-instructions.md) explicitly out of scope — intentional
per-tool duplication, not documentation debt.
Step 3 (merge, no information lost):
- docs/PROJECT.md -> docs/PROJECT_INDEX.md, rewritten as the single
entry point: system overview, living-doc index, archive pointer,
current status, and a critical-finding callout up top.
- docs/backend/BACKEND-INTEGRATION.md -> docs/BACKEND_API.md,
docs/backend/REMAINING-BACKEND-WORK.md ->
docs/BACKEND_API_REMAINING_WORK.md (also folded in a legitimate
uncommitted status update that had been sitting unstaged all
session: categories marked DONE, order-creation endpoint noted done).
- RELEASE-NOTES.md merged into CHANGELOG.md (was a near-duplicate of
the same release content in friendlier prose), then deleted.
- KNOWN-ISSUES.md: added item 13 (see below) and item 14 (missing
canDeactivate on admin/products edit, from the archived PROJECT-STATE
audit, re-verified still true); added a correction note to Fixed
item 7.
- All cross-references to renamed/moved files fixed across every
kept doc (grep+sed pass, then verified with a link-existence check
across all 58 in-scope markdown files -> 0 broken links).
Step 4 (archive, nothing deleted without merging first): created
docs/archive/, moved 19 files there (3 root sprint reports, 1 platform
report, SPRINT-PLAN.md, and 14 one-off audit/review/report docs).
Added correction headers to the 3 archived docs whose conclusions were
affected by the finding below, rather than silently leaving them
misleading.
Step 5: docs/PROJECT_INDEX.md rewritten per the mission brief -
someone opening the repo should understand the whole system from it.
IMPORTANT FINDING (surfaced during this audit, not the mission's
primary goal but too significant to bury): pages/category/*,
pages/search/*, pages/item-detail/*, pages/info/**, pages/legal/**
(40+ files) are entirely unrouted dead code - app.routes.ts's
cmsContentRoutes is a literal empty array, and category/search/product
routes redirect to CatalogContainerComponent/
ProductDetailsContainerComponent, not these files. Confirmed against
app.routes.ts directly and cross-checked against FRONTEND.md's own
routing description. This means several fixes from earlier this cycle
(RC-Premium-01, RC STORE-01) and the dead-code cleanup sprint's
conclusion that these files were live were all wrong - documented as
KNOWN-ISSUES.md item 13, flagged at the top of PROJECT_INDEX.md, and
noted on the 3 archived docs whose conclusions it affects. No
application code was changed to fix this (out of scope per this
session's 'documentation only' constraint) - it needs a wire-it-up-or-
delete-it decision first.
Verification: tsc --noEmit clean, npm run build green, all markdown
links across 58 in-scope files resolve (checked programmatically).
No application/Angular/backend code modified.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No upgrade performed, per mission ('do NOT upgrade automatically').
Verdict: safe, ~2-3.5 days effort. Repo is actually already on Angular
21.1.5 (not 18 as docs implied) — one major behind, not several.
Key findings:
- 2 concrete blockers before any upgrade attempt: barry-cache@^0.1.0
no longer resolves (ETARGET, root cause of the primeng-removal
blocker already tracked in KNOWN-ISSUES item 12), and this dev
environment's Node (v22.16.0) doesn't satisfy Angular 22 CLI's
requirement (^22.22.3 | ^24.15.0 | >=26.0.0).
- Zero usage of any Angular 22-removed API (ComponentFactoryResolver,
provideRoutes, CanMatchFn) found in src/app/**.
- One real behavioral risk: route param inheritance default changes
emptyOnly -> always; app has no explicit override, needs a manual
route-by-route audit, not just a green build.
- App's existing standalone/signals/OnPush posture (190/191 OnPush)
means most of the v22 migration cost is already paid.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Documents the confirmed-dead deletions from e0bcf9d, plus an important
process note: the first attempt at this task was interrupted mid-run
and left an unverified, incorrect mass-deletion staged (117 files
including live routed pages/category, pages/search, pages/info/**,
pages/legal/**) which was reverted before commit. Root cause: knip has
a confirmed false-positive blind spot on this codebase's locale-nested
component pattern under pages/**. Flagged for future cleanup passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dead code sweep verified manually against app.routes.ts, DI registries, and
cross-repo grep for every candidate (per prior false-positive incident with
knip on pages/**). Deleted only what has zero reachable reference:
Auth (unregistered, comment-only mention):
- core/auth/guards/ed25519-auth.guard.ts - ed25519AuthGuard never imported;
only mentioned inside a doc-comment in admin-login-page.component.ts.
- core/auth/guards/permission.guard.ts - permissionGuard never imported.
- core/auth/interceptors/auth.interceptor.ts - authInterceptor not present
in app.config.ts's withInterceptors([...]) list; not imported elsewhere.
Search feature:
- features/search/services/search-analytics.service.ts - SearchAnalyticsService
never imported outside its own file.
- features/search/components/empty-results/* - app-search-empty-results
selector never used in any template; search-bar.component.html implements
its own inline @if (noResults) empty state instead.
Content management:
- features/content-management/pages/content-management-page.component.ts -
thin wrapper around StaticPagesEditorComponent with zero route pointing at
it in app.routes.ts. The rest of features/content-management/* (facade,
static-pages-editor, page-editor, etc.) remains: it is used by
project-editor and stays.
Backoffice CRUD scaffolding (re-verified the UI-COMPOSITION-REVIEW.md claim
independently): app.routes.ts backoffice section only loads
features/admin/{dashboard,products,categories,transactions,orders,customers,
moderation,users,monitoring,analytics} and features/backoffice/media. Grepped
every other backoffice/* folder for cross-references - none found.
- features/backoffice/{categories,customers,inventory,orders,products,settings}
- each contained only a placeholder .gitkeep from the original scaffold
commit (b957112); no real components were ever added, so this is not the
"duplicate implementation" the prior doc described, just unused scaffold
dirs. Removing corrects that doc's premise.
- features/backoffice/shared/backoffice-coming-soon-page.component.* - only
consumer would have been those scaffold dirs; unreferenced elsewhere.
- assets/mock/backoffice/{customers,orders}/list.json - mock data with no
corresponding fetch call; BackofficeDataProvider only exposes
loadProducts()/loadCategories(), backed by the products/categories mock
files, which are kept.
Dead shared barrels/models (no importer anywhere in src/app):
- shared/index.ts, shared/models/index.ts, shared/types/index.ts - unused
re-export barrels.
- shared/models/domain/index.ts + user-preferences.model.ts (whole domain/
subfolder) - UserPreferences interface has zero consumers.
Storefront pages (pages/public/platform-home.component.ts) - PlatformHomeComponent
has no route in app.routes.ts and is not imported anywhere; distinct from the
pages/category, pages/search, pages/info/**, pages/legal/**, pages/item-detail
components which ARE routed and were correctly left untouched.
Verification: npx tsc --noEmit -p tsconfig.app.json clean after each batch;
npm run build succeeded (pre-existing initial-bundle-budget warning only,
unrelated to this change).
- PROJECT.md: Current Status updated (perf/a11y/RC walkthrough all
done, new report docs added to index).
- FRONTEND-ROADMAP.md: RC PERF-01, RC A11Y-01, and Release Candidate
walkthrough entries added; known-open-items list updated (2 new
flags from RC walkthrough, primeng removal blocker, large chunks,
backend-ready sprint explicitly deferred pending a real API contract).
- KNOWN-ISSUES.md: corrected item 6 (payment modal focus-trap
assumption was wrong, now actually fixed); added items 9-12 (brand
contrast failures, Contacts content gap, WYSIWYG editor mislabeled,
primeng removal blocker); added 2 Fixed entries for this cycle's
P0s (query-param routing, Categories CRUD).
- Graphify graph regenerated (graphify-out/, cache only, not tracked).
- Obsidian: skipped, no running Obsidian instance in this session.
- No architecture change this cycle (perf/a11y/bug fixes only) — no
new ADR.
- No application code touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Admin Categories CRUD (create/edit/delete/reorder) silently failed
end-to-end in local dev: ADMIN_CATEGORIES_GATEWAY resolved
strategy.getBackofficeProviderMode(), which (unlike
getBootstrapProviderMode()) has no localhost fallback, so it always
picked AdminCategoriesApiGateway (real HTTP, 404s here) over the
purpose-built AdminCategoriesLocalGateway mock. saveDraft()'s
subscribe() has no error branch, so a create/publish click gave zero
feedback: the category never saved, dirty stayed true forever, and
the unsaved-changes guard then blocked navigation with no
explanation. Live-verified end-to-end: created 3 categories, edited,
reordered via the keyboard move-up/move-down buttons - all persist
correctly now. Fixed by wiring the token to the category-specific
strategy.getCategoryProviderMode() (was already defined, just never
called) and giving it the same isLocalhost() mock fallback
getBootstrapProviderMode() already uses. Production behavior
(non-localhost) is unchanged - still resolves to the real API
gateway.
- Categories list (tree/table/grid views) mislabeled its Edit button
'Edit product' (adminProducts.edit) instead of 'Edit category' -
copy-pasted the wrong existing i18n key; adminCategories.edit
already exists with the correct translation in en/ru/hy. Not part
of the tracked ~178-key missing-translation gap (docs/KNOWN-ISSUES.md) -
this key exists and is simply wrong, not missing.
Verified live via browser walkthrough of every Backoffice route
(dashboard, products list/create/edit, categories list/create/edit/
reorder, orders list/detail, transactions list/detail+audit dialog,
customers list/detail, moderation list+reports queue, users, monitoring,
analytics, media library) at desktop and mobile widths. Console/network
noise from the mock backoffice API 404ing locally is pre-existing and
already documented (docs/ADMIN.md's prior bug-hunt audit pass) - not
re-reported. Product create/edit CRUD already worked end-to-end
(AdminProductsFacade injects its local gateway unconditionally, no
swappable-provider mistake there).
npx tsc --noEmit and npm run build both green (only the pre-existing
700kB initial-bundle budget warning, already tracked as out of scope).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Legacy no-lang-prefix URLs with a query string (e.g. the dev
?devBypassAdmin=true bypass itself, or any bookmarked/shared deep link
into the Builder) got their query string percent-encoded into the path
instead of preserved (language.guard.ts) - router.createUrlTree([...])
treats a single array element as a literal path segment, so
`/edit/branding?devBypassAdmin=true` became
`/ru/edit/branding%3FdevBypassAdmin%3Dtrue`, a 0-result route. Switched
to router.parseUrl() on the full redirect string so path, query params,
and fragment are parsed and preserved correctly. This guard runs on
every top-level route in the app (not just Builder), so this was
silently breaking any legacy URL with a query string app-wide.
- "Reset draft" (Sbrosit' chernovik) left the save-bar showing "unsaved
changes" immediately after the reset, even though the reset already
discarded everything and cleared the persisted localStorage draft
(project-editor.facade.ts resetDraft()) - it updated the in-memory
bootstrap and cleared the draft but never resynced lastSavedBootstrap,
which the dirty computed diffs against. Now resetDraft() also resets
lastSavedBootstrap to match, so the status bar correctly reads as clean
right after a full discard.
Verified live via browser walkthrough of every Builder section (General,
Branding, Theme, Header, Footer, Homepage, Widgets, Static Pages,
Languages, Features, Navigation, Preview) plus save/publish/undo/redo/
reset-section/reset-draft/draft-restore flows, the media picker dialog,
and the Homepage block / Footer column keyboard-fallback reorder buttons
(WCAG 2.1.1 fallback added in the prior a11y pass) - all functioned
correctly end-to-end, no console errors, no untranslated i18n keys, no
unexpected 4xx/5xx, no layout overflow at desktop or mobile widths.
Investigated and flagged, not fixed (needs a design decision, not a bug
fix): the static page's actual body content editor
(app-marketplace-html-editor, per-locale) is not on the page editor's
"Content" tab at all - it only has title/hero-image/thumbnail fields.
The real WYSIWYG/HTML editor is nested inside a collapsed <details>
disclosure under the "Advanced" tab, labeled "Source HTML (advanced)" as
if it were a raw-HTML power-user fallback, when it is in fact the only
way to edit a static page's body content. Functions correctly once
found/expanded; the placement/labeling just doesn't match the "Content"
tab a merchant would expect it under, and moving it is a navigation
change beyond this pass's fix-what's-broken scope.
npx tsc --noEmit and npm run build both green.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Cart item description showed a stray literal "..." when the item had no
description text (cart.component.html) — now only renders the trailing
ellipsis when a description is present.
- Compare table showed raw internal stock enum values ("high"/"low"/etc.)
instead of localized labels (compare-table.component.ts) — now reuses the
same stock-label mapping used by product cards.
- Search with zero results incorrectly showed the empty-category messaging
("browse categories" / "go to parent category") stacked on top of the
search's own "nothing found" message (catalog-container.component.ts) —
isEmptyCategoryState now excludes active search queries so only the
search-appropriate empty state renders.
- Footer "About" link pointed to /about, which 404s; the actual CMS page
route is /about-us (bootstrap.json mock nav data) — corrected the route.
- Added missing public/assets/images/placeholder.svg, the fallback image
referenced by getMainImage() for items without photos (previously 404s
if that fallback path is ever hit).
Investigated and left as-is (not code bugs): /images/*.webp 404s on
product cards are references to a real backend/CDN not present in local
dev (confirmed via mock-data.interceptor.ts and api.service.ts image-URL
resolution) — expected dev-only gap. Footer "Contacts" link (/contacts)
has no corresponding static page content at all in mock data; flagging
for a content decision rather than fabricating copy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>