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>
35 KiB
Gaps & Improvements
Findings only — nothing in this document has been fixed as part of writing it. Sourced from re-verifying prior audits against current source, plus a fresh automated review pass across the storefront (website) and backoffice (admin). Organized by the lens each finding matters most to; several findings matter to more than one role and are cross-referenced rather than duplicated.
As a Customer / End User
- FIXED (verified 2026-08-17).
Ed25519 admin-auth "session expired"/"invalid signature" screens were dead UI—toAuthErrorShape()now readserror.error.codeviaauthErrorCodeFromBackendCode()before falling back to HTTP status. SeeBACKEND-API-REFERENCE.md§5. - FIXED (2026-08-17).
Dark mode selector did nothing— structural dark overrides (bg/text/border/shadow) now wired for all three tenant themes under[data-theme-mode="dark"]. Brand colors intentionally unchanged pending a theme-owner-approved dark palette. - FIXED (verified 2026-08-17).
"Site Layout" selector had no effect—SectionEngineService.resolveLayoutType()now falls back tobootstrap.layout.typewhen a page has no layout of its own. - Footer "Contacts" link has nothing behind it. No static-page content exists for it at all in the bootstrap data (unlike other footer legal pages, which are populated).
- FIXED (verified 2026-08-17).
Product pages got no per-product SEO—SeoService.setItemMeta(item)is called fromproduct-details-container.component.ts. - FIXED (verified 2026-08-17).
— readsog:localewas hardcoded toru_RUlanguageService.currentLanguage()viaOG_LOCALE_MAPat both call sites. - No structured data (JSON-LD) and no sitemap generation exist anywhere — confirmed absent, not partially built. Sitemap is backend-only work; JSON-LD would need net-new frontend code.
- Checkout's payment-description fallback is a hardcoded Russian string (
'Покупка на Маркетплейсе') used as a last resort when no brand name or hostname is available — single-tenant-framed wording in a multi-tenant product. - Brand color contrast fails WCAG AA.
--border-colormeasures 1.24–1.42:1 against a 3:1 UI-component requirement in every theme;--success/--warning/--error/--info-colorfail 4.5:1 when used as plain text. Real palette colors, not a token bug — see Accessibility. - FIXED (verified 2026-08-17).
— now usesstars.component.scss:10used a literal hex colorvar(--border-color). - No multi-vendor cart handling exists. Checkout is one inline flow producing exactly one order from one payment popup; a cart with items from multiple sellers has no defined behavior (relevant the moment Seller Management ships beyond its current disabled-by-default placeholder).
As Product Owner / Business
- Backend completion is ~10%. Only Categories has a real HTTP implementation on the admin side; every other domain (Orders, Products, Users, Transactions, Monitoring, Moderation, Analytics, Customers) runs entirely on mock data today. The frontend is feature-complete against that mock data; production readiness is blocked entirely on backend work, not frontend polish.
- The admin role model is decorative.
AdminRole/permissions exist in code, but nothing gates any button, page, or action on them anywhere in the app. Anyone who passes admin authentication has full access regardless of their assigned role. This is a real authorization gap, not a display nicety, and should be scoped before any real admin backend goes live with multiple operators. - Payment options are limited to QR and card via one custom flow — no additional providers (wallets, buy-now-pay-later) are wired or planned; needs a business decision on which providers, if any, before integration work starts.
- Advanced analytics (traffic, funnels, heatmaps) has no data source at all — not a missing endpoint, a missing tracking pipeline. Flagged as the single largest ("XL") remaining backend effort, deliberately last in the build order because it depends on every other commerce domain being real first.
- Seller Management has eight cross-linked documents for a capability that is disabled by default and has zero backend bytes. Real risk if it proceeds: at least three of those documents independently restate the same undecided "Unified vs. Split Orders" question — a decision change means updating multiple documents in sync, not one. Worth a consolidation pass before backend implementation starts.
- Two competing "seller" type shapes exist with no conversion between them (
SellerConfigin bootstrap models vs.Seller/SellerBrandingin the domain layer) — self-flagged during Seller Management design work, restated here as unresolved. Recommend resolving (pick one, or document a mapping) before real backend work on that capability begins. - No reusable feature-flag/capability-guard service exists, despite one being promised by an existing ADR. The one current consumer of
sellerManagement.enabledhand-rolls the check inline; every future flag will either duplicate that pattern or need the promised service built retroactively under time pressure. - The Seller Management "enabled" code path has never been manually exercised, even once — every verification claim about it was tested with the flag at its real-world value,
false. Low risk today (nothing renders differently yet), but worth a fixture-based test the first time any enabled-state UI is actually built. - Two large lazy-loaded bundle chunks remain unaddressed:
project-editor(~1.0 MB) andcatalog-container(~330–375 kB). No mechanical split has been found; needs a dedicated profiling pass, ideally under real backend latency rather than instant mock responses.
As QA / Test Engineering
- Automated test coverage is thin relative to the stated 80% target. 11 spec files exist repo-wide (up from 5 before this cycle's test-foundation sprint); measured baseline is ~32% statements, ~19% branches, ~22% functions, ~33% lines. This is an honest foundation, not a coverage floor — no CI gate is set on it yet, deliberately, until a real floor number can be justified.
- Zero E2E tests exist anywhere in the repo. No Playwright/Cypress/equivalent config found. Critical flows (storefront checkout, admin CRUD, builder draft→publish→live) have no automated regression coverage beyond the unit/facade specs added this cycle.
- Several "verified live" claims in prior audits were actually code-inspection only, not real authenticated click-throughs — consistently because
/edit,/edit/:section, and/backofficerequire Telegram admin login, which cannot be completed in the automated environment those passes ran in. Worth flagging to a human tester before trusting those UI claims as fully proven: the manifest-aware layout picker (Sprint E), and multiple backoffice-auth-gated wording checks (Monitoring, Reports) among them. - No real screen-reader software pass (NVDA/VoiceOver) has ever been performed anywhere in the app — every accessibility claim in every audit to date is based on automated accessibility-tree inspection only (
role,aria-*attribute presence), never an actual screen-reader session. This is a repo-wide gap, not specific to one page. - A reactive-signal staleness bug was found and fixed in Seller Management's enabled-flag read (it read the bootstrap snapshot once at construction instead of reactively) — worth a general regression-test pattern for any future flag/config read that should track
bootstrapRevision(), since this bug class is easy to reintroduce and was invisible until specifically looked for. - No facade-level tests exist yet for cart/checkout, moderation, or most admin domains (Orders, Products, Users, Transactions, Monitoring were explicitly scoped out of this cycle's test-foundation sprint to stay within its time budget) — these are exactly the domains about to get real backends, so they carry the most regression risk with the least current coverage.
As Backend / API Engineer
See BACKEND-API-REFERENCE.md for the full contract. Structural gaps worth flagging here specifically:
- Only 2 of 11 admin gateway domains (Categories, Dashboard-metrics) have a DI-token seam. The other 9 — Orders, Products, Users, Transactions, Monitoring, Moderation, plus derived Customers/Analytics — inject their mock gateway class directly. A token has to be added to each before any real backend can be bound, independent of how easy that domain's actual endpoint is to build.
- FIXED (verified 2026-08-17).
— only oneAdminRolewas defined twice with unrelated shapesAdminRoleexport exists (core/auth/models/permission.model.ts); the Users-page shape isAdminUserRoleRecordwith a disambiguating comment. - Two unrelated
Categorytypes exist, both fed by the same/categoryresponse, both still in active use. - Duplicate search models exist under two different module paths.
- The error envelope is entirely a proposal — no interceptor in the app inspects error response bodies today; every error reaction happens at the raw HTTP-status level. Adopting an envelope is a net-new build for both sides, not a preservation of existing behavior.
- 429 (rate limiting) has zero client-side handling anywhere — no interceptor, facade, or component references it. If the backend rate-limits, today's frontend has no graceful path for that response.
- No API versioning scheme has been decided — no version segment, no version header, anywhere in the client.
- Centralized error-handling scaffolding exists but was never built.
src/app/core/error-handling/,src/app/core/guards/, andsrc/app/core/interceptors/each contain only a.gitkeepfile — someone planned a shared error-handling layer, and every caller still handles failures ad hoc at the call site instead. Worth building once real backends start returning the error envelope in BACKEND-API-REFERENCE.md, rather than adding another one-off handler per facade. - Admin Reports and Seller Management pages have zero data wiring of any kind — not even a mock gateway call. Reports reuses
AdminAnalyticsFacade(itself mock-derived) for its numbers; Seller Management is a static placeholder page with noHttpClientreference anywhere. Neither is currently a "swap the gateway" job — Reports inherits whatever Analytics becomes, Seller Management has no data layer to swap yet. - FIXED (verified 2026-08-17).
— both tokens' factories now resolve directly to the real API implementation with the dead switch removed, documented inline as intentional.PRODUCT_DATA_PROVIDER/CATEGORY_REPOSITORYhad a dead mock branch
As Accessibility Reviewer
- Brand color contrast genuinely fails WCAG AA — see Product Owner item 9 above for the numbers. This requires a theme-owner sign-off before any fix ships, since it changes brand appearance, not just token values.
- No screen-reader software testing has ever been performed on this codebase — every existing accessibility verification (including in this review) is automated accessibility-tree inspection, never a real NVDA/VoiceOver session. Recommend at least one manual pass on the highest-traffic flows (checkout, product page, admin login) before treating any part of the app as accessibility-verified end to end.
- Known past pattern worth re-checking elsewhere: a raw
<textarea>(no dedicated shared textarea component exists in the codebase) previously shipped without itsaria-label/label association wired correctly in one place (Seller Management's Message field, since fixed). Any other raw<textarea>usage in the app should be checked for the same gap, since the sharedapp-inputcomponent handles this automatically but plain textareas do not.
As Engineering / Tech Debt
navigation.header(header top-nav list) is editable in the builder but has zero runtime consumer — the header's actual menu comes from a different source entirely. Needs a product decision on positioning/behavior before it's real feature work, not a wiring fix.catalog.navigationModerenders an intentional placeholder — confirmed not a bug, but the alternate nav UIs it implies (mega-menu, top-carousel, left-nav) don't exist yet if ever wanted.- Angular 22 upgrade is researched but not started (~2–3.5 days estimated, needs a dependency fix and Node version bump first). Explicitly recommended as its own dedicated session, never bundled with feature work.
MarketplaceRefandTenantConfigboth represent "a marketplace" from two different vantage points — a deliberate, documented distinction today, but worth consolidating if a third marketplace-shaped type is ever proposed.- FIXED (verified 2026-08-17).
—sellerIdfields were typed as barestringcore/sellers/models/seller-scope.model.tsand all other sellers-domain usages type itUUID. - No shared breadcrumb component exists anywhere — the only breadcrumb logic in the entire storefront is one local signal inside the catalog container, duplicated conceptually wherever a future breadcrumb might be needed.
- Bootstrap
apiEndpoints.{website,builder,backoffice}are empty objects in the mock today — meaning no builder or backoffice CRUD path exists as a literal anywhere in the client. Any concrete path documented for those domains is a proposal until this is populated.
Cross-cutting / process
- Documentation was spread across 60+ overlapping markdown files at the time of this review (status trackers, sprint plans, multiple overlapping backend specs, several audit reports referencing each other) — consolidated as part of this same pass into this file, BACKEND-API-REFERENCE.md, and whatever the team chooses to keep going forward. Recommend a lighter-weight doc set than before: one living gaps list (this file), one backend contract, source-of-truth code — not a new pile of point-in-time sprint reports.
- A running list of "Requires backend decision" items with recommended defaults already exists inside
BACKEND-API-REFERENCE.mdand the source material behind it — treat those as the first thing to walk through with the client/backend team, since most already have a suggested default and don't need a meeting, only a sign-off.
Automated code review — website (storefront)
Findings from a fresh source-level pass over src/app/pages, src/app/features/website, src/app/features/search, src/app/widgets, and the project-editor/builder. Each item includes a file:line reference and the role it matters most to.
Cart / Checkout
[Product Owner]No dedicated checkout feature exists —src/app/features/website/checkout/andsrc/app/features/website/cart/are empty.gitkeepplaceholders; the entire cart/payment flow lives in the legacysrc/app/pages/cart/.[Engineering]The post-payment email/phone capture flow (submitEmail,onEmailInput,onPhoneInput,validateEmail,validatePhone) is dead code — the template has no matching<input>anywhere, so these methods are never invoked (src/app/pages/cart/cart.component.ts:507-729).[Product Owner]Because that form is unreachable,recordOrder()always submits the backoffice order with an emptyemail/phonefor every purchase (src/app/pages/cart/cart.component.ts:418-441).[Engineering]autoSubmitPurchase()schedules navigation to home viasetTimeout(…, 0)unconditionally at the top of the method, before checking for a Telegram user ID or waiting on thesubmitPurchaseEmailcall — navigation fires regardless of submission success or failure (cart.component.ts:443-454).[User]When no Telegram user ID is available,autoSubmitPurchase()only logs to console and returns silently — no toast/notification, even as the popup is already closing (cart.component.ts:450-454).[Engineering / Security]Paymentcurrencyis hardcoded to'RUB'in bothcreatePayment()andrecordOrder(), ignoringLanguageService.currentCurrency()— the total shown to the user can diverge from the currency actually sent to the payment gateway (cart.component.ts:257,436).[Security]amountand per-item prices sent toPOST /cartare computed entirely client-side from cart data in localStorage/Telegram CloudStorage, with no server round-trip to re-verify live prices before payment creation — a tampered local cart could request payment at an incorrect amount unless the backend independently revalidates (cart.component.ts:253-266,services/cart.service.ts:133-190).[QA]copyPaymentLink()failure path only doesconsole.error— no visible feedback that "copy link" failed (cart.component.ts:495-505).[Engineering]Hardcoded Russian fallback string'Покупка на Маркетплейсе'used as the QR payment description when no brand name/hostname resolves — bypasses i18n entirely (cart.component.ts:592-604). See also Customer item 8.[QA]Cart quantity increases (increaseQuantity,CartService.updateQuantity/addItem) never validate against the item's available stock — a user can raise a cart line past what's in stock with no cap or warning (cart.component.ts:119-121,cart.service.ts:206-256).[Accessibility]Swipe-to-reveal-delete on mobile cart rows is touch-only; a fallback always-visible delete button exists, but nothing makes the swipe state itself keyboard-reachable (cart.component.ts:140-163).[Product Owner]Terms-of-service links (public offer, return policy, guarantee, privacy policy) are plain placeholder text on the cart page, explicitly flagged in-code as needing real backend-configured links (cart.component.html:147-152).
Auth
[Security]The customer web session id is stored in a plain, non-HttpOnlycookie set viadocument.cookie— readable by any script, exfiltratable via XSS (services/auth.service.ts:173-180).
Search
[i18n]SearchFacade.popularSearchesis a hardcoded English list ("Smartphones", "Sneakers", …) never routed through translation — renders in English regardless of active locale (features/search/facade/search.facade.ts:58-91).[Product Owner]SearchTrendingService.loadTrending()is a stub that always returnsnull("Endpoint not available yet") — trending searches are non-functional end to end, and it overwrites the (already-hardcoded) fallback popular list with an empty one every time (features/search/services/search-trending.service.ts:7-10).
Catalog
[Performance]Catalog fetches at most 200 products per category in one call, then filters/sorts/paginates entirely client-side over that fixed batch — categories with more than 200 products silently truncate with no indication, and every filter/sort change re-processes the whole in-memory array instead of re-querying (features/website/catalog/containers/catalog-container.component.ts:160,675-699).[Engineering / tech-debt]restoreContinueBrowsing()is fully implemented (restores search/sort/layout/scroll) but never called anywhere — "continue browsing" state is saved on every interaction but never actually restored (catalog-container.component.ts:901-929).[Engineering]Non-numeric category route tokens are resolved by fetching the entire category tree and slugifying titles client-side — fragile against duplicate or renamed category titles, and loads the full tree just to resolve one slug (catalog-container.component.ts:943-959).[Performance]Price-range filter inputs trigger a full catalog recompute + URL sync on every keystroke, with no debounce (unlike the search box) (features/website/catalog/components/filters-panel/filters-panel.component.ts:80-94).[QA]Range filter min/max inputs have no validation preventingmin > max— an inverted range silently yields zero results with no explicit error state (filters-panel.component.ts:80-94,.html:56-76).
Product details
[User]The "Notify Me" button (shown when out of stock) is wired totoggleWishlist()— it does not create any real back-in-stock subscription, just relabels the wishlist button (features/website/product/containers/product-details-container.component.ts:356-358,product-actions.component.html:22-24).[Engineering]"Buy Now" callsaddToCart()(which resolves item data via an async, subscribed call insideCartService.addItem) and immediately navigates to/cartwithout awaiting completion — the cart page can render before the item has actually been added (product-details-container.component.ts:306-320,cart.service.ts:206-243).
Product cards / search results
[Engineering / tech-debt]The "Quick View" button on every search-results product card emitsquickViewPlaceholder, but no parent component anywhere binds that output — clicking it is a dead end (components/product-card/product-card.component.html:23-25,.ts:83-87,catalog/components/search-results/search-results.component.html:18-33).
Wishlist / Compare
[i18n]The Compare table rendersproduct.name/description fields/color/size straight off the raw product object instead of throughgetTranslatedField()— names and specs on the Compare page always show the source language regardless of active locale (features/website/user-experience/compare/components/compare-table.component.ts:42-58).[Product Owner]Wishlist, compare, recently-viewed, and saved searches are all localStorage-only viaUSER_EXPERIENCE_REPOSITORY, with no server sync to the authenticated Telegram session — data is lost on device change or storage clear despite the app having real login (facades/platform/user-experience.facade.ts:1-137).
Widgets / Page builder
[Engineering]DataSourceResolverService.resolve()has nocatchError/fallback on any branch — an API failure while loading a widget's data propagates as an unhandled Observable error (widgets/resolvers/data-source-resolver.service.ts:20-52).[User]Because of the above, a single failing widget just silently fails to render (stays blank) — no retry, error message, or loading skeleton anywhere in the chain (layouts/containers/dynamic-page-layout.component.ts:55-61,dynamic-renderer/widget-host/widget-host.service.ts:23-58).[Engineering / tech-debt]'html','banner', and'partners'widget types have full data-resolution logic written but no entry inAPPROVED_WIDGET_COMPONENTS— configuring one of these rendersUnknownWidgetComponenton the live storefront instead of real content (widgets/registry/widget-registry.bootstrap.service.ts:9-17,data-source-resolver.service.ts:218-257).[Accessibility]The hero widget carousel auto-advances every 5s wheneverdata.autoplayis set, with no pause/stop control exposed to the user — only the CSS entrance animation respectsprefers-reduced-motion, the autoplay timer itself does not (WCAG 2.2.2 risk) (widgets/ui/hero-widget.component.ts:292-301).
Static / CMS pages
[User]loadByKey/loadByPathsubscribe with only anexthandler, noerrorcallback — if bootstrap loading fails,loadingstaystrueforever and the page shows an infinite spinner with no error state (pages/static-page/static-page.component.ts:76-92).
i18n / Performance
[Performance]TranslatePipeis declaredpure: false, so every| translatebinding (hundreds across templates — 40+ on the cart page alone) re-evaluates on every change-detection cycle instead of only when the language changes — a real cost at scale even underOnPushcomponents (i18n/translate.pipe.ts:4-14).
Automated code review — backoffice (admin)
Findings from a fresh source-level pass over every src/app/features/admin/* module and src/app/features/backoffice. Each item includes a file:line reference and the role it matters most to.
Security / Authorization
[Security]adminAuthGuardonly checksisAuthenticated()— there is no role/permission check anywhere in the codebase (zero matches for a permission check project-wide). Any authenticated admin, including a seeded "viewer" role, can perform every destructive action: delete products/orders, change any user's role, refund orders (core/admin-auth/admin-auth.guard.ts:6-15). Same root cause as Product Owner item 2.[Security]AdminRole.permissionsarrays (owner/admin/editor/viewer) exist only as display labels — nothing gates a button, route, or action on them (features/admin/users/services/admin-users-local.gateway.ts:7-12,admin-users-page.component.ts:59-64).[Security]Nothing prevents suspending or demoting the last remainingowner-role user —setStatus/setRoleapply unconditionally (features/admin/users/facade/admin-users.facade.ts:35-41).[Security]Category slug-uniqueness check fails open: on API error,isSlugTakenswallows the error and returnsfalse("not taken"), letting a duplicate/conflicting slug through silently instead of blocking submission (features/admin/categories/services/admin-categories-api.gateway.ts:56-65).
Audit / Traceability
[Security]Audit/timeline entries hardcodeactor: 'admin'as a literal string instead of the real authenticated admin's identity — the "who did this" record is meaningless the moment more than one admin uses the system. Affects role/status changes, transaction retry/fraud-flag, and review moderation (features/admin/users/services/admin-users-local.gateway.ts:93-94;transactions/services/admin-transactions-local.gateway.ts:41,50;moderation/services/admin-moderation-local.gateway.ts:64,74).[Security]Orders have no actor/audit field at all —AdminOrderTimelineEntryhas noactorproperty, so cancel/refund/status-change history records what changed but never who changed it, for the most financially sensitive module in the app (features/admin/orders/models/admin-order.model.ts:32-36).
Destructive actions with missing/inconsistent confirmation
[Admin-operator]Product delete (single row and bulk) removes the product permanently with zero confirmation of any kind, not even a nativeconfirm()(features/admin/products/components/admin-products-list.component.html:134,161→admin-products.facade.ts:316-317; bulk:admin-products-list-page.component.ts:36→facade.ts:175-178).[Admin-operator]Order bulk-delete removes selected orders permanently with zero confirmation — destroys financial records in one click (features/admin/orders/pages/admin-orders-list-page.component.html:48→admin-orders.facade.ts:134-140).[Admin-operator]The review bulk-action button is labeled "archive" (implying reversible) but actually callsdeleteReview, which permanently splices the review out — no confirmation dialog (moderation/pages/admin-reviews-list-page.component.html:56→admin-moderation.facade.ts:148-154→admin-moderation-local.gateway.ts:94-97).[Admin-operator]Category bulk-delete has no confirmation, inconsistent with the same module's single-delete flow, which does confirm (categories/pages/admin-categories-list-page.component.ts:40vs76-84).[QA]The order-detail "Change status" dropdown bypasses the confirm-gated Cancel/Refund buttons next to it — pickingcancelled/refundedfrom the dropdown applies immediately with no confirmation (orders/pages/admin-order-detail-page.component.html:49vs55-57).[QA]Terminal order statuses aren't enforced in the UI — the status dropdown stays active after an order reachescancelled/refunded, so a terminal order can be silently moved back to any other status (admin-order-detail-page.component.html:47-58).[Accessibility / Engineering]Confirmation UX is implemented three inconsistent ways across the app: nativewindow.confirm()/alert()(Categories, Orders cancel/refund, Users suspend), a themed dialog component (Media Library only), and nothing at all (Products, Orders/Reviews bulk-delete) (categories/pages/admin-categories-list-page.component.ts:78,81;orders/pages/admin-order-detail-page.component.ts:80,86;users/pages/admin-users-page.component.ts:43; vsfeatures/backoffice/media/media-library-page.component.html:126-140).
Missing/incorrect loading, empty, error states
[QA]Order-detail and Customer-detail pages collapse "loading," "not found," and "error" into one static "Loading…" string shown forever if the record isn't found or the request errors —loadDetailhas noerrorhandler (orders/pages/admin-order-detail-page.component.html:89-91, facadeadmin-orders.facade.ts:98-100;customers/pages/admin-customer-detail-page.component.html:51-53).[QA]Products, Categories, Orders, Customers, and Transactions facades swallow load errors into an empty array with no distincterrorsignal — a genuine API failure renders as "No results found" rather than an error-with-retry state, unlike Users/Monitoring/Analytics, which do track error separately (products/facade/admin-products.facade.ts:101-114;customers/facade/admin-customers.facade.ts:42-54;transactions/facade/admin-transactions.facade.ts:15-29).[QA]The Reports page never checksfacade.error()even thoughAdminAnalyticsFacadeexposes it — on load failure it silently renders 0%/0 stats instead of an error message (admin/reports/pages/admin-reports-page.component.html:1-32, facadeadmin-analytics.facade.ts:41,77).[Engineering]Save/mutate calls across Products, Categories, and Users subscribe with only anexthandler — a failed save/delete/role-change fails completely silently with no user-facing feedback (products/facade/admin-products.facade.ts:305-314;categories/facade/admin-categories.facade.ts:314-332;users/facade/admin-users.facade.ts:35-50).
Fake/stubbed data presented as real
[Engineering / Product Owner]Monitoring's security/audit events, queue depths, and webhook deliveries are entirely synthetic (seeded fake generators, hardcoded queue states, modulo-based fake webhook statuses) with no connection to any real backend, yet presented as a live security/audit surface (monitoring/services/admin-monitoring-local.gateway.ts:14-92).[Admin-operator]The Monitoring page loads once on construction with no polling/auto-refresh and no manual refresh control (only a retry-on-error button) (monitoring/pages/admin-monitoring-page.component.ts:39-41; template:79).[Admin-operator]The topbar global search input has no(input)/(keyup.enter)binding and no handler anywhere — it is entirely decorative (shell/admin-layout.component.html:118).[Admin-operator]The notification bell always opens a panel showing a static "no notifications" message — no notification data source is wired up at all (shell/admin-layout.component.html:141-157).[Product Owner]The Dashboard's "images without alt text" health check is hardcoded tostatus: 'unknown'with no code path that could ever resolve it — a permanent placeholder sitting alongside real, resolvable checks (dashboard/facade/admin-dashboard.facade.ts:132).[Product Owner]"Request Refund" doesn't touch any payment processor — it only flipspayment.statustorefund_requested; actually completing the refund means separately picking "refunded" from the unrelated status dropdown, with no workflow linking the two (orders/services/admin-orders-local.gateway.ts:43-50).
Incomplete modules
[Product Owner]Settings (/backoffice/settings) is fully routed and linked in nav but contains exactly one control (density toggle to localStorage) — no store/payment/tax/shipping/notification settings exist despite the nav entry implying a general settings page.[Product Owner]Seller Management's "Request Access" form submission is mocked with a baresetTimeout— no backend call exists, "Learn more" is static copy. Confirms Product Owner item 5-8 are still accurate against current source.[Product Owner]Customer-detail "Notes" card always shows a static "notes unavailable" message — no way to add customer notes at all, unlike Orders, which supports both customer-facing and internal notes (customers/pages/admin-customer-detail-page.component.html:28-31).[Product Owner]"Reports" duplicates "Analytics" 1:1 — both consume the same facade and independently re-run the same nested aggregation — but Reports exposes only 3 CSV export buttons. Unclear differentiation between the two nav entries for an operator (reports/pages/admin-reports-page.component.ts:15-20).
Missing validation
[QA / Product Owner]The product create/edit form has zero client-side validation — no required-field checks (name, price, SKU), no min/max on price/discount/quantity. A completely empty or negative-priced product can be saved with no warning (products/components/admin-product-form.component.ts, entire file; save pathadmin-products.facade.ts:305-314).
Performance
[Performance]AdminAnalyticsFacade.load()chains four nested subscriptions (orders → products → categories → reviews) instead offorkJoin/combineLatest, with no cancellation of in-flight requests — rapidly toggling the date-range filter can let a stale response overwrite a newer one (analytics/facade/admin-analytics.facade.ts:65-130).[Performance]Dashboard-stat computations across Orders, Customers, Transactions, and Analytics each independently re-fetch the entire order list withpageSize: 100000rather than sharing one cached read (orders/facade/admin-orders.facade.ts:166-169;customers/facade/admin-customers.facade.ts:44,57;analytics/facade/admin-analytics.facade.ts:79,92).
Engineering / tech-debt
[Engineering]AdminCustomersFacade.buildCustomers()treatscustomerOrders[0]as the customer's "latest" order with no local sort — correctness depends entirely on the orders gateway happening to already return descending-by-createdAtorder; swapping in a differently-ordered real gateway would silently corrupt "last order" with no compiler or runtime signal (customers/facade/admin-customers.facade.ts:24-39vsorders/services/admin-orders-local.gateway.ts:20).[Engineering]Bulk operations (Orders, Categories, Products, Moderation) fire N independent gateway calls in a loop with noforkJoin, no per-item error handling, and no aggregate loading indicator — one failed item in a batch gives the user no signal at all (moderation/facade/admin-moderation.facade.ts:133-154;orders/facade/admin-orders.facade.ts:119-140;categories/facade/admin-categories.facade.ts:391-397).
Doc-drift confirmed against the Seller-Management audit
[Engineering]Seller-Management-Backoffice-Readiness-Audit.mdstated Settings "No route exists... Skipped, nothing to audit" — now stale:/backoffice/settingsis a real routed page with nocomingSoonflag (shell/admin-nav.model.ts:48,app.routes.ts:266-274).[Engineering]Since that audit,AdminOrderandAdminProducthave both gained an explicit, unreadsellerId?: stringgroundwork field — partially updates the audit's "no injection point" framing at the order level, though its core point (no per-item seller attribution onAdminOrderItem) remains accurate (orders/models/admin-order.model.ts:54-59;products/models/admin-product.model.ts:115-120).