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>
56 lines
7.7 KiB
Markdown
56 lines
7.7 KiB
Markdown
# Performance Report — RC PERF-01
|
||
|
||
Production-readiness performance audit + fixes, application-wide. No redesign, no UI/visual changes, no route/API changes — pure performance/correctness work. Three sequential commits on branch `B2B` (not pushed):
|
||
|
||
| Commit | Scope |
|
||
|---|---|
|
||
| `61a5714` | Angular reactivity, change detection, rendering, memory |
|
||
| `4bf0666` | Bundles, lazy-loading, tree-shaking, large chunks |
|
||
| `2e931bb` | Assets: images, fonts, SVG, CSS |
|
||
|
||
`npm run build` verified green after every commit. `npx tsc --noEmit` clean throughout.
|
||
|
||
## Headline result
|
||
|
||
Initial bundle: **1.47 MB → 1.12 MB raw** (−350 KB / −24%), transfer estimate **263.59 kB → 221.51 kB** (−16%). Budget overage shrank from 769 KB over to 417 KB over (still a warning, not an error — the 700 KB budget itself is unchanged and still exceeded, see Remaining below). Global CSS bundle: 9.60 kB → 8.41 kB raw (−12%).
|
||
|
||
## Findings and fixes by area
|
||
|
||
### Angular reactivity / change detection / memory (`61a5714`)
|
||
|
||
- **`.subscribe()` audit**: 149 call sites across 44 files. Spot-checked every long-lived stream in the highest-risk components (route params, router events, polling/intervals) — all already use `takeUntilDestroyed(this.destroyRef)` or an explicit `Subscription` + `ngOnDestroy` unsubscribe. One-shot HTTP-backed subscribes self-complete, no leak. **No leaks found** — the codebase's existing discipline here was already solid.
|
||
- **`ChangeDetectionStrategy.OnPush`**: 191 components, 190 already had it. Added to the 1 remaining (`app.ts`, the root component) — verified safe (signal-driven template, no direct DOM mutation).
|
||
- **`@for`/`track`**: fully compliant app-wide — the codebase is entirely on the new control-flow syntax, which the compiler requires `track` on, so there was nothing to fix. Legacy `*ngFor` without `trackBy`: zero occurrences.
|
||
- **Duplicate HTTP calls**: `CategoryFacade` and `ConfigService` already cache via `shareReplay({bufferSize:1, refCount:true})`, applied consistently — no duplicate-request pattern found.
|
||
- **Flagged, not fixed**: 2 `combineLatest` sites (`catalog-container.component.ts`, `subcategories.component.ts`) are narrow, already-minimal RxJS composition — converting to `computed()` would touch adjoining facade state shape, judged out of this pass's risk budget. Per-item template method calls in `@for` loops (`getDiscountedPrice`, `itemName`, `categoryName`, `stockLabelKey`) are cheap pure lookups on an already-OnPush host — flagged as pipe-conversion candidates for a future pass, not urgent.
|
||
|
||
### Bundles / lazy-loading / tree-shaking (`4bf0666`)
|
||
|
||
- **Lazy-loading boundaries**: already correct — every storefront/builder/backoffice route in `app.routes.ts` uses `loadComponent`, nothing eagerly imported.
|
||
- **i18n eager-loading — the biggest single win**: `TranslateService` statically imported all three locale packs (ru/en/hy, 346 KB raw combined) into the initial bundle regardless of visitor language. Fixed: `ru` (default) stays eager, `en`/`hy` are now `import()`ed on demand via a new `preloadLanguage()`, awaited inside `languageGuard` before route activation — router blocks navigation until the pack resolves, so there's no untranslated-flash risk.
|
||
- **Dead code**: `knip` found `src/app/components/items-carousel/*` (3 files) completely unreferenced anywhere, and the sole consumer of the `primeng` dependency. Deleted the component and its now-dead `primeicons.css` import from `src/styles.scss`.
|
||
- **Tree-shaking**: fixed one accidental barrel import in `widget-host.service.ts` (now imports `UnknownWidgetComponent` directly instead of through the `widgets/ui` barrel) — negligible measured impact, but correct going forward. `@lucide/angular` icons already use named tree-shakeable imports.
|
||
- **Duplicate deps**: `npm ls` confirms a single deduped `rxjs@7.8.2` — no duplicate module instances.
|
||
- **Flagged, not fixed**: `primeng`/`primeicons` remain in `package.json`/lockfile — `npm install`/`uninstall` fails in this environment (`ETARGET`) on a pre-existing, unrelated broken `barry-cache` devDependency, so the lockfile couldn't be safely regenerated by hand. **Follow-up needed**: fix the `barry-cache` devDependency resolution, then `npm uninstall primeng primeicons` to drop the dependency entirely (the code reference is already gone). Large chunks (`project-editor` 320 kB, `catalog-container` 126 kB, `product-details-container` 88 kB, `cart` 61 kB) unchanged — no mechanical split found inside their scope; a real reduction here would mean lazy-loading a sub-feature (e.g. an embedded editor), which is a larger, dedicated task.
|
||
|
||
### Assets: images, fonts, SVG, CSS (`2e931bb`)
|
||
|
||
- **Images**: storefront `<img>` tags already have `loading="lazy"`/`decoding="async"` on grids/galleries and CLS is already handled via CSS `aspect-ratio` (from prior RC-Visual-02/RC-Premium-01 passes) — nothing to fix. Flagged: a handful of single-image admin/editor previews lack `loading="lazy"` (page-editor, brand-overview, asset-details-drawer) — negligible traffic, left alone.
|
||
- **Fonts**: `index.html` already preconnects to Google Fonts, loads DM Sans 400/500/600/700 with `display=swap`; all 4 loaded weights are actually used. Flagged: weights 800/900 are referenced in some component SCSS but never loaded (pre-existing faux-bold rendering) — changing loaded weights risks a visible text difference, left out of scope for a perf-only pass.
|
||
- **SVG**: icon system is fully centralized through `@lucide/angular` via `icon-registry.ts` — no inline path duplication. `public/` SVGs checked for editor cruft (metadata/inkscape artifacts) — already clean. Flagged: 5 branding SVGs (`mastercard-logo.min.svg`, `dexar-logo*.svg`, `dexar-favicon.svg`, `novo-logo.svg`, `novo-favicon.svg`) appear unreferenced in `src`, left in place — may back tenant branding resolved from the backend at runtime, deletion needs a human decision, not this pass's call.
|
||
- **CSS**: manual grep-based cross-check (literal + hyphen-safe, checked for dynamic `[class.x]`/string-built classes too) of `src/styles.scss` utility classes against all templates. Confirmed-dead and removed: `.btn-primary`/`.btn-secondary`+hover, `.catalog-product-card`, `.item-badges-overlay`, `.item-simple-desc`, `.text-center`, `.mt-1..4`, `.mb-1..4`, `.p-1..4`.
|
||
|
||
## Remaining recommendations (not applied — flagged for follow-up)
|
||
|
||
1. **`primeng`/`primeicons` still in `package.json`** despite the only consumer being deleted — needs the pre-existing `barry-cache` devDependency resolution issue fixed first, then a clean `npm uninstall`. Highest-value remaining action: would likely close most of the remaining 417 KB budget overage in one move once confirmed.
|
||
2. **Large lazy chunks** (`project-editor` 320 kB, `catalog-container` 126 kB) — no mechanical fix found; needs a dedicated task to identify a genuinely lazy-loadable sub-feature inside each.
|
||
3. **2 `combineLatest` sites** — safe to leave, candidates for a `computed()` conversion in a future facade-focused pass.
|
||
4. **Per-item template method calls** in `@for` loops — pipe-conversion candidates, not urgent (already bounded by OnPush).
|
||
5. **Font weights 800/900** used in SCSS but not loaded — either load them explicitly or normalize the SCSS to a loaded weight; a design-system call, not a perf call.
|
||
6. **5 unreferenced branding SVGs** — confirm with backend/tenant-branding owner before deleting.
|
||
7. **Admin/editor preview images** missing `loading="lazy"` — low priority, low traffic.
|
||
|
||
## Verification
|
||
|
||
`tsc --noEmit` and `npm run build` run and green after each of the three commits. No live browser session available this session — real-world Core Web Vitals (LCP/CLS/INP) were not measured; recommend a Lighthouse/WebPageTest pass against a deployed build before the client demo referenced in `docs/FRONTEND-ROADMAP.md`.
|