Sprint E: homepage section editor now filters the layout-strategy picker to each widget's widget-manifest.json supportedLayouts instead of always showing all 5 strategies. columns field gated to widgets that read it (hero, product-collection carousel). Sprint F: closes client bug report (no items-per-page control, hero carousel not manually/automatically scrollable, no 1-2 slide big-carousel option). Product carousel item width now driven by layout.columns (reused, was already editable but dead). Hero widget gains prev/next arrows, touch swipe, and 1-2 panel mode via the same field. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
11 KiB
Global Sprint Plan — "Coming Soon" Stub Closure
Supersedes docs/COMING-SOON-AUDIT.md §5 sprint breakdown. One consolidated tracker for the four stub-closure sprints. Approved decisions (from AskUserQuestion): Reports/Settings ship as minimal real pages (not fake data, not empty shells); Documentation/Help nav uses an external-link approach; docs/COMING-SOON-AUDIT.md is deleted once all sprints land, folded into docs/KNOWN-ISSUES.md. Profile control constraint: login/logout only — no dropdown, no account links.
Sprint A — Profile menu (storefront header)
- i18n:
header.login/header.logoutkeys in en/ru/hy (translations.tstype already updated) header.component.ts: injectAuthService, exposeisAuthenticated, addlogin()/logout()header.component.ts: importTelegramLoginComponentheader.component.html: profile control gated byheaderConfig().showProfile, login/logout only,<app-telegram-login />rendered once- SCSS matches existing header button conventions (reused
.platform-ux-btn, no new SCSS needed)
What shipped: Header profile control wired to the customer AuthService (Telegram QR login). Gated by headerConfig().showProfile (already a real toggle in Project Editor, previously dead). Logged-out shows a login button (user icon), logged-in shows a logout button (logOut icon) — no dropdown, no account links, per the explicit constraint.
Sprint B — Admin Reports page
admin-reports-page.component.ts/.html/.scss(mirrorsadmin-analytics-pagestructure), reusesAdminAnalyticsFacade- Report cards: Sales, Top Products, Marketplace Health
- CSV export wired to existing facade export methods / existing download helper (same Blob pattern as
admin-analytics-page.component.ts) - Route
backoffice/reportsinapp.routes.ts, i18n keysadminShell.pages.reports.*+ newadminReports.*block - Remove
comingSoon: truefromreportsnav entry
What shipped: Minimal real Reports page with 3 cards (Sales, Top Products, Marketplace Health), each showing a live summary from AdminAnalyticsFacade and a CSV export button. Orders card was scoped out — see final report for why (reuse would require mutating a shared singleton facade's pagination state).
Sprint C — Admin Settings page
AdminPreferencesService(density signal, localStorage-backed, keyadminPreferences.density.v1)admin-layout.componentappliesadmin-density-compactclass to#admin-contentshell wrapperadmin-settings-page.component.ts/.html/.scss— density toggle (app-toggle), auto-persists on change, no separate Save button- Route
backoffice/settings, i18n keysadminShell.pages.settings.*+adminSettings.*block - Remove
comingSoon: truefrom nav entry AND dashboard shortcut; shortcut route →['backoffice','settings'] - Compact-density CSS rule added to the shared
app-tablecomponent stylesheet (.admin-density-compact .app-table th/td) — applies to every admin list page built onapp-table(orders, products, categories, etc.), not just one
What shipped: Genuinely real, backend-independent UI density preference. No maintenance-mode toggle built (explicitly deferred per docs/NEXT_PHASE.md Phase 4).
Sprint D — Documentation / Help nav
- Help:
mailto:using existingsupportEmailread path (UiRuntimeFacade.contactEmail(), same oneheader.component.tsalready uses forbootstrap.branding.supportEmail) AdminNavLinkgains optionalexternalHref?: string; nav renderer renders<a>branch (bottom nav)- Documentation: added
tenant.documentationUrl?: stringtoTenantConfig, populated mock withhttps://docs.marketplace.local help/documentationresolved dynamically inadmin-layout.component.ts(navBottomcomputed) — real<a>when bootstrap data present, staticcomingSoon: trueentries kept as defensive fallback for the (currently unreachable, since mock always has both fields) case where the backend omits them
What shipped: Both Help and Documentation wired to real external links, not just Help. comingSoon: true remains in admin-nav.model.ts source as a fallback flag only — it is overridden to false at render time whenever bootstrap actually has the data, which it does today.
Sprint E — Widget layout config correctness (manifest-aware editor)
Root cause confirmed 2026-08-05: widget-manifest.json already declares supportedLayouts per widget type (hero→[hero, split], categories→[grid], product-collection→[carousel, grid]), but homepage-section.component.ts's layoutStrategyPickerOptions is a static 5-option list (stack/grid/hero/carousel/split) shown identically for every homepage section regardless of which widget backs it — it never reads the manifest. The columns field (homepage-section.component.html:49) is shown for every section too, but no widget component reads layout.columns — it is currently dead everywhere.
homepage-section.component.ts: resolve each section's widget type (via its bound widget id →widget-registry/manifest lookup) and filterlayoutStrategyPickerOptionsdown to that widget'ssupportedLayoutsbefore rendering the picker- Hide/disable the
columnsfield for any section whose resolved widget doesn't consume it (onlyproduct-collectionand, after Sprint F,herowill) - No behavior change for widgets that already worked (categories/recently-viewed/footer-nav keep their single valid layout, picker just stops offering the other 4 nonsensically)
What shipped: homepage-section.component.ts now injects WidgetManifestService, resolves each section's manifest entry directly by section.type (confirmed identical to the manifest type key — no separate widget-id lookup needed), and derives layoutOptionsFor(section) by filtering the static option list down to that entry's supportedLayouts. A stale/unsupported saved strategy value is appended back into the options list rather than dropped, so app-visual-layout-picker never renders with no active card. showColumnsFor(section) gates the columns field to the two componentKeys that actually read it (hero always, product-collection only in carousel strategy — grid mode ignores it). One correction to the plan's assumption: recently-viewed's actual manifest entry declares supportedLayouts: ["stack", "grid", "carousel"] (3 options, not 1) — the picker now correctly reflects that per the manifest rather than the plan's guess.
Sprint F — Carousel items-per-page (closes the client bug report)
Confirmed real, reported by a client, not fixed anywhere: neither carousel widget has an "items/slides per page" concept. Design: reuse the existing (currently dead) layout.columns field rather than inventing a new one — it is already editable in the Homepage section editor once Sprint E gates it to the right widgets.
ProductCarouselWidgetComponent: readsection.layout.columns(default 4, min 1) to size.catalog-product-shellwidth as a fraction of the scroller instead of the hardcoded220px— gives real "items per page" control, arrows/scroll logic unchanged (already works)HeroWidgetComponent: add manual prev/next arrows (parity with the product carousel's arrow buttons) in addition to the existing dots — closes "not scrollable manually"HeroWidgetComponent: add swipe/drag (pointer events) support for touch — closes "not scrollable manually" on mobileHeroWidgetComponent: supportlayout.columns= 1 or 2 to show one or two slide panels at once ("big carousel one or two slides per page") — 2-panel mode shows the active slide plus the next one side by side- Verify autoplay (
props.autoplay, already exists, editor toggle already exists perwidgets-section.component.html:61) still functions correctly alongside the new manual controls (manual interaction should not fight the autoplay timer — reset/pause timer on manual nav, matching common carousel UX) - i18n: any new aria-labels for the new hero arrows (reuse
common.previousProducts/common.nextProductskeys if wording fits, or addcommon.previousSlide/common.nextSlide)
What shipped: ProductCarouselWidgetComponent sets --items-per-page as a CSS custom property ([style.--items-per-page]) driven by itemsPerPage() (default 4, min 1, floored), and .catalog-product-shell width is now calc((100% - (var(--items-per-page, 4) - 1) * var(--space-md, 16px)) / var(--items-per-page, 4)) instead of a fixed 220px. HeroWidgetComponent gained prev/next arrow buttons (same circular/bordered visual language as the product carousel's arrows), touch-event swipe (same threshold-based approach as cart.component.ts's onSwipeStart, 50px threshold, left swipe = next, right swipe = prev), and 2-panel support via layout.columns (defaults to 1; columns === 2 shows the active slide plus the next one side by side, falling back to 1 panel when there's only one slide total). All manual navigation (arrows, swipe, dots) routes through the existing goTo(), which already clears+restarts the autoplay timer, so no duplicate timer logic was needed. New i18n keys common.previousSlide / common.nextSlide added to translations.ts, en.ts, ru.ts, hy.ts.
Verification: npx tsc --noEmit and npx ng build --configuration=development both clean. Visually verified in the browser preview (ng serve on port 4200) by temporarily patching the embedded home-page sections in src/assets/mock/bootstrap/bootstrap.json (the actual runtime source for / — src/assets/mock/bootstrap/homepage.json is a separate, unused-by-this-route file) to columns: 2 + a second slide for hero and columns: 3 for the product carousel, confirming via DOM/computed-style inspection: hero rendered 2 slide panels with 2 working arrows, arrow clicks and simulated touch swipe both advanced/reversed the active dot correctly, and the carousel's --items-per-page CSS var read 3 with each .catalog-product-shell measuring ~348px (vs. the fixed 1110px/220px before). All temporary mock-data edits were reverted afterward (git checkout) — bootstrap.json and homepage.json are unchanged in the final diff. The Sprint E manifest-aware picker itself could only be verified by code inspection, not live in the browser — /edit/:section requires Telegram admin login, which cannot be completed in this environment.
Housekeeping
- Delete
docs/COMING-SOON-AUDIT.md - Fold summary into
docs/KNOWN-ISSUES.md"Fixed (this cycle)"; remove theHeaderConfig.showProfiledead-toggle entry from "Open" - Update
docs/BACKEND.md(tenant.documentationUrlfield added §1.3; nodocs/backend/BACKEND-INTEGRATION.mdexists in this repo) npm run barry -- validate(clean, only pre-existing unrelated warnings)- Typecheck touched files (
tsc --noEmit+ fullng buildboth clean)