# Release Candidate Audit (RC1)

**Date:** 2026-07-19 (audit) / 2026-07-19 (P0 fix pass, same day)
**Role played:** Staff Engineer + Senior UX Designer + QA Lead + Accessibility reviewer + Product Owner, auditing the whole platform (storefront + admin) for demo/RC readiness.
**Method:** Live click-through of the running dev build (`ng serve`) across storefront and admin routes, accessibility-tree inspection, source-code verification of every finding below (file/line cited where the root cause was located), plus review of this repo's own prior audit docs (`docs/KNOWN-ISSUES.md`, `docs/ADMIN-UX-AUDIT.md`, `docs/ADMIN.md`, `docs/SPRINT-PLAN.md`) to avoid re-reporting already-fixed items and to flag which older findings are now stale.
**Correction from the original audit pass:** the storefront's product/category data is **live backend data** (`proxy.conf.json` proxies `/api` to `https://novo.market`), not a local mock fixture as first assumed — this matters for P0-4 and P0-5 below (real third-party seller data, not something this repo's mock fixtures can simply be "reseeded" to fix).

**Fix pass status: all 8 P0 items resolved or closed as false-positive.** Every fix below is scoped to production polish only — no new features, no data-model changes beyond the one flagged and explicitly approved (P0-3), no architecture changes. Each commit was gated on `tsc --noEmit` and `ng build` passing, and live-verified in the running app. See §6 for the fix log.

**Environment caveat:** screenshot/visual-pixel capture was not obtainable in this session (browser tooling timeout); findings below are backed by live DOM/accessibility-tree inspection and source verification, not pixel screenshots. Color-only-signal and fine visual-hierarchy judgments are flagged as "needs visual follow-up" rather than asserted.

**Important — some prior findings are now stale.** `docs/ADMIN-UX-AUDIT.md` (dated 2026-07-17) reported "no admin shell" and "~178 raw i18n keys" as the two biggest P0s. Both are now substantially fixed: an admin nav/shell exists (`features/admin/shell/`), the admin dashboard renders fully in Russian with real copy, and recent commits (`fix(i18n): eliminate all raw translation key leaks across admin pages`, `c452d28 fix(admin): P0 user-reported bugs`) closed most of that gap. Do not re-triage those two items from the old doc as open — see §4 for what was re-verified live and what wasn't.

---

## P0 — Must fix before demo

| # | Status | Page | Problem | Fix |
|---|---|---|---|---|
| P0-1 | ✅ Fixed | Home, Catalog, Search, Wishlist, Compare, PDP "similar products" (every product card sitewide) | Every product card showed an unexplained raw badge reading exactly **"High"** — `product-card.component.html:9` rendered `item.remainings` directly, untranslated. | `catalog.stockHigh/Medium/Low/Out` keys added to all 3 locales; badge now translates via the value (case-insensitive), `out` styling fixed to match. Commit `1a5d435`. |
| P0-2 | ✅ Fixed | Home, Catalog, Search, Wishlist, Compare (every product card) | Favorite/compare/share/quick-view icon buttons' `aria-label`s rendered literal untranslated keys (`catalog.favorite`, `catalog.share`, `catalog.quickView` — none existed in any locale file, and even `catalog.compare` was unused/missing). | Added all 4 keys to `Translations` + `en/ru/hy.ts`. Commit `1a5d435`. |
| P0-3 | ✅ Fixed | Home hero section | Hero title/subtitle/CTA rendered hardcoded English on every locale — `HeroWidgetProps` had no per-locale text support, unlike nav labels (`NavigationLocalizedText`). | **User explicitly approved the real fix** (not a demo-data-only patch): `DataSourceResolverService.toHeroData()` now accepts a per-locale text map (`LocalizedTextContent`, same shape/fallback as footer group titles) alongside the existing plain-string form — existing tenants unaffected. Mock bootstrap hero props updated to a real ru/en/hy map. Verified live in all 3 locales. Commit `5b063d5`. |
| P0-4 | ✅ Fixed | Catalog & Search facet panel ("Category" filter) | Category filter showed placeholder labels like "Категория 2008" for every option — traced to `search.facade.ts` synthesizing `Category {id}` for every distinct `product.categoryID`. | **Investigated further and found this isn't a missing-lookup bug — it's a real data gap.** The storefront's product data is live backend data (`novo.market`, via `proxy.conf.json`), and its `categoryID` values don't correspond to any id in the demo tenant's own (much smaller) category tree — there is no real name to show. Wired `CategoryFacade` into `SearchFacade`; ids that do resolve now show their real title, ids that don't are dropped from the facet entirely instead of showing a fabricated label. The category filter group simply doesn't render when nothing resolves, which is honest given the data. Commit `3747749`. |
| P0-5 | ✅ Fixed | Search result cards / PDP description tab | Product descriptions rendered literal HTML-entity markup as visible text, e.g. `&lt;attention&gt;...&lt;/attention&gt;`, `&quot;AppStops&quot;` — confirmed this is live third-party seller content (via the `novo.market` proxy), not mock data. | Added `cleanDescription()` (`utils/item.utils.ts`) — decodes common HTML entities, then strips any resulting tag-like markup. Wired into `ProductCardComponent` (Home/Catalog/Search/Wishlist/Compare/PDP-similar) and `ProductDescriptionComponent` (PDP description tab). Output stays plain text via interpolation, never `innerHTML` — no new XSS surface. Verified live on the "iphone" search query that originally showed the bug. Commit `a39b342`. |
| P0-6 | ❌ Not a bug (false positive) | Cart | Original audit read "Цвет:" with nothing visibly after it and assumed the selected color value was lost. | **Re-investigated with the accessibility tree, not text extraction.** `cart.component.html:49-54` already renders a color swatch (`<span class="cart-colour-swatch" [style.background-color]="item.colour" [title]="item.colour">`) — a visual CSS box, not text, so it has no visible characters for a text-only reader to pick up. Confirmed live: the swatch's accessible name is `#00008B`, matching the PDP selection, exactly as designed. No code change made. This was an artifact of the original audit's text-only method, not a real defect — flagging the correction so it isn't "fixed" twice. |
| P0-7 | ✅ Fixed (descoped, not built) | Storefront Account | No account/profile area exists anywhere; `HeaderConfig.showProfile` is a Project Editor toggle with no corresponding UI. | Building a real account/order-history page is feature work, explicitly out of scope for this polish-only pass. Removed the dangling "Profile" toggle from the header-section editor and its field-schema entry instead, so the editor no longer implies a feature that doesn't exist. `HeaderConfig.showProfile` field/default unchanged (data model untouched) in case a future account feature wires it up. Commit `e2d97d1`. |
| P0-8 | ✅ Fixed (verification + 2 new leaks closed) | Admin — Orders, Transactions, Users, Monitoring, Analytics | Re-verify whether the ~178-key i18n gap and missing-admin-shell items from `docs/ADMIN-UX-AUDIT.md` (2026-07-17) are actually still open, given later commits claim to have fixed them. | **Confirmed stale**: admin shell and dashboard localization are genuinely fixed. Live-walked the 5 remaining CRUD areas and found 2 real remaining leaks: `adminOrders.status.all` (primary status filter's "All" option) and `adminUsers.suspend`/`adminUsers.reactivate` (row action button). Transactions/Monitoring/Analytics showed no raw dot-key leaks. Added the missing keys to all 3 locales; verified live. Commit `1c39263`. |

---

## P1 — Should fix

| # | Page | Problem | Why it matters | Est. effort | Solution |
|---|---|---|---|---|---|
| P1-1 | Catalog & Search "Popular searches" chips | Chips read **"Smartphones, Sneakers, Headphones, Laptops"** in English while every surrounding label on the same page (`ru` locale) is Russian. | Same locale-inconsistency problem as the hero (P0-3) but lower-visibility (secondary UI, not first-screen). | S | Route these through the translate pipe / locale-aware config the same way the rest of the search UI already is. |
| P1-2 | Catalog & Search "Size" filter | First option in the Size filter chip list is literally **"default"** — a technical placeholder value, not a size. | A customer sees a nonsense filter option before the real sizes (S/M/L/XL). Low effort, easy trust hit. | S | Filter out or relabel placeholder enum values before rendering facet options. |
| P1-3 | Every product card with no reviews (majority of the catalog) | Rating always renders **"0.0 (0)"** instead of hiding the rating block or showing a neutral "No reviews yet" state, per `product-card.component.html:45-50` (`showRating` doesn't gate on `item.rating > 0` or review count). | A brand-new store with zero reviews looks like it's selling 0-star-rated products across the board — actively worse than showing nothing. | S | Hide the rating row (or swap to a neutral "No reviews yet" chip) when review count is 0, regardless of the numeric rating value. |
| P1-4 | PDP color/variant swatches | The color swatch's accessible name/tooltip is the raw hex code (`#00008B`) instead of the human color name ("Deep Blue," which is already present in the product title). | Screen-reader and low-vision users get a hex code instead of a color name; sighted users hovering get the same unhelpful string. | S | Prefer a `colorName` field for the swatch's `aria-label`/title, falling back to hex only if no name exists. |
| P1-5 | Cart line item price | Price renders as raw `166126.9 RUB` (no thousands separator, single decimal) directly under the product row, while the same page's "Итого"/"К оплате" totals correctly show `166,126.90 RUB` a few lines down. | Two different number formats for the same currency on one screen reads as unpolished/inconsistent, and the more prominent (unformatted) one is right next to the product a customer is about to buy. | S | Apply the same `number:'1.2-2'` (or currency) pipe used elsewhere in cart/checkout to the line-item price. |
| P1-6 | Admin Dashboard "System status" | Products/Categories show a red **"Проблема" (Problem)** status purely because the tenant currently has 0 products/categories seeded — this conflates "empty/not started yet" with "broken." Same class of issue `docs/ADMIN-UX-AUDIT.md` R6 already flagged for the old English-language dashboard; re-confirmed live against the now-localized version — the *design*, not just the translation, still needs a distinct "not started" state. | A merchant opening a brand-new store sees red "Problem" badges before they've done anything wrong, which is discouraging and inaccurate framing for an onboarding moment. | S–M | Give the health-check list a third state ("not started" / neutral) distinct from "problem," reserved for genuinely-empty-by-design conditions (0 products on a fresh tenant is not a config problem). |
| P1-7 | PDP tabs | Live text extraction of the product detail tab strip showed `Описание / Характеристики / Отзывы / Вопросы и ответы / Доставка / Гарантия / Описание` — "Описание" (Description) appears to occur twice in sequence. Flagged as **needs a visual follow-up** (couldn't confirm via screenshot this session) to rule out this being the tab label immediately followed by the active panel's own heading rather than an actual duplicate tab. | If it's a genuine duplicate tab, it's a straightforward but visible bug on the highest-traffic storefront page (PDP). If it's just adjacent label/heading text, no action needed. | XS to verify | Visually confirm with a screenshot pass once browser tooling is available; fix tab config if duplicated. |
| P1-8 | Storefront-wide | `docs/KNOWN-ISSUES.md` items still open and unresolved as of this audit: Theme Mode selector has no runtime effect (light/dark/system all look identical); the `dynamic-renderer/` pipeline is fully built but never wired to any template (dead code, and two Project Editor fields — Site Layout, homepage section `type` — silently do nothing); homepage hero-to-categories dead space gap. All three re-confirmed still open by source inspection. | Each is a real "this control does nothing" trap for a merchant using the editor, discovered by the platform's own prior audits — repeating them here so they aren't lost before RC sign-off. | See original entries in `docs/KNOWN-ISSUES.md` for effort/detail | Either finish or explicitly descope (and hide the corresponding editor controls for) Theme Mode and the unwired renderer pipeline before calling the editor "done." |
| P1-9 | Admin — Orders/Transactions/Users/Monitoring dangerous actions | `docs/ADMIN-UX-AUDIT.md` R7 flagged Suspend user / Retry payment / Clear fraud flag / Export financial data as same-visual-weight inline actions with no confirmation. Not re-verified live this session (lower-traffic screens, time-boxed pass) — carrying forward as still-likely-open pending a final confirm pass. | Financial/security-adjacent actions without a confirm step are a real risk even in a demo environment (a stray click "retries" a payment or exports customer PII). | S–M per action | Add an explicit confirm step stating the concrete consequence before firing any of these actions. |

---

## P2 — Nice improvements

| # | Page | Problem | Why it matters | Est. effort | Solution |
|---|---|---|---|---|---|
| P2-1 | Catalog & Search "Rating" filter | Only shows "5 звёзд" and "1 звёзд" chips (5-star and 1-star), skipping 2/3/4 — unclear if intentional (min/max only) or a truncated facet list. | Minor UX ambiguity; a shopper wanting "4 stars and up" has no obvious option. | XS to verify, S to fix | Confirm intent; if meant to be a full 1–5 range, render all 5 chips or switch to a min-rating slider. |
| P2-2 | Home hero-to-categories | `docs/KNOWN-ISSUES.md` item 1 (dead space gap between hero and categories) traced to mock config padding values, not code — re-confirm against real tenant data before RC since this doc's own note says it's unconfirmed outside the mock fixture. | Cosmetic but visible on the highest-traffic page. | XS–S | Re-test with a non-mock bootstrap once available; adjust section/widget padding tokens if it reproduces. |
| P2-3 | Bundle size | `angular.json` production budget: initial bundle was already **1.29MB, over the pre-existing 1MB error threshold**, before any P0 fix — confirmed via `git stash` on a clean tree, i.e. `ng build` failed on `main`/`B2B` already. Raised `maximumError` to 1.5MB (commit `8d99510`, user-approved) purely to unblock the build-gate requirement for this fix pass; the `700kB` warning threshold is untouched, so the size regression stays visible in every build. This does **not** fix the underlying size problem, only stops it from hard-failing `ng build`. | Doesn't block a demo; affects first-load performance in production. Was already broken before this session — not introduced by any P0 fix. | M (main-bundle/core-module import audit) | Track as its own post-RC performance sprint, not an RC blocker. Consider whether `maximumError` should come back down once the real fix lands. |
| P2-4 | Storefront-wide | Live browser screenshot/visual capture was unavailable in this session (tooling timeout) — several judgment calls above (P1-7 tab duplication, color-contrast/status-icon clarity on the admin dashboard, general spacing/typography rhythm across pages) could only be text/DOM-verified, not visually confirmed. | A pixel-level pass (Lighthouse/axe or manual screenshot review) is still owed before RC sign-off, consistent with the same caveat already logged in `docs/ADMIN.md` Sprint 28 ("no live Lighthouse/browser run available in this environment"). | S (once tooling allows) | Re-run this audit's visual-dependent items with a working screenshot tool, or manually in a real browser, before final RC sign-off. |
| P2-5 | Search "Найдено товаров: 200" vs "200 товаров" | The results-count string appears to render twice in slightly different phrasing right next to each other ("Найдено товаров: 200" then "200 товаров" a line below, same pattern seen on Catalog too). Needs visual confirmation — may be a result-count component plus a separate view-mode/count label that just read as adjacent text in this text-only pass. | If genuinely duplicated, it's redundant/confusing; low severity either way. | XS to verify | Visual/DOM follow-up once screenshots are available. |

---

## 4. What was re-verified vs. carried forward from prior docs

To avoid duplicating this repo's own extensive audit history, the following prior documents were treated as background, not re-derived from scratch:

- **`docs/KNOWN-ISSUES.md`** — all "Open" items re-confirmed still open by source inspection this session (see P1-8). "Fixed" items were not re-tested (no reason to doubt them; they're specific and were verified live at the time).
- **`docs/ADMIN-UX-AUDIT.md`** (2026-07-17) — its two headline P0s (no admin shell, ~178 raw i18n keys) are **stale**; both look substantially fixed based on live re-verification of Dashboard/Categories/Products this session and recent commit history (`fix(i18n): eliminate all raw translation key leaks across admin pages`, `refactor(admin): unify platform UX and consistency`, `c452d28`). Its lower-priority items (R7 confirm-steps on dangerous actions, R9 Monitoring audience mismatch, R10–R15 polish items) were **not** re-verified live this session and are carried forward as likely-still-relevant (P1-9, and implicitly the rest) rather than re-litigated — a follow-up pass specifically re-walking Orders/Transactions/Users/Monitoring/Analytics is the single highest-value next step to close this audit out (P0-8).
- **`docs/SPRINT-PLAN.md`** — confirms Sprint 29's translation-validation work and Sprint 30's final-verify pass both ran (`tsc`, `ng build`, `arch:check`) and reported clean; this audit did not re-run those build-level checks (out of scope for a UX/product audit) and takes them as current.

## 5. Areas requested but not separately itemized above

- **Builder / Project Editor**: `docs/EDITOR.md`'s own "Bug-hunt audit pass" and "Known gaps" sections already cover this in more depth than a fresh pass would in the time available (9 verified-and-fixed defects, 3 documented open gaps — Theme Mode, dynamic-renderer, showProfile — carried into P1-8 above). No new Builder-specific findings beyond what's already tracked there.
- **Static Pages, Legal, Info pages**: not separately walked live this session; `docs/StaticPages.md` describes the module as feature-complete with draft/publish, SEO, and device preview. Recommend a follow-up pass if any tenant-authored legal/static content will be shown in the demo, since content quality (not code) is the main open risk there, matching the pattern found in P0-4/P0-5.
- **Reviews, Media Library, Diagnostics (`/__diagnostics`)**: Media Library is called out in `docs/ADMIN-UX-AUDIT.md` §1.12 as the best-executed screen in the admin — no reason to doubt that holds. Diagnostics is dev-only and excluded from production, so it's not a demo-readiness concern by design.

## 6. P0 fix pass log (2026-07-19)

Executed immediately after this audit, same day, per explicit instruction to fix P0 only. Constraints: architecture unchanged, no invented backend APIs, no data-model changes unless absolutely necessary, no feature additions, production polish only. Every commit below passed `tsc --noEmit` and `ng build` before being made, and every fix was live-verified in the running dev app (not just typechecked).

1. `8d99510` — **Build-gate prerequisite.** `ng build` failed on an unmodified tree (pre-existing 1.29MB bundle vs 1MB error budget). Raised `angular.json`'s `maximumError` only, after asking the user how to handle it. Not a P0 item itself — logged in P2-3.
2. `1a5d435` — P0-1, P0-2 (stock badge translation, favorite/share/quickView aria-label keys).
3. `5b063d5` — P0-3 (hero locale-map). **Asked the user** whether to do a demo-data-only patch or the real (data-shape-widening) fix, since it crossed the "avoid data-model changes" constraint; user chose the real fix.
4. `3747749` — P0-4 (category filter: resolve real names via `CategoryFacade`, drop unresolvable options instead of fabricating a label).
5. `a39b342` — P0-5 (decode/strip HTML-entity markup from product descriptions, `product-card` + PDP description tab).
6. `e2d97d1` — P0-7 (removed dangling header "Profile" toggle from the editor; did not build the account feature it implied, per "no feature additions").
7. `1c39263` — P0-8 (verification pass over Orders/Transactions/Users/Monitoring/Analytics; found and fixed 2 more raw i18n key leaks).
8. P0-6 — investigated, determined to be a false positive from the original audit's text-only method. No fix needed; corrected in this doc.

**Stopped and asked the user twice**, per "stop only if a business decision is required": once for the build-budget gate (pre-existing failure unrelated to any P0 fix), once for P0-3 (whether hero localization warranted the data-model widening the constraints otherwise ask to avoid). Both were explicitly resolved by the user before proceeding.
