@mohasinac/appkit 4.39.1 → 4.40.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 (39) hide show
  1. package/dist/_internal/server/jobs/core/countersReconcile.js +21 -0
  2. package/dist/_internal/server/jobs/core/onProductWrite.js +35 -1
  3. package/dist/features/categories/components/CategoryDetailPageView.js +17 -5
  4. package/dist/features/categories/repository/categories.repository.d.ts +65 -1
  5. package/dist/features/categories/repository/categories.repository.js +264 -78
  6. package/dist/features/categories/types/index.d.ts +2 -2
  7. package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.d.ts +2 -0
  8. package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +145 -0
  9. package/dist/features/tester/seed-data/authored/admin__firebase-function-effects.d.ts +2 -0
  10. package/dist/features/tester/seed-data/authored/admin__firebase-function-effects.js +234 -0
  11. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +32 -0
  12. package/dist/features/tester/seed-data/authored/buying__cart.js +60 -0
  13. package/dist/features/tester/seed-data/authored/buying__order-detail-actions.d.ts +2 -0
  14. package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +138 -0
  15. package/dist/features/tester/seed-data/authored/buying__wishlist-history.js +30 -0
  16. package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.d.ts +2 -0
  17. package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +145 -0
  18. package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.d.ts +2 -0
  19. package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +154 -0
  20. package/dist/features/tester/seed-data/authored/content-discovery__store-reviews-aggregate.d.ts +2 -0
  21. package/dist/features/tester/seed-data/authored/content-discovery__store-reviews-aggregate.js +88 -0
  22. package/dist/features/tester/seed-data/authored/index.js +22 -0
  23. package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +134 -7
  24. package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +89 -0
  25. package/dist/features/tester/seed-data/authored/public-pages__newly-wired-browse-indexes.d.ts +2 -0
  26. package/dist/features/tester/seed-data/authored/public-pages__newly-wired-browse-indexes.js +141 -0
  27. package/dist/features/tester/seed-data/authored/public-pages__store-tabs.d.ts +2 -0
  28. package/dist/features/tester/seed-data/authored/public-pages__store-tabs.js +115 -0
  29. package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.d.ts +2 -0
  30. package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.js +148 -0
  31. package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.d.ts +2 -0
  32. package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +118 -0
  33. package/dist/features/tester/seed-data/authored/selling__seller-orders-at-scale.d.ts +2 -0
  34. package/dist/features/tester/seed-data/authored/selling__seller-orders-at-scale.js +69 -0
  35. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +471 -0
  36. package/dist/styles.css +1 -1
  37. package/dist/tailwind-utilities.css +1 -1
  38. package/dist/ui/components/tabs-overflow.js +30 -7
  39. package/package.json +1 -1
@@ -0,0 +1,148 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for selling/digital-content-delivery.
3
+ * WHAT: 8 cases, keyed by full checklist id.
4
+ *
5
+ * 🛑 THE POOL HAD NO WRITER (Root Cause #103). Its one seller-facing route
6
+ * answered `501 not implemented`, so the pool was empty in every environment,
7
+ * always — and the claim at checkout logged "code pool exhausted" and returned
8
+ * SILENTLY. The order completed normally and the buyer's reveal panel answered
9
+ * 404. Nothing errored, and the seller form's "Code Pool Size" field made the
10
+ * listing advertise stock that had never existed.
11
+ *
12
+ * So the first case here is deliberately about the EMPTY state, and several
13
+ * others assert a number moving rather than a screen appearing: "the reveal
14
+ * page loads" was true throughout the entire period the feature delivered
15
+ * nothing.
16
+ *
17
+ * @tag domain:tester
18
+ * @tag layer:seed
19
+ * @tag pattern:none
20
+ * @tag access:server-only
21
+ * @tag consumers:seed-data/authored/index.ts
22
+ * @tag sideEffects:none
23
+ */
24
+ export const authored = {
25
+ "checklist-selling-digital-content-delivery-pool-empty-by-default": {
26
+ roles: ["seller"],
27
+ startPage: "/store/digital-codes",
28
+ steps: [
29
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
30
+ "Open /store/digital-codes and open any listing's Edit action.",
31
+ "Scroll to the Code Details section.",
32
+ "Read the pool area beneath the delivery fields.",
33
+ ],
34
+ expectedBehaviour: "The editor states what the listing will actually deliver. A listing whose pool is empty can still be bought, and the buyer receives nothing — so the editor has to say that rather than leave the seller to infer it from a Pool Size field they typed themselves.",
35
+ expectedUiState: "A pool area is present, showing an available count and an already-delivered count. It says in words that an empty pool delivers nothing.",
36
+ expectedData: { poolSectionVisible: true },
37
+ endResult: "Nothing is saved; the section was only read.",
38
+ },
39
+ "checklist-selling-digital-content-delivery-add-codes-bulk": {
40
+ roles: ["seller"],
41
+ startPage: "/store/digital-codes",
42
+ steps: [
43
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
44
+ "Open any digital-code listing's Edit action and find the pool section.",
45
+ "Write down the current available count.",
46
+ "Paste exactly these four lines into the Add codes box: TEST-AAA, TEST-BBB, TEST-AAA, TEST-CCC — one per line.",
47
+ "Press Add codes.",
48
+ "Read the available count.",
49
+ "Reload the page and read the available count again.",
50
+ ],
51
+ inputs: { pasted: "TEST-AAA\nTEST-BBB\nTEST-AAA\nTEST-CCC", distinctCodes: 3 },
52
+ expectedBehaviour: "Four lines containing three distinct codes add three entries. A duplicate inside one paste is dropped: re-pasting a list is the obvious way to double a pool by accident, and a duplicated code means a second buyer is sold something already delivered.",
53
+ expectedUiState: "The available count rises by exactly 3, and three new rows appear in the list, each reading Code / available.",
54
+ expectedData: { availableDelta: 3 },
55
+ endResult: "After the reload the count is still the original plus 3 — the entries are stored, not just rendered.",
56
+ },
57
+ "checklist-selling-digital-content-delivery-buy-then-reveal-code": {
58
+ roles: ["buyer"],
59
+ startPage: "/digital-codes",
60
+ steps: [
61
+ "Sign in as the bot buyer claude-tester@letitrip.in / TempPass123!.",
62
+ "Open /digital-codes and open a listing that shows codes available.",
63
+ "Add it to the cart and complete checkout.",
64
+ "Open /user/digital-codes.",
65
+ "Find the row for what you just bought and press Reveal Code.",
66
+ "Read what appears.",
67
+ ],
68
+ expectedBehaviour: "The purchase claims one entry from that listing's pool and hands it to this buyer. If the pool is empty the claim logs and returns silently — the order still completes, so an order confirmation is NOT evidence that anything was delivered.",
69
+ expectedUiState: "A real code is shown in a monospace box with a Copy button. Not an error, and not 'No code found for this order'.",
70
+ expectedData: { codeRevealed: true },
71
+ endResult: "Reloading /user/digital-codes and revealing again shows the SAME code — it was claimed for this order, not generated on demand.",
72
+ },
73
+ "checklist-selling-digital-content-delivery-available-count-drops-after-purchase": {
74
+ roles: ["buyer", "seller"],
75
+ startPage: "/digital-codes",
76
+ steps: [
77
+ "Open a digital-code listing's public page and write down the codes-available number it shows.",
78
+ "Sign in as the bot buyer claude-tester@letitrip.in / TempPass123! and buy that listing.",
79
+ "Reload the listing's public page and read the number again.",
80
+ ],
81
+ expectedBehaviour: "The counter is derived from the pool, so a claim reduces it. A counter a human typed into the seller form and that nothing recomputes will sit at its original value forever — which lets a sold-out listing keep advertising stock, because the availability predicate reads exactly that field.",
82
+ expectedUiState: "The number shown is one lower than before the purchase.",
83
+ expectedData: { availableDelta: -1 },
84
+ endResult: "The lower number survives a reload.",
85
+ },
86
+ "checklist-selling-digital-content-delivery-claimed-entry-cannot-be-removed": {
87
+ roles: ["seller"],
88
+ startPage: "/store/digital-codes",
89
+ steps: [
90
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
91
+ "Open the Edit action for the listing a code was just bought from.",
92
+ "Find the pool list and locate the row whose status reads claimed.",
93
+ "Look for a Remove button on that row.",
94
+ "Look at a row whose status reads available and compare.",
95
+ ],
96
+ expectedBehaviour: "A claimed entry is somebody's purchase. Deleting it makes their reveal answer 404 with no record of what they bought, so the control is absent AND the server refuses it — the UI alone is not the boundary.",
97
+ expectedUiState: "The claimed row has no Remove button. The available row does.",
98
+ expectedData: { removeOnClaimedRow: false },
99
+ endResult: "The claimed entry is still present after a reload.",
100
+ },
101
+ "checklist-selling-digital-content-delivery-asset-download-requires-ownership": {
102
+ roles: ["guest", "buyer"],
103
+ startPage: "/user/orders",
104
+ steps: [
105
+ "Sign in as the bot buyer and open an order for a digital listing that delivered an image or a file.",
106
+ "Press Reveal, then press Download, and confirm the file arrives.",
107
+ "Copy the download URL from the address bar or the network panel.",
108
+ "Open a private window with no session and paste that URL.",
109
+ "Read what comes back.",
110
+ "Sign in as a DIFFERENT buyer in that window and load the same URL again.",
111
+ ],
112
+ expectedBehaviour: "The bytes live outside the public media path and are served only by an authenticated route that re-checks order ownership on every hit. A URL that works while signed out means the asset is reachable by anyone who learns the path — and product media filenames here are content-derived and therefore guessable.",
113
+ expectedUiState: "The buyer gets the file. The signed-out window and the other buyer both get a not-found page, not the file and not a sign-in redirect that then serves it.",
114
+ expectedData: { guestGetsFile: false, otherBuyerGetsFile: false },
115
+ endResult: "Nothing about the order changes. The buyer can still download it afterwards.",
116
+ },
117
+ "checklist-selling-digital-content-delivery-seller-cannot-upload-non-image": {
118
+ roles: ["seller", "admin"],
119
+ startPage: "/store/digital-codes",
120
+ steps: [
121
+ "Sign in as tyson@beybladearena.in / TempPass123! and open a digital-code listing's Edit action.",
122
+ "In the pool section, press the upload button and read its label.",
123
+ "Choose a PNG image and confirm it is accepted.",
124
+ "Try to choose a PDF and note whether the picker even offers it.",
125
+ "Sign out and sign in as admin@letitrip.in / TempPass123!.",
126
+ "Open the same listing's Edit action and read the upload button's label.",
127
+ "Try a PDF as admin.",
128
+ ],
129
+ expectedBehaviour: "A seller may attach the QR image they were given; any other file type is staff-only, because those bytes are later streamed to a buyer and a mislabelled document served inline is stored XSS. The rule is enforced on the server at BOTH the sign and the finalize step — hiding the button is convenience, not the boundary.",
130
+ expectedUiState: "As seller the button reads 'Upload QR image' and the picker is restricted to images. As admin it reads 'Upload QR or file' and a PDF is accepted.",
131
+ expectedData: { sellerPdfAccepted: false, adminPdfAccepted: true },
132
+ endResult: "Whatever was accepted is present in the pool after a reload.",
133
+ },
134
+ "checklist-selling-digital-content-delivery-pool-list-never-shows-the-code": {
135
+ roles: ["seller"],
136
+ startPage: "/store/digital-codes",
137
+ steps: [
138
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
139
+ "Open a digital-code listing's Edit action and find the pool list.",
140
+ "Read every column of a row whose status is available.",
141
+ "Open the browser network panel, reload, and read the response body of the request that fetched the pool.",
142
+ ],
143
+ expectedBehaviour: "The pool view answers 'how many are left', not 'what are they'. The response is an allow-list, so the code and the asset path are absent from the payload rather than merely unrendered — a field that reaches the browser has been disclosed whether or not a component draws it.",
144
+ expectedUiState: "Each row shows a kind (Code / QR / File), a status, and a filename for assets. No row shows a redemption code.",
145
+ expectedData: { codeInResponseBody: false },
146
+ endResult: "Nothing is changed; this case only reads.",
147
+ },
148
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,118 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for selling/listing-edit-roundtrip.
3
+ * WHAT: 6 cases, keyed by full checklist id.
4
+ *
5
+ * 🛑 THE UPDATE PATH HAD NO CASES AT ALL. `/store/products/new` carries 57; the
6
+ * editors carried zero — and the editors are where the 2026-09-14 data-loss bug
7
+ * lived (Root Cause #98). Nine of them spread an `ActionResult` envelope as if
8
+ * it were the product, so `notFound()` could never fire, every field resolved
9
+ * `undefined`, and `status === "published" ? … : "draft"` evaluated
10
+ * `undefined === "published"` — meaning **pressing Save wrote draft over a live
11
+ * listing** and removed it from every public surface.
12
+ *
13
+ * Every case below is written so it FAILS against that behaviour. A case reading
14
+ * "editing a listing works" passes on a blank form that destroys the record.
15
+ *
16
+ * @tag domain:tester
17
+ * @tag layer:seed
18
+ * @tag pattern:none
19
+ * @tag access:server-only
20
+ * @tag consumers:seed-data/authored/index.ts
21
+ * @tag sideEffects:none
22
+ */
23
+ export const authored = {
24
+ "checklist-selling-listing-edit-roundtrip-edit-opens-populated": {
25
+ roles: ["seller"],
26
+ startPage: "/store/products",
27
+ steps: [
28
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
29
+ "Open /store/products and find a listing whose status reads Published.",
30
+ "Write down its title, its price and its stock quantity from the row.",
31
+ "Open that listing's Edit action.",
32
+ "Wait for the form to finish loading.",
33
+ "Read the Title, Price and Stock fields.",
34
+ ],
35
+ expectedBehaviour: "The editor is seeded from the listing's stored document. A blank form means the page received something other than a product — an ActionResult envelope spreads to all-undefined and renders exactly this way, with no error.",
36
+ expectedUiState: "Title, Price and Stock each hold the values written down from the row. No field that had a value on the row is empty here.",
37
+ expectedData: { emptyRequiredFieldCount: 0 },
38
+ endResult: "Nothing is saved; the form was only opened. Leaving without saving must not change the listing.",
39
+ },
40
+ "checklist-selling-listing-edit-roundtrip-edit-category-preselected": {
41
+ roles: ["seller"],
42
+ startPage: "/store/products",
43
+ steps: [
44
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
45
+ "Open /store/products and pick any published listing.",
46
+ "Open its public page in a second tab and read which category it is filed under.",
47
+ "Return to the first tab and open the listing's Edit action.",
48
+ "Find the Category selector and read what it currently shows.",
49
+ ],
50
+ expectedBehaviour: "The selector is seeded from the listing's stored category. The stored field is `categorySlugs[]` and its FIRST entry is the leaf; a form reading a singular `categorySlug` gets undefined and opens blank — and then saving that blank submits it.",
51
+ expectedUiState: "The Category selector shows the same category name the public page showed — for example Original Plastic Gen. It is not empty and is not sitting on its unchosen placeholder.",
52
+ endResult: "Nothing is saved. If this case fails, do NOT press Save — saving a blank category is the damage it is warning about.",
53
+ },
54
+ "checklist-selling-listing-edit-roundtrip-edit-save-keeps-published": {
55
+ roles: ["seller"],
56
+ startPage: "/store/products",
57
+ steps: [
58
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
59
+ "Open /store/products and find a listing whose status reads Published. Write down its title.",
60
+ "Open its Edit action.",
61
+ "Change only the Description — append the word roundtrip to it.",
62
+ "Press Save.",
63
+ "Return to /store/products and reload the page.",
64
+ "Find the same listing and read its status.",
65
+ "Open its public detail page.",
66
+ ],
67
+ inputs: { descriptionSuffix: "roundtrip" },
68
+ expectedBehaviour: "Editing one field changes that field and nothing else. The status must survive the round trip: an editor that read the status as undefined will coerce it to draft on save, which silently unpublishes a live listing.",
69
+ expectedUiState: "After the reload the row still reads Published, and the public detail page still loads rather than 404ing.",
70
+ expectedData: { statusAfterSave: "published" },
71
+ endResult: "The description keeps the appended word after a reload, and the listing is still published and still publicly reachable.",
72
+ },
73
+ "checklist-selling-listing-edit-roundtrip-edit-missing-id-404s": {
74
+ roles: ["seller"],
75
+ startPage: "/store/products",
76
+ steps: [
77
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
78
+ "Navigate directly to /store/products/zzzznope-not-a-listing-42/edit — a deliberately invented id, not a fixture.",
79
+ "Read what the page shows.",
80
+ ],
81
+ inputs: { listingId: "zzzznope-not-a-listing-42" },
82
+ expectedBehaviour: "An id that resolves to no listing must 404. A blank editor here is the tell that the page never checked: an always-truthy envelope makes the not-found branch unreachable, and the empty form it renders is indistinguishable from a real listing with no data.",
83
+ expectedUiState: "A not-found page. NOT an empty product form, and not a form with a Save button on it.",
84
+ expectedData: { showsEditForm: false },
85
+ endResult: "Nothing is created or saved.",
86
+ },
87
+ "checklist-selling-listing-edit-roundtrip-edit-other-sellers-listing-404s": {
88
+ roles: ["seller"],
89
+ startPage: "/store/products",
90
+ steps: [
91
+ "Sign in as the bot seller claude-tester@letitrip.in / TempPass123! (its store is empty).",
92
+ "In a second tab open /products and copy the slug of any listing belonging to Beyblade Arena.",
93
+ "Back in the first tab, navigate to /store/products/<that slug>/edit.",
94
+ "Read what the page shows.",
95
+ ],
96
+ expectedBehaviour: "Ownership is checked against the caller's STORE, and a product's `storeId` is the store SLUG rather than the owner's Auth uid. A check comparing `storeId` to a uid compares two different namespaces and can never pass — which returns null for every legitimate seller too, so a page that 404s here must be verified to still open the seller's OWN listing.",
97
+ expectedUiState: "A not-found page, with no editable fields.",
98
+ expectedData: { showsEditForm: false },
99
+ endResult: "Nothing is changed on the other seller's listing. Then re-open one of your own listings to confirm the guard has not locked everyone out.",
100
+ },
101
+ "checklist-selling-listing-edit-roundtrip-edit-ancestor-pages-after-recategorise": {
102
+ roles: ["seller"],
103
+ startPage: "/store/products",
104
+ steps: [
105
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
106
+ "Open /categories/original-plastic-gen — a tier-3 category whose parent is original-tops and whose root is spinning-tops.",
107
+ "Open /store/products, pick a published listing, and open its Edit action.",
108
+ "Change its Category to Original Plastic Gen and press Save.",
109
+ "Open /categories/original-plastic-gen and look for the listing.",
110
+ "Open /categories/original-tops and look for the same listing.",
111
+ "Open /categories/spinning-tops and look for it again.",
112
+ ],
113
+ expectedBehaviour: "A product stores the FULL ancestor chain, so it is reachable from its own category and from every ancestor with one query. If only the leaf is stored, the ancestor pages match nothing — and the leaf page can fail too, because the stored field and the field the form sends are not the same one.",
114
+ expectedUiState: "The listing's card appears on all three pages: the deep category, its parent, and its root.",
115
+ expectedData: { visibleOnLeaf: true, visibleOnParent: true, visibleOnRoot: true },
116
+ endResult: "After a reload the listing is still filed under the deep category and still appears on all three pages.",
117
+ },
118
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,69 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for selling/seller-orders-at-scale.
3
+ * WHAT: 3 cases, keyed by full checklist id.
4
+ *
5
+ * 🛑 SCALE IS THE WHOLE POINT OF THIS PAGE. The seller order list queried
6
+ * `productId in [...]` with the seller's entire product list, against Firestore's
7
+ * 30-value cap on `in`. So it was a permanent 500 for the only real seller
8
+ * (65 products) and perfectly fine for both small stores — which is exactly why
9
+ * it survived: every existing case exercised a store below the cap.
10
+ *
11
+ * On the dashboard the same throw was caught by `.catch(() => ({items: []}))`
12
+ * and rendered as zero orders and ₹0 revenue with no error anywhere, so the
13
+ * second case asserts a NUMBER rather than that a page loaded.
14
+ *
15
+ * Always run these against Beyblade Arena. A store with fewer than 30 listings
16
+ * passes them all while broken.
17
+ *
18
+ * @tag domain:tester
19
+ * @tag layer:seed
20
+ * @tag pattern:none
21
+ * @tag access:server-only
22
+ * @tag consumers:seed-data/authored/index.ts
23
+ * @tag sideEffects:none
24
+ */
25
+ export const authored = {
26
+ "checklist-selling-seller-orders-at-scale-orders-list-loads-for-large-store": {
27
+ roles: ["seller"],
28
+ startPage: "/store/orders",
29
+ steps: [
30
+ "Sign in as tyson@beybladearena.in / TempPass123! — this store has more than 30 listings, which is the condition under test.",
31
+ "Open /store/products and read the total listing count shown by the pager.",
32
+ "Open /store/orders.",
33
+ "Wait for the list to finish loading.",
34
+ "Open the browser network panel and read the status of the /api/store/orders request.",
35
+ ],
36
+ expectedBehaviour: "The list is scoped by the store, not by a list of its product ids. Firestore rejects an `in` clause of more than 30 values, so a per-product query breaks at exactly the 31st listing and cannot be reproduced on a small store.",
37
+ expectedUiState: "Order rows are listed, or a genuine empty state. Not an error boundary and not a perpetual skeleton.",
38
+ expectedData: { ordersApiStatus: 200 },
39
+ endResult: "Reloading shows the same list.",
40
+ },
41
+ "checklist-selling-seller-orders-at-scale-dashboard-revenue-not-zero": {
42
+ roles: ["seller"],
43
+ startPage: "/store",
44
+ steps: [
45
+ "Sign in as tyson@beybladearena.in / TempPass123!.",
46
+ "Open /store/orders and count how many orders are listed.",
47
+ "Open /store.",
48
+ "Read the total-orders figure and the revenue figure on the dashboard.",
49
+ ],
50
+ expectedBehaviour: "The dashboard's headline numbers come from the same query as the order list, so they must agree with it. A failed query here is swallowed into an empty array, which renders as a confident zero rather than as an error.",
51
+ expectedUiState: "The order count matches what /store/orders listed, and revenue is greater than ₹0 for a store with delivered orders.",
52
+ expectedData: { revenueIsZero: false },
53
+ endResult: "The same figures survive a reload.",
54
+ },
55
+ "checklist-selling-seller-orders-at-scale-orders-only-this-store": {
56
+ roles: ["seller"],
57
+ startPage: "/store/orders",
58
+ steps: [
59
+ "Sign in as tyson@beybladearena.in / TempPass123! and open /store/orders.",
60
+ "Open any order and read which product it is for.",
61
+ "In a second tab open that product's public page and read which store it belongs to.",
62
+ "Repeat for two more orders, choosing rows from different pages of the list.",
63
+ ],
64
+ expectedBehaviour: "Scoping by store must not widen what a seller can see. A cart splits into one order per store, so every row here belongs to this store and no other seller's order is reachable.",
65
+ expectedUiState: "Every product checked belongs to Beyblade Arena.",
66
+ expectedData: { foreignOrdersFound: 0 },
67
+ endResult: "Nothing is changed; this case only reads.",
68
+ },
69
+ };