@mohasinac/appkit 4.10.0 → 4.11.1

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.
Files changed (324) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +6 -1
  2. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
  3. package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
  4. package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
  5. package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
  6. package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
  7. package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
  8. package/dist/_internal/server/features/audit-log/actions.js +38 -0
  9. package/dist/_internal/server/features/brands/actions.js +0 -2
  10. package/dist/_internal/server/features/brands/og.d.ts +4 -1
  11. package/dist/_internal/server/features/brands/og.js +1 -1
  12. package/dist/_internal/server/features/grouped/data.d.ts +4 -0
  13. package/dist/_internal/server/features/grouped/data.js +24 -0
  14. package/dist/_internal/server/features/grouped/index.d.ts +1 -1
  15. package/dist/_internal/server/features/grouped/index.js +1 -1
  16. package/dist/_internal/server/features/orders/actions.js +9 -0
  17. package/dist/_internal/server/features/orders/adapters.js +25 -0
  18. package/dist/_internal/server/features/products/data.d.ts +2 -2
  19. package/dist/_internal/server/features/products/data.js +5 -23
  20. package/dist/_internal/server/functions/scheduled.d.ts +3 -1
  21. package/dist/_internal/server/functions/scheduled.js +17 -1
  22. package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
  23. package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
  24. package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
  25. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
  26. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
  27. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
  28. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
  29. package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
  30. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
  31. package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
  32. package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
  33. package/dist/_internal/server/jobs/handlers/index.js +3 -0
  34. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
  35. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
  36. package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
  37. package/dist/_internal/server/notifications/channel-health.js +101 -0
  38. package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
  39. package/dist/_internal/shared/features/brands/schema.js +0 -1
  40. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
  41. package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
  42. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  43. package/dist/_internal/shared/features/products/to-product-item.d.ts +25 -0
  44. package/dist/_internal/shared/features/products/to-product-item.js +45 -0
  45. package/dist/client.d.ts +21 -6
  46. package/dist/client.js +13 -3
  47. package/dist/constants/api-endpoints.d.ts +6 -9
  48. package/dist/constants/api-endpoints.js +2 -3
  49. package/dist/contracts/client-auth.d.ts +3 -7
  50. package/dist/contracts/email.d.ts +1 -0
  51. package/dist/features/account/components/AddressForm.js +24 -2
  52. package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
  53. package/dist/features/account/components/BecomeSellerView.js +1 -1
  54. package/dist/features/account/components/NotificationBell.js +1 -1
  55. package/dist/features/account/components/UserBidsView.d.ts +1 -0
  56. package/dist/features/account/components/UserBidsView.js +47 -0
  57. package/dist/features/account/components/UserOrdersView.d.ts +4 -11
  58. package/dist/features/account/components/UserOrdersView.js +54 -4
  59. package/dist/features/account/components/UserReturnsView.d.ts +4 -9
  60. package/dist/features/account/components/UserReturnsView.js +37 -3
  61. package/dist/features/account/components/index.d.ts +3 -2
  62. package/dist/features/account/components/index.js +1 -0
  63. package/dist/features/admin/actions/admin-actions.js +22 -0
  64. package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
  65. package/dist/features/admin/actions/notification-actions.js +4 -3
  66. package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
  67. package/dist/features/admin/components/AdminAdsView.js +86 -89
  68. package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
  69. package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
  70. package/dist/features/admin/components/AdminAuditLogView.js +95 -0
  71. package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
  72. package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
  73. package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
  74. package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
  75. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
  76. package/dist/features/admin/components/AdminCartsView.js +34 -4
  77. package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
  78. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  79. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  80. package/dist/features/admin/components/AdminHistoryView.js +11 -1
  81. package/dist/features/admin/components/AdminNotificationsView.js +27 -1
  82. package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
  83. package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
  84. package/dist/features/admin/components/AdminOrdersView.js +92 -24
  85. package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
  86. package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
  87. package/dist/features/admin/components/AdminPayoutsView.js +15 -31
  88. package/dist/features/admin/components/AdminProductEditorView.js +26 -3
  89. package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
  90. package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
  91. package/dist/features/admin/components/AdminStoresView.js +7 -0
  92. package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
  93. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
  94. package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
  95. package/dist/features/admin/components/AdminUserEditorView.js +4 -2
  96. package/dist/features/admin/components/AdminUsersView.js +1 -1
  97. package/dist/features/admin/components/AdminWishlistsView.js +14 -1
  98. package/dist/features/admin/components/DataListingView.d.ts +2 -2
  99. package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
  100. package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
  101. package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
  102. package/dist/features/admin/components/ViewNotificationModal.js +15 -0
  103. package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
  104. package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
  105. package/dist/features/admin/components/index.d.ts +8 -1
  106. package/dist/features/admin/components/index.js +4 -0
  107. package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
  108. package/dist/features/admin/constants/filter-tabs.js +27 -0
  109. package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
  110. package/dist/features/admin/hooks/useAdminListing.js +3 -1
  111. package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
  112. package/dist/features/admin/hooks/useAdminListingData.js +9 -2
  113. package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
  114. package/dist/features/admin/schemas/firestore.d.ts +12 -0
  115. package/dist/features/analytics/types.d.ts +1 -1
  116. package/dist/features/analytics/types.js +8 -0
  117. package/dist/features/auctions/schemas/index.d.ts +5 -0
  118. package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
  119. package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
  120. package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
  121. package/dist/features/audit-log/schemas/firestore.js +35 -0
  122. package/dist/features/auth/actions/index.d.ts +0 -1
  123. package/dist/features/auth/actions/index.js +0 -1
  124. package/dist/features/auth/hooks/useAuth.d.ts +8 -35
  125. package/dist/features/auth/hooks/useAuth.js +21 -37
  126. package/dist/features/auth/permissions/constants.d.ts +1 -1
  127. package/dist/features/auth/permissions/constants.js +2 -0
  128. package/dist/features/blog/schemas/index.d.ts +32 -0
  129. package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
  130. package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
  131. package/dist/features/categories/components/BrandDetailPageView.js +14 -12
  132. package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
  133. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
  134. package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
  135. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
  136. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  137. package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
  138. package/dist/features/categories/schemas/firestore.d.ts +19 -2
  139. package/dist/features/categories/schemas/index.d.ts +24 -3
  140. package/dist/features/categories/schemas/index.js +3 -1
  141. package/dist/features/categories/types/index.d.ts +7 -0
  142. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
  143. package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
  144. package/dist/features/contact/components/ContactForm.js +17 -4
  145. package/dist/features/contact/email.d.ts +1 -0
  146. package/dist/features/contact/email.js +3 -0
  147. package/dist/features/events/components/AdminEventEditorView.js +54 -2
  148. package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
  149. package/dist/features/events/components/AdminEventEntriesView.js +56 -89
  150. package/dist/features/events/components/EventFormDrawer.js +5 -1
  151. package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
  152. package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
  153. package/dist/features/events/schemas/index.d.ts +22 -0
  154. package/dist/features/grouped/components/GroupedListingsCarousel.js +4 -1
  155. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
  156. package/dist/features/grouped/repository/grouped-listings.repository.js +18 -0
  157. package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
  158. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
  159. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  160. package/dist/features/layout/TitleBarLayout.d.ts +1 -1
  161. package/dist/features/layout/TitleBarLayout.js +3 -3
  162. package/dist/features/media/MediaImage.js +39 -3
  163. package/dist/features/media/types/index.d.ts +10 -0
  164. package/dist/features/media/types/index.js +1 -0
  165. package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
  166. package/dist/features/media/upload/MediaUploadField.js +11 -7
  167. package/dist/features/media/upload/video-poster.d.ts +2 -0
  168. package/dist/features/media/upload/video-poster.js +16 -1
  169. package/dist/features/media/upload/video-poster.test.js +1 -1
  170. package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
  171. package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
  172. package/dist/features/orders/components/index.d.ts +2 -0
  173. package/dist/features/orders/components/index.js +1 -0
  174. package/dist/features/orders/constants/payment-window.d.ts +25 -0
  175. package/dist/features/orders/constants/payment-window.js +25 -0
  176. package/dist/features/orders/repository/orders.repository.d.ts +32 -0
  177. package/dist/features/orders/repository/orders.repository.js +56 -0
  178. package/dist/features/orders/schemas/index.d.ts +24 -24
  179. package/dist/features/orders/types/index.d.ts +33 -0
  180. package/dist/features/pre-orders/schemas/index.d.ts +5 -0
  181. package/dist/features/products/components/BidHistory.js +9 -1
  182. package/dist/features/products/components/GroupSettingsPanel.js +25 -3
  183. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  184. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
  185. package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
  186. package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
  187. package/dist/features/products/components/ProductDetailActions.js +1 -1
  188. package/dist/features/products/components/ProductGrid.js +15 -1
  189. package/dist/features/products/constants/action-defs.d.ts +1 -0
  190. package/dist/features/products/constants/action-defs.js +1 -0
  191. package/dist/features/products/schemas/index.d.ts +5 -0
  192. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
  193. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  194. package/dist/features/search/components/SearchView.d.ts +1 -3
  195. package/dist/features/search/components/SearchView.js +1 -1
  196. package/dist/features/seller/components/QuickProductForm.js +2 -1
  197. package/dist/features/seller/components/SellerBidsView.js +66 -107
  198. package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
  199. package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
  200. package/dist/features/seller/components/SellerOrdersView.js +134 -163
  201. package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
  202. package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
  203. package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
  204. package/dist/features/seller/components/SellerPayoutsView.js +25 -5
  205. package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
  206. package/dist/features/seller/components/SellerProductShell.js +89 -36
  207. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
  208. package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
  209. package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
  210. package/dist/features/seller/components/SellerProductsView.js +131 -189
  211. package/dist/features/seller/components/SellerReviewsView.js +95 -133
  212. package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
  213. package/dist/features/seller/components/SellerShippingView.js +41 -4
  214. package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
  215. package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
  216. package/dist/features/seller/components/SellerStorefrontView.js +42 -5
  217. package/dist/features/seller/components/index.d.ts +2 -2
  218. package/dist/features/seller/components/index.js +2 -2
  219. package/dist/features/shell/FormShell.d.ts +24 -4
  220. package/dist/features/shell/FormShell.js +12 -6
  221. package/dist/features/shell/QuickFormDrawer.js +67 -12
  222. package/dist/features/shell/StepForm.d.ts +30 -1
  223. package/dist/features/shell/StepForm.js +47 -4
  224. package/dist/features/shell/index.d.ts +1 -1
  225. package/dist/features/shell/index.js +1 -1
  226. package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
  227. package/dist/features/shipments/schemas/validation.d.ts +14 -4
  228. package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
  229. package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
  230. package/dist/features/tester/components/TesterHubView.js +3 -2
  231. package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
  232. package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
  233. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +404 -15
  234. package/dist/index.d.ts +15 -3
  235. package/dist/index.js +22 -5
  236. package/dist/next/routing/route-map.d.ts +11 -0
  237. package/dist/next/routing/route-map.js +5 -0
  238. package/dist/providers/email-resend/provider.js +1 -0
  239. package/dist/providers/firebase-client/auth.d.ts +1 -0
  240. package/dist/providers/firebase-client/auth.js +7 -1
  241. package/dist/repositories/index.d.ts +1 -0
  242. package/dist/repositories/index.js +1 -0
  243. package/dist/schemas/registry.d.ts +61 -25
  244. package/dist/security/pii-mask.js +1 -1
  245. package/dist/seed/categories-seed-data.js +69 -0
  246. package/dist/seed/products-auctions-seed-data.js +11 -0
  247. package/dist/seed/products-standard-seed-data.js +93 -4
  248. package/dist/seed/site-settings-seed-data.js +13 -1
  249. package/dist/seed/store-extensions-seed-data.js +1 -1
  250. package/dist/server-entry.d.ts +2 -1
  251. package/dist/server-entry.js +20 -2
  252. package/dist/server.d.ts +7 -2
  253. package/dist/server.js +8 -3
  254. package/dist/styles.css +1 -1
  255. package/dist/tailwind-utilities.css +1 -1
  256. package/dist/ui/components/Form.d.ts +11 -2
  257. package/dist/ui/components/Form.js +4 -3
  258. package/dist/ui/components/FormField.d.ts +3 -1
  259. package/dist/ui/components/FormField.js +22 -4
  260. package/dist/ui/components/ListingLayout.d.ts +1 -2
  261. package/dist/ui/components/ListingLayout.js +1 -1
  262. package/dist/ui/components/RecordDetailModal.d.ts +68 -0
  263. package/dist/ui/components/RecordDetailModal.js +8 -0
  264. package/dist/ui/components/SlottedListingView.js +9 -1
  265. package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
  266. package/dist/ui/forms/FormErrorSummary.js +37 -0
  267. package/dist/ui/forms/FormShell.d.ts +37 -2
  268. package/dist/ui/forms/FormShell.js +37 -7
  269. package/dist/ui/forms/FormShell.style.css +17 -0
  270. package/dist/ui/forms/index.d.ts +2 -0
  271. package/dist/ui/forms/index.js +1 -0
  272. package/dist/ui/index.d.ts +4 -0
  273. package/dist/ui/index.js +5 -0
  274. package/dist/utils/media-url.d.ts +3 -1
  275. package/dist/utils/media-url.js +20 -1
  276. package/dist/validation/schemas.d.ts +4 -4
  277. package/package.json +1 -1
  278. package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
  279. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
  280. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
  281. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
  282. package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
  283. package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
  284. package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
  285. package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
  286. package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
  287. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
  288. package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
  289. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
  290. package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
  291. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
  292. package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
  293. package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
  294. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
  295. package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
  296. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
  297. package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
  298. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
  299. package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
  300. package/dist/features/auth/consent-otp.d.ts +0 -57
  301. package/dist/features/auth/consent-otp.js +0 -127
  302. package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
  303. package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
  304. package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
  305. package/dist/features/checkout/actions/checkout-actions.js +0 -124
  306. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
  307. package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
  308. package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
  309. package/dist/features/classified/components/ClassifiedListView.js +0 -44
  310. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
  311. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
  312. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
  313. package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
  314. package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
  315. package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
  316. package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
  317. package/dist/features/live/components/LiveItemsListView.js +0 -44
  318. package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
  319. package/dist/features/seller/components/SellerTemplatesView.js +0 -276
  320. package/dist/react/hooks/useVisibleItems.d.ts +0 -37
  321. package/dist/react/hooks/useVisibleItems.js +0 -59
  322. package/dist/ui/components/TabStrip.d.ts +0 -34
  323. package/dist/ui/components/TabStrip.js +0 -56
  324. package/dist/ui/components/TabStrip.style.css +0 -97
@@ -32,7 +32,10 @@ function group(groupKey, groupLabel, pages, opts) {
32
32
  pageLabel: page.pageLabel,
33
33
  label: c.label,
34
34
  description: c.description,
35
- href: c.href,
35
+ // Every case gets a link: its own href, or the page's default —
36
+ // guarantees "Go test this ->" always has somewhere real to send
37
+ // the tester, even for cases nobody bothered to link individually.
38
+ href: c.href ?? page.href,
36
39
  order: (opts?.orderOffset ?? 0) + pageIdx * 10 + caseIdx,
37
40
  isActive: true,
38
41
  adminOnly: opts?.adminOnly ?? false,
@@ -52,6 +55,7 @@ const rawTesterChecklistItems = [
52
55
  {
53
56
  pageKey: "signup-login",
54
57
  pageLabel: "Signup & Login",
58
+ href: "/auth/login",
55
59
  cases: [
56
60
  { key: "email-signup", label: "Sign up with email works", href: "/auth/register" },
57
61
  { key: "google-oauth", label: "Sign up / log in with Google works", href: "/auth/login" },
@@ -83,20 +87,33 @@ const rawTesterChecklistItems = [
83
87
  { key: "logout", label: "Log out works and clears the session" },
84
88
  { key: "email-verify", label: "Email verification link works" },
85
89
  { key: "password-reset", label: "Forgot-password / reset-password flow works" },
90
+ {
91
+ key: "signup-verification-email-arrives",
92
+ label: "The verification email actually arrives in the inbox after signing up — not just a \"check your email\" message on screen",
93
+ description: "Changed 2026-08-21 — signup verification is now sent by Firebase itself (client SDK) instead of being generated server-side and delivered through Resend. Register a brand-new account with a real inbox you can check, and confirm the email lands (check spam too) and its link marks the account verified. The email will come from Firebase's sender with Firebase's template, NOT the branded LetItRip template — that difference is expected, not a bug.",
94
+ href: "/auth/register",
95
+ },
96
+ {
97
+ key: "forgot-password-no-account-enumeration",
98
+ label: "Submitting \"Forgot password\" for an email that has NO account shows the same generic message as a real account — it never reveals whether the account exists",
99
+ description: "Changed 2026-08-21 — this flow now calls Firebase directly from the browser instead of going through a server route, so the client must swallow Firebase's auth/user-not-found error. Submit a made-up address like nobody-here-12345@example.com and confirm you see \"If an account exists for that email, a reset link is on its way.\" — the same wording a real address produces, with no error toast and nothing in the UI distinguishing the two cases.",
100
+ href: "/auth/forgot-password",
101
+ },
86
102
  ],
87
103
  },
88
104
  {
89
105
  pageKey: "profile-settings",
90
106
  pageLabel: "Profile & Settings",
107
+ href: "/user/settings",
91
108
  cases: [
92
109
  { key: "edit-profile", label: "Editing display name / bio saves correctly", href: "/user/profile" },
93
110
  { key: "avatar-upload", label: "Uploading a profile avatar works" },
94
111
  { key: "notification-prefs", label: "Notification preferences save correctly" },
95
112
  { key: "public-profile-toggle", label: "Public profile visibility toggle works" },
96
113
  {
97
- key: "password-change-otp-required",
98
- label: "Changing your password from Settings requires entering an emailed 6-digit code before it actually takes effect — the password does not change just from submitting the current/new password form",
99
- description: "Fixed 2026-08-20the password-change API previously trusted the session cookie alone, with no server-side check of the current password at all. Submit the Change Password form with a correct current password; confirm you land on a \"we sent a code to your email\" step, and the password only actually updates after entering the correct code. Also verify: an expired/wrong code is rejected with a clear error, and \"Resend code\" works.",
114
+ key: "password-change-reset-link",
115
+ label: "Changing your password from Settings sends a reset link to your account email — the password only changes after you open that link, never from the Settings page alone",
116
+ description: "Changed 2026-08-21password change is now Firebase-native (the same reset-link flow as \"Forgot Password\"), replacing the older emailed 6-digit-code flow. Click \"Send password reset link\", confirm the email arrives at your account address, and that following the link lets you set a new password which then works for sign-in. Identity is proved by access to the inbox, so verify no password change is possible from the Settings page by itself.",
100
117
  href: "/user/settings",
101
118
  },
102
119
  {
@@ -120,6 +137,7 @@ const rawTesterChecklistItems = [
120
137
  {
121
138
  pageKey: "testing-program",
122
139
  pageLabel: "Tester Hub",
140
+ href: "/user/tester",
123
141
  cases: [
124
142
  { key: "tester-hub-loads", label: "Tester Hub loads the full checklist grouped by section", href: "/user/tester" },
125
143
  { key: "tester-hub-search", label: "Tester Hub search finds test cases by typing part of the title or the route (e.g. \"/store/payouts\")", href: "/user/tester" },
@@ -139,6 +157,7 @@ const rawTesterChecklistItems = [
139
157
  {
140
158
  pageKey: "browsing-search",
141
159
  pageLabel: "Browsing & Search",
160
+ href: "/products",
142
161
  cases: [
143
162
  { key: "browse-categories", label: "Browsing categories shows relevant products", href: "/categories" },
144
163
  { key: "search", label: "Search returns relevant results", href: "/search" },
@@ -208,14 +227,16 @@ const rawTesterChecklistItems = [
208
227
  {
209
228
  pageKey: "product-detail",
210
229
  pageLabel: "Product / Auction / Pre-order Detail",
230
+ href: "/products",
211
231
  cases: [
212
- { key: "standard-detail", label: "Standard product detail page loads correctly" },
232
+ { key: "standard-detail", label: "Standard product detail page loads correctly", href: "/products/product-tester-standard-1" },
213
233
  {
214
234
  key: "auction-detail",
215
235
  label: "Auction detail page shows current bid + a live, ticking countdown correctly",
216
236
  description: "The countdown (\"Ends in 2d 5h 30m\", ticking every second — not a static date) must appear directly above every \"Place a bid\" button: the info panel, the desktop and mobile compact bid-summary cards, inside the \"Place your bid\" modal above the submit button, and in the mobile sticky bottom bar (as a row above the current-bid/bid-count line). It should switch to \"Ended\" once the end time passes.",
237
+ href: "/auctions/auction-tester-sandbox-cycle-1",
217
238
  },
218
- { key: "preorder-detail", label: "Pre-order detail page shows expected ship date correctly" },
239
+ { key: "preorder-detail", label: "Pre-order detail page shows expected ship date correctly", href: "/pre-orders/preorder-tester-sandbox-1" },
219
240
  {
220
241
  key: "image-gallery",
221
242
  label: "Product image gallery thumbnails load reliably (no broken-image icons) and click-to-zoom/rotate works in the lightbox",
@@ -224,7 +245,24 @@ const rawTesterChecklistItems = [
224
245
  {
225
246
  key: "video-playback",
226
247
  label: "A product's video slide opens in theater mode with playback, zoom, and rotate controls",
227
- description: "Product video is no longer a YouTube embed — when a product has a video, it appears as a trailing gallery slide (poster image + play badge) alongside the photos. Clicking it opens the full-screen lightbox in theater mode, plays the video with native controls, and the zoom (+/-) and rotate (R) buttons in the top bar still apply. Test on the two seeded fixtures: \"Beyblade Original — Dragoon F (Video Demo)\" and \"Beyblade X BX-02 Dran Sword (Video Demo)\".",
248
+ description: "When a product has a video, it appears as a trailing gallery slide (poster image + play badge) alongside the photos. Clicking it opens the full-screen lightbox in theater mode. For a raw-file video (native <video> element) the zoom (+/-) and rotate (R) buttons in the top bar apply; for a YouTube-sourced video (see \"video-playback-youtube\" below) they don't — the embed has its own player chrome. Test on the raw-file fixtures: \"Beyblade Original — Dragoon F (Video Demo)\" and \"Beyblade X BX-02 Dran Sword (Video Demo)\".",
249
+ },
250
+ {
251
+ key: "video-playback-youtube",
252
+ label: "A product whose video is sourced from YouTube (via MediaUploadField's \"YouTube\" tab) actually plays — not \"No video with supported format\"",
253
+ description: "Fixed 2026-08-21 — a YouTube-sourced video.url (e.g. youtube.com/watch?v=...) was always rendered as a raw <video src>, which can't play a YouTube watch-page URL. getYouTubeVideoId() now detects this and renders a youtube-nocookie.com iframe embed instead, in both the gallery lightbox and the standalone MediaVideo preview (used by the upload form's own \"YouTube\" tab preview). Verify on \"Metal Fight Beyblade BB-118 Dark Bull (Video Demo, YouTube)\" (standard product) and \"Beyblade Original — Dragoon Storm (Rare Sealed)\" (auction) — the video slide should open and actually play the embedded YouTube video, not show an error.",
254
+ href: "/products",
255
+ },
256
+ {
257
+ key: "video-lightbox-fullscreen-sizing",
258
+ label: "The video/YouTube-embed lightbox has a real minimum size on both mobile and desktop, and the top-bar \"expand\" button toggles real browser fullscreen",
259
+ description: "Fixed 2026-08-21 — the lightbox's \"Maximize2\" button used to just duplicate the zoom-reset button (no real fullscreen). It now toggles the native Fullscreen API (icon swaps to a \"shrink\" glyph while active) and syncs correctly if you exit via Esc instead of the button. Separately, the video/embed area now has a minimum width/height (bigger on desktop than mobile) so it never collapses to a tiny box while loading or on a low-resolution video. Test on a narrow (mobile-width) browser window and a full desktop window against \"Beyblade Burst B-97 Spryzen S2 (Video Demo, Wikimedia)\".",
260
+ },
261
+ {
262
+ key: "video-real-file-upload",
263
+ label: "Uploading a real video file via the product form's \"Upload\" tab (not YouTube or External URL) plays back correctly with an auto-captured poster frame",
264
+ description: "This path can't be covered by a permanent seed fixture — there's no real Storage object for a seeded URL to point at, so it has to be tested by hand. As a seller/admin, edit any product's Video field, use the default \"Upload\" tab (not the YouTube or External URL tab) to upload a real .mp4/.webm/.mov file, and confirm: (1) a poster/thumbnail frame is auto-captured and shown once upload finishes, (2) the video plays correctly in both the product form's own preview panel and the public product detail page's gallery lightbox, (3) it opens the trim modal if enabled, and (4) removing it and re-uploading works without leaving orphaned files (no error toast).",
265
+ href: "/store/products",
228
266
  },
229
267
  {
230
268
  key: "related-listings-sections",
@@ -232,22 +270,22 @@ const rawTesterChecklistItems = [
232
270
  description: "Verify against \"Beyblade Burst B-01 Valkyrie\" (product-beyblade-burst-valkyrie) — all 4 sections should show real items: other Beyblade Burst products, other \"Beyblade\"-brand products, other attack-type/starter-set tagged products, and other Beyblade Arena store listings.",
233
271
  href: "/products",
234
272
  },
235
- { key: "prizedraw-buy-reveal", label: "Buying a prize-draw entry correctly assigns a prize once payment is confirmed (instant mode) or shows a pending state until the draw closes (scheduled mode)" },
273
+ { key: "prizedraw-buy-reveal", label: "Buying a prize-draw entry correctly assigns a prize once payment is confirmed (instant mode) or shows a pending state until the draw closes (scheduled mode)", href: "/prize-draws/prizedraw-tester-sandbox-1" },
236
274
  {
237
275
  key: "bundle-purchase",
238
276
  label: "Purchasing a bundle works and shows all included items in the order",
239
277
  description: "Verify against \"Test Bundle\" (bundle-tester-sandbox, findable from the bundles listing page) — after checkout, the order should show a single \"Test Bundle\" line item, not two separate product lines.",
240
- href: "/bundles",
278
+ href: "/bundles/bundle-tester-sandbox",
241
279
  },
242
280
  {
243
281
  key: "product-group-set-widget",
244
282
  label: "A product's detail page shows a collapsible \"Part of / Parts in this group\" panel with a working thumbnail strip and a \"View whole group\" table when the product belongs to a product-group (\"Set\")",
245
283
  description: "Verify against \"Test Product Set — Standard #1 + Standard #2\" (group-tester-sandbox-bundle) and either of its two children (product-tester-standard-1 / product-tester-standard-2), findable from the products listing page — all three should show the panel with each other listed, the arrow/triangle expand icons should render as real glyphs (not garbled text), and \"View whole group\" should open a working modal/drawer.",
246
- href: "/products",
284
+ href: "/products/group-tester-sandbox-bundle",
247
285
  },
248
- { key: "classified-contact-flow", label: "A classified listing shows a contact-seller flow with deliberately no checkout/buy button" },
249
- { key: "digitalcode-delivery", label: "Purchasing a digital-code listing delivers the code to the buyer post-purchase" },
250
- { key: "live-item-detail", label: "A live-item listing's detail page shows the livestream link correctly" },
286
+ { key: "classified-contact-flow", label: "A classified listing shows a contact-seller flow with deliberately no checkout/buy button", href: "/classified/classified-tester-sandbox-1" },
287
+ { key: "digitalcode-delivery", label: "Purchasing a digital-code listing delivers the code to the buyer post-purchase", href: "/digital-codes/digitalcode-tester-sandbox-1" },
288
+ { key: "live-item-detail", label: "A live-item listing's detail page shows the livestream link correctly", href: "/live/live-tester-sandbox-1" },
251
289
  {
252
290
  key: "live-item-video-mandatory",
253
291
  label: "Creating a live-item listing (species: animals/plants) without a video is rejected with a clear error; a live listing WITH a video plays correctly in the gallery's video slide and its poster thumbnail is watermarked",
@@ -259,6 +297,7 @@ const rawTesterChecklistItems = [
259
297
  {
260
298
  pageKey: "buying-checkout",
261
299
  pageLabel: "Buying & Checkout",
300
+ href: "/checkout",
262
301
  cases: [
263
302
  { key: "add-to-cart", label: "Add to cart works from the product page" },
264
303
  { key: "add-to-cart-out-of-stock", label: "Add to cart is disabled/blocked once a listing's stock reaches zero" },
@@ -276,6 +315,16 @@ const rawTesterChecklistItems = [
276
315
  label: "Carts ≥ the admin-configured high-value OTP threshold (Site Settings → Shipping → \"High-value checkout OTP threshold\", default ₹5,000) prompt a \"Verify this order\" email OTP right before payment (except COD); carts below the threshold check out directly with no OTP step at all",
277
316
  description: "Root-caused 2026-08-20 — the OTP email send used to be fire-and-forget, so a Resend/API failure silently left the buyer stuck with no code and no error. Sending now surfaces a real error if the email genuinely fails to send, and the \"already sent, retry in N minutes\" rate-limit message is a clear sentence instead of a raw error code. Place a real order ≥ the threshold and confirm the code actually arrives by email (check spam too) — report the exact error text if it still doesn't.",
278
317
  },
318
+ {
319
+ key: "checkout-otp-whatsapp-option",
320
+ label: "When the admin has WhatsApp OTP switched on, the high-value checkout verification step offers a \"Send via WhatsApp instead\" option — and email, not WhatsApp, is still what gets sent by default",
321
+ description: "Added 2026-08-21. WhatsApp is deliberately opt-in for OTP: the code must arrive by email unless the buyer explicitly clicks the WhatsApp option. Requires Site Settings → Notifications → WhatsApp → \"WhatsApp OTP\" enabled AND real Meta Cloud API credentials saved, AND the selected delivery address having a phone number. Verify: (a) the default send is email; (b) the WhatsApp option only appears when all three conditions hold; (c) clicking it delivers the code to the address's phone and the on-screen text switches to the masked phone number; (d) the code from WhatsApp verifies successfully.",
322
+ },
323
+ {
324
+ key: "checkout-otp-whatsapp-hidden-without-phone",
325
+ label: "The \"Send via WhatsApp instead\" option is NOT offered when the selected delivery address has no phone number on it, even with WhatsApp OTP enabled",
326
+ description: "Added 2026-08-21. The phone is resolved server-side from the selected address (never from anything the browser sends), so an address with no phone has nowhere to send the code. Select/create a delivery address with the phone field empty and confirm the WhatsApp option is absent rather than appearing and then failing.",
327
+ },
279
328
  { key: "payment-method-selection", label: "Choosing between COD, UPI/manual, and Razorpay (when enabled) at checkout works" },
280
329
  { key: "payment-window-countdown", label: "Manual-payment orders show a 15-minute countdown timer on the payment page" },
281
330
  { key: "payment-proof-upload", label: "Uploading manual payment proof (screenshot, UTR, mark-as-paid + agreement checkboxes) works" },
@@ -316,6 +365,7 @@ const rawTesterChecklistItems = [
316
365
  {
317
366
  pageKey: "my-orders",
318
367
  pageLabel: "My Orders — List & Dashboard",
368
+ href: "/user/orders",
319
369
  cases: [
320
370
  {
321
371
  key: "orders-item-summary",
@@ -339,19 +389,66 @@ const rawTesterChecklistItems = [
339
389
  description: "A 2026-08-19 bug meant real checkout orders never carried a per-item image at all (the field didn't exist on the order document, so the detail page's image block was silently skipped rather than showing a broken-image icon). Place a fresh order through checkout and confirm its item thumbnail shows up both in the My Orders list and on the order-detail page.",
340
390
  href: "/user/orders",
341
391
  },
392
+ {
393
+ key: "my-orders-search-filter-sort",
394
+ label: "My Orders has a working search box (by order id), a status filter (drawer), and a sort dropdown (Newest/Oldest/Highest total/Lowest total) — the same toolbar pattern as every other dashboard listing",
395
+ description: "Converted 2026-08-21 off a page-specific hand-wired toolbar onto the standard DataListingView scaffold. Type part of a real order id into search and confirm it narrows the list, open the filter drawer and pick a status, and confirm changing sort actually reorders the cards.",
396
+ href: "/user/orders",
397
+ },
398
+ {
399
+ key: "order-tracking-timeline",
400
+ label: "\"Track Shipment\" opens a real page with a status timeline (Order placed → Shipped, each with a real date) and, when a tracking URL is set, a \"Track with carrier\" link that opens in a new tab — not a blank page",
401
+ description: "Fixed 2026-08-21 — /user/orders/[id]/track previously rendered <UserOrderTrackView /> with zero render-props (a Root Cause #8 blank slot-shell), and the underlying adapter dropped orderDate/shippingDate/deliveryDate/cancellationDate/trackingUrl entirely, so even a fixed page would have had nothing to show. From My Orders, open the seeded \"order-tester-sandbox-standard-shipped\" order and click \"Track Shipment\" — confirm both timeline steps show real dates and the tracking link opens www.example.com/track/TEST-TRACK-001 in a new tab.",
402
+ href: "/user/orders",
403
+ },
404
+ {
405
+ key: "manual-payment-panel-on-order-detail",
406
+ label: "A manual-payment (UPI/Cash) order's detail page shows a \"Payment pending\" panel with a \"Complete payment\" button that opens the proof-upload page — you can get back to it at any time, not only right after checkout",
407
+ description: "Fixed 2026-08-21. `ROUTES.USER.ORDER_PAYMENT` previously had exactly one caller — the post-checkout redirect — so a buyer who navigated away could never find the upload page again. Place a UPI/Cash order, leave the payment page WITHOUT uploading, go to My Orders, open that order, and confirm the panel + \"Complete payment\" button are there and land on the upload page.",
408
+ href: "/user/orders",
409
+ },
410
+ {
411
+ key: "manual-payment-page-renders-upi-and-countdown",
412
+ label: "The payment-proof page for a UPI/Cash order actually shows the upload form, the UPI ID to pay, and a live 15-minute countdown — NOT the message \"This order does not require manual payment upload\"",
413
+ description: "Fixed 2026-08-21 — the order adapter (`orderDocumentToOrder`) dropped `paymentMethod`, `displayedUpiId` and `paymentDeadline` entirely, so the page's own manual-payment check always failed and every buyer saw the \"does not require manual payment upload\" dead end, with no UPI ID and no timer. This is the single most important case in this group: if it fails, the whole manual-payment flow is unusable.",
414
+ href: "/user/orders",
415
+ },
416
+ {
417
+ key: "manual-payment-awaiting-review-state",
418
+ label: "After submitting proof, the order detail page switches to a \"Payment under review\" panel and the \"Complete payment\" button disappears (you can't double-submit)",
419
+ href: "/user/orders",
420
+ },
421
+ {
422
+ key: "manual-payment-reupload-note-visible-to-buyer",
423
+ label: "When an admin requests a proof re-upload, the buyer's order detail page shows \"Payment proof needs correction\" WITH the admin's note, and a \"Re-upload proof\" button that works",
424
+ description: "Added 2026-08-21. Pair with the admin-side case `admin-orders-request-reupload`. The buyer previously got a notification telling them to re-upload but had no link anywhere to do it. Confirm the admin's exact note text is shown to the buyer, and that re-submitting succeeds (it must not fail with \"proof already attached\").",
425
+ href: "/user/orders",
426
+ },
427
+ {
428
+ key: "manual-payment-rejected-state",
429
+ label: "An order rejected as fraudulent shows a \"Payment rejected\" panel with the admin's reason, and the account is suspended for 7 days",
430
+ description: "Pair with the admin-side case `admin-orders-reject-fraud`. Use a throwaway buyer account — this really does ban it for 7 days.",
431
+ href: "/user/orders",
432
+ },
342
433
  ],
343
434
  },
344
435
  {
345
436
  pageKey: "bidding",
346
437
  pageLabel: "Bidding",
438
+ href: "/user/bids",
347
439
  cases: [
348
- { key: "place-bid", label: "Placing a bid on an auction works", href: "/user/bids" },
440
+ { key: "place-bid", label: "Placing a bid on an auction works", href: "/auctions/auction-tester-sandbox-cycle-1" },
349
441
  { key: "place-bid-live-self", label: "After placing a bid, the current bid amount and bid count update immediately on the auction page for the bidder — no manual page refresh needed" },
350
442
  { key: "place-bid-live-other-viewer", label: "Opening the same auction in two browser tabs (or two accounts) and placing a bid in one updates the current bid and bid count in the other within a few seconds, without a manual refresh (realtime SSE)" },
351
443
  { key: "outbid-notification", label: "Getting outbid triggers a notification" },
352
- { key: "win-auction", label: "Winning an auction creates a payable order correctly" },
444
+ { key: "win-auction", label: "Winning an auction creates a payable order correctly", href: "/auctions/auction-tester-sandbox-won" },
353
445
  { key: "bid-history", label: "My Bids page shows accurate bid history, paginated with the most recent bid first", href: "/user/bids" },
354
446
  { key: "bid-history-auction-detail-pagination", label: "An auction detail page's Bid History section shows the most recent bid first and paginates once there are more bids than fit on one page (try the L-Drago auction — 13 seeded bids)" },
447
+ {
448
+ key: "bid-history-shows-date-time-and-masked-name",
449
+ label: "Each row in an auction detail page's Bid History section shows the bid amount, the exact date AND time the bid was placed (e.g. \"Aug 21, 3:45 PM\"), and the bidder's identity as a masked name (e.g. \"R*** K***\") or a partial bidder id — never a bidder's real, unmasked full name",
450
+ description: "Fixed 2026-08-21 — `maskPublicBid()` (the helper meant to mask a bidder's display name before it reaches the public product page) was a silent no-op that returned the bid document unchanged, so a real bidder's full name was being sent to every visitor; separately, the Bid History row never displayed any bidder identity at all (only amount + date), so the leak had no visible symptom. Open the L-Drago auction (or any auction with bids) as a DIFFERENT, non-bidder account and expand Bid History — every row should show a masked name, not a bidder's real full name.",
451
+ },
355
452
  {
356
453
  key: "bid-increment-tiered",
357
454
  label: "The \"min increment\" shown on an auction matches the admin-configured tier for the current bid amount, not a flat ₹1 — and a bid below that increment is rejected",
@@ -371,6 +468,7 @@ const rawTesterChecklistItems = [
371
468
  {
372
469
  pageKey: "wishlist-history",
373
470
  pageLabel: "Wishlist & History",
471
+ href: "/wishlist",
374
472
  cases: [
375
473
  { key: "add-wishlist-pdp", label: "Adding a product to the wishlist from the product detail page works", href: "/wishlist" },
376
474
  { key: "add-wishlist-card", label: "Adding a product to the wishlist from a listing card (checkbox/long-press) works on both listing and search pages" },
@@ -397,6 +495,7 @@ const rawTesterChecklistItems = [
397
495
  {
398
496
  pageKey: "cart",
399
497
  pageLabel: "Cart",
498
+ href: "/cart",
400
499
  cases: [
401
500
  { key: "update-qty", label: "Updating item quantity in cart recalculates the total" },
402
501
  { key: "apply-coupon", label: "Applying a coupon code at checkout works" },
@@ -433,6 +532,7 @@ const rawTesterChecklistItems = [
433
532
  {
434
533
  pageKey: "reviews",
435
534
  pageLabel: "Reviews",
535
+ href: "/reviews",
436
536
  cases: [
437
537
  { key: "leave-review", label: "Leaving a review with rating + photo works" },
438
538
  { key: "view-seller-reviews", label: "Viewing a seller's reviews on their store page works" },
@@ -454,6 +554,7 @@ const rawTesterChecklistItems = [
454
554
  {
455
555
  pageKey: "messaging",
456
556
  pageLabel: "Messaging a Seller",
557
+ href: "/user/messages",
457
558
  cases: [
458
559
  { key: "start-conversation", label: "Starting a conversation with a seller works" },
459
560
  { key: "receive-reply", label: "Receiving and reading a seller's reply works" },
@@ -464,6 +565,7 @@ const rawTesterChecklistItems = [
464
565
  {
465
566
  pageKey: "user-dashboard-extras",
466
567
  pageLabel: "User Dashboard — Addresses, Catalogue, Settings, My Orders-by-Type",
568
+ href: "/user",
467
569
  cases: [
468
570
  { key: "addresses-crud", label: "Adding, editing, and listing delivery addresses works", href: "/user/addresses" },
469
571
  { key: "catalogue-crud", label: "Adding, editing, and deleting a personal catalogue item works", href: "/user/catalogue" },
@@ -478,11 +580,18 @@ const rawTesterChecklistItems = [
478
580
  href: "/user/returns",
479
581
  },
480
582
  { key: "my-reviews", label: "\"My Reviews\" shows reviews the user has left", href: "/user/reviews" },
583
+ {
584
+ key: "user-personal-listings-search-sort",
585
+ label: "My Digital Codes, My Pre-Orders, My Prize Draws, and My Reviews each now have a working search box and sort dropdown (Newest/Oldest, plus a rating sort on Reviews) using the standard listing toolbar — not a bare unsearchable list",
586
+ description: "Converted 2026-08-21 off page-specific hand-wired toolbars onto the standard DataListingView scaffold. Spot-check at least two of the four: type a product name into search and confirm it narrows the list, and change the sort dropdown and confirm the order changes.",
587
+ href: "/user/digital-codes",
588
+ },
481
589
  ],
482
590
  },
483
591
  {
484
592
  pageKey: "user-dashboard-navigation",
485
593
  pageLabel: "User Dashboard Navigation",
594
+ href: "/user",
486
595
  cases: [
487
596
  { key: "sidebar-all-links-work", label: "Every item in the user dashboard sidebar navigates to its page without a 404 or broken layout", href: "/user" },
488
597
  { key: "sidebar-active-highlight", label: "The sidebar correctly highlights the currently active section as you navigate between pages" },
@@ -505,6 +614,7 @@ const rawTesterChecklistItems = [
505
614
  {
506
615
  pageKey: "become-seller",
507
616
  pageLabel: "Become a Seller & Store Setup",
617
+ href: "/user/become-seller",
508
618
  cases: [
509
619
  { key: "apply-seller", label: "Applying to become a seller works", href: "/user/become-seller" },
510
620
  { key: "store-setup", label: "Setting up store name/description/logo works" },
@@ -514,42 +624,82 @@ const rawTesterChecklistItems = [
514
624
  {
515
625
  pageKey: "listing-a-product",
516
626
  pageLabel: "Listing a Product",
627
+ href: "/store/products",
517
628
  cases: [
518
629
  { key: "list-standard", label: "Listing a standard product works" },
519
630
  { key: "list-auction", label: "Listing an auction works" },
520
631
  { key: "list-preorder", label: "Listing a pre-order works" },
521
632
  { key: "edit-listing", label: "Editing an existing listing works" },
522
633
  { key: "media-upload", label: "Uploading product images/video during listing works" },
634
+ {
635
+ key: "media-upload-preview-no-white-box",
636
+ label: "A freshly-uploaded image's thumbnail renders as a real preview within a couple seconds — it never gets stuck as a blank/white box",
637
+ description: "Fixed 2026-08-21 — a fresh upload can briefly 404 while the Firestore doc and Storage object finish propagating; the thumbnail now retries with backoff instead of latching a permanent broken-image placeholder. Try uploading 2-3 images back-to-back on a slower connection to see the retry in action.",
638
+ href: "/store/products/new",
639
+ },
640
+ {
641
+ key: "media-upload-images-capped-at-5",
642
+ label: "The product gallery upload UI caps at 5 images (not 10) and its label reads \"up to 5\"",
643
+ description: "Fixed 2026-08-21 — the UI previously advertised/allowed up to 10 images while the server schema only ever accepted 5, so a 6th+ image silently failed validation with no clear reason.",
644
+ href: "/store/products/new",
645
+ },
646
+ {
647
+ key: "media-upload-video-duration",
648
+ label: "Attaching a directly-uploaded video file during listing captures its duration automatically and saves without a validation error; attaching a YouTube or external video URL also saves fine without needing a duration",
649
+ description: "Fixed 2026-08-21 — the video schema always required a duration the UI never collected, so ANY product with a directly-uploaded video previously failed server validation invisibly. Duration is now captured client-side for file uploads; YouTube/external sources are exempt since their duration can't be read client-side.",
650
+ href: "/store/products/new",
651
+ },
523
652
  { key: "seller-quick-add-drawer-flips", label: "With Left-hand mode ON, the seller's quick-add-listing side drawer opens from the left instead of the right" },
524
653
  ],
525
654
  },
526
655
  {
527
656
  pageKey: "seller-orders",
528
657
  pageLabel: "Seller Order Management & Shipping/Tracking",
658
+ href: "/store/orders",
529
659
  cases: [
530
660
  { key: "view-orders", label: "Seller order list shows accurate incoming orders", href: "/store/orders" },
661
+ {
662
+ key: "seller-order-manual-payment-badge",
663
+ label: "A manual-payment (UPI/Cash) order's seller detail shows a payment badge — Awaiting payment / Awaiting verification / Verified / Re-upload requested / Rejected — next to the Payment heading, plus the UTR once the buyer submits one",
664
+ description: "Added 2026-08-21. Sellers previously saw only the payment method word (\"upi_manual\") with no indication of whether the money had actually landed. The buyer's payment screenshot is deliberately NOT shown to sellers — it's a bank/UPI capture, and verifying is admin/moderator-only — so confirm the badge and UTR appear but no screenshot image does.",
665
+ href: "/store/orders",
666
+ },
531
667
  { key: "confirm-payment", label: "Approving a buyer's manual payment proof works" },
532
668
  { key: "request-reupload", label: "Requesting a proof re-upload (honest-mistake tier) clears the proof and extends the buyer's deadline" },
533
669
  { key: "reject-fraud", label: "Rejecting a proof as fraudulent cancels the order, restores stock, and bans the buyer's account for 7 days" },
534
670
  { key: "whatsapp-admin-share", label: "Uploading payment proof pings the admin WhatsApp numbers, and the buyer's \"Share for review\" link opens with a pre-filled message" },
535
671
  { key: "mark-shipped", label: "Marking an order shipped with tracking info works" },
536
672
  { key: "tracking-visible", label: "Buyer sees updated tracking status after seller ships" },
673
+ {
674
+ key: "seller-order-detail-full-page",
675
+ label: "Every seller order row has an \"Open full page\" action landing on a real bookmarkable /store/orders/[id]/view page showing the same items (with thumbnails)/address/payment/EMI/status content as the drawer",
676
+ description: "Added 2026-08-21 — sellers previously had no dedicated order-detail page, only a drawer, unlike buyer/admin. The drawer and the new page now share one content component (SellerOrderDetailPanel) so they can't drift.",
677
+ href: "/store/orders",
678
+ },
537
679
  ],
538
680
  },
539
681
  {
540
682
  pageKey: "seller-analytics-payouts",
541
683
  pageLabel: "Seller Analytics & Payouts",
684
+ href: "/store/analytics",
542
685
  cases: [
543
686
  { key: "view-analytics", label: "Seller analytics dashboard shows accurate sales data", href: "/store/analytics" },
544
687
  { key: "view-payouts", label: "Seller payouts list shows accurate payout history", href: "/store/payouts" },
545
688
  { key: "payouts-checkbox-select", label: "Selecting payouts with the row checkboxes shows a working bulk action bar (Export Selected)", href: "/store/payouts" },
546
689
  { key: "payouts-detail-panel", label: "Opening \"View Details\" on a payout shows a side panel with status progress, transaction ID, and expected payout date" },
547
690
  { key: "payouts-reminder-toggle", label: "Toggling the payout reminder flag in the detail panel saves correctly" },
691
+ {
692
+ key: "seller-payout-detail-full-page",
693
+ label: "Every payout row has an \"Open full page\" action landing on a real /store/payouts/[id]/view page showing a gross/platform-fee/refund-deduction/net breakdown, not just the drawer's flat amount",
694
+ description: "Added 2026-08-21 — the drawer previously showed only a flat amount with orderIds as plain unlinked monospace text. Both the drawer and the new page now render from one shared SellerPayoutDetailContent component.",
695
+ href: "/store/payouts",
696
+ },
548
697
  ],
549
698
  },
550
699
  {
551
700
  pageKey: "seller-shipping-payouts-setup",
552
701
  pageLabel: "Seller Shipping & Payout Setup",
702
+ href: "/store/shipping",
553
703
  cases: [
554
704
  { key: "shipping-page", label: "Store shipping settings page saves correctly", href: "/store/shipping" },
555
705
  { key: "shipping-configs-crud", label: "Creating, editing, and listing shipping configs works", href: "/store/shipping-configs" },
@@ -560,6 +710,7 @@ const rawTesterChecklistItems = [
560
710
  {
561
711
  pageKey: "seller-listing-types",
562
712
  pageLabel: "Seller — All Listing Types (Coupons, Bundles, Classifieds, Digital Codes, Live, Prize Draws, Art, Stickers)",
713
+ href: "/store/products",
563
714
  cases: [
564
715
  { key: "seller-coupons-crud", label: "Seller can create, edit, and list their own coupons", href: "/store/coupons" },
565
716
  { key: "seller-bundles-crud", label: "Seller can create, edit, and list bundles/grouped listings", href: "/store/bundles" },
@@ -585,15 +736,23 @@ const rawTesterChecklistItems = [
585
736
  {
586
737
  pageKey: "seller-catalog-org",
587
738
  pageLabel: "Seller Categories, Sublisting Categories & Listing Templates",
739
+ href: "/store/categories",
588
740
  cases: [
589
741
  { key: "seller-categories-crud", label: "Seller can create and edit their own categories", href: "/store/categories" },
590
742
  { key: "seller-sublisting-categories-crud", label: "Seller can create and edit sublisting categories", href: "/store/sublisting-categories" },
743
+ {
744
+ key: "sublisting-categories-standard-toolbar",
745
+ label: "Seller Sublisting Categories now uses the same search+sort+pagination toolbar and \"New Category\" button placement as every other dashboard listing, instead of its own bespoke layout",
746
+ description: "Converted 2026-08-21 off a fully custom self-contained page onto the standard DataListingView scaffold. Confirm search, sort, and pagination all still work, and the row-level View/Edit/Delete buttons are unchanged.",
747
+ href: "/store/sublisting-categories",
748
+ },
591
749
  { key: "seller-listing-templates-crud", label: "Seller can create, edit, and reuse listing templates when creating a new product", href: "/store/listing-templates" },
592
750
  ],
593
751
  },
594
752
  {
595
753
  pageKey: "seller-ops-comms",
596
754
  pageLabel: "Seller Addresses, Messages, Fulfillment & Print",
755
+ href: "/store/addresses",
597
756
  cases: [
598
757
  { key: "seller-addresses-crud", label: "Seller can add and edit store addresses", href: "/store/addresses" },
599
758
  { key: "seller-messages", label: "Seller messages list and thread view both work", href: "/store/messages" },
@@ -605,6 +764,7 @@ const rawTesterChecklistItems = [
605
764
  {
606
765
  pageKey: "seller-marketing-extras",
607
766
  pageLabel: "Seller Offers, Features, Google Reviews & WhatsApp Catalog",
767
+ href: "/store/offers",
608
768
  cases: [
609
769
  {
610
770
  key: "seller-offers-list",
@@ -621,6 +781,7 @@ const rawTesterChecklistItems = [
621
781
  {
622
782
  pageKey: "seller-guide",
623
783
  pageLabel: "Seller Guide Pages",
784
+ href: "/store/guide",
624
785
  cases: [
625
786
  { key: "seller-guide-pages", label: "The 5 seller guide pages (overview, capabilities, finance, listings, orders, settings) all load correctly", href: "/store/guide" },
626
787
  ],
@@ -628,6 +789,7 @@ const rawTesterChecklistItems = [
628
789
  {
629
790
  pageKey: "store-dashboard-navigation",
630
791
  pageLabel: "Store Dashboard Navigation",
792
+ href: "/store",
631
793
  cases: [
632
794
  { key: "store-sidebar-all-links-work", label: "Every item in the store/seller dashboard sidebar navigates to its page without a 404 or broken layout", href: "/store" },
633
795
  { key: "store-sidebar-active-highlight", label: "The store sidebar correctly highlights the currently active section as you navigate between pages" },
@@ -649,6 +811,7 @@ const rawTesterChecklistItems = [
649
811
  {
650
812
  pageKey: "blog",
651
813
  pageLabel: "Blog",
814
+ href: "/blog",
652
815
  cases: [
653
816
  { key: "read-post", label: "Reading a blog post renders correctly (images, formatting)" },
654
817
  { key: "blog-listing", label: "Blog listing page shows all published posts" },
@@ -665,6 +828,7 @@ const rawTesterChecklistItems = [
665
828
  {
666
829
  pageKey: "events",
667
830
  pageLabel: "Events, Raffles & Spin Wheel",
831
+ href: "/events",
668
832
  cases: [
669
833
  { key: "view-event", label: "Viewing an event detail page works", href: "/user/events" },
670
834
  { key: "events-listing-cards-images", label: "The events listing page shows each event's real cover image (not a generic icon placeholder) when one is set, and all cards in a row are the same height", href: "/events" },
@@ -713,6 +877,7 @@ const rawTesterChecklistItems = [
713
877
  {
714
878
  pageKey: "coupons",
715
879
  pageLabel: "Coupons",
880
+ href: "/user/coupons",
716
881
  cases: [
717
882
  { key: "view-claimed-coupons", label: "Claimed coupons list shows accurate coupons", href: "/user/coupons" },
718
883
  { key: "coupon-discount-applied", label: "Coupon discount is correctly reflected in the order total" },
@@ -725,6 +890,7 @@ const rawTesterChecklistItems = [
725
890
  {
726
891
  pageKey: "notifications",
727
892
  pageLabel: "Notifications",
893
+ href: "/user/notifications",
728
894
  cases: [
729
895
  { key: "receive-notification", label: "In-app notifications appear for order/bid/message events", href: "/user/notifications" },
730
896
  { key: "mark-read", label: "Marking a notification as read works" },
@@ -736,6 +902,7 @@ const rawTesterChecklistItems = [
736
902
  {
737
903
  pageKey: "faq-help",
738
904
  pageLabel: "FAQ & Help",
905
+ href: "/faqs",
739
906
  cases: [
740
907
  { key: "faq-bottom-borders", label: "FAQ question rows show a clear bottom-border divider on the homepage and the FAQs page", href: "/faqs" },
741
908
  { key: "faq-mobile-count", label: "Homepage FAQ section shows a good number of questions on mobile, not just 1-2", href: "/" },
@@ -747,14 +914,22 @@ const rawTesterChecklistItems = [
747
914
  {
748
915
  pageKey: "support-tickets",
749
916
  pageLabel: "Support Tickets",
917
+ href: "/user/support",
750
918
  cases: [
751
919
  { key: "create-ticket", label: "Creating a support ticket works", href: "/user/support" },
752
920
  { key: "reply-ticket", label: "Replying to an open support ticket works" },
921
+ {
922
+ key: "support-tickets-search-box",
923
+ label: "The support tickets list now has a working search box (by subject, id, or category) — it did not have one at all before",
924
+ description: "Converted 2026-08-21 off a hand-wired toolbar (which had status filter + \"hide resolved/closed\" toggle + sort, but no search input) onto the standard DataListingView scaffold, which adds search for free. Confirm typing part of a ticket's subject narrows the list, and the existing status filter + \"Hide resolved/closed\" toggle still work.",
925
+ href: "/user/support",
926
+ },
753
927
  ],
754
928
  },
755
929
  {
756
930
  pageKey: "public-profile",
757
931
  pageLabel: "Public Profiles & Stores",
932
+ href: "/stores",
758
933
  cases: [
759
934
  { key: "view-seller-store", label: "Viewing a seller's public store page works" },
760
935
  { key: "view-public-profile", label: "Viewing another user's public profile works" },
@@ -765,6 +940,7 @@ const rawTesterChecklistItems = [
765
940
  {
766
941
  pageKey: "general-design",
767
942
  pageLabel: "Colors, Styles, Readability, Mobile",
943
+ href: "/",
768
944
  cases: [
769
945
  { key: "contrast-readability", label: "Text contrast/readability is good on product cards" },
770
946
  { key: "mobile-nav", label: "Mobile navigation (bottom bar, menu) works and looks correct" },
@@ -782,9 +958,38 @@ const rawTesterChecklistItems = [
782
958
  },
783
959
  ],
784
960
  },
961
+ {
962
+ pageKey: "form-validation-errors",
963
+ pageLabel: "Form Validation & Error Summary",
964
+ href: "/store/products/new",
965
+ cases: [
966
+ {
967
+ key: "error-summary-shows-beside-submit",
968
+ label: "Submitting an admin/seller form (e.g. new product, new blog post, new event) with missing/invalid required fields shows a clearly-visible list of every problem right beside the Publish/Save button — not a generic \"something went wrong\" message",
969
+ description: "Fixed 2026-08-21 — validation failures previously surfaced as an opaque, unhelpful production error with no indication of which field failed. A new shared FormErrorSummary component now lists every simultaneous issue live.",
970
+ href: "/store/products/new",
971
+ },
972
+ {
973
+ key: "error-summary-live-on-change",
974
+ label: "The error summary beside Publish/Save updates live as you fix a field (the error disappears from the list immediately), not only after you click Submit again",
975
+ href: "/store/products/new",
976
+ },
977
+ {
978
+ key: "error-summary-step-tagged",
979
+ label: "On a multi-step form (e.g. new product wizard), an error for a field on a step you're not currently viewing is labeled with that step's name in the summary, and clicking it jumps you to the correct step",
980
+ href: "/store/products/new",
981
+ },
982
+ {
983
+ key: "error-summary-supplements-inline",
984
+ label: "Field-level inline error messages (shown directly under/beside the input) still appear as before — the new summary is in addition to them, not a replacement",
985
+ href: "/store/products/new",
986
+ },
987
+ ],
988
+ },
785
989
  {
786
990
  pageKey: "dashboard-layout",
787
991
  pageLabel: "Dashboards — Collapsible Sections & Mobile Tables",
992
+ href: "/admin/dashboard",
788
993
  cases: [
789
994
  { key: "collapsible-admin", label: "Admin dashboard sections expand/collapse and remember their state on reload", href: "/admin/dashboard" },
790
995
  { key: "collapsible-store", label: "Store dashboard sections expand/collapse and remember their state on reload", href: "/store" },
@@ -806,11 +1011,18 @@ const rawTesterChecklistItems = [
806
1011
  label: "Row-level action buttons (the same ones in the table's overflow menu — edit, approve, delete, etc.) also appear directly on each list/grid card, not just in the table view",
807
1012
  href: "/admin/orders",
808
1013
  },
1014
+ {
1015
+ key: "listing-toolbar-consistency",
1016
+ label: "Every admin/seller/user dashboard listing page uses the exact same search+filter-drawer+sort-dropdown+pagination toolbar layout — no page has a bespoke, differently-laid-out search/filter UI of its own",
1017
+ description: "A 2026-08-21 sweep found 22 dashboard listings (admin Page Views/Ads/Carousel-adjacent/Event Entries, seller Bids/Orders/Products/Shipping Configs/Payout Methods/Store Categories/Reviews, and 10 user pages — Orders, Returns, Bids, Digital Codes, Events, Pre-Orders, Prize Draws, Reviews, Support, Notifications, plus seller Sublisting Categories) that had each hand-rolled their own toolbar with inconsistent capabilities (some had no search at all, some had no filter drawer). All were migrated onto the shared DataListingView scaffold, and a new strict-zero audit (audit-listing-view-standard.mjs) now blocks any future page from reintroducing a bespoke one. Spot-check 2-3 pages across different portals (e.g. /admin/analytics, /store/payout-methods, /user/support) and confirm they all look and behave identically in toolbar layout.",
1018
+ href: "/admin/analytics",
1019
+ },
809
1020
  ],
810
1021
  },
811
1022
  {
812
1023
  pageKey: "hand-mode-layout",
813
1024
  pageLabel: "Left-Hand Mode",
1025
+ href: "/user/settings",
814
1026
  cases: [
815
1027
  { key: "sidebar-flips", label: "With Left-hand mode ON, the admin/store/user dashboard's persistent left navigation sidebar (and its collapse handle) moves to the right side of the screen; with it OFF (default), the sidebar stays on the left", href: "/admin/dashboard" },
816
1028
  { key: "drawers-flip", label: "With Left-hand mode ON, side drawers/panels (filters, quick-add forms, cart, edit/create panels) that normally slide in from the right now slide in from the left", href: "/products" },
@@ -826,6 +1038,7 @@ const rawTesterChecklistItems = [
826
1038
  {
827
1039
  pageKey: "footer-theme",
828
1040
  pageLabel: "Footer & Dark Mode",
1041
+ href: "/",
829
1042
  cases: [
830
1043
  { key: "footer-dark-mode", label: "Footer background and all link/text colors switch correctly between light and dark mode", href: "/" },
831
1044
  {
@@ -839,6 +1052,7 @@ const rawTesterChecklistItems = [
839
1052
  {
840
1053
  pageKey: "homepage-carousels",
841
1054
  pageLabel: "Homepage Carousels",
1055
+ href: "/",
842
1056
  cases: [
843
1057
  { key: "carousel-loops", label: "Homepage carousels (Shop by Category, Top Brands, Featured Products, Live Auctions, Reserve Before It Ships, Verified Stores, Tournaments & Events, Collector Reviews) loop back to the first item after reaching the last instead of getting stuck at the end", href: "/" },
844
1058
  { key: "carousel-no-flicker", label: "Homepage carousel auto-scroll does not flash/flicker when looping back to the first item" },
@@ -868,6 +1082,7 @@ const rawTesterChecklistItems = [
868
1082
  {
869
1083
  pageKey: "core-listing-pages",
870
1084
  pageLabel: "Homepage & Core Listing Pages",
1085
+ href: "/",
871
1086
  cases: [
872
1087
  { key: "homepage-loads", label: "The homepage loads without errors on both desktop and mobile", href: "/" },
873
1088
  { key: "about-us-in-main-nav", label: "\"About Us\" appears as an item in the main public top navigation, not just the footer", href: "/about" },
@@ -906,11 +1121,18 @@ const rawTesterChecklistItems = [
906
1121
  description: "Verify against \"Beyblade Burst\" (category-beyblade-burst) — Related Categories should show Beyblade Original, Metal Fight, and Beyblade X (siblings under the \"Spinning Tops\" root).",
907
1122
  href: "/categories",
908
1123
  },
1124
+ {
1125
+ key: "category-brand-highlights-faq-grouped-listings",
1126
+ label: "A category detail page shows a highlights list + FAQ accordion right after the hero, a brand detail page shows the same plus an \"About this brand\" panel (website/country/founded), and both show a \"Grouped listings\" carousel populated with real items",
1127
+ description: "Added 2026-08-21 — CategoryDocument previously had no schema field at all for editorial content (highlights/FAQ), and GroupedListingsCarousel had zero public consumers on category/brand pages. Verify against \"Beyblade Burst\" (category-beyblade-burst, /categories/category-beyblade-burst) and \"Takara-Tomy\" (brand-takara-tomy, /brands/brand-takara-tomy) — both should show 3-5 highlight bullets, 2-4 FAQ entries, and (brand only) a working website link + country + founded year.",
1128
+ href: "/categories/category-beyblade-burst",
1129
+ },
909
1130
  ],
910
1131
  },
911
1132
  {
912
1133
  pageKey: "stores-sellers-directories",
913
1134
  pageLabel: "Store & Seller Directories",
1135
+ href: "/stores",
914
1136
  cases: [
915
1137
  { key: "store-directory", label: "The store directory page loads correctly", href: "/stores" },
916
1138
  { key: "store-detail-tabs", label: "A store detail page's listing-type dropdown (Products/Auctions/Pre-Orders/Prize Draws/Bundles/Classifieds/Digital Codes/Live Items/Art & Stickers) switches correctly between listing types, and the separate Coupons/Reviews/About tabs next to it all load correctly", description: "The listing-type dropdown is always a dropdown (not just on narrow/mobile widths, unlike category/brand/product/event tabs) since a store can have up to 9 listing types — Coupons, Reviews, and About stay as standalone tabs beside it, never folded into the dropdown." },
@@ -934,6 +1156,7 @@ const rawTesterChecklistItems = [
934
1156
  {
935
1157
  pageKey: "help-how-it-works",
936
1158
  pageLabel: "Help & How-It-Works Pages",
1159
+ href: "/help",
937
1160
  cases: [
938
1161
  { key: "contact-page", label: "The contact page loads and the form submits correctly", href: "/contact" },
939
1162
  { key: "help-page", label: "The help page loads correctly", href: "/help" },
@@ -944,6 +1167,7 @@ const rawTesterChecklistItems = [
944
1167
  {
945
1168
  pageKey: "legal-policy-pages",
946
1169
  pageLabel: "Legal & Policy Pages",
1170
+ href: "/help",
947
1171
  cases: [
948
1172
  { key: "shipping-refund-policy", label: "Shipping-policy and refund-policy pages load correctly" },
949
1173
  { key: "privacy-cookies-security", label: "Privacy, cookies, and security pages load correctly" },
@@ -952,6 +1176,7 @@ const rawTesterChecklistItems = [
952
1176
  {
953
1177
  pageKey: "auth-error-pages",
954
1178
  pageLabel: "Remaining Auth & Error Pages",
1179
+ href: "/auth/login",
955
1180
  cases: [
956
1181
  { key: "register-page", label: "The register page loads and account creation works", href: "/auth/register" },
957
1182
  { key: "forgot-reset-password-pages", label: "Forgot-password and reset-password pages both work" },
@@ -964,6 +1189,7 @@ const rawTesterChecklistItems = [
964
1189
  {
965
1190
  pageKey: "bug-hunters",
966
1191
  pageLabel: "Bug Hunters Leaderboard",
1192
+ href: "/bug-hunters",
967
1193
  cases: [
968
1194
  {
969
1195
  key: "leaderboard-loads",
@@ -980,6 +1206,7 @@ const rawTesterChecklistItems = [
980
1206
  {
981
1207
  pageKey: "catalog-listings",
982
1208
  pageLabel: "Catalog & Listings",
1209
+ href: "/admin/products",
983
1210
  cases: [
984
1211
  { key: "brands-crud", label: "Admin can create, edit, and list brands", href: "/admin/brands" },
985
1212
  { key: "categories-crud", label: "Admin can create, edit, and list categories", href: "/admin/categories" },
@@ -1006,6 +1233,7 @@ const rawTesterChecklistItems = [
1006
1233
  {
1007
1234
  pageKey: "coupons",
1008
1235
  pageLabel: "Coupons",
1236
+ href: "/admin/coupons",
1009
1237
  cases: [
1010
1238
  { key: "coupon-create-percentage", label: "Admin can create a percentage-type coupon", href: "/admin/coupons/new" },
1011
1239
  { key: "coupon-create-fixed-freeship-bxgy", label: "Admin can create fixed, free_shipping, and buy_x_get_y coupon types" },
@@ -1018,6 +1246,7 @@ const rawTesterChecklistItems = [
1018
1246
  {
1019
1247
  pageKey: "events-raffles-spin",
1020
1248
  pageLabel: "Events, Raffles & Spin Wheel",
1249
+ href: "/admin/events",
1021
1250
  cases: [
1022
1251
  { key: "raffle-create-open", label: "Admin can create an open_raffle event", href: "/admin/events/new" },
1023
1252
  { key: "raffle-create-top-n-scorers", label: "Admin can create a top_n_scorers raffle event" },
@@ -1026,11 +1255,18 @@ const rawTesterChecklistItems = [
1026
1255
  { key: "spin-wheel-create", label: "Admin can create a spin_wheel event with weighted prizes" },
1027
1256
  { key: "spin-wheel-limits-enforced", label: "spinMaxPerUser and spinWindowStart/End are correctly enforced once configured by admin" },
1028
1257
  { key: "event-entries-admin-view", label: "Admin event-entries list shows accurate entries", href: "/admin/event-entries" },
1258
+ {
1259
+ key: "event-entries-view-before-deciding",
1260
+ label: "Admin → Event Entries rows have a \"View details\" action (and are click-openable) showing the entrant's email, points and submitted responses before Confirm / Waitlist / Cancel is used",
1261
+ description: "Fixed 2026-08-21 — the row offered only Confirm/Waitlist/Cancel, so an admin decided an entry's fate without ever seeing what the entrant actually submitted. Open an entry on a poll or survey event and confirm its responses payload is visible in the detail modal.",
1262
+ href: "/admin/event-entries",
1263
+ },
1029
1264
  ],
1030
1265
  },
1031
1266
  {
1032
1267
  pageKey: "prize-draws-lotteries",
1033
1268
  pageLabel: "Prize Draws / Lotteries",
1269
+ href: "/admin/prize-draws",
1034
1270
  cases: [
1035
1271
  { key: "prizedraw-create", label: "Admin can create a prize-draw listing, choosing instant or scheduled reveal mode and a 1–15 day duration", href: "/admin/prize-draws" },
1036
1272
  { key: "prizedraw-reveal-winner", label: "Winners are assigned automatically via crypto.randomInt (on payment confirmation for instant mode, or at expiry/sellout for scheduled mode) — never by a manual admin click" },
@@ -1042,15 +1278,23 @@ const rawTesterChecklistItems = [
1042
1278
  {
1043
1279
  pageKey: "bundles",
1044
1280
  pageLabel: "Bundles / Grouped Listings",
1281
+ href: "/admin/bundles",
1045
1282
  cases: [
1046
1283
  { key: "bundle-create", label: "Admin can create a bundle from existing products", href: "/admin/bundles" },
1047
1284
  { key: "bundle-stock-sync", label: "Bundle stock correctly syncs when a component product's stock changes" },
1048
1285
  { key: "bundle-edit-delete", label: "Admin can edit and delete a bundle" },
1286
+ {
1287
+ key: "bundle-brand-picker",
1288
+ label: "The bundle editor has a \"Brand\" select (Takara-Tomy / Beyblade / No specific brand) that saves to the bundle's own brandSlug field, and that bundle then appears under the matching brand's page",
1289
+ description: "Added 2026-08-21 — bundle→brand association used to be a fragile heuristic (checking the brand name against seo.keywords), replaced with a real brandSlug field. Edit an existing bundle (e.g. \"Original Series Collector's Set\"), confirm the Brand select shows its current brand, change it, save, and verify it now appears on the new brand's page instead of the old one.",
1290
+ href: "/admin/bundles",
1291
+ },
1049
1292
  ],
1050
1293
  },
1051
1294
  {
1052
1295
  pageKey: "classifieds-digitalcodes-live",
1053
1296
  pageLabel: "Classifieds, Digital Codes & Live Listings",
1297
+ href: "/admin/classified",
1054
1298
  cases: [
1055
1299
  { key: "classified-create-moderate", label: "Admin can create and moderate classified listings", href: "/admin/classified" },
1056
1300
  { key: "digitalcode-create-moderate", label: "Admin can create and moderate digital-code listings", href: "/admin/digital-codes" },
@@ -1060,6 +1304,7 @@ const rawTesterChecklistItems = [
1060
1304
  {
1061
1305
  pageKey: "blog-faqs",
1062
1306
  pageLabel: "Blog & FAQs",
1307
+ href: "/admin/blog",
1063
1308
  cases: [
1064
1309
  { key: "blog-create-edit-publish", label: "Admin can create, edit, and publish a blog post", href: "/admin/blog" },
1065
1310
  { key: "blog-media-step-save", label: "On the blog editor's Media step, setting a Cover Image and/or a YouTube Video ID and saving succeeds (no validation error) and both persist correctly when reopening the post for edit" },
@@ -1069,8 +1314,47 @@ const rawTesterChecklistItems = [
1069
1314
  {
1070
1315
  pageKey: "orders-fulfillment",
1071
1316
  pageLabel: "Orders & Fulfillment",
1317
+ href: "/admin/orders",
1072
1318
  cases: [
1073
1319
  { key: "orders-status-change", label: "Admin orders list shows accurate orders and status changes save correctly", href: "/admin/orders" },
1320
+ {
1321
+ key: "admin-orders-payment-review-filters",
1322
+ label: "The Admin Orders filter drawer has a \"Manual payment\" chip group with \"Awaiting payment\" and \"Awaiting verification\" — and each one actually returns the right orders",
1323
+ description: "Added 2026-08-21 — before this there was no way to find manual-payment orders needing action; they were indistinguishable from any other pending order. \"Awaiting payment\" = buyer hasn't uploaded a screenshot yet. \"Awaiting verification\" = proof submitted, nobody has approved/rejected it. Place a UPI/Cash order and check it appears under \"Awaiting payment\"; upload proof and confirm it moves to \"Awaiting verification\". Picking a Manual-payment chip clears the Status chip (and vice versa) on purpose — the queue is always status=pending, so combining them could only ever return nothing.",
1324
+ href: "/admin/orders",
1325
+ },
1326
+ {
1327
+ key: "admin-orders-payment-state-on-row",
1328
+ label: "Each manual-payment order's row in the Admin Orders list shows its payment state inline (\"Awaiting payment\" / \"Awaiting verification\" / \"Payment verified\" / \"Re-upload requested\" / \"Payment rejected\") — you don't have to open the drawer to tell which ones need action",
1329
+ href: "/admin/orders",
1330
+ },
1331
+ {
1332
+ key: "admin-orders-view-payment-proof",
1333
+ label: "Opening a manual-payment order shows the buyer's payment screenshot, the UTR, the expected-vs-reported UPI IDs, and a red \"UPI mismatch\" warning when they disagree",
1334
+ href: "/admin/orders",
1335
+ },
1336
+ {
1337
+ key: "admin-orders-verify-payment",
1338
+ label: "\"Verify payment\" on an order with submitted proof marks it paid and moves it to Processing — and it then disappears from the \"Awaiting verification\" queue",
1339
+ href: "/admin/orders",
1340
+ },
1341
+ {
1342
+ key: "admin-orders-request-reupload",
1343
+ label: "\"Request re-upload\" (requires a review note) clears the buyer's proof, gives them another 15 minutes, and sends them a notification containing the note",
1344
+ description: "Pair with the buyer-side case `manual-payment-reupload-note-visible-to-buyer`. Critically, verify the buyer CAN actually re-submit afterwards, and that the re-submitted proof shows up again under admin \"Awaiting verification\" — a 2026-08-21 fix; previously the re-upload left a stale review outcome on the order, so the corrected proof was invisible to both the admin queue and the 2-hour auto-approve sweep, and the order just silently stalled.",
1345
+ href: "/admin/orders",
1346
+ },
1347
+ {
1348
+ key: "admin-orders-reject-fraud",
1349
+ label: "\"Reject as fraud\" (requires a review note) cancels the order, returns the item to stock, and suspends the buyer's account for 7 days",
1350
+ description: "Use a throwaway buyer account — this really does ban it. Confirm the stock actually goes back up on the product page, and that the banned account can't sign in.",
1351
+ href: "/admin/orders",
1352
+ },
1353
+ {
1354
+ key: "admin-orders-payment-actions-hidden-when-paid",
1355
+ label: "Once a payment is verified, the Verify / Request re-upload / Reject buttons are replaced by a \"Payment verified\" badge — an already-paid order can't be re-verified or rejected",
1356
+ href: "/admin/orders",
1357
+ },
1074
1358
  { key: "bids-admin-view", label: "Admin bids view shows accurate bid data", href: "/admin/bids" },
1075
1359
  { key: "return-requests-triage", label: "Admin can triage return requests", href: "/admin/return-requests" },
1076
1360
  { key: "fulfillment-queue-admin", label: "Admin fulfillment queue shows accurate pending items", href: "/admin/fulfillment" },
@@ -1078,13 +1362,32 @@ const rawTesterChecklistItems = [
1078
1362
  { key: "print-center-admin", label: "Admin print-center generates labels/invoices correctly", href: "/admin/print-center" },
1079
1363
  { key: "payouts-export-admin", label: "Admin can export payouts", href: "/admin/payouts" },
1080
1364
  { key: "bulk-action-realtime-progress", label: "A bulk admin action (e.g. bulk order status update) shows live progress via the bulk_events realtime channel and resolves without polling" },
1365
+ {
1366
+ key: "admin-order-list-item-and-detail",
1367
+ label: "Admin order list rows show the order's item (thumbnail + title), not a raw order id, and clicking through (or \"Open full page\") shows the full items list on the order detail",
1368
+ description: "Fixed 2026-08-21 — AdminOrdersView.mapRows built \"Order {id}\" from a nonexistent orderNumber field, and AdminOrderEditorView showed zero items even when opened. Both now read the order's already-denormalized items[] (Root Cause #52).",
1369
+ href: "/admin/orders",
1370
+ },
1371
+ {
1372
+ key: "admin-payout-detail-view",
1373
+ label: "Every admin payout row has an \"Open full page\" action + a working \"Mark as paid\" action, landing on a real /admin/payouts/[id]/view page with a full gross/platform-fee/gateway-fee/GST/refund-deduction/net breakdown and linked order ids — not just a bare \"transaction ID\" modal",
1374
+ description: "Added 2026-08-21 — admin payouts previously had no detail view of any kind. Open any payout from /admin/payouts and confirm the breakdown numbers add up (gross − fees − deductions = net).",
1375
+ href: "/admin/payouts",
1376
+ },
1081
1377
  ],
1082
1378
  },
1083
1379
  {
1084
1380
  pageKey: "users-trust",
1085
1381
  pageLabel: "Users & Trust",
1382
+ href: "/admin/users",
1086
1383
  cases: [
1087
1384
  { key: "users-role-change", label: "Admin can change a user's role and toggle isTester/canTestAdmin", href: "/admin/users" },
1385
+ {
1386
+ key: "admin-user-detail-enriched",
1387
+ label: "An admin user's own detail page (/admin/users/[id]) shows an avatar, stat tiles (orders/auctions won/items sold/reviews/rating), the user's public profile (bio/location/website/social links), last-sign-in + login count, and a small inline address list — not just 3 plain text lines",
1388
+ description: "Fixed 2026-08-21 — the page fetched the full UserDocument but rendered almost none of it. Open any real user (e.g. a tester or seller persona) from /admin/users and confirm the header/stats/profile/addresses sections are populated, not blank.",
1389
+ href: "/admin/users",
1390
+ },
1088
1391
  {
1089
1392
  key: "admin-delete-user-complete",
1090
1393
  label: "Deleting a user from the admin Users editor removes their Firestore profile, their active sessions, AND their Firebase Auth record — not just the Firestore doc",
@@ -1102,11 +1405,18 @@ const rawTesterChecklistItems = [
1102
1405
  { key: "reports-admin", label: "Admin reports queue works correctly", href: "/admin/reports" },
1103
1406
  { key: "payment-methods-clusters-admin", label: "Admin can manage payment methods and payment-method clusters", href: "/admin/payment-methods" },
1104
1407
  { key: "catalogue-approvals-admin", label: "Admin can approve/reject personal catalogue submissions", href: "/admin/catalogue-approvals" },
1408
+ {
1409
+ key: "catalogue-approvals-view-before-deciding",
1410
+ label: "Admin → Catalogue Approvals rows have a \"View\" action (and are click-openable) showing the submitted item's PHOTOS, description, estimated price, quantity and condition — with Approve and Reject available from inside that detail view",
1411
+ description: "Fixed 2026-08-21 — the row previously offered only Approve/Reject buttons, so an admin accepted or refused a user's submission with none of its content rendered anywhere: no photos, no description, no price. This was the most severe finding of the dead-end-listing sweep. Confirm you can see the item's images before deciding, and that approving/rejecting from inside the modal behaves the same as the row buttons (reject still prompts for a reason the owner will see).",
1412
+ href: "/admin/catalogue-approvals",
1413
+ },
1105
1414
  ],
1106
1415
  },
1107
1416
  {
1108
1417
  pageKey: "content-marketing",
1109
1418
  pageLabel: "Content & Marketing",
1419
+ href: "/admin/ads",
1110
1420
  cases: [
1111
1421
  { key: "ads-crud-preview", label: "Admin can create, edit, and preview ads", href: "/admin/ads" },
1112
1422
  { key: "newsletter-export-admin", label: "Admin can export the newsletter subscriber list", href: "/admin/newsletter" },
@@ -1120,6 +1430,7 @@ const rawTesterChecklistItems = [
1120
1430
  {
1121
1431
  pageKey: "site-system",
1122
1432
  pageLabel: "Site & System",
1433
+ href: "/admin/site",
1123
1434
  cases: [
1124
1435
  { key: "site-settings-admin", label: "Admin site settings page saves correctly", href: "/admin/site" },
1125
1436
  {
@@ -1128,14 +1439,63 @@ const rawTesterChecklistItems = [
1128
1439
  description: "Each tier row has an editable \"up to (₹)\" amount and \"increment (₹)\" amount; the last row is fixed as \"and above\" (open-ended) and can't have its threshold edited. Add a new tier, edit an existing increment, remove a tier, save, then reload the Site Settings page and confirm the tier list matches what was saved — not reverted to the old defaults.",
1129
1440
  href: "/admin/site",
1130
1441
  },
1442
+ {
1443
+ key: "daily-digest-recipients-save",
1444
+ label: "Site Settings → Notifications → \"Daily status digest\" saves its recipient and CC lists (one address per line) and they survive a page reload",
1445
+ description: "Added 2026-08-21. Toggle the digest on, enter a couple of addresses in Recipients (one per line) and one in CC, save, then reload Site Settings and confirm both lists come back exactly as entered. Also confirm the whole recipients/CC block is hidden when the toggle is off.",
1446
+ href: "/admin/site",
1447
+ },
1448
+ {
1449
+ key: "daily-digest-on-deploy",
1450
+ label: "A digest email arrives once after a new version is deployed — exactly once per deployment, not repeatedly as the site gets traffic",
1451
+ description: "Added 2026-08-21. The deploy digest fires from server startup, which on Vercel happens on every serverless cold start — so it's guarded by a stored version marker and only the first cold start of a given deployment sends. After a deploy, confirm: (a) one digest arrives whose body opens with \"Deployment <version> is live.\"; (b) browsing the site for a while (forcing more cold starts) does NOT produce further copies; (c) the next deploy produces exactly one new email again.",
1452
+ href: "/admin/site",
1453
+ },
1454
+ {
1455
+ key: "daily-digest-email-content",
1456
+ label: "The daily status digest email arrives with subject exactly \"Daily Status\" and shows the last 24h order count, revenue, active listings, pending-over-24h count, and a per-status breakdown",
1457
+ // audit-hardcoded-api-routes-ok: prose in a tester-facing description (a copy-pasteable console snippet), not a call site — nothing to route through the registry.
1458
+ description: "Added 2026-08-21. The digest runs automatically at 10:00 IST, but you don't need to wait — an admin can trigger it on demand by POSTing to /api/admin/daily-digest/trigger (e.g. from the browser console while logged in as admin: fetch('/api/admin/daily-digest/trigger',{method:'POST'})). Confirm the email reaches every configured recipient AND any CC addresses, and that the numbers match what the admin orders list actually shows for the last 24 hours. Note: this requires the Firebase Functions deploy to have happened for the scheduled 10:00 run — the manual trigger works regardless.",
1459
+ href: "/admin/site",
1460
+ },
1131
1461
  { key: "admin-dashboard-widgets", label: "Admin dashboard widgets show accurate data", href: "/admin/dashboard" },
1132
1462
  { key: "analytics-admin", label: "Admin analytics dashboard shows accurate data", href: "/admin/analytics" },
1463
+ {
1464
+ key: "pageviews-report-listing-standard",
1465
+ label: "The \"Page Views\" tab in Admin Analytics is a full standard listing — a search box (by entity id or URL), an entity-type filter drawer, a \"Most views\"/\"Fewest views\" sort dropdown, and real pagination — not a bare unsearchable table",
1466
+ description: "Converted 2026-08-21 off a hand-rolled two-table layout onto the standard DataListingView scaffold. Switch to the Page Views tab, confirm the search box and filter drawer are present and actually narrow the rows, the sort dropdown reorders by view count, and clicking a row's entity/URL navigates to that real page.",
1467
+ href: "/admin/analytics",
1468
+ },
1469
+ {
1470
+ key: "pageviews-tracks-all-listing-types",
1471
+ label: "Visiting a blog post, event, pre-order, prize draw, classified, digital-code, live item, or bundle detail page records a page view that shows up in Admin Analytics → Page Views, filtered to that entity type",
1472
+ description: "Added 2026-08-21 — these 8 detail-page types previously recorded nothing at all (only products/auctions/categories/homepage/stores/reviews/profiles were tracked). Visit a few of the following, then filter the Page Views report to the matching entity type and confirm a row appears: /blog/spot-genuine-takara-tomy-beyblade (blog), /events/event-original-series-clearance (event), /pre-orders/preorder-tester-sandbox-1 (pre-order), /prize-draws/prizedraw-tester-sandbox-1 (prize-draw), /classified/classified-tester-sandbox-1 (classified), /digital-codes/digitalcode-tester-sandbox-1 (digital-code), /live/live-tester-sandbox-1 (live), /bundles/bundle-tester-sandbox (bundle).",
1473
+ href: "/blog/spot-genuine-takara-tomy-beyblade",
1474
+ },
1133
1475
  { key: "maintenance-pages-admin", label: "The maintenance pages (analysis, client-errors, cloud-logs, function-errors, payment-rollbacks, server-errors + detail) all load correctly", href: "/admin/maintenance" },
1134
1476
  { key: "copilot-admin", label: "Admin copilot page works correctly", href: "/admin/copilot" },
1135
1477
  { key: "team-admin", label: "Admin team page works correctly", href: "/admin/team" },
1136
1478
  { key: "guide-pages-admin", label: "The 8 admin guide pages all load correctly", href: "/admin/guide" },
1137
1479
  { key: "tester-checklist-crud-admin", label: "Admin can create, edit, and toggle adminOnly on tester checklist items", href: "/admin/tester-checklist" },
1138
1480
  { key: "tester-feedback-report-export", label: "Admin tester-feedback report shows Yes/No analytics grouped correctly and the Download Report export works", href: "/admin/tester-feedback" },
1481
+ {
1482
+ key: "tester-feedback-view-before-confirming-bug",
1483
+ label: "Admin → Tester Feedback rows have a \"View details\" action (and are click-openable) showing the tester's full comment and screenshot before \"Confirm bug\" is used",
1484
+ description: "Fixed 2026-08-21 — the row truncated the comment into a one-line secondary and never surfaced the screenshot at all, yet offered \"Mark reviewed\" and \"Confirm bug\" (which credits the reporting tester and disables the checklist item). Answer a checklist item \"No\" with a comment + screenshot as a tester, then confirm an admin can read both in the detail modal.",
1485
+ href: "/admin/tester-feedback",
1486
+ },
1487
+ {
1488
+ key: "admin-audit-log-page",
1489
+ label: "The new /admin/audit-log page (Finance nav group) lists real entries — actor, action, target, date — with working Action and Actor UID filters, and clicking a row opens a detail modal with the full reason + metadata payload",
1490
+ description: "Added 2026-08-21 — no admin action audit trail existed anywhere before this (the only prior \"logs\" surface was raw Cloud Logging infra output, not actor/action semantics). Perform any instrumented action — hard-ban/soft-ban/unban a test user, mark a payout paid, edit a coupon, change a store's status, change a user's role, or use admin checkout bypass — then confirm a matching entry appears here within a few seconds.",
1491
+ href: "/admin/audit-log",
1492
+ },
1493
+ {
1494
+ key: "admin-notification-detail-modal",
1495
+ label: "Admin Notifications rows have a \"View details\" action (and the row itself is clickable) opening a modal with the full title/message/image/related-entity/action-link — not list-only with just Resend/Delete",
1496
+ description: "Added 2026-08-21 — admin/notifications was list-only before, with no way to see a notification's full body/payload/link.",
1497
+ href: "/admin/notifications",
1498
+ },
1139
1499
  {
1140
1500
  key: "admin-sidebar-logout-button",
1141
1501
  label: "The admin dashboard sidebar has a visible \"Log out\" action at the bottom (not just the header profile dropdown), and clicking it signs out and redirects to login",
@@ -1152,20 +1512,46 @@ const rawTesterChecklistItems = [
1152
1512
  {
1153
1513
  pageKey: "buyer-data-admin",
1154
1514
  pageLabel: "Buyer-Data Admin Views",
1515
+ href: "/admin/carts",
1155
1516
  cases: [
1156
1517
  { key: "carts-admin-view", label: "Admin carts view shows accurate data", href: "/admin/carts" },
1518
+ {
1519
+ key: "carts-admin-row-opens-items",
1520
+ label: "Clicking a row on Admin → Carts opens a detail modal listing the actual items in that cart (thumbnail, title, quantity, line total) — not just the \"N items\" count the row already showed",
1521
+ description: "Fixed 2026-08-21 — the list response always contained the cart's items[] array, but mapRows only ever read `.length` for the row subtitle and discarded the rest, with no surface to show it (Root Cause #52). Open a cart that has at least one item and confirm each item renders with a thumbnail; a guest cart should show its session id, an authenticated one its user id.",
1522
+ href: "/admin/carts",
1523
+ },
1157
1524
  { key: "wishlists-admin-view", label: "Admin wishlists view shows accurate data", href: "/admin/wishlists" },
1525
+ {
1526
+ key: "wishlists-history-admin-row-opens-user",
1527
+ label: "Clicking a row on Admin → Wishlists or Admin → History navigates to that user's admin detail page",
1528
+ description: "Added 2026-08-21 — both rows were previously inert. Their list APIs deliberately return only a per-user summary (userId / itemCount / cap state), never the items themselves, since pulling every user's items into one payload would breach the Vercel Hobby response ceiling (Rule #6) — so the row already shows its whole record and the useful destination is the owning user. Confirm the click lands on /admin/users/{that user's id} and that page loads their real profile.",
1529
+ href: "/admin/wishlists",
1530
+ },
1158
1531
  { key: "history-admin-view", label: "Admin history view shows accurate data", href: "/admin/history" },
1159
1532
  { key: "notifications-admin-view", label: "Admin notifications and admin-notifications views show accurate data" },
1160
1533
  { key: "reviews-admin-view", label: "Admin reviews view shows accurate data", href: "/admin/reviews" },
1161
1534
  { key: "store-addresses-admin", label: "Admin store-addresses view shows accurate data", href: "/admin/store-addresses" },
1535
+ {
1536
+ key: "store-addresses-admin-row-opens-detail",
1537
+ label: "Clicking a row on Admin → Store Addresses opens a detail modal with the full address (contact name, phone, both address lines, landmark, city, state, postal code, country) and a \"Default pickup location\" badge where applicable",
1538
+ description: "Added 2026-08-21 — the row was completely inert (no click, no row actions, no editor) and truncated the address to label/city/state, so the phone and street lines were unreachable anywhere in the admin UI.",
1539
+ href: "/admin/store-addresses",
1540
+ },
1162
1541
  { key: "addresses-crud-admin", label: "Admin can create and edit addresses", href: "/admin/addresses" },
1163
1542
  { key: "stores-admin-view", label: "Admin stores view shows accurate data", href: "/admin/stores" },
1543
+ {
1544
+ key: "admin-store-detail-page",
1545
+ label: "Every admin store row's row menu has a \"View full page\" action landing on a real dedicated /admin/stores/[id]/view page — logo, status/verified/featured badges, an owner link to that owner's (now-enriched) user page, stats (products/items sold/reviews/rating), capabilities, and a \"Manage\" button opening the existing edit drawer",
1546
+ description: "Added 2026-08-21 — admin previously had no dedicated store detail page at all, only the edit drawer (no logo, no owner link, no stats). From /admin/stores, open the seeded \"Tester Sandbox Store\" (store-tester-sandbox) and confirm every section renders real data, and the owner link lands on that seller's admin user page.",
1547
+ href: "/admin/stores",
1548
+ },
1164
1549
  ],
1165
1550
  },
1166
1551
  {
1167
1552
  pageKey: "media-watermark",
1168
1553
  pageLabel: "Media Watermark Settings",
1554
+ href: "/admin/site",
1169
1555
  cases: [
1170
1556
  { key: "watermark-size-opacity-controls", label: "Adjusting the watermark Size and Opacity sliders in Site Settings → Watermark visibly changes how prominent the watermark is on newly-loaded product images", href: "/admin/site" },
1171
1557
  { key: "watermark-position-presets", label: "Each of the 5 watermark Position presets (Center, Top left, Top right, Bottom left, Bottom right) correctly repositions the watermark on newly-loaded images" },
@@ -1177,6 +1563,7 @@ const rawTesterChecklistItems = [
1177
1563
  {
1178
1564
  pageKey: "bug-hunter-rewards",
1179
1565
  pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
1566
+ href: "/admin/tester-feedback",
1180
1567
  cases: [
1181
1568
  {
1182
1569
  key: "confirm-bug",
@@ -1216,6 +1603,7 @@ const rawTesterChecklistItems = [
1216
1603
  pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
1217
1604
  label: "Demo fixture — reported bug, already confirmed and reopened (v1, disabled)",
1218
1605
  description: "Seed-only fixture demonstrating a confirmed bug: this v1 case is disabled (isActive:false) and credited to \"Mock User 18\". Its retest is \"Demo fixture — reported bug, already confirmed and reopened (v2, active)\" in this same page.",
1606
+ href: "/admin/tester-checklist",
1219
1607
  order: 100,
1220
1608
  isActive: false,
1221
1609
  adminOnly: true,
@@ -1234,6 +1622,7 @@ const rawTesterChecklistItems = [
1234
1622
  pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
1235
1623
  label: "Demo fixture — reported bug, already confirmed and reopened (v2, active)",
1236
1624
  description: "Seed-only fixture — the retest version reopened from the disabled v1 case in this same page. Active and answerable again; a fresh \"No\" answer here can be used to try Mark as Bug end-to-end.",
1625
+ href: "/admin/tester-checklist",
1237
1626
  order: 101,
1238
1627
  isActive: true,
1239
1628
  adminOnly: true,