@mohasinac/appkit 4.53.0 → 4.53.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/client/scaffolds/AppShell.js +1 -1
- package/dist/_internal/client/theme/ThemeProvider.js +15 -1
- package/dist/_internal/server/features/auctions/og.d.ts +3 -1
- package/dist/_internal/server/features/auctions/og.js +3 -1
- package/dist/_internal/server/features/bundles/actions.js +1 -1
- package/dist/_internal/server/features/business-documents/download.d.ts +41 -0
- package/dist/_internal/server/features/business-documents/download.js +91 -0
- package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
- package/dist/_internal/server/features/categories/adapters.js +10 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
- package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +14 -0
- package/dist/_internal/server/features/checkout/actions.js +106 -12
- package/dist/_internal/server/features/checkout/bundle-expansion.js +17 -0
- package/dist/_internal/server/features/checkout/data.d.ts +22 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.d.ts +34 -0
- package/dist/_internal/server/features/checkout/group-rule-revalidation.js +124 -0
- package/dist/_internal/server/features/checkout/supplier-identity.d.ts +55 -0
- package/dist/_internal/server/features/checkout/supplier-identity.js +81 -0
- package/dist/_internal/server/features/classified/metadata.js +1 -1
- package/dist/_internal/server/features/classified/og.d.ts +3 -1
- package/dist/_internal/server/features/classified/og.js +3 -1
- package/dist/_internal/server/features/digital-code/metadata.js +1 -1
- package/dist/_internal/server/features/digital-code/og.d.ts +3 -1
- package/dist/_internal/server/features/digital-code/og.js +3 -1
- package/dist/_internal/server/features/digital-code/pool.d.ts +19 -4
- package/dist/_internal/server/features/digital-code/pool.js +19 -4
- package/dist/_internal/server/features/live/metadata.js +1 -1
- package/dist/_internal/server/features/live/og.d.ts +3 -1
- package/dist/_internal/server/features/live/og.js +3 -1
- package/dist/_internal/server/features/messages/actions.js +1 -1
- package/dist/_internal/server/features/parts/og.js +1 -1
- package/dist/_internal/server/features/pre-orders/og.d.ts +3 -1
- package/dist/_internal/server/features/pre-orders/og.js +3 -1
- package/dist/_internal/server/features/price-index/market.d.ts +57 -0
- package/dist/_internal/server/features/price-index/market.js +120 -0
- package/dist/_internal/server/features/price-index/search.d.ts +18 -0
- package/dist/_internal/server/features/price-index/search.js +47 -7
- package/dist/_internal/server/features/prize-draws/og.d.ts +3 -1
- package/dist/_internal/server/features/prize-draws/og.js +3 -1
- package/dist/_internal/server/features/products/group-members.d.ts +26 -0
- package/dist/_internal/server/features/products/group-members.js +7 -1
- package/dist/_internal/server/features/products/list-public.d.ts +12 -0
- package/dist/_internal/server/features/products/list-public.js +10 -1
- package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
- package/dist/_internal/server/features/products/listing-tab-counts.js +128 -10
- package/dist/_internal/server/features/products/og.d.ts +3 -1
- package/dist/_internal/server/features/products/og.js +3 -1
- package/dist/_internal/server/features/search/scoped-sources.d.ts +26 -0
- package/dist/_internal/server/features/search/scoped-sources.js +252 -0
- package/dist/_internal/server/features/search/search-everything.d.ts +57 -0
- package/dist/_internal/server/features/search/search-everything.js +70 -20
- package/dist/_internal/server/features/seo/sitemap.js +6 -0
- package/dist/_internal/server/features/shared/listing-adapters.js +4 -2
- package/dist/_internal/server/features/sticker-trace/adapters.d.ts +11 -0
- package/dist/_internal/server/features/sticker-trace/adapters.js +1 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.d.ts +26 -0
- package/dist/_internal/server/features/sticker-trace/promote-to-listings.js +264 -0
- package/dist/_internal/server/features/sticker-trace/sheet-actions.d.ts +3 -1
- package/dist/_internal/server/features/sticker-trace/sheet-actions.js +32 -0
- package/dist/_internal/server/features/sticker-trace/storage.d.ts +20 -1
- package/dist/_internal/server/features/sticker-trace/storage.js +20 -1
- package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
- package/dist/_internal/server/features/stores/adapters.js +16 -0
- package/dist/_internal/server/features/stores/index.d.ts +1 -0
- package/dist/_internal/server/features/stores/index.js +1 -0
- package/dist/_internal/server/features/stores/tabs.d.ts +30 -0
- package/dist/_internal/server/features/stores/tabs.js +124 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +0 -2
- package/dist/_internal/shared/checkout/rules/_limits.d.ts +14 -1
- package/dist/_internal/shared/checkout/rules/_limits.js +14 -1
- package/dist/_internal/shared/checkout/rules/_registry.js +2 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +9 -1
- package/dist/_internal/shared/checkout/rules/bundle.rule.js +13 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +9 -0
- package/dist/_internal/shared/checkout/rules/offer.rule.js +0 -1
- package/dist/_internal/shared/checkout/rules/payment-gate.d.ts +26 -0
- package/dist/_internal/shared/checkout/rules/payment-gate.js +133 -0
- package/dist/_internal/shared/checkout/rules/prize-draw.rule.js +29 -8
- package/dist/_internal/shared/checkout/rules/spares.rule.d.ts +16 -0
- package/dist/_internal/shared/checkout/rules/spares.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +26 -2
- package/dist/_internal/shared/config/schema.d.ts +122 -0
- package/dist/_internal/shared/features/cart/schema.js +3 -2
- package/dist/_internal/shared/features/products/group-rules.d.ts +75 -0
- package/dist/_internal/shared/features/products/group-rules.js +142 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +24 -0
- package/dist/_internal/shared/listing-types/_registry.js +39 -1
- package/dist/_internal/shared/listing-types/art/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/config.js +2 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/auction/config.js +2 -0
- package/dist/_internal/shared/listing-types/availability.js +48 -0
- package/dist/_internal/shared/listing-types/capabilities.js +19 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/classified/config.js +2 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +2 -0
- package/dist/_internal/shared/listing-types/feature-flags.js +1 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/live/config.js +2 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +2 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +2 -0
- package/dist/_internal/shared/listing-types/spares/config.d.ts +74 -0
- package/dist/_internal/shared/listing-types/spares/config.js +60 -0
- package/dist/_internal/shared/listing-types/spares/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/ctas.js +4 -0
- package/dist/_internal/shared/listing-types/spares/og.js +1 -0
- package/dist/_internal/shared/listing-types/spares/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/spares/schema.js +3 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/spares/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/standard/config.js +2 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +2 -0
- package/dist/_internal/shared/search/match.d.ts +11 -0
- package/dist/_internal/shared/search/match.js +30 -3
- package/dist/_internal/shared/search/to-groups.d.ts +52 -0
- package/dist/_internal/shared/search/to-groups.js +141 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +46 -15
- package/dist/constants/api-endpoints.js +35 -5
- package/dist/constants/cache-invalidation.js +3 -1
- package/dist/constants/field-names.d.ts +6 -0
- package/dist/constants/field-names.js +6 -0
- package/dist/features/about/components/PolicyPageView.d.ts +22 -2
- package/dist/features/about/components/PolicyPageView.js +14 -2
- package/dist/features/about/components/PublicProfileView.js +2 -1
- package/dist/features/about/components/ShippingPolicyView.js +42 -2
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/hooks/useProfileStats.js +5 -1
- package/dist/features/addresses/repository/addresses.repository.d.ts +16 -0
- package/dist/features/addresses/repository/addresses.repository.js +21 -0
- package/dist/features/admin/actions/admin-actions.js +16 -1
- package/dist/features/admin/components/AdminCategoryEditorView.js +19 -2
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminPageHeader.js +1 -1
- package/dist/features/admin/components/AdminProductEditorView.js +17 -2
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +39 -8
- package/dist/features/admin/components/AdminSparesView.d.ts +12 -0
- package/dist/features/admin/components/AdminSparesView.js +30 -0
- package/dist/features/admin/components/AdminUsersView.js +9 -7
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +7 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/firestore.d.ts +26 -2
- package/dist/features/auctions/components/AuctionDetailPageView.js +12 -18
- package/dist/features/auth/repository/user.repository.d.ts +13 -0
- package/dist/features/auth/repository/user.repository.js +28 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/business-documents/repository/business-documents.repository.d.ts +58 -0
- package/dist/features/business-documents/repository/business-documents.repository.js +54 -0
- package/dist/features/business-documents/schemas/firestore.d.ts +105 -0
- package/dist/features/business-documents/schemas/firestore.js +75 -0
- package/dist/features/cart/actions/cart-actions.js +83 -6
- package/dist/features/cart/repository/cart.repository.js +32 -4
- package/dist/features/cart/schemas/firestore.d.ts +20 -0
- package/dist/features/cart/schemas/index.d.ts +2 -2
- package/dist/features/catalogue/components/PublicCatalogueItemDetailView.js +1 -1
- package/dist/features/categories/api/[id]/price-guidance/route.d.ts +42 -0
- package/dist/features/categories/api/[id]/price-guidance/route.js +90 -0
- package/dist/features/categories/components/BrandDetailPageView.js +32 -8
- package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/BrandDetailTabs.js +28 -3
- package/dist/features/categories/components/BundleCollage.js +3 -2
- package/dist/features/categories/components/BundleItemsPicker.js +3 -4
- package/dist/features/categories/components/CategoriesIndexListing.js +23 -8
- package/dist/features/categories/components/CategoryDetailPageView.js +157 -20
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +41 -7
- package/dist/features/categories/components/CategoryGrid.js +10 -1
- package/dist/features/categories/components/PriceGuidanceHint.d.ts +29 -0
- package/dist/features/categories/components/PriceGuidanceHint.js +61 -0
- package/dist/features/categories/components/SubcategoryCardRow.d.ts +27 -0
- package/dist/features/categories/components/SubcategoryCardRow.js +98 -0
- package/dist/features/categories/constants/category-tabs.d.ts +20 -25
- package/dist/features/categories/constants/category-tabs.js +22 -39
- package/dist/features/categories/repository/categories.repository.d.ts +12 -0
- package/dist/features/categories/repository/categories.repository.js +20 -0
- package/dist/features/categories/schemas/firestore.d.ts +22 -1
- package/dist/features/categories/schemas/firestore.js +10 -0
- package/dist/features/categories/schemas/index.d.ts +6 -0
- package/dist/features/categories/schemas/index.js +2 -0
- package/dist/features/categories/types/index.d.ts +8 -0
- package/dist/features/categories/utils/taxonomy-visual.d.ts +16 -3
- package/dist/features/categories/utils/taxonomy-visual.js +26 -10
- package/dist/features/classified/components/ClassifiedDetailPageView.js +14 -10
- package/dist/features/contact/components/ContactPageView.d.ts +33 -1
- package/dist/features/contact/components/ContactPageView.js +58 -28
- package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +14 -10
- package/dist/features/grouped/components/GroupedListingDetailView.js +9 -1
- package/dist/features/grouped/schemas/firestore.d.ts +5 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +3 -3
- package/dist/features/homepage/components/CollectionCardsSection.d.ts +28 -6
- package/dist/features/homepage/components/CollectionCardsSection.js +43 -8
- package/dist/features/homepage/components/HowItWorksSection.d.ts +23 -6
- package/dist/features/homepage/components/HowItWorksSection.js +4 -4
- package/dist/features/homepage/components/PromoGrid.d.ts +31 -2
- package/dist/features/homepage/components/PromoGrid.js +12 -3
- package/dist/features/homepage/components/TestimonialsCarousel.d.ts +34 -2
- package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
- package/dist/features/homepage/components/index.d.ts +0 -20
- package/dist/features/homepage/components/index.js +0 -11
- package/dist/features/homepage/index.d.ts +0 -2
- package/dist/features/homepage/index.js +0 -2
- package/dist/features/homepage/lib/section-renderer.d.ts +9 -0
- package/dist/features/homepage/lib/section-renderer.js +202 -58
- package/dist/features/homepage/repository/homepage-sections.repository.d.ts +35 -3
- package/dist/features/homepage/repository/homepage-sections.repository.js +58 -8
- package/dist/features/homepage/schemas/firestore.d.ts +106 -3
- package/dist/features/homepage/schemas/firestore.js +32 -2
- package/dist/features/homepage/schemas/index.d.ts +36 -7
- package/dist/features/homepage/schemas/index.js +39 -27
- package/dist/features/homepage/server.d.ts +0 -3
- package/dist/features/homepage/server.js +0 -3
- package/dist/features/homepage/types/index.d.ts +0 -47
- package/dist/features/homepage/types/index.js +49 -0
- package/dist/features/layout/AppLayoutShell.js +1 -1
- package/dist/features/layout/BottomNavItem.js +1 -1
- package/dist/features/layout/BottomSheet.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/live/components/LiveItemDetailPageView.js +14 -10
- package/dist/features/media/hooks/useMedia.js +17 -0
- package/dist/features/media/repository/media-assets.repository.d.ts +46 -0
- package/dist/features/media/repository/media-assets.repository.js +31 -0
- package/dist/features/media/trust-signals.d.ts +85 -0
- package/dist/features/media/trust-signals.js +126 -0
- package/dist/features/parts/components/PartDetailPageView.d.ts +14 -1
- package/dist/features/parts/components/PartDetailPageView.js +2 -2
- package/dist/features/parts/components/PartsIndexPageView.d.ts +11 -2
- package/dist/features/parts/components/PartsIndexPageView.js +2 -2
- package/dist/features/parts/components/PartsSearchBox.d.ts +9 -0
- package/dist/features/parts/components/PartsSearchBox.js +57 -0
- package/dist/features/parts/schemas/firestore.d.ts +149 -3
- package/dist/features/parts/schemas/firestore.js +184 -0
- package/dist/features/payments/repository/payout.repository.d.ts +15 -0
- package/dist/features/payments/repository/payout.repository.js +21 -0
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -18
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +1 -1
- package/dist/features/price-index/components/PriceIndexToolView.d.ts +24 -1
- package/dist/features/price-index/components/PriceIndexToolView.js +299 -17
- package/dist/features/price-index/lookup-target.d.ts +48 -0
- package/dist/features/price-index/lookup-target.js +107 -0
- package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
- package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
- package/dist/features/products/components/CompareOverlay.d.ts +20 -2
- package/dist/features/products/components/CompareOverlay.js +23 -3
- package/dist/features/products/components/CustomSectionTabContent.d.ts +31 -0
- package/dist/features/products/components/CustomSectionTabContent.js +29 -3
- package/dist/features/products/components/GroupMemberPicker.d.ts +19 -1
- package/dist/features/products/components/GroupMemberPicker.js +46 -8
- package/dist/features/products/components/GroupSettingsPanel.d.ts +11 -1
- package/dist/features/products/components/GroupSettingsPanel.js +92 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +15 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +70 -8
- package/dist/features/products/components/ProductDetailPageView.js +81 -17
- package/dist/features/products/components/ProductForm.d.ts +13 -1
- package/dist/features/products/components/ProductForm.js +16 -2
- package/dist/features/products/components/ProductsIndexListing.d.ts +16 -1
- package/dist/features/products/components/ProductsIndexListing.js +3 -3
- package/dist/features/products/components/ShowGroupSection.js +15 -2
- package/dist/features/products/components/SparesListView.d.ts +7 -0
- package/dist/features/products/components/SparesListView.js +39 -0
- package/dist/features/products/components/SublistingCarouselSection.js +2 -1
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/repository/products.repository.d.ts +99 -0
- package/dist/features/products/repository/products.repository.js +240 -18
- package/dist/features/products/schemas/firestore.d.ts +97 -4
- package/dist/features/products/schemas/firestore.js +104 -0
- package/dist/features/products/schemas/index.d.ts +10 -19
- package/dist/features/products/schemas/index.js +23 -6
- package/dist/features/products/types/index.d.ts +45 -1
- package/dist/features/products/utils/group-member-image.d.ts +46 -0
- package/dist/features/products/utils/group-member-image.js +4 -0
- package/dist/features/products/utils/listing-badge-variant.js +4 -0
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/scams/components/ScamProfileView.js +1 -1
- package/dist/features/search/components/EntityTypeahead.d.ts +44 -0
- package/dist/features/search/components/EntityTypeahead.js +92 -0
- package/dist/features/search/components/Search.d.ts +12 -1
- package/dist/features/search/components/Search.js +47 -3
- package/dist/features/search/components/SearchFacetRail.d.ts +11 -0
- package/dist/features/search/components/SearchFacetRail.js +92 -0
- package/dist/features/search/components/SearchResultsClient.d.ts +33 -0
- package/dist/features/search/components/SearchResultsClient.js +103 -0
- package/dist/features/search/components/SearchResultsPageView.d.ts +15 -1
- package/dist/features/search/components/SearchResultsPageView.js +2 -2
- package/dist/features/search/components/index.d.ts +0 -6
- package/dist/features/search/components/index.js +0 -3
- package/dist/features/search/hooks/useNavSuggestions.d.ts +13 -0
- package/dist/features/search/hooks/useScopedSearch.d.ts +34 -0
- package/dist/features/search/hooks/useScopedSearch.js +114 -0
- package/dist/features/search/hooks/useSiteSearch.d.ts +26 -0
- package/dist/features/search/hooks/useSiteSearch.js +149 -0
- package/dist/features/search/index.d.ts +0 -4
- package/dist/features/search/index.js +0 -4
- package/dist/features/search/manifest.d.ts +12 -0
- package/dist/features/search/manifest.js +17 -2
- package/dist/features/search/server.d.ts +0 -3
- package/dist/features/search/server.js +0 -3
- package/dist/features/seller/components/SellerListingTypeView.d.ts +1 -1
- package/dist/features/seller/components/SellerListingTypeView.js +20 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +35 -14
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
- package/dist/features/seller/components/SellerProductShell.js +2 -1
- package/dist/features/seller/components/SellerProductsView.js +3 -2
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/components/SellerSparesView.d.ts +17 -0
- package/dist/features/seller/components/SellerSparesView.js +6 -0
- package/dist/features/seller/components/index.d.ts +2 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/shell/CommandPalette.js +1 -1
- package/dist/features/sticker-trace/schemas/firestore.d.ts +19 -0
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
- package/dist/features/stores/components/StoreDetailLayoutView.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +7 -82
- package/dist/features/stores/components/StoreHeader.js +1 -2
- package/dist/features/stores/components/StoreSparesPageView.d.ts +27 -0
- package/dist/features/stores/components/StoreSparesPageView.js +48 -0
- package/dist/features/stores/schemas/firestore.d.ts +19 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__spares-and-groups.js +96 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +392 -45
- package/dist/features/tester/seed-data/authored/content-discovery__category-tabs-franchise-bundles.js +54 -32
- package/dist/features/tester/seed-data/authored/content-discovery__parts-database.js +3 -2
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__price-index-and-compare.js +73 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__site-wide-index.js +340 -0
- package/dist/features/tester/seed-data/authored/index.js +16 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +1 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__spares-and-group-editing.js +77 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-promote-to-listings.js +58 -0
- package/dist/features/tester/seed-data/authored/tools__sticker-tracer.js +5 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +384 -18
- package/dist/index.d.ts +17 -57
- package/dist/index.js +35 -96
- package/dist/next/routing/route-map.d.ts +42 -1
- package/dist/next/routing/route-map.js +45 -0
- package/dist/providers/db-firebase/base.repository.d.ts +22 -0
- package/dist/providers/db-firebase/base.repository.js +36 -0
- package/dist/schemas/registry.d.ts +15 -6
- package/dist/security/blind-index-tokens.d.ts +54 -0
- package/dist/security/blind-index-tokens.js +152 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/settings-encryption.d.ts +35 -0
- package/dist/security/settings-encryption.js +91 -0
- package/dist/seed/_helpers/brand-rows.js +38 -14
- package/dist/seed/_helpers/category-forest.js +73 -7
- package/dist/seed/_helpers/category-images-generated.d.ts +25 -6
- package/dist/seed/_helpers/category-images-generated.js +81 -6
- package/dist/seed/_helpers/category-models.d.ts +1 -1
- package/dist/seed/_helpers/category-models.js +7 -1
- package/dist/seed/_helpers/category-parts-glossary-map.js +8 -0
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +50 -2
- package/dist/seed/_helpers/character-features.d.ts +1 -1
- package/dist/seed/_helpers/character-features.js +2 -1
- package/dist/seed/_helpers/franchise-rows.js +10 -2
- package/dist/seed/_helpers/media.d.ts +47 -0
- package/dist/seed/_helpers/media.js +34 -0
- package/dist/seed/authenticity-knowledge-seed-data.d.ts +49 -5
- package/dist/seed/authenticity-knowledge-seed-data.js +10001 -549
- package/dist/seed/categories-seed-data.js +124 -20
- package/dist/seed/grouped-listings-seed-data.js +16 -0
- package/dist/seed/homepage-sections-seed-data.js +94 -5
- package/dist/seed/index.d.ts +2 -3
- package/dist/seed/index.js +2 -2
- package/dist/seed/manifest.js +3 -0
- package/dist/seed/media-assets-seed-data.d.ts +1 -1
- package/dist/seed/media-assets-seed-data.js +746 -196
- package/dist/seed/model-composition-seed-data.js +122 -6
- package/dist/seed/part-glossary-seed-data.d.ts +1 -1
- package/dist/seed/part-glossary-seed-data.js +37219 -463
- package/dist/seed/products-art-seed-data.js +7 -18
- package/dist/seed/products-auctions-seed-data.js +56 -47
- package/dist/seed/products-beyblade-x-seed-data.d.ts +2 -0
- package/dist/seed/products-beyblade-x-seed-data.js +476 -0
- package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +1500 -1240
- package/dist/seed/products-classifieds-seed-data.js +9 -27
- package/dist/seed/products-digital-codes-seed-data.js +9 -18
- package/dist/seed/products-live-items-seed-data.js +5 -13
- package/dist/seed/products-preorders-seed-data.js +67 -33
- package/dist/seed/products-prize-draws-seed-data.js +8 -17
- package/dist/seed/products-spares-seed-data.d.ts +2 -0
- package/dist/seed/products-spares-seed-data.js +368 -0
- package/dist/seed/products-standard-seed-data.js +39 -126
- package/dist/seed/products-stickers-seed-data.js +59 -15
- package/dist/seed/site-settings-seed-data.js +8 -0
- package/dist/seo/json-ld.d.ts +25 -0
- package/dist/seo/json-ld.js +28 -0
- package/dist/server-entry.d.ts +3 -1
- package/dist/server-entry.js +2 -2
- package/dist/server.d.ts +11 -9
- package/dist/server.js +35 -25
- package/dist/styles.css +202 -1
- package/dist/tailwind-input.css +31 -17
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Accordion.js +1 -1
- package/dist/ui/components/Breadcrumb.js +1 -1
- package/dist/ui/components/DetailPageGallery.js +0 -2
- package/dist/ui/components/DetailPageHero.js +0 -1
- package/dist/ui/components/DetailPageTabs.js +1 -1
- package/dist/ui/components/Divider.js +3 -3
- package/dist/ui/components/GatedPrice.js +5 -1
- package/dist/ui/components/HorizontalScroller.js +1 -1
- package/dist/ui/components/ListingLayout.js +3 -3
- package/dist/ui/components/MediaTabs.style.css +81 -0
- package/dist/ui/components/Pagination.js +1 -1
- package/dist/ui/components/PendingValue.d.ts +45 -0
- package/dist/ui/components/PendingValue.js +7 -0
- package/dist/ui/components/Radio.style.css +119 -0
- package/dist/ui/components/RatingDisplay.js +2 -2
- package/dist/ui/components/SettingsSection.js +0 -2
- package/dist/ui/components/SiteLogo.js +3 -0
- package/dist/ui/components/SiteMark.js +3 -0
- package/dist/ui/components/SortDropdown.js +1 -1
- package/dist/ui/components/SpecTable.d.ts +58 -0
- package/dist/ui/components/SpecTable.js +8 -0
- package/dist/ui/components/StarRating.js +1 -3
- package/dist/ui/components/SummaryCard.js +1 -1
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/icons/icon-registry.d.ts +1 -0
- package/dist/ui/icons/icon-registry.js +9 -1
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +2 -0
- package/dist/utils/search-txt-query.d.ts +12 -0
- package/dist/utils/search-txt-query.js +12 -0
- package/package.json +1 -1
- package/scripts/dedupe-peer-deps.mjs +18 -0
- package/scripts/seed-cli.mjs +250 -35
- package/scripts/verify-css-build.mjs +118 -37
- package/dist/_internal/server/features/search/actions.d.ts +0 -7
- package/dist/_internal/server/features/search/actions.js +0 -21
- package/dist/_internal/server/features/search/data.d.ts +0 -15
- package/dist/_internal/server/features/search/data.js +0 -18
- package/dist/_internal/server/features/search/index.d.ts +0 -3
- package/dist/_internal/server/features/search/index.js +0 -2
- package/dist/features/homepage/api/[id]/route.d.ts +0 -23
- package/dist/features/homepage/api/[id]/route.js +0 -103
- package/dist/features/homepage/api/route.d.ts +0 -14
- package/dist/features/homepage/api/route.js +0 -140
- package/dist/features/homepage/api/sections/[id]/route.d.ts +0 -26
- package/dist/features/homepage/api/sections/[id]/route.js +0 -95
- package/dist/features/homepage/api/sections/route.d.ts +0 -13
- package/dist/features/homepage/api/sections/route.js +0 -82
- package/dist/features/homepage/components/AdvertisementBanner.d.ts +0 -14
- package/dist/features/homepage/components/AdvertisementBanner.js +0 -35
- package/dist/features/homepage/components/BeforeAfterCard.d.ts +0 -9
- package/dist/features/homepage/components/BeforeAfterCard.js +0 -73
- package/dist/features/homepage/components/FeaturedResultsSection.d.ts +0 -17
- package/dist/features/homepage/components/FeaturedResultsSection.js +0 -17
- package/dist/features/homepage/components/HeroBanner.d.ts +0 -7
- package/dist/features/homepage/components/HeroBanner.js +0 -43
- package/dist/features/homepage/components/HeroSection.d.ts +0 -7
- package/dist/features/homepage/components/HeroSection.js +0 -6
- package/dist/features/homepage/components/HomepageSkeleton.d.ts +0 -2
- package/dist/features/homepage/components/HomepageSkeleton.js +0 -21
- package/dist/features/homepage/components/HomepageView.d.ts +0 -25
- package/dist/features/homepage/components/HomepageView.js +0 -5
- package/dist/features/homepage/components/NewsletterBanner.d.ts +0 -23
- package/dist/features/homepage/components/NewsletterBanner.js +0 -37
- package/dist/features/homepage/components/SiteFeaturesSection.d.ts +0 -14
- package/dist/features/homepage/components/SiteFeaturesSection.js +0 -11
- package/dist/features/homepage/components/TrustBadges.d.ts +0 -6
- package/dist/features/homepage/components/TrustBadges.js +0 -46
- package/dist/features/homepage/components/TrustIndicatorsSection.d.ts +0 -12
- package/dist/features/homepage/components/TrustIndicatorsSection.js +0 -11
- package/dist/features/homepage/hooks/useHomepage.d.ts +0 -11
- package/dist/features/homepage/hooks/useHomepage.js +0 -17
- package/dist/features/homepage/hooks/useHomepageSections.d.ts +0 -2
- package/dist/features/homepage/hooks/useHomepageSections.js +0 -10
- package/dist/features/homepage/repository/homepage.repository.d.ts +0 -11
- package/dist/features/homepage/repository/homepage.repository.js +0 -25
- package/dist/features/search/actions/index.d.ts +0 -1
- package/dist/features/search/actions/index.js +0 -1
- package/dist/features/search/actions/search-actions.d.ts +0 -18
- package/dist/features/search/actions/search-actions.js +0 -43
- package/dist/features/search/api/route.d.ts +0 -22
- package/dist/features/search/api/route.js +0 -128
- package/dist/features/search/columns/index.d.ts +0 -17
- package/dist/features/search/columns/index.js +0 -49
- package/dist/features/search/components/SearchFiltersRow.d.ts +0 -22
- package/dist/features/search/components/SearchFiltersRow.js +0 -21
- package/dist/features/search/components/SearchResultsSection.d.ts +0 -53
- package/dist/features/search/components/SearchResultsSection.js +0 -35
- package/dist/features/search/components/SearchView.d.ts +0 -27
- package/dist/features/search/components/SearchView.js +0 -8
- package/dist/features/search/hooks/useSearch.d.ts +0 -21
- package/dist/features/search/hooks/useSearch.js +0 -33
- package/dist/features/search/repository/search.repository.d.ts +0 -14
- package/dist/features/search/repository/search.repository.js +0 -59
- package/dist/features/search/schemas/index.d.ts +0 -70
- package/dist/features/search/schemas/index.js +0 -36
- package/dist/features/search/types/index.d.ts +0 -48
- package/dist/features/stores/components/StoreScopedSearch.d.ts +0 -17
- package/dist/features/stores/components/StoreScopedSearch.js +0 -27
- package/dist/seed/defaults/homepage-sections.d.ts +0 -2
- package/dist/seed/defaults/homepage-sections.js +0 -60
- package/dist/seed/factories/homepage-section.factory.d.ts +0 -10
- package/dist/seed/factories/homepage-section.factory.js +0 -13
- /package/dist/{features/search/types/index.js → _internal/shared/listing-types/spares/og.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* WHY: Authored six-part procedures for the categories-index tabs, the
|
|
3
3
|
* franchise unit and the bundle collage (2026-10-14).
|
|
4
|
-
* WHAT:
|
|
4
|
+
* WHAT: 9 cases, keyed by full checklist id.
|
|
5
5
|
*
|
|
6
6
|
* 🛑 EVERY CASE IS BEFORE → AFTER, because every defect this work produced
|
|
7
7
|
* rendered a page that looked fine:
|
|
@@ -9,17 +9,19 @@
|
|
|
9
9
|
* 1. The index rendered all 1,185 rows flat — six roots buried under 752
|
|
10
10
|
* part leaves. A case reading "the categories page loads" passes against
|
|
11
11
|
* that.
|
|
12
|
-
* 2.
|
|
13
|
-
* as well as the leaves, because their own `parentIds` also pass through
|
|
14
|
-
* a `*-parts` node. A list mixing "Attack Rings" with attack rings is not
|
|
15
|
-
* visibly wrong.
|
|
16
|
-
* 3. Seven franchises have no stock. Active, each is a card opening an empty
|
|
12
|
+
* 2. Seven franchises have no stock. Active, each is a card opening an empty
|
|
17
13
|
* shop; absent, seventeen `CharacterHotspot` links stay 404. Both look
|
|
18
14
|
* correct from any single page — which is why two cases here check the
|
|
19
15
|
* index and the detail page SEPARATELY.
|
|
20
|
-
*
|
|
16
|
+
* 3. Every bundle also carries a placeholder cover, so a collage tested
|
|
21
17
|
* after the cover never renders — and one grey tile is not "broken".
|
|
22
18
|
*
|
|
19
|
+
* 🛑 A fifth PARTS tab was removed 2026-10-20 and its case deleted with it.
|
|
20
|
+
* Parts live at `/parts/[classification]/[code]` and in the spares listing
|
|
21
|
+
* type; a flat tab over 752 leaves was the worse half of both. The
|
|
22
|
+
* product-detail Parts COMPOSITION tab is unrelated and still covered, on the
|
|
23
|
+
* `parts-database` page.
|
|
24
|
+
*
|
|
23
25
|
* So each case counts an exact number or compares two surfaces. Several carry
|
|
24
26
|
* a nonsense control, because a filter that returns everything looks identical
|
|
25
27
|
* to a filter that works.
|
|
@@ -47,49 +49,36 @@ export const authored = {
|
|
|
47
49
|
expectedData: { rootCards: 6 },
|
|
48
50
|
endResult: "Nothing is changed; this case only reads.",
|
|
49
51
|
},
|
|
50
|
-
"checklist-content-discovery-category-tabs-franchise-bundles-
|
|
52
|
+
"checklist-content-discovery-category-tabs-franchise-bundles-four-tabs-no-all-no-parts": {
|
|
51
53
|
roles: ["guest"],
|
|
52
54
|
startPage: "/categories",
|
|
53
55
|
steps: [
|
|
54
56
|
"Open /categories.",
|
|
55
57
|
"Read the tab bar.",
|
|
56
|
-
"Confirm there are exactly
|
|
58
|
+
"Confirm there are exactly four tabs: Categories, Brands, Franchises, Bundles.",
|
|
57
59
|
"Answer no if a tab labelled 'All' is present.",
|
|
60
|
+
"Answer no if a tab labelled 'Parts' is present.",
|
|
61
|
+
"Open a product detail page for a named-model Beyblade — for example /categories/category-ace-dragon-sting-charge-zan reached through Spinning Tops, or any complete-top listing — and confirm its own 'Parts' / 'What it is made of' composition section is STILL there. That is a different tab on a different surface and must not have been removed.",
|
|
58
62
|
],
|
|
59
|
-
expectedBehaviour: "BEFORE: the tabs were All / Categories / Brands, and 'All' was the DEFAULT — it is what rendered the 1,185 rows. AFTER:
|
|
60
|
-
expectedUiState: "
|
|
61
|
-
expectedData: { tabCount:
|
|
62
|
-
endResult: "Nothing is changed; this case only reads.",
|
|
63
|
-
},
|
|
64
|
-
"checklist-content-discovery-category-tabs-franchise-bundles-parts-tab-is-leaves-only": {
|
|
65
|
-
roles: ["guest"],
|
|
66
|
-
startPage: "/categories",
|
|
67
|
-
steps: [
|
|
68
|
-
"Open /categories and click the Parts tab.",
|
|
69
|
-
"Read the total the pager reports.",
|
|
70
|
-
"Confirm it reads 752 and not 772.",
|
|
71
|
-
"Scan the first page and confirm every card is an individual PART — '1B', 'Ten Heavy', 'Neo Right SG'.",
|
|
72
|
-
"Answer no if a classification GROUP appears as a card: 'Attack Rings', 'Weight Disks', 'Performance Tips', 'Bit Chips'.",
|
|
73
|
-
],
|
|
74
|
-
expectedBehaviour: "BEFORE: the tab returned 772, because the predicate matched any row whose ancestry passes a `*-parts` node — which is true of the 20 classification NODES as well as the leaves beneath them. The list mixed groups with their own contents and was not visibly wrong. AFTER: leaves only, 752. A part is a leaf by itself; a classification is a branch you reach by drilling down.",
|
|
75
|
-
expectedUiState: "752 parts reported. Every card is a single part; no classification group appears.",
|
|
76
|
-
expectedData: { partsTotal: 752, classificationNodesShown: 0 },
|
|
63
|
+
expectedBehaviour: "BEFORE the first fix: the tabs were All / Categories / Brands, and 'All' was the DEFAULT — it is what rendered the 1,185 rows. BEFORE this one: a fifth 'Parts' tab listed all 752 part leaves flat, duplicating /parts and the spares listing type with a worse version of both. AFTER: four tabs, no 'All' and no 'Parts'. The part leaves still exist and are still reached by drilling into a `*-parts` node; only the flat shortcut tab is gone. The product-level composition tab is untouched — removing that would have deleted the part database's own reason to exist.",
|
|
64
|
+
expectedUiState: "Four tabs, named exactly as above. No 'All', no 'Parts'. A model listing still shows its composition section.",
|
|
65
|
+
expectedData: { tabCount: 4, hasAllTab: false, hasPartsTab: false },
|
|
77
66
|
endResult: "Nothing is changed; this case only reads.",
|
|
78
67
|
},
|
|
79
68
|
"checklist-content-discovery-category-tabs-franchise-bundles-tabs-do-not-overlap": {
|
|
80
69
|
roles: ["guest"],
|
|
81
70
|
startPage: "/categories",
|
|
82
71
|
steps: [
|
|
83
|
-
"Open /categories and note the total each of the
|
|
84
|
-
"Expect 6, 28, 8,
|
|
72
|
+
"Open /categories and note the total each of the four tabs reports: Categories, Brands, Franchises, Bundles.",
|
|
73
|
+
"Expect 6, 28, 8, 5.",
|
|
85
74
|
"Pick one brand by name on the Brands tab — for example Takara-Tomy.",
|
|
86
|
-
"Open each of the other
|
|
75
|
+
"Open each of the other three tabs and search for that same name.",
|
|
87
76
|
"Answer no if it appears on any tab other than Brands.",
|
|
88
77
|
"Repeat once with a bundle name taken from the Bundles tab.",
|
|
89
78
|
],
|
|
90
79
|
expectedBehaviour: "Brands, franchises and bundles are all tier-0 rows, so a predicate that tested the tier before the discriminator would list every one of them under Categories as well. The type check has to come first. A row on two tabs double-counts the catalogue and makes the totals unreadable.",
|
|
91
|
-
expectedUiState: "Tab totals read 6 / 28 / 8 /
|
|
92
|
-
expectedData: { categories: 6, brands: 28, franchises: 8,
|
|
80
|
+
expectedUiState: "Tab totals read 6 / 28 / 8 / 5. The sampled brand and bundle each appear on exactly one tab.",
|
|
81
|
+
expectedData: { categories: 6, brands: 28, franchises: 8, bundles: 5 },
|
|
93
82
|
endResult: "Nothing is changed; this case only reads.",
|
|
94
83
|
},
|
|
95
84
|
"checklist-content-discovery-category-tabs-franchise-bundles-franchise-index-hides-unstocked": {
|
|
@@ -149,4 +138,37 @@ export const authored = {
|
|
|
149
138
|
expectedData: { bundleCards: 5, cardsWithCollage: 5 },
|
|
150
139
|
endResult: "Nothing is changed; this case only reads.",
|
|
151
140
|
},
|
|
141
|
+
"checklist-content-discovery-category-tabs-franchise-bundles-tabs-collapse-on-narrow-viewport": {
|
|
142
|
+
roles: ["guest"],
|
|
143
|
+
startPage: "/categories",
|
|
144
|
+
steps: [
|
|
145
|
+
"Resize the viewport to a phone width, around 390px.",
|
|
146
|
+
"Open /categories.",
|
|
147
|
+
"Look at the tab row reading Categories / Brands / Franchises / Bundles.",
|
|
148
|
+
"BEFORE a fix landed 2026-10-19: this was a plain row of `<Button variant=\"ghost\">`s with a hand-written underline — no `role=\"tablist\"`, no overflow handling, and on a narrow viewport the later tabs ran past the right edge with no scrollbar and no visible way to reach them.",
|
|
149
|
+
"AFTER: the row is `<OverflowRow>`. Confirm it has collapsed into a single trigger button showing the active tab's name plus a chevron.",
|
|
150
|
+
"Click the trigger. Confirm a searchable dropdown opens listing all four tabs.",
|
|
151
|
+
"Pick a different tab from the dropdown and confirm the page re-filters to it.",
|
|
152
|
+
],
|
|
153
|
+
expectedBehaviour: "A row of controls that does not fit its container must become a trigger that opens a searchable list, not a row the visitor has to discover can be scrolled. `<OverflowRow>` is the one primitive this project built for exactly this shape (see CLAUDE.md § Overflowing Pill & Tab Rows) — the old row predates it and was never migrated. 🛑 Four tabs can still overflow 390px: the threshold is MEASURED width, never a count (that is why `TabsList`'s old `items.length > 5` rule was deleted), so dropping the fifth tab does not retire this case.",
|
|
154
|
+
expectedUiState: "At 390px: one trigger button, not four separate tab buttons. Opening it shows all four tabs in a dropdown, each clickable, with the active one marked.",
|
|
155
|
+
expectedData: { tabsVisibleAsRowAt390px: false, collapsedTriggerPresent: true },
|
|
156
|
+
endResult: "Nothing is changed; this case only reads.",
|
|
157
|
+
},
|
|
158
|
+
"checklist-content-discovery-category-tabs-franchise-bundles-tabs-hover-changes-ink": {
|
|
159
|
+
roles: ["guest"],
|
|
160
|
+
startPage: "/categories",
|
|
161
|
+
steps: [
|
|
162
|
+
"Open /categories on a desktop-width viewport (at least 1024px, so the tabs render as a row rather than a collapsed trigger).",
|
|
163
|
+
"Pick a tab that is NOT currently active.",
|
|
164
|
+
"BEFORE a fix landed 2026-10-19: this row (and several others — the notification bell, the admin sidebar/nav/header, the mobile bottom-nav item) carried two competing `hover:text-*` classes on one element, one of which resolved to the element's own RESTING colour. Hovering therefore changed nothing, which reads as 'hover is broken' rather than as a styling bug.",
|
|
165
|
+
"Hover the mouse pointer over the inactive tab's label without clicking.",
|
|
166
|
+
"Compare its text colour before and during the hover.",
|
|
167
|
+
"Move the pointer away and confirm the colour returns to the resting shade.",
|
|
168
|
+
],
|
|
169
|
+
expectedBehaviour: "Every hover state must visibly differ from the resting state. A hover ink that equals the resting ink is indistinguishable from no hover handler at all.",
|
|
170
|
+
expectedUiState: "The inactive tab's text colour visibly changes while hovered, and reverts when the pointer leaves.",
|
|
171
|
+
expectedData: { hoverChangesTextColor: true },
|
|
172
|
+
endResult: "Nothing is changed; this case only reads.",
|
|
173
|
+
},
|
|
152
174
|
};
|
|
@@ -36,12 +36,13 @@ export const authored = {
|
|
|
36
36
|
startPage: "/parts",
|
|
37
37
|
steps: [
|
|
38
38
|
"Open /parts.",
|
|
39
|
+
"Confirm the page heading reads 'Beyblade parts gallery'.",
|
|
39
40
|
"Count the classification tiles.",
|
|
40
41
|
"Confirm every tile reads as a part NAME in sentence case — 'Performance Tip', 'Fusion Wheel', 'Bit Chip' — and not as a URL slug like 'performance-tip' or 'bit-chip'.",
|
|
41
42
|
"Open any one tile and confirm it loads a page rather than 404ing.",
|
|
42
43
|
],
|
|
43
|
-
expectedBehaviour: "BEFORE: there was no parts
|
|
44
|
-
expectedUiState: "Exactly 20 tiles, each labelled in sentence case, each a working link.",
|
|
44
|
+
expectedBehaviour: "BEFORE: there was no parts reference at all, so a buyer reading '105RF' on a listing had nowhere to learn that 105 is a spin-track height and RF is a rubber flat tip. AFTER: 20 classifications, each a real page, under the heading 'Beyblade parts gallery'. The labels come from a compile-checked map rather than being title-cased from the slug, because 'Bit Chip' is not 'bit-chip' title-cased and 'Armour' is not 'armour'.",
|
|
45
|
+
expectedUiState: "The heading reads 'Beyblade parts gallery'. Exactly 20 tiles, each labelled in sentence case, each a working link.",
|
|
45
46
|
expectedData: { classificationTiles: 20 },
|
|
46
47
|
endResult: "Nothing is changed; this case only reads.",
|
|
47
48
|
},
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Authored six-part procedures for the two Wave-11 adoptions —
|
|
3
|
+
* price-index local resolution and the compare overlay's new
|
|
4
|
+
* "add another" typeahead.
|
|
5
|
+
* WHAT: 4 case(s), keyed by full checklist id.
|
|
6
|
+
*
|
|
7
|
+
* @tag domain:tester
|
|
8
|
+
* @tag layer:seed
|
|
9
|
+
* @tag pattern:none
|
|
10
|
+
* @tag access:server-only
|
|
11
|
+
* @tag consumers:seed-data/authored/index.ts
|
|
12
|
+
* @tag sideEffects:none
|
|
13
|
+
*/
|
|
14
|
+
export const authored = {
|
|
15
|
+
"checklist-content-discovery-price-index-tool-price-index-resolves-locally": {
|
|
16
|
+
roles: ["guest"],
|
|
17
|
+
startPage: "/tools/price-index",
|
|
18
|
+
steps: [
|
|
19
|
+
"Open /tools/price-index in a private window and open DevTools → Network.",
|
|
20
|
+
"Clear the network log.",
|
|
21
|
+
"Type a real model name into the search box and submit.",
|
|
22
|
+
"Read the network log for what fired.",
|
|
23
|
+
"Read the results on the page.",
|
|
24
|
+
],
|
|
25
|
+
inputs: { query: "Dragoon G" },
|
|
26
|
+
expectedBehaviour: "The query-to-leaf resolution step runs in the browser against the local search artifact, at zero Firestore reads — before this, it was a searchTxt push-down query on every submit. The server is now asked only for the sale bands of the already-resolved id(s).",
|
|
27
|
+
expectedUiState: "The network log shows the one-time artifact fetch (a .json, if not already cached from an earlier visit) plus exactly one request to a bands endpoint carrying resolved id(s) — not a raw free-text query parameter. The page shows real min/median/mean/max figures for a model with recorded sales.",
|
|
28
|
+
endResult: "Read-only; nothing persists.",
|
|
29
|
+
},
|
|
30
|
+
"checklist-content-discovery-price-index-tool-price-index-falls-back-when-index-off": {
|
|
31
|
+
roles: ["admin"],
|
|
32
|
+
startPage: "/tools/price-index",
|
|
33
|
+
steps: [
|
|
34
|
+
"Sign in as admin and flip siteSettings.search.indexEnabled to false (via Firestore console or an admin settings surface, if one exists for it).",
|
|
35
|
+
"Open /tools/price-index in a private window.",
|
|
36
|
+
"Search a real model name and submit.",
|
|
37
|
+
"Read the results.",
|
|
38
|
+
"Restore the flag to true afterwards.",
|
|
39
|
+
],
|
|
40
|
+
needsReview: true,
|
|
41
|
+
reviewNote: "Needs the kill switch flipped off to observe the fallback path, which an ordinary run never exercises — flagged for a human or an admin-tooling pass.",
|
|
42
|
+
expectedBehaviour: "With the index unavailable, the tool must fall back to the original query-based endpoint rather than going blank. The fallback pays a real Firestore query, which is the accepted cost of the flag being off.",
|
|
43
|
+
expectedUiState: "The same real sale figures appear as when the index is on — slower, possibly, but not absent.",
|
|
44
|
+
endResult: "Restore siteSettings.search.indexEnabled to true before ending the session.",
|
|
45
|
+
},
|
|
46
|
+
"checklist-content-discovery-compare-overlay-add-item-compare-add-another-via-typeahead": {
|
|
47
|
+
roles: ["guest"],
|
|
48
|
+
startPage: "/products",
|
|
49
|
+
steps: [
|
|
50
|
+
"Open /products and select one item for comparison (checkbox).",
|
|
51
|
+
"Open the compare overlay.",
|
|
52
|
+
"Find the 'Add another to compare' box inside the overlay.",
|
|
53
|
+
"Type a different product's name and read the suggestions.",
|
|
54
|
+
"Click one.",
|
|
55
|
+
"Read the overlay's columns.",
|
|
56
|
+
],
|
|
57
|
+
expectedBehaviour: "Before this, the only way to add an item was selecting it via a listing-page checkbox BEFORE opening the overlay — there was no way to add a further item once inside it. The typeahead resolves a slug locally and the overlay fetches that product the same way it already fetches checkbox-selected ones.",
|
|
58
|
+
expectedUiState: "A new column appears for the picked item — its image, price and specs — without closing the overlay or returning to the grid. The originally-selected item's column is still there.",
|
|
59
|
+
endResult: "Close the overlay; nothing persists.",
|
|
60
|
+
},
|
|
61
|
+
"checklist-content-discovery-compare-overlay-add-item-compare-add-hidden-at-column-limit": {
|
|
62
|
+
roles: ["guest"],
|
|
63
|
+
startPage: "/products",
|
|
64
|
+
steps: [
|
|
65
|
+
"Open /products and select items for comparison until the compare overlay's maximum column count is reached (checkboxes, then the typeahead if room remains).",
|
|
66
|
+
"Open or stay in the overlay once full.",
|
|
67
|
+
"Look for the 'Add another to compare' box.",
|
|
68
|
+
],
|
|
69
|
+
expectedBehaviour: "A picker that cannot actually add anything because the overlay is full is worse than an absent one — it invites a click that does nothing.",
|
|
70
|
+
expectedUiState: "The 'Add another' box is completely ABSENT once the column limit is reached, not merely disabled or greyed out.",
|
|
71
|
+
endResult: "Close the overlay; nothing persists.",
|
|
72
|
+
},
|
|
73
|
+
};
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Authored six-part procedures for the site-wide search index cases
|
|
3
|
+
* added 2026-10-19 to the content-discovery/search page.
|
|
4
|
+
* WHAT: 17 case(s), keyed by full checklist id.
|
|
5
|
+
*
|
|
6
|
+
* 🛑 EVERY CASE CARRIES A CONTROL. A search box that has stopped filtering
|
|
7
|
+
* returns plausible rows for any real term and looks identical to one that
|
|
8
|
+
* works — "zzzznope" returning zero is the only kind of assertion here that
|
|
9
|
+
* cannot pass by accident. That is this directory's standing rule and it is
|
|
10
|
+
* why the control is a STEP, not a footnote.
|
|
11
|
+
*
|
|
12
|
+
* 🛑 Several of these check the NETWORK PANEL rather than the page, and that
|
|
13
|
+
* is deliberate. "Zero Firestore reads per keystroke" and "a guest issues no
|
|
14
|
+
* authenticated request" are the two claims the whole design rests on, and
|
|
15
|
+
* neither is visible on screen — a page that fetches per keystroke looks
|
|
16
|
+
* exactly like one that does not.
|
|
17
|
+
*
|
|
18
|
+
* @tag domain:tester
|
|
19
|
+
* @tag layer:seed
|
|
20
|
+
* @tag pattern:none
|
|
21
|
+
* @tag access:server-only
|
|
22
|
+
* @tag consumers:seed-data/authored/index.ts
|
|
23
|
+
* @tag sideEffects:none
|
|
24
|
+
*/
|
|
25
|
+
export const authored = {
|
|
26
|
+
"checklist-content-discovery-search-search-finds-every-type": {
|
|
27
|
+
roles: ["guest"],
|
|
28
|
+
startPage: "/",
|
|
29
|
+
steps: [
|
|
30
|
+
"Open / in a private window with no session.",
|
|
31
|
+
"Click the header search and type dranzer.",
|
|
32
|
+
"Press Enter.",
|
|
33
|
+
"Read the URL in the address bar.",
|
|
34
|
+
"Count how many distinct section headings the results page shows.",
|
|
35
|
+
"Go back, type zzzznope, and press Enter.",
|
|
36
|
+
"Read what the page says.",
|
|
37
|
+
],
|
|
38
|
+
inputs: { query: "dranzer", control: "zzzznope" },
|
|
39
|
+
expectedBehaviour: "Submitting navigates to the cross-resource results page and searches every indexed type at once, rather than redirecting to one browse route chosen by the type dropdown.",
|
|
40
|
+
expectedUiState: "The URL is /search?q=dranzer, not /products?q=dranzer. Results appear under several headings (for example Products, Categories, Parts, Articles), each with its own 'See all … →' link. For zzzznope the page says nothing matched and shows ZERO result rows — that control is the only assertion here that cannot pass by accident.",
|
|
41
|
+
endResult: "Read-only; nothing persists.",
|
|
42
|
+
},
|
|
43
|
+
"checklist-content-discovery-search-search-finds-a-part": {
|
|
44
|
+
roles: ["guest"],
|
|
45
|
+
startPage: "/search",
|
|
46
|
+
steps: [
|
|
47
|
+
"Open /search?q=Rubber Flat in a private window.",
|
|
48
|
+
"Read every result row and note which section each sits under.",
|
|
49
|
+
"Change the query to RF and search again.",
|
|
50
|
+
"Compare the two result sets.",
|
|
51
|
+
"Click the part row and read the page it lands on.",
|
|
52
|
+
],
|
|
53
|
+
inputs: { byName: "Rubber Flat", byCode: "RF" },
|
|
54
|
+
expectedBehaviour: "Parts are searchable by full name and by code. Before this they had no search tokens at all — all 752 were reachable only by drilling /parts into a classification and then a code.",
|
|
55
|
+
expectedUiState: "Both queries return the part under a Parts heading, and the row shows its classification on a second line underneath the name. Clicking it lands on a real /parts/<classification>/<code> page, not a 404.",
|
|
56
|
+
endResult: "Read-only; nothing persists.",
|
|
57
|
+
},
|
|
58
|
+
"checklist-content-discovery-search-search-ambiguous-part-code": {
|
|
59
|
+
roles: ["guest"],
|
|
60
|
+
startPage: "/search",
|
|
61
|
+
steps: [
|
|
62
|
+
"Open /search?q=105 in a private window.",
|
|
63
|
+
"Count the rows under the Parts heading.",
|
|
64
|
+
"Read the second line of each row and write down the classification it names.",
|
|
65
|
+
"Click two different rows in turn and write down the URL each lands on.",
|
|
66
|
+
],
|
|
67
|
+
inputs: { query: "105" },
|
|
68
|
+
expectedBehaviour: "A bare code is ambiguous across generations — 105 is a Metal Fight spin-track height while a bare number in Burst is a disc — so the engine must return all of them rather than picking one.",
|
|
69
|
+
expectedUiState: "SEVERAL rows, each naming a DIFFERENT classification, each linking to a different /parts/<classification>/105 URL. Exactly one row is the FAILURE: it means something chose a winner for the user.",
|
|
70
|
+
endResult: "Read-only; nothing persists.",
|
|
71
|
+
},
|
|
72
|
+
"checklist-content-discovery-search-search-midword": {
|
|
73
|
+
roles: ["guest"],
|
|
74
|
+
startPage: "/search",
|
|
75
|
+
steps: [
|
|
76
|
+
"Open /search?q=ariza in a private window.",
|
|
77
|
+
"Read the result rows.",
|
|
78
|
+
"Change the query to zzzz and search again.",
|
|
79
|
+
"Read what the page says.",
|
|
80
|
+
],
|
|
81
|
+
inputs: { midword: "ariza", control: "zzzz" },
|
|
82
|
+
expectedBehaviour: "The browser scans the whole index, so a fragment from the MIDDLE of a word matches. The Firestore path structurally cannot do this — its tokens are word-prefix only.",
|
|
83
|
+
expectedUiState: "'ariza' returns Charizard rows. 'zzzz' returns nothing — without that control a matcher returning everything for any fragment would also pass the first half.",
|
|
84
|
+
endResult: "Read-only; nothing persists.",
|
|
85
|
+
},
|
|
86
|
+
"checklist-content-discovery-search-search-typo": {
|
|
87
|
+
roles: ["guest"],
|
|
88
|
+
startPage: "/search",
|
|
89
|
+
steps: [
|
|
90
|
+
"Open /search?q=dragon g in a private window.",
|
|
91
|
+
"Read the result rows.",
|
|
92
|
+
"Search again for Pegasis (note the spelling: 'sis', not 'sus').",
|
|
93
|
+
"Read the result rows.",
|
|
94
|
+
],
|
|
95
|
+
inputs: { typo1: "dragon g", typo2: "Pegasis" },
|
|
96
|
+
expectedBehaviour: "Misspellings are expanded at INDEX time from a crawl of a counterfeit seller's real titles, on the measured insight that an evasion spelling is the same string a genuine buyer mistypes.",
|
|
97
|
+
expectedUiState: "'dragon g' returns Dragoon G. 'Pegasis' returns Storm Pegasus. Neither returns an empty state.",
|
|
98
|
+
endResult: "Read-only; nothing persists.",
|
|
99
|
+
},
|
|
100
|
+
"checklist-content-discovery-search-search-normalised-away": {
|
|
101
|
+
roles: ["guest"],
|
|
102
|
+
startPage: "/search",
|
|
103
|
+
steps: [
|
|
104
|
+
"Open /search?q=!!! in a private window.",
|
|
105
|
+
"Read the message on the page word for word.",
|
|
106
|
+
"Count the result rows.",
|
|
107
|
+
"Now search zzzznope and read that message too.",
|
|
108
|
+
"Compare the two messages.",
|
|
109
|
+
],
|
|
110
|
+
inputs: { punctuation: "!!!", nonsense: "zzzznope" },
|
|
111
|
+
expectedBehaviour: "A query that normalises to no searchable words must return NOTHING, never everything. The inverse of this bug shipped on /api/products once: a punctuation-only query produced no filter clause and returned the entire published catalogue as search results.",
|
|
112
|
+
expectedUiState: "'!!!' says the search had no searchable words in it. 'zzzznope' says nothing matched. The two messages are DIFFERENT — one means we could not form a query, the other means we ran one and found none. Any rows at all for '!!!' is the failure.",
|
|
113
|
+
endResult: "Read-only; nothing persists.",
|
|
114
|
+
},
|
|
115
|
+
"checklist-content-discovery-search-search-zero-reads": {
|
|
116
|
+
roles: ["guest"],
|
|
117
|
+
startPage: "/",
|
|
118
|
+
steps: [
|
|
119
|
+
"Open / in a private window and open DevTools → Network.",
|
|
120
|
+
"Clear the network log.",
|
|
121
|
+
"Click into the header search and type d.",
|
|
122
|
+
"Wait for suggestions to appear, then type r, a, n, z, e, r one character at a time.",
|
|
123
|
+
"Read the network log and count the requests made after the first one.",
|
|
124
|
+
],
|
|
125
|
+
inputs: { query: "dranzer" },
|
|
126
|
+
expectedBehaviour: "The index is fetched ONCE per page session and searched locally thereafter. Before this, every keystroke was a request to /api/search/suggestions, which was four parallel Firestore reads.",
|
|
127
|
+
expectedUiState: "The log shows ONE large .json fetch from firebasestorage (a few hundred KB) on the first focus or keystroke, and NOTHING further as you keep typing. A request per character is the failure even though the suggestions look identical either way.",
|
|
128
|
+
endResult: "Read-only; nothing persists.",
|
|
129
|
+
},
|
|
130
|
+
"checklist-content-discovery-search-search-no-prices": {
|
|
131
|
+
roles: ["guest"],
|
|
132
|
+
startPage: "/",
|
|
133
|
+
steps: [
|
|
134
|
+
"Open / in a private window with no session.",
|
|
135
|
+
"Click the header search and type dranzer.",
|
|
136
|
+
"Read every suggestion row, including the small second line.",
|
|
137
|
+
"Press Enter and read every row on the results page.",
|
|
138
|
+
"Search the rendered page for the ₹ character.",
|
|
139
|
+
],
|
|
140
|
+
inputs: { query: "dranzer" },
|
|
141
|
+
expectedBehaviour: "Prices are hidden from signed-out visitors so the catalogue cannot be read at scale without an account. The suggestion subtitle used to be the product's price, served from a route cached PUBLIC for 60 seconds — a live leak on every page of the site.",
|
|
142
|
+
expectedUiState: "Suggestion subtitles show the brand and category, e.g. 'Takara-Tomy · Attack Rings'. No ₹ appears anywhere in the dropdown or in the results, signed out.",
|
|
143
|
+
endResult: "Read-only; nothing persists.",
|
|
144
|
+
},
|
|
145
|
+
"checklist-content-discovery-search-search-no-sandbox": {
|
|
146
|
+
roles: ["guest"],
|
|
147
|
+
startPage: "/search",
|
|
148
|
+
steps: [
|
|
149
|
+
"Open /search?q=sandbox in a private window with no session.",
|
|
150
|
+
"Read every result row.",
|
|
151
|
+
"Search again for tester and read every row.",
|
|
152
|
+
"Note any row whose title or detail names a tester or sandbox fixture.",
|
|
153
|
+
],
|
|
154
|
+
inputs: { query1: "sandbox", query2: "tester" },
|
|
155
|
+
expectedBehaviour: "The index is ONE shared file every browser downloads, with no per-viewer filter anywhere after it is built — so a test-data row in it is published to the world for that version's whole lifetime, and an immutable object cannot be recalled.",
|
|
156
|
+
expectedUiState: "No row seeded as test data appears. Finding even one is a disclosure, not a cosmetic issue.",
|
|
157
|
+
endResult: "Read-only; nothing persists.",
|
|
158
|
+
},
|
|
159
|
+
"checklist-content-discovery-search-search-freshness": {
|
|
160
|
+
roles: ["seller"],
|
|
161
|
+
startPage: "/store/products/new",
|
|
162
|
+
steps: [
|
|
163
|
+
"Create and PUBLISH a listing with a distinctive title, e.g. Freshness Probe Dranzer.",
|
|
164
|
+
"Write down the time.",
|
|
165
|
+
"Open /search in a private window and search that exact title.",
|
|
166
|
+
"If it is absent, wait and retry every few minutes for up to 20 minutes.",
|
|
167
|
+
"Once it appears, go back and UNPUBLISH the listing.",
|
|
168
|
+
"Search the same title again, retrying for up to 20 minutes.",
|
|
169
|
+
],
|
|
170
|
+
inputs: { title: "Freshness Probe Dranzer" },
|
|
171
|
+
expectedBehaviour: "A content write marks the index stale and the scheduled job rebuilds within about 15 minutes. An unpublished listing still has a fresh updatedAt, so the incremental pass re-reads it, sees it fail the published filter, and removes it.",
|
|
172
|
+
expectedUiState: "The listing becomes findable within ~15 minutes of publishing and disappears within ~15 minutes of unpublishing. A row that NEVER appears and a row that never LEAVES are both failures, and both mean the rebuild has stopped — note which one you saw.",
|
|
173
|
+
endResult: "Delete the probe listing afterwards. Its absence from search within ~15 minutes is itself the final check.",
|
|
174
|
+
},
|
|
175
|
+
"checklist-content-discovery-search-search-facet-counts": {
|
|
176
|
+
roles: ["guest"],
|
|
177
|
+
startPage: "/search",
|
|
178
|
+
steps: [
|
|
179
|
+
"Open /search?q=beyblade in a private window.",
|
|
180
|
+
"Find the facet chips above the results and write down each chip's label and number.",
|
|
181
|
+
"Count the result rows actually shown for one type and compare it with that chip's number.",
|
|
182
|
+
"Click one chip.",
|
|
183
|
+
"Read the result rows again, and read the other chips' numbers again.",
|
|
184
|
+
"Click the same chip a second time to clear it.",
|
|
185
|
+
],
|
|
186
|
+
inputs: { query: "beyblade" },
|
|
187
|
+
expectedBehaviour: "Facet counts are computed over the hits the current query produced, in memory. The Firestore path cannot afford this — it is one aggregation query per facet value, each needing its own composite index, and it returns no count at all when an index is missing.",
|
|
188
|
+
expectedUiState: "Chips show a number each. Clicking one narrows the results AND lowers the other chips' numbers to match. Clicking again restores both. A chip that does not change the results, or a number that disagrees with the rows you can count, is the failure.",
|
|
189
|
+
endResult: "Read-only; the selection is not persisted and is gone on reload.",
|
|
190
|
+
},
|
|
191
|
+
"checklist-content-discovery-search-search-guest-no-private": {
|
|
192
|
+
roles: ["guest"],
|
|
193
|
+
startPage: "/search",
|
|
194
|
+
steps: [
|
|
195
|
+
"Open a private window with no session and open DevTools → Network.",
|
|
196
|
+
"Clear the network log.",
|
|
197
|
+
"Go to /search?q=order.",
|
|
198
|
+
"Read every request in the log.",
|
|
199
|
+
"Look specifically for any request whose path contains /api/search/scoped.",
|
|
200
|
+
"Read the page for any section headed 'Your …' or 'Admin'.",
|
|
201
|
+
],
|
|
202
|
+
inputs: { query: "order" },
|
|
203
|
+
expectedBehaviour: "A signed-out visitor must make NO authenticated request at all — not a 401, not an empty 200. The client gate, the route's auth requirement and the empty source list are three independent gates, because the expensive failure is not a guest seeing an error, it is a guest silently receiving someone's data.",
|
|
204
|
+
expectedUiState: "No /api/search/scoped request appears in the log in any form. No account or admin section renders on the page. A 401 in the log is still a FAIL — it means the request was issued.",
|
|
205
|
+
endResult: "Read-only; nothing persists.",
|
|
206
|
+
},
|
|
207
|
+
"checklist-content-discovery-search-search-buyer-isolation": {
|
|
208
|
+
roles: ["buyer"],
|
|
209
|
+
startPage: "/search",
|
|
210
|
+
steps: [
|
|
211
|
+
"Sign in as one buyer.",
|
|
212
|
+
"From an admin session in another browser, find a DIFFERENT buyer's order and note a distinctive word from its product title.",
|
|
213
|
+
"Back in the first buyer's session, search that word on /search.",
|
|
214
|
+
"Read every row, including any under 'Your orders'.",
|
|
215
|
+
"Now open /api/search/scoped?q=<that word> directly in the same signed-in session.",
|
|
216
|
+
"Read the raw JSON response end to end.",
|
|
217
|
+
],
|
|
218
|
+
expectedBehaviour: "Every scoped source carries an owner clause built from the verified session, so the QUERY itself cannot return another viewer's rows. The API half of this check is the half that matters.",
|
|
219
|
+
expectedUiState: "Neither the page nor the JSON contains the other buyer's order. A page that hides the row while the endpoint returns it is precisely the failure this case exists for, and only the second half can see it.",
|
|
220
|
+
endResult: "Read-only; nothing persists.",
|
|
221
|
+
},
|
|
222
|
+
"checklist-content-discovery-search-search-seller-own-store": {
|
|
223
|
+
roles: ["seller"],
|
|
224
|
+
startPage: "/store/products/new",
|
|
225
|
+
steps: [
|
|
226
|
+
"Signed in as a seller, create a listing with a distinctive title and leave it as a DRAFT.",
|
|
227
|
+
"Go to /search and search that title.",
|
|
228
|
+
"Read which section the row appears under.",
|
|
229
|
+
"Note a draft title belonging to a DIFFERENT store (ask an admin for one).",
|
|
230
|
+
"Search that second title and read every row.",
|
|
231
|
+
],
|
|
232
|
+
inputs: { ownDraft: "Isolation Probe Draft" },
|
|
233
|
+
expectedBehaviour: "A seller's own drafts are returned by the scoped tier. Published listings are deduped away because the public index already has them, so what survives in that section is exactly the drafts — which is why it is labelled as such.",
|
|
234
|
+
expectedUiState: "Your own draft appears under 'Your listings (incl. drafts)'. The other store's draft returns nothing at all.",
|
|
235
|
+
endResult: "Delete the probe draft afterwards.",
|
|
236
|
+
},
|
|
237
|
+
"checklist-content-discovery-search-search-listing-boxes-still-filter": {
|
|
238
|
+
roles: ["guest", "seller", "admin"],
|
|
239
|
+
startPage: "/stores",
|
|
240
|
+
steps: [
|
|
241
|
+
"Open /stores and type a real store name into the page's own search box.",
|
|
242
|
+
"Confirm the list narrows, then type zzzznope and confirm it empties.",
|
|
243
|
+
"Sign in as a seller, open /store/orders, and repeat both searches there.",
|
|
244
|
+
"Check the pager still works and the filter-drawer badge still shows the right count.",
|
|
245
|
+
"Sign in as an admin, open /admin/users, and repeat both searches there.",
|
|
246
|
+
],
|
|
247
|
+
inputs: { control: "zzzznope" },
|
|
248
|
+
expectedBehaviour: "The per-collection boxes are a DIFFERENT system from site-wide search — they filter one table, carry URL state and feed real pagination — and nothing in the index work touches them. This case exists because that is a promise, and a promise with no check is a hope.",
|
|
249
|
+
expectedUiState: "All three boxes narrow on a real term and return zero on the control. Pagination still pages, and the filter-drawer badge still counts only drawer filters.",
|
|
250
|
+
endResult: "Read-only; the URL carries the query but nothing persists server-side.",
|
|
251
|
+
},
|
|
252
|
+
"checklist-content-discovery-search-search-support-ticket-two-words": {
|
|
253
|
+
roles: ["admin"],
|
|
254
|
+
startPage: "/admin/support-tickets",
|
|
255
|
+
steps: [
|
|
256
|
+
"Open /admin/support-tickets and read several ticket subjects.",
|
|
257
|
+
"Pick TWO words that appear together in exactly one subject, where the longer word also appears in others.",
|
|
258
|
+
"Type just the longer word into the search box and count the rows.",
|
|
259
|
+
"Now type both words and count the rows again.",
|
|
260
|
+
"Compare the two counts.",
|
|
261
|
+
],
|
|
262
|
+
expectedBehaviour: "Both words must narrow the result. Before this the second word was discarded entirely — only the longest term reached the query — so a two-word search returned everything matching the longer word while looking like it was working.",
|
|
263
|
+
expectedUiState: "The two-word search returns FEWER rows than the one-word search, and every row it returns contains both words. Identical counts mean the second word is still being thrown away.",
|
|
264
|
+
endResult: "Read-only; nothing persists.",
|
|
265
|
+
},
|
|
266
|
+
"checklist-content-discovery-search-search-parts-page-has-a-box": {
|
|
267
|
+
roles: ["guest"],
|
|
268
|
+
startPage: "/parts",
|
|
269
|
+
steps: [
|
|
270
|
+
"Open /parts in a private window.",
|
|
271
|
+
"Look above the grid of classifications for a search input.",
|
|
272
|
+
"Type RF and read the rows that appear.",
|
|
273
|
+
"Read the second line of each row.",
|
|
274
|
+
"Clear it and type zzzznope.",
|
|
275
|
+
"Scroll down and confirm the classification grid is still present.",
|
|
276
|
+
],
|
|
277
|
+
inputs: { query: "RF", control: "zzzznope" },
|
|
278
|
+
expectedBehaviour: "Before this the page was browse-only: 752 parts reachable only by clicking a classification and then a code, with no search input anywhere on the surface.",
|
|
279
|
+
expectedUiState: "A search box sits above the grid. 'RF' returns the part with its classification on a second line; 'zzzznope' says no part matches. The classification grid is still there underneath — the box adds a way in, it does not replace browsing.",
|
|
280
|
+
endResult: "Read-only; nothing persists.",
|
|
281
|
+
},
|
|
282
|
+
"checklist-content-discovery-search-search-facet-carries-through": {
|
|
283
|
+
roles: ["guest"],
|
|
284
|
+
startPage: "/search",
|
|
285
|
+
steps: [
|
|
286
|
+
"Open /search?q=beyblade in a private window.",
|
|
287
|
+
"Tick one facet chip, e.g. a brand.",
|
|
288
|
+
"Find that group's own 'See all →' link and read its href before clicking.",
|
|
289
|
+
"Click it.",
|
|
290
|
+
"Read the URL you land on and whether the listing page shows the same filter applied.",
|
|
291
|
+
],
|
|
292
|
+
inputs: { query: "beyblade" },
|
|
293
|
+
expectedBehaviour: "The refinement a visitor builds on /search must survive the jump to the real browse page — losing it means re-doing work they already did.",
|
|
294
|
+
expectedUiState: "The destination URL carries the same filter (e.g. a brand query parameter), and the browse page opens already narrowed to it, not showing the unfiltered full list.",
|
|
295
|
+
endResult: "Read-only; nothing persists.",
|
|
296
|
+
},
|
|
297
|
+
"checklist-content-discovery-search-search-admin-person-exact": {
|
|
298
|
+
roles: ["admin"],
|
|
299
|
+
startPage: "/admin/users",
|
|
300
|
+
steps: [
|
|
301
|
+
"Sign in as admin and open /admin/users.",
|
|
302
|
+
"Pick a real user and note their first name only.",
|
|
303
|
+
"Type just that first name into the search box.",
|
|
304
|
+
"Read the results.",
|
|
305
|
+
"Clear the box and type only the first 3-4 letters of that same first name — a prefix, not the whole word.",
|
|
306
|
+
"Read the results again.",
|
|
307
|
+
],
|
|
308
|
+
expectedBehaviour: "The admin search resolves through a whole-WORD index, not a whole-STRING exact match. Typing a first name alone must find a user whose displayName is 'First Last' — before this it required the exact full string. A PREFIX of the word must find nobody: the index is whole-word only on purpose, so it cannot be unpicked by counting partial-match frequencies.",
|
|
309
|
+
expectedUiState: "The full first name returns the user. The 3-4 letter prefix returns an empty list — not the same user, not anybody else.",
|
|
310
|
+
endResult: "Read-only; nothing persists.",
|
|
311
|
+
},
|
|
312
|
+
"checklist-content-discovery-search-search-no-plaintext-pii": {
|
|
313
|
+
roles: ["admin"],
|
|
314
|
+
startPage: "/admin/users",
|
|
315
|
+
steps: [
|
|
316
|
+
"With Firestore console access, open any `users` document.",
|
|
317
|
+
"Find the `nameTokensIndex` field and read its values.",
|
|
318
|
+
"Confirm every entry is an opaque hex string with an `hmac:` prefix, never a readable name fragment.",
|
|
319
|
+
"Separately, fetch the public search artifact's .json file (the one the header search downloads) and search its raw text for the word 'TokensIndex'.",
|
|
320
|
+
],
|
|
321
|
+
needsReview: true,
|
|
322
|
+
reviewNote: "Needs Firestore console access, which an automated browser session does not have — flagged for a human or an admin-tooling pass rather than answered null.",
|
|
323
|
+
expectedBehaviour: "A blind index lets admin search without ever decrypting anyone's name. If the stored values are readable, or if the field reaches the public artifact (a deterministic per-person identifier published to every browser, cross-referenceable even unbroken), the whole design has failed regardless of what the UI shows.",
|
|
324
|
+
expectedUiState: "Every `nameTokensIndex` entry is an `hmac:`-prefixed digest. The public artifact's raw text contains no occurrence of 'TokensIndex' at all.",
|
|
325
|
+
endResult: "Read-only; nothing persists.",
|
|
326
|
+
},
|
|
327
|
+
"checklist-content-discovery-search-faq-punctuation-search": {
|
|
328
|
+
roles: ["guest"],
|
|
329
|
+
startPage: "/faqs",
|
|
330
|
+
steps: [
|
|
331
|
+
"Open /faqs in a private window.",
|
|
332
|
+
"Type !!! into the FAQ search box.",
|
|
333
|
+
"Read the message shown and count the FAQs displayed.",
|
|
334
|
+
],
|
|
335
|
+
inputs: { punctuation: "!!!" },
|
|
336
|
+
expectedBehaviour: "GUARD CASE — pins behaviour that is already correct. A punctuation-only query has no searchable words, and must say so rather than silently falling through to 'no filter', which would return the entire FAQ catalogue disguised as search results.",
|
|
337
|
+
expectedUiState: "The page says the search had no searchable words. Zero FAQs are shown — not the full list.",
|
|
338
|
+
endResult: "Read-only; nothing persists.",
|
|
339
|
+
},
|
|
340
|
+
};
|