Sprint G: audited every BootstrapConfig field for a real runtime consumer (docs/DEAD-CONFIG-AUDIT.md). Wired 3 previously-dead editable fields: footer.logoUrl, company.address.street/contacts.phone, catalog.suggestionsEnabled. Remaining dead fields needing a business/design decision tracked in PRODUCT_BACKLOG.md/KNOWN-ISSUES.md, not silently left. Sprint H: 6 new spec files (test count 57 -> 83), covering ProjectEditorFacade (undo/redo, draft persistence, publish gating), AdminAnalyticsFacade (never-fabricate-a-number contract), and regression coverage for this session's carousel/hero/profile-toggle fixes. Sprint I: widget settingsSchema (declared in widget-manifest.json, never validated) now enforced via a new lightweight schema check in ProjectValidator, surfaced through the existing issuesByField pipeline. Same check reused in diagnostics so editor and diagnostics can't disagree. Verification: tsc clean, ng build clean, 83/83 tests pass, barry-cache validate clean (2 pre-existing unrelated warnings only). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
14 KiB
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.
- Enumerate every field in
BootstrapConfigand its sub-models (src/app/shared/models/config/*.model.ts) — produce the full field inventory as a working list - 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-modecase) - Cross-check against the editor: which dead/inert fields are user-editable today (those are the client-facing ones, highest priority)
- Produce a findings table: field → status → editable? → recommendation (wire it / hide the control / delete the field)
- Fix the trivially-wireable ones in the same pass (a field with an obvious consumer that was simply never connected)
- 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
- 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.
- 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 - 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
- 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) - Unit tests for the pure validator primitives (
project-editor/schema/validators/primitives.ts) — zero-dependency, highest value per line of test - Regression tests for the bugs fixed this cycle so they cannot silently return (carousel
layout.columnssizing, herolayout.columnspanel count, header profile login/logout gating) - Wire coverage reporting — not done:
ng test --code-coveragefails (Can not load reporter "coverage", it is not registered!) becausekarma-coverageisn't installed, and installing it would be a new dependency, which is out of scope for this pass per the explicit no-new-dependencies constraint. Left for a follow-up that also gets sign-off on adding the package. - 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.)
- Read
settingsSchemain the Widgets editor section and validate widget props against it, surfacing failures through the existingProjectValidatorissue pipeline (fieldKey/section/severity) rather than a parallel mechanism - Add a
widgetSettingsSchemavalidator alongside the existingwidgetConfigcheck inproject-validator.service.ts - 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
- 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.mdOpen #1) —session-expiredandinvalid-signaturerecovery screens are built and wired but permanently unreachable, becausetoAuthErrorShape()derives the code purely from HTTP status and never reads a body-level code. Needs: backend returning a distinguishableerror.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.mdPhase 4) - Re-profile performance under real latency (
NEXT_PHASE.mdPhase 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 +
matchMediafor "system"), not a wiring fix. Blocks the theme-mode selector, which is inert today. - Brand color contrast (WCAG AA) —
--border-colorfails 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) andcatalog-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.