Some checks failed
Architecture Governance / architecture (push) Has been cancelled
@lucide/angular shipped its entire ~1500-icon set in the initial bundle despite the app only using 85 named-imported icons - confirmed upstream tree-shaking failure (sideEffects:false, clean named imports, single non-splittable fesm file). Replaced icon-registry.ts/icon.component.ts with hand-rolled inline SVG rendering of just the 85 used icons, transcribed from lucide's own node data for pixel-identical output. Zero call-site changes - AppIconName and app-icon's public API unchanged. Also: karma-coverage wired (npm run test:coverage), baseline captured in docs/SPRINT-PLAN-NEXT.md (32% statements / 18.5% branches). Cart-modal -> app-dialog migration was attempted and reverted - real conflicts (backdrop-close, nested-modal escape priority, iframe sizing), documented in docs/FUTURE_FEATURES.md for a properly scoped follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
95 lines
14 KiB
Markdown
95 lines
14 KiB
Markdown
# Sprint Plan — Next Wave (G onward)
|
||
|
||
Continues the sprint lettering from `docs/GLOBAL-SPRINT-PLAN.md` (Sprints A–F, all closed 2026-08-05: stub-page closure + widget layout/carousel fixes). Created 2026-08-05.
|
||
|
||
**Relationship to `docs/NEXT_PHASE.md`:** that file stays the one *phase-level* roadmap and owns the backend-integration sequencing. This file is the *task-level* tracker for work that is actionable now, plus an explicit parking list for what is blocked and on what. Where the two overlap, `NEXT_PHASE.md` wins on ordering.
|
||
|
||
---
|
||
|
||
## Tier 1 — Actionable now (nothing blocks these)
|
||
|
||
### Sprint G — Dead-config sweep
|
||
|
||
**Why:** This is a config-driven multi-tenant product, so "setting exists in the editor, nothing reads it at runtime" is the signature failure mode — and it reaches clients directly. Three instances were found *by accident* during other work: theme mode (`data-theme-mode` set, no CSS reads it), `HeaderConfig.showProfile` (fixed, Sprint A), `layout.columns` (fixed, Sprint F, and was the root cause of a real client bug report). A mechanical sweep finds the rest in one pass instead of one complaint at a time.
|
||
|
||
- [x] Enumerate every field in `BootstrapConfig` and its sub-models (`src/app/shared/models/config/*.model.ts`) — produce the full field inventory as a working list
|
||
- [x] For each field, grep for a real runtime consumer (a component/service that reads it and changes behavior), distinguishing: **live** (read + has effect), **dead** (never read), **inert** (read but effect is unreachable/no-op — the `data-theme-mode` case)
|
||
- [x] Cross-check against the editor: which dead/inert fields are *user-editable* today (those are the client-facing ones, highest priority)
|
||
- [x] Produce a findings table: field → status → editable? → recommendation (wire it / hide the control / delete the field)
|
||
- [x] Fix the trivially-wireable ones in the same pass (a field with an obvious consumer that was simply never connected)
|
||
- [x] For each remaining dead field, either hide its editor control or open a scoped follow-up — do **not** leave an editable control for a field nothing reads
|
||
- [x] Record findings in `docs/KNOWN-ISSUES.md` (real defects) / `docs/PRODUCT_BACKLOG.md` (needs a decision), matching how the earlier audit was folded in
|
||
|
||
**Known starting points (already confirmed dead/inert):** theme mode (`PRODUCT_BACKLOG.md`, needs a dark-mode decision — not a wiring fix). Verify no others in `HeaderConfig`, `FooterConfig`, `CatalogConfig`, `ProductPageConfig`, `UserExperienceConfig`, `FeatureFlags`, `SeoConfig`.
|
||
|
||
**What shipped:** Full findings table in `docs/DEAD-CONFIG-AUDIT.md`. Fixed and wired: `footer.logoUrl` (new `LogoComponent.srcOverride` input), `company.address.street` + `company.contacts.phone` (new `UiRuntimeFacade.companyAddress()`/`contactPhone()`, rendered in footer bottom bar), `catalog.suggestionsEnabled` (`SearchFacade.autocomplete()` now gates on it). Left dead but tracked (needs a business/design decision, not a mechanical fix): `layout.type` site-layout selector, `company.companyName` copyright-fallback wording (both → `PRODUCT_BACKLOG.md`), `navigation.header` top-nav rendering (→ `KNOWN-ISSUES.md`). `catalog.navigationMode` confirmed intentionally inert (labeled placeholder card, not a bug). No editor control was hidden — every remaining dead field's saved value stays visible and none risked losing already-saved client data.
|
||
|
||
### Sprint H — Test suite foundation
|
||
|
||
**Why:** 5 `.spec.ts` files exist in the entire repository. Project standards mandate 80% coverage and a TDD workflow; neither is happening. `NEXT_PHASE.md` Phase 2 defers testing until after backend integration — **this sprint deliberately front-runs part of that**, on the argument that tests written against the *current mock gateways* lock in today's behavior and make the eventual real-gateway swap far safer. Post-backend E2E work stays in Phase 2 where it is.
|
||
|
||
- [x] Confirm the test runner actually works end to end (`npm test` → `ng test --watch=false --browsers=ChromeHeadlessNoSandbox`) and fix the harness if it doesn't
|
||
- [x] Establish the house pattern with one exemplar spec per layer, so later tests have something to copy: a pure util, a service, a facade, a component
|
||
- [x] Facade-level tests against existing mock gateways for the highest-risk domains first: `ProjectEditorFacade` (undo/redo, draft persistence, validation gating on publish), `AdminAnalyticsFacade` (the never-fabricate-a-number contract)
|
||
- [x] Unit tests for the pure validator primitives (`project-editor/schema/validators/primitives.ts`) — zero-dependency, highest value per line of test
|
||
- [x] Regression tests for the bugs fixed this cycle so they cannot silently return (carousel `layout.columns` sizing, hero `layout.columns` panel count, header profile login/logout gating)
|
||
- [x] Wire coverage reporting — **done**: installed `karma-coverage` as a devDependency, added it to `karma.conf.js` (`coverage` reporter + `coverageReporter` block emitting `text-summary`, `html`, and `lcovonly` into `coverage/`). `npx ng test --watch=false --code-coverage` runs clean (83/83 specs pass). Baseline: Statements 32.02% (1025/3201), Branches 18.53% (353/1904), Functions 21.73% (220/1012), Lines 32.76% (946/2887).
|
||
- [x] Decide whether to gate CI on it — **no, not yet**: 11 spec files is a foundation, not the coverage floor CI gating implies; gate once coverage reporting exists and a real floor number can be set, not before.
|
||
|
||
**What shipped:** Harness confirmed working (`npm test` was already green, 57/57). Added 6 new spec files (test count 57 → 75): `ProjectEditorFacade` facade spec (undo/redo, draft-persistence round-trip via a second facade instance reading the same localStorage draft, publish blocked/allowed on `hasBlockingIssues()`) mocking `CONFIG_PROVIDER` as the gateway boundary; `AdminAnalyticsFacade` facade spec asserting `summary().conversionRate` stays `null` and `performance`/`backend-connectivity` health checks stay `'unknown'` rather than being guessed, mocking all 4 gateways + `AdminDashboardFacade`; `HeroWidgetComponent` and `ProductCarouselWidgetComponent` component specs regression-covering `layout.columns` (panel count / items-per-page); `HeaderComponent` component spec regression-covering the login/logout profile toggle (asserts on icon name, not translated aria-label text, since Russian is the default active language in tests). `primitives.ts` and the pure-util/service exemplar layers were already covered by pre-existing specs — verified, not re-done. Cart/checkout facade tests and a "manifest-filtered layout options" regression were scoped out to stay within this sprint's time budget — breadth across the 4 required layers (util/service/facade/component) was prioritized over a 5th facade.
|
||
|
||
### Sprint I — Widget `settingsSchema` enforcement
|
||
|
||
**Why:** Same disease Sprint E cured for `supportedLayouts`. Every widget in `widget-manifest.json` declares a JSON Schema for its props under `settingsSchema`, and **nothing reads it** — verified: only `supportedDataSources` is consumed anywhere (and only by a diagnostics validator, not the editor). Consequences: widget props are never validated against their own declared contract, and unknown widget types fall back to raw JSON editing in the Widgets section. (`enabled` *is* honored correctly — `widget-registry.bootstrap.service.ts` filters on it.)
|
||
|
||
- [x] Read `settingsSchema` in the Widgets editor section and validate widget props against it, surfacing failures through the existing `ProjectValidator` issue pipeline (`fieldKey`/`section`/`severity`) rather than a parallel mechanism
|
||
- [x] Add a `widgetSettingsSchema` validator alongside the existing `widgetConfig` check in `project-validator.service.ts`
|
||
- [x] Evaluate replacing the raw-JSON fallback editor with schema-generated fields for widget types that have no hand-authored editor — scope this honestly; if the schemas are too thin to generate a decent UI, keep the JSON fallback and just add validation on top
|
||
- [x] Confirm the diagnostics page (`features/diagnostics/`) reflects schema violations too, since it already consumes the manifest
|
||
|
||
**What shipped:** `validateAgainstSchemaLite(value, schema)` (`schema/validators/primitives.ts`) — a shallow, dependency-free type+required checker (no nested schemas/enums/$ref; checked first, no existing schema-validation utility or library in the repo). `ProjectValidator.widgetSettingsSchemaIssues()` runs it against every widget's `props` vs. its manifest entry's `settingsSchema`, added to the same `validate()` composition as a `widgets`-section warning tagged `fieldKey: 'pages'` — it surfaces automatically through the existing `fieldError('pages')` call already in `widgets-section.component.html`, no template changes needed. `WidgetManifestService` gained a synchronous `getManifestSnapshot()` (same pattern as `ConfigService.getBootstrapSnapshot()`) since `ProjectValidator.validate()` is called synchronously and can't await the manifest HTTP fetch; the check no-ops (matching `RuntimeDiagnosticsValidator`'s existing null-manifest convention) until the manifest has loaded once elsewhere in the app (it always has, by the time a user reaches the editor). Schema-generated form fields were evaluated and explicitly skipped: every widget's `settingsSchema.properties` tops out at 7 flat string/number fields with zero `required` arrays and zero enums/nesting across all 10 widget types in `widget-manifest.json` — too thin to justify generated UI over the existing JSON fallback (`widgets-section.component.ts`'s `updateJson`/`widgetJsonError`), so the JSON editor stays and only gets the new validation layered on top. Diagnostics: `BootstrapDiagnosticsValidator` gained a sibling `validateWidgetSettingsSchema()` next to its existing `validateUnknownWidgetTypes()`, reusing the identical `validateAgainstSchemaLite` call so the editor and diagnostics page can never disagree about what counts as a violation — one check, two surfaces, not a parallel one.
|
||
|
||
---
|
||
|
||
## Tier 2 — Blocked on backend
|
||
|
||
Sequencing is owned by `docs/BACKEND.md` §9 and `docs/NEXT_PHASE.md` Phase 1. Not re-planned here — that checklist is already the authoritative task list. Frontend-side items that unblock the moment backend lands:
|
||
|
||
- [ ] **Ed25519 auth error codes** (`docs/KNOWN-ISSUES.md` Open #1) — `session-expired` and `invalid-signature` recovery screens are built and wired but permanently unreachable, because `toAuthErrorShape()` derives the code purely from HTTP status and never reads a body-level code. Needs: backend returning a distinguishable `error.code` (`BACKEND.md` §6), then a small frontend change to prefer it over the status fallback.
|
||
- [ ] **Swap every mock gateway for its real counterpart** behind the existing DI tokens, in the dependency order `BACKEND.md` §8 specifies
|
||
- [ ] **Maintenance-mode frontend UI** (`BACKEND.md` §10 flags full-page takeover, per-module banners, scheduled countdown as not existing) — deliberately not built during Sprint C for exactly this reason
|
||
- [ ] **Real Monitoring data source** — page currently renders mock activity (`NEXT_PHASE.md` Phase 4)
|
||
- [ ] **Re-profile performance under real latency** (`NEXT_PHASE.md` Phase 3) — mock responses are instant, real ones won't be; loading/skeleton timing is untested against reality
|
||
|
||
## Tier 3 — Blocked on a business decision
|
||
|
||
No engineering work should start on these until answered. Full detail in `docs/PRODUCT_BACKLOG.md`.
|
||
|
||
- [ ] **Dark mode** — does the client want it? If yes it's a real project (dark palette + CSS strategy + `matchMedia` for "system"), not a wiring fix. Blocks the theme-mode selector, which is inert today.
|
||
- [ ] **Brand color contrast (WCAG AA)** — `--border-color` fails 3:1 in every theme; several status colors fail 4.5:1 as text. Fixing means visibly changing the brand — needs theme-owner sign-off.
|
||
- [ ] **Stars rating glyph token** — literal hex with no matching design token; add a token or reuse an existing one (visual shift either way).
|
||
- [ ] **Contacts page content** — nothing written for it at all. Content question.
|
||
- [ ] **Advanced analytics** — no data source exists for traffic/funnels/heatmaps. Build vs. buy, and launch vs. later.
|
||
- [ ] **Additional payment providers** — which ones, if any, before integration work starts.
|
||
|
||
## Tier 4 — Deferred, non-blocking
|
||
|
||
From `docs/FUTURE_FEATURES.md`. No decision needed, just not worth doing now.
|
||
|
||
- [ ] **Angular 22 upgrade** — researched, ~2–3.5 days, needs a dependency fix and Node bump first. Plan: `docs/ANGULAR22_PLAN.md`. **Run as its own dedicated session** — framework upgrades don't share a session with feature work.
|
||
- [ ] **Bundle splitting** — `project-editor` (~896 kB) and `catalog-container` (~330 kB) lazy chunks are large; no mechanical split found, needs a dedicated profiling task, ideally under real backend latency
|
||
- [ ] **Cart payment modal → `app-dialog`** — composition cleanup, functionally and accessibly complete as-is
|
||
- [ ] **Homepage hero-to-categories spacing** — traces to mock fixture padding values, not a confirmed defect; needs reproduction with real tenant data before it's worth investigating
|
||
|
||
## Tier 5 — Infrastructure
|
||
|
||
- [ ] **Server deploy** — no deploy pipeline exists in this repo (only `.github/workflows/architecture-governance.yml`). Deploys are currently manual/out-of-band. Worth deciding whether a real pipeline should exist; separately, SSH from the agent harness is blocked, so agent-driven deploys need either a permission rule or a different mechanism.
|
||
|
||
---
|
||
|
||
## Suggested order
|
||
|
||
**G → H → I.** Sprint G is cheap, mechanical, and directly prevents more client-reported ghost settings (it is the same class of bug as the one already reported). Sprint H is the highest-value thing available that isn't blocked on anything, and it gets more valuable the earlier it lands, since every later change rides on it. Sprint I is real but narrower — it hardens an editor path rather than fixing something users hit today.
|
||
|
||
Tier 2 starts the moment backend Phase 1 lands. Tier 3 needs answers, not engineering. Tier 4 is genuinely optional.
|