output:
Chunk ID: 9fbdda
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 10337
Output:
Total output lines: 423

specs/04-STOREFRONT-UI.md:1:# 04 - Storefront UI/UX Specification
specs/04-STOREFRONT-UI.md:81:| Featured Collections | Grid of collection cards | Home |
specs/04-STOREFRONT-UI.md:82:| Featured Products | Grid of product cards (lazy-loaded) | Home |
specs/04-STOREFRONT-UI.md:145:| Search Icon | Right group | Button that opens the search modal |
specs/04-STOREFRONT-UI.md:242:2. Featured Collections
specs/04-STOREFRONT-UI.md:243:3. Featured Products
specs/04-STOREFRONT-UI.md:282:### 3.2 Featured Collections Section
specs/04-STOREFRONT-UI.md:292:**Collection Card:**
specs/04-STOREFRONT-UI.md:296:|  [Collection Image]       |
specs/04-STOREFRONT-UI.md:317:### 3.3 Featured Products Section
specs/04-STOREFRONT-UI.md:319:**Livewire Component:** FeaturedProducts
specs/04-STOREFRONT-UI.md:327:| Products | 4 to 8, configurable. Sourced from a configured collection or "best sellers" logic |
specs/04-STOREFRONT-UI.md:376:## 4. Collection Page (GET /collections/{handle})
specs/04-STOREFRONT-UI.md:378:**Livewire Component:** CollectionPage
specs/04-STOREFRONT-UI.md:380:### 4.1 Collection Header
specs/04-STOREFRONT-UI.md:384:| Breadcrumbs | Home > Collections > {Collection Title} |
specs/04-STOREFRONT-UI.md:538:|  [Search icon - large, muted]                                 |
specs/04-STOREFRONT-UI.md:625:Home > {Primary Collection} > {Product Title}. Small, muted text with separator characters.
specs/04-STOREFRONT-UI.md:1408:## 11. Search
specs/04-STOREFRONT-UI.md:1410:### 11.1 Search Modal
specs/04-STOREFRONT-UI.md:1412:**Livewire Component:** SearchModal
specs/04-STOREFRONT-UI.md:1418:|  [Search input with icon]                           [X close] |
specs/04-STOREFRONT-UI.md:1420:|  Products                                                     |
specs/04-STOREFRONT-UI.md:1424:|  Collections                                                  |
specs/04-STOREFRONT-UI.md:1425:|  Summer Collection                                            |
specs/04-STOREFRONT-UI.md:1426:|  Winter Collection                                            |
specs/04-STOREFRONT-UI.md:1436:| Search input | Large text, search icon prefix, autofocus on open. Live binding with 300ms debounce |
specs/04-STOREFRONT-UI.md:1437:| Results | Appear below input as user types. Grouped by type: "Products" and "Collections" headings |
specs/04-STOREFRONT-UI.md:1439:| Collection results | Title only. Clickable to collection page |
specs/04-STOREFRONT-UI.md:1446:| ARIA | Dialog role, modal, labeled "Search". Results list as listbox with option items |
specs/04-STOREFRONT-UI.md:1448:### 11.2 Search Results Page (GET /search?q=)
specs/04-STOREFRONT-UI.md:1450:**Livewire Component:** SearchResults
specs/04-STOREFRONT-UI.md:1456:| Heading | H1, "X results for '{query}'" or "Search results for '{query}'" |
specs/04-STOREFRONT-UI.md:1457:| Breadcrumbs | Home > Search results |
specs/04-STOREFRONT-UI.md:1490:|  [Search input]                                               |
specs/04-STOREFRONT-UI.md:1501:| Search | Simple input + button, submits to search page |
specs/04-STOREFRONT-UI.md:1547:| Collection filters | Drawer overlay | Drawer overlay | Persistent sidebar |
specs/04-STOREFRONT-UI.md:1580:| Collection Page | Live region for product count/grid on filter change. Filter sidebar labeled as navigation. Sort dropdown has associated label |
specs/04-STOREFRONT-UI.md:1584:| Search Modal | Dialog role with modal behavior. Results as listbox with option items. Active descendant tracking for keyboard navigation |
specs/04-STOREFRONT-UI.md:1596:| Search modal | Escape | Close |
specs/04-STOREFRONT-UI.md:1597:| Search results | Arrow Up/Down | Navigate results |
specs/04-STOREFRONT-UI.md:1598:| Search results | Enter | Select highlighted result |
specs/04-STOREFRONT-UI.md:1727:| FeaturedProducts | Home page | Lazy-loaded featured products grid |
specs/04-STOREFRONT-UI.md:1729:| CollectionPage | Collection page | Filtering, sorting, pagination |
specs/04-STOREFRONT-UI.md:1734:| SearchModal | Layout (global) | Autocomplete search overlay |
specs/04-STOREFRONT-UI.md:1735:| SearchResults | Search page | Full search results with filters |
specs/04-STOREFRONT-UI.md:1751:| open-search-modal | Header search icon click | SearchModal | None |
specs/04-STOREFRONT-UI.md:1752:| close-search-modal | SearchModal close actions | SearchModal | None |
specs/04-STOREFRONT-UI.md:1766:| Collection | "{Collection title} - {Store name}" | Collection description (stripped of markup) |
specs/04-STOREFRONT-UI.md:1769:| Search | "Search results - {Store name}" | Static |
specs/04-STOREFRONT-UI.md:1802:    B --> C[Collection Page]
specs/04-STOREFRONT-UI.md:1803:    B --> D[Search Modal]
specs/04-STOREFRONT-UI.md:1804:    D --> E[Search Results Page]
specs/03-ADMIN-UI.md:1:# 03 - Admin Panel UI/UX Specification
specs/03-ADMIN-UI.md:11:## 1. Admin Layout Shell
specs/03-ADMIN-UI.md:21:**Livewire component:** `App\Livewire\Admin\Layout\Sidebar`
specs/03-ADMIN-UI.md:47:|  [cube]         Products      |
specs/03-ADMIN-UI.md:48:|  [rect-stack]   Collections   |
specs/03-ADMIN-UI.md:81:Products (group label)
specs/03-ADMIN-UI.md:82:  Products                       -> admin.products.index
specs/03-ADMIN-UI.md:83:  Collections                    -> admin.collections.index
specs/03-ADMIN-UI.md:118:**Livewire component:** `App\Livewire\Admin\Layout\TopBar`
specs/03-ADMIN-UI.md:127:| `stores` | `Collection` | List of stores the user has access to |
specs/03-ADMIN-UI.md:175:**Breadcrumbs:** Every page includes a Flux breadcrumbs component at the top of the content area. The first item is always "Home" linking to `/admin`. Subsequent items reflect the page hierarchy. Example for product edit: Home > Products > "Blue T-Shirt".
specs/03-ADMIN-UI.md:206:**Livewire component:** `App\Livewire\Admin\Dashboard`
specs/03-ADMIN-UI.md:226:| `topProducts` | `array` | Top 5 products: `{title, units_sold, revenue}` |
specs/03-ADMIN-UI.md:234:| `loadTopProducts()` | Queries top 5 products by revenue |
specs/03-ADMIN-UI.md:296:### Top Products Table
specs/03-ADMIN-UI.md:337:## 3. Products List
specs/03-ADMIN-UI.md:341:**Livewire component:** `App\Livewire\Admin\Products\Index`
specs/03-ADMIN-UI.md:349:| `search` | `string` | Search query, live-debounced at 300ms |
specs/03-ADMIN-UI.md:359:| `updatedSearch()` | Resets pagination |
specs/03-ADMIN-UI.md:378:| Products                                    [+ Add product]       |
specs/03-ADMIN-UI.md:380:| [search icon] Search products...   [Status: All v] [Type: All v] |
specs/03-ADMIN-UI.md:432:| Body text | "This will archive X product(s). Products with orders cannot be permanently deleted." |
specs/03-ADMIN-UI.md:442:| Search field | `input` (icon: magnifying-glass) |
specs/03-ADMIN-UI.md:468:**Livewire component:** `App\Livewire\Admin\Products\Form`
specs/03-ADMIN-UI.md:508:| `availableCollections` | All collections for the current store |
specs/03-ADMIN-UI.md:569:|  > Search engine listing                 |                   |
specs/03-ADMIN-UI.md:628:- Toggle button: chevron icon + "Search engine listing" text
specs/03-ADMIN-UI.md:646:#### Collections Card
specs/03-ADMIN-UI.md:647:- Flux field with label "Collections"
specs/03-ADMIN-UI.md:665:| Body text | "This product will be archived. Products with existing orders cannot be permanently removed." |
specs/03-ADMIN-UI.md:700:## 5. Collections List and Edit
specs/03-ADMIN-UI.md:702:### 5.1 Collections List
specs/03-ADMIN-UI.md:706:**Livewire component:** `App\Livewire\Admin\Collections\Index`
specs/03-ADMIN-UI.md:714:| `search` | `string` | Search query |
specs/03-ADMIN-UI.md:719:| `updatedSearch()` | Resets pagination |
specs/03-ADMIN-UI.md:720:| `deleteCollection(int $id)` | Deletes a collection after confirmation |
specs/03-ADMIN-UI.md:728:Same pattern as Products list:
specs/03-ADMIN-UI.md:729:- Heading "Collections" with "Add collection" primary button
specs/03-ADMIN-UI.md:730:- Search input
specs/03-ADMIN-UI.md:738:| Products count | Number of products in collection |
specs/03-ADMIN-UI.md:744:### 5.2 Collection Edit/Create
specs/03-ADMIN-UI.md:748:**Livewire component:** `App\Livewire\Admin\Collections\Form`
specs/03-ADMIN-UI.md:756:| `collection` | `?Collection` | The collection being edited |
specs/03-ADMIN-UI.md:757:| `title` | `string` | Collection title |
specs/03-ADMIN-UI.md:759:| `descriptionHtml` | `string` | Collection description |
specs/03-ADMIN-UI.md:761:| `productSearch` | `string` | Search input for product assignment |
specs/03-ADMIN-UI.md:769:| `reorderProducts(array $order)` | Updates product positions |
specs/03-ADMIN-UI.md:773:| `searchResults` | Products matching `productSearch` that are not already assigned |
specs/03-ADMIN-UI.md:774:| `assignedProducts` | Ordered collection of assigned Product models |
specs/03-ADMIN-UI.md:782:|  Title: [Summer Collection         ]     | Status: [Active v] |
specs/03-ADMIN-UI.md:788:|  Search: [Search products...       ]     |                   |
specs/03-ADMIN-UI.md:808:- Products assignment section:
specs/03-ADMIN-UI.md:809:  - Search input with live debounce (300ms)
specs/03-ADMIN-UI.md:810:  - Search results dropdown (conditionally shown): list of matching products with "Add" button
specs/03-ADMIN-UI.md:823:**Livewire component:** `App\Livewire\Admin\Inventory\Index`
specs/03-ADMIN-UI.md:831:| `search` | `string` | Search by product title or SKU |
specs/03-ADMIN-UI.md:844:| [search] Search by product or SKU   [Stock: All v]               |
specs/03-ADMIN-UI.md:857:- Search input and stock filter dropdown
specs/03-ADMIN-UI.md:866:**Livewire component:** `App\Livewire\Admin\Orders\Index`
specs/03-ADMIN-UI.md:874:| `search` | `string` | Search by order number or customer email |
specs/03-ADMIN-UI.md:881:| `updatedSearch()` | Resets pagination |
specs/03-ADMIN-UI.md:895:| [search] Search by order # or email...                           |
specs/03-ADMIN-UI.md:930:| Search field | `input` |
specs/03-ADMIN-UI.md:940:**Livewire component:** `App\Livewire\Admin\Orders\Show`
specs/03-ADMIN-UI.md:1140:**Livewire component:** `App\Livewire\Admin\Customers\Index`
specs/03-ADMIN-UI.md:1148:| `search` | `string` | Search by name or email |
specs/03-ADMIN-UI.md:1157:- Search input
specs/03-ADMIN-UI.md:1165:**Livewire component:** `App\Livewire\Admin\Customers\Show`
specs/03-ADMIN-UI.md:1239:**Livewire component:** `App\Livewire\Admin\Discounts\Index`
specs/03-ADMIN-UI.md:1247:| `search` | `string` | Search by discount code |
specs/03-ADMIN-UI.md:1257:- Search input and status filter
specs/03-ADMIN-UI.md:1274:**Livewire component:** `App\Livewire\Admin\Discounts\Form`
specs/03-ADMIN-UI.md:1289:| `specificCollectionIds` | `array<int>` | Specific collections the discount applies to |
specs/03-ADMIN-UI.md:1295:| `productSearch` | `string` | Search for products to add |
specs/03-ADMIN-UI.md:1296:| `collectionSearch` | `string` | Search for collections to add |
specs/03-ADMIN-UI.md:1304:| `addCollection(int $collectionId)` | Adds collection to specific collections |
specs/03-ADMIN-UI.md:1305:| `removeCollection(int $collectionId)` | Removes collection |
specs/03-ADMIN-UI.md:1330:|  [Search products...          ]                                   |
specs/03-ADMIN-UI.md:1384:**Livewire component:** `App\Livewire\Admin\Settings\General`
specs/03-ADMIN-UI.md:1425:**Livewire component:** `App\Livewire\Admin\Settings\Domains`
specs/03-ADMIN-UI.md:1433:| `domains` | `Collection` | Store domains |
specs/03-ADMIN-UI.md:1468:- Type select: Storefront, Admin, API
specs/03-ADMIN-UI.md:1475:**Livewire component:** `App\Livewire\Admin\Settings\Shipping`
specs/03-ADMIN-UI.md:1483:| `zones` | `Collection` | Shipping zones with rates |
specs/03-ADMIN-UI.md:1592:**Livewire component:** `App\Livewire\Admin\Settings\Taxes`
specs/03-ADMIN-UI.md:1661:**Livewire component:** `App\Livewire\Admin\Themes\Index`
specs/03-ADMIN-UI.md:1669:| `themes` | `Collection` | All themes for the store |
specs/03-ADMIN-UI.md:1718:**Livewire component:** `App\Livewire\Admin\Themes\Editor`
specs/03-ADMIN-UI.md:1753:| Products   |  |  preview rendered      | |  Logo text:          |
specs/03-ADMIN-UI.md:1809:**Livewire component:** `App\Livewire\Admin\Pages\Index`
specs/03-ADMIN-UI.md:1817:| `search` | `string` | Search by page title |
specs/03-ADMIN-UI.md:1826:- Search input
specs/03-ADMIN-UI.md:1834:**Livewire component:** `App\Livewire\Admin\Pages\Form`
specs/03-ADMIN-UI.md:1873:**Livewire component:** `App\Livewire\Admin\Navigation\Index`
specs/03-ADMIN-UI.md:1881:| `menus` | `Collection` | Navigation menus (Main Menu, Footer Menu) |
specs/03-ADMIN-UI.md:1918:| | [drag] Products           collection: All    [edit] [trash]  | |
specs/03-ADMIN-UI.md:1949:- Type select: Custom link, Page, Collection, Product (live-bound)
specs/03-ADMIN-UI.md:1952:  - **Page/Collection/Product:** Resource select dropdown populated with available resources of that type
specs/03-ADMIN-UI.md:1961:**Livewire component:** `App\Livewire\Admin\Apps\Index`
specs/03-ADMIN-UI.md:1969:| `installedApps` | `Collection` | Apps installed for this store |
specs/03-ADMIN-UI.md:2013:**Livewire component:** `App\Livewire\Admin\Developers\Index`
specs/03-ADMIN-UI.md:2021:| `tokens` | `Collection` | API tokens for the store |
specs/03-ADMIN-UI.md:2022:| `webhooks` | `Collection` | Webhook subscriptions |
specs/03-ADMIN-UI.md:2045:| Manage personal access tokens for the Admin API.                 |
specs/03-ADMIN-UI.md:2126:**Livewire component:** `App\Livewire\Admin\Analytics\Index`
specs/03-ADMIN-UI.md:2144:| `topProducts` | `Collection` | Top products by revenue |
specs/03-ADMIN-UI.md:2193:- Channel filter: Flux select with All, Storefront, API
specs/03-ADMIN-UI.md:2203:**Top Products table:** Extended version with 10-20 rows. Columns: Rank, Product, Units Sold, Revenue, Percentage of Total.
specs/03-ADMIN-UI.md:2209:## 18. Search Settings
specs/03-ADMIN-UI.md:2213:**Livewire component:** `App\Livewire\Admin\Search\Settings`
specs/03-ADMIN-UI.md:2239:| Search Settings                                                   |
specs/03-ADMIN-UI.md:2283:- Heading "Search index" (size lg)
specs/03-ADMIN-UI.md:2298:2. Search input with live debounce (300ms)
specs/03-ADMIN-UI.md:2334:- Intermediate items: parent section (e.g., "Products" linking to products index)
specs/03-ADMIN-UI.md:2382:| Collection saved | "Collection saved" | success |
specs/03-ADMIN-UI.md:2402:| `App\Livewire\Admin\Layout\Sidebar` | `livewire.admin.layout.sidebar` | Layout (all pages) |
specs/03-ADMIN-UI.md:2403:| `App\Livewire\Admin\Layout\TopBar` | `livewire.admin.layout.top-bar` | Layout (all pages) |
specs/03-ADMIN-UI.md:2404:| `App\Livewire\Admin\Dashboard` | `livewire.admin.dashboard` | `GET /admin` |
specs/03-ADMIN-UI.md:2405:| `App\Livewire\Admin\Products\Index` | `livewire.admin.products.index` | `GET /admin/products` |
specs/03-ADMIN-UI.md:2406:| `App\Livewire\Admin\Products\Form` | `livewire.admin.products.form` | `GET /admin/products/create`, `GET /admin/products/{product}/edit` |
specs/03-ADMIN-UI.md:2407:| `App\Livewire\Admin\Collections\Index` | `livewire.admin.collections.index` | `GET /admin/collections` |
specs/03-ADMIN-UI.md:2408:| `App\Livewire\Admin\Collections\Form` | `livewire.admin.collections.form` | `GET /admin/collections/create`, `GET /admin/collections/{collection}/edit` |
specs/03-ADMIN-UI.md:2409:| `App\Livewire\Admin\Inventory\Index` | `livewire.admin.inventory.index` | `GET /admin/inventory` |
specs/03-ADMIN-UI.md:2410:| `App\Livewire\Admin\Orders\Index` | `livewire.admin.orders.index` | `GET /admin/orders` |
specs/03-ADMIN-UI.md:2411:| `App\Livewire\Admin\Orders\Show` | `livewire.admin.orders.show` | `GET /admin/orders/{order}` |
specs/03-ADMIN-UI.md:2412:| `App\Livewire\Admin\Customers\Index` | `livewire.admin.customers.index` | `GET /admin/customers` |
specs/03-ADMIN-UI.md:2413:| `App\Livewire\Admin\Customers\Show` | `livewire.admin.customers.show` | `GET /admin/customers/{customer}` |
specs/03-ADMIN-UI.md:2414:| `App\Livewire\Admin\Discounts\Index` | `livewire.admin.discounts.index` | `GET /admin/discounts` |
specs/03-ADMIN-UI.md:2415:| `App\Livewire\Admin\Discounts\Form` | `livewire.admin.discounts.form` | `GET /admin/discounts/create`, `GET /admin/discounts/{discount}/edit` |
specs/03-ADMIN-UI.md:2416:| `App\Livewire\Admin\Settings\General` | `livewire.admin.settings.general` | `GET /admin/settings` |
specs/03-ADMIN-UI.md:2417:| `App\Livewire\Admin\Settings\Domains` | `livewire.admin.settings.domains` | Tab within `GET /admin/settings` |
specs/03-ADMIN-UI.md:2418:| `App\Livewire\Admin\Settings\Shipping` | `livewire.admin.settings.shipping` | `GET /admin/settings/shipping` |
specs/03-ADMIN-UI.md:2419:| `App\Livewire\Admin\Settings\Taxes` | `livewire.admin.settings.taxes` | `GET /admin/settings/taxes` |
specs/03-ADMIN-UI.md:2420:| `App\Livewire\Admin\Themes\Index` | `livewire.admin.themes.index` | `GET /admin/themes` |
specs/03-ADMIN-UI.md:2421:| `App\Livewire\Admin\Themes\Editor` | `livewire.admin.themes.editor` | `GET /admin/themes/{theme}/editor` |
specs/03-ADMIN-UI.md:2422:| `App\Livewire\Admin\Pages\Index` | `livewire.admin.pages.index` | `GET /admin/pages` |
specs/03-ADMIN-UI.md:2423:| `App\Livewire\Admin\Pages\Form` | `livewire.admin.pages.form` | `GET /admin/pages/create`, `GET /admin/pages/{page}/edit` |
specs/03-ADMIN-UI.md:2424:| `App\Livewire\Admin\Navigation\Index` | `livewire.admin.navigation.index` | `GET /admin/navigation` |
specs/03-ADMIN-UI.md:2425:| `App\Livewire\Admin\Apps\Index` | `livewire.admin.apps.index` | `GET /admin/apps` |
specs/03-ADMIN-UI.md:2426:| `App\Livewire\Admin\Developers\Index` | `livewire.admin.developers.index` | `GET /admin/developers` |
specs/03-ADMIN-UI.md:2427:| `App\Livewire\Admin\Analytics\Index` | `livewire.admin.analytics.index` | `GET /admin/analytics` |
specs/03-ADMIN-UI.md:2428:| `App\Livewire\Admin\Search\Settings` | `livewire.admin.search.settings` | `GET /admin/search/settings` |
specs/08-PLAYWRIGHT-E2E-PLAN.md:11:| 1 - Smoke Tests | `tests/Browser/SmokeTest.php` | 10 | Hit every major page, assert HTTP 200 and no JS errors | Store 1, Products, Collections, Pages |
specs/08-PLAYWRIGHT-E2E-PLAN.md:12:| 2 - Admin Authentication | `tests/Browser/Admin/AuthenticationTest.php` | 10 | Admin login, logout, invalid credentials, session access control | Admin user |
specs/08-PLAYWRIGHT-E2E-PLAN.md:13:| 3 - Admin Product Management | `tests/Browser/Admin/ProductManagementTest.php` | 7 | Product CRUD: listing, creating, editing, archiving, filtering | Admin user, Products (incl. #15 draft) |
specs/08-PLAYWRIGHT-E2E-PLAN.md:14:| 4 - Admin Order Management | `tests/Browser/Admin/OrderManagementTest.php` | 11 | Order listing, filtering, detail view, fulfillment, refund, confirm payment, fulfillment guard, mark shipped/delivered | Admin user, Orders (#1001, #1005), Customer |
specs/08-PLAYWRIGHT-E2E-PLAN.md:15:| 5 - Admin Discount Management | `tests/Browser/Admin/DiscountManagementTest.php` | 6 | Discount code listing, creation, editing | Admin user, Discounts |
specs/08-PLAYWRIGHT-E2E-PLAN.md:16:| 6 - Admin Settings | `tests/Browser/Admin/SettingsTest.php` | 7 | Store settings, shipping zones, tax config, domains | Admin user, Shipping zones, Store 1 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:17:| 7 - Storefront Browsing | `tests/Browser/Storefront/BrowsingTest.php` | 15 | Home page, collections, product detail, variants, search, pages | Products, Collections, Pages, Products #15/#17/#18 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:18:| 8 - Cart Flow | `tests/Browser/Storefront/CartTest.php` | 12 | Cart lifecycle: add, update qty, remove, discounts, totals | Products, Discounts (all codes) |
specs/08-PLAYWRIGHT-E2E-PLAN.md:19:| 9 - Checkout Flow | `tests/Browser/Storefront/CheckoutTest.php` | 13 | Full checkout: contact, address, shipping, payment method selection, payment, confirmation, magic card decline, bank transfer flow | Products, Shipping zones, Discounts |
specs/08-PLAYWRIGHT-E2E-PLAN.md:20:| 10 - Customer Account | `tests/Browser/Storefront/Cu…337 tokens truncated…/Browser/Admin/PageManagementTest.php` | 3 | CMS page management | Admin user, Pages |
specs/08-PLAYWRIGHT-E2E-PLAN.md:28:| 18 - Admin Analytics | `tests/Browser/Admin/AnalyticsTest.php` | 3 | Analytics dashboard rendering | Admin user, Orders |
specs/08-PLAYWRIGHT-E2E-PLAN.md:89:| **Admin user** | Email: `admin@acme.test`, password: `password`, role: `owner` on Store 1 | 2, 3, 4, 5, 6, 12, 13, 15, 16, 17, 18 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:97:| **Products (20 total)** | Seeded across collections, with variants, options, images, inventory | 1, 3, 7, 8, 9, 11, 13 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:98:| **Collections** | "T-Shirts" (handle: `t-shirts`), "New Arrivals" (handle: `new-arrivals`), plus others | 1, 7, 13, 15 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:114:    S1[Suite 1: Smoke Tests] --> S2[Suite 2: Admin Auth]
specs/08-PLAYWRIGHT-E2E-PLAN.md:115:    S1 --> S7[Suite 7: Storefront Browsing]
specs/08-PLAYWRIGHT-E2E-PLAN.md:116:    S2 --> S3[Suite 3: Admin Products]
specs/08-PLAYWRIGHT-E2E-PLAN.md:117:    S2 --> S4[Suite 4: Admin Orders]
specs/08-PLAYWRIGHT-E2E-PLAN.md:118:    S2 --> S5[Suite 5: Admin Discounts]
specs/08-PLAYWRIGHT-E2E-PLAN.md:119:    S2 --> S6[Suite 6: Admin Settings]
specs/08-PLAYWRIGHT-E2E-PLAN.md:120:    S2 --> S15[Suite 15: Admin Collections]
specs/08-PLAYWRIGHT-E2E-PLAN.md:121:    S2 --> S16[Suite 16: Admin Customers]
specs/08-PLAYWRIGHT-E2E-PLAN.md:122:    S2 --> S17[Suite 17: Admin Pages]
specs/08-PLAYWRIGHT-E2E-PLAN.md:123:    S2 --> S18[Suite 18: Admin Analytics]
specs/08-PLAYWRIGHT-E2E-PLAN.md:137:| Phase 3 | Suites 3, 4, 5, 6, 10, 11, 15, 16, 17, 18 | Admin CRUD and storefront feature suites (can run in parallel) |
specs/08-PLAYWRIGHT-E2E-PLAN.md:149:    Admin/
specs/08-PLAYWRIGHT-E2E-PLAN.md:155:        CollectionManagementTest.php
specs/08-PLAYWRIGHT-E2E-PLAN.md:159:    Storefront/
specs/08-PLAYWRIGHT-E2E-PLAN.md:293:- Page displays "Collections"
specs/08-PLAYWRIGHT-E2E-PLAN.md:312:## Suite 2: Admin Authentication
specs/08-PLAYWRIGHT-E2E-PLAN.md:314:**File:** `tests/Browser/Admin/AuthenticationTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:326:    Dashboard --> Products: click "Products"
specs/08-PLAYWRIGHT-E2E-PLAN.md:436:6. Click on "Admin User" (profile/user menu)
specs/08-PLAYWRIGHT-E2E-PLAN.md:453:5. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:454:6. Verify "Products" heading is visible
specs/08-PLAYWRIGHT-E2E-PLAN.md:508:## Suite 3: Admin Product Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:510:**File:** `tests/Browser/Admin/ProductManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:537:5. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:553:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:563:13. Click "Products" to return to the product list
specs/08-PLAYWRIGHT-E2E-PLAN.md:578:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:583:8. Click "Products" to return to the product list
specs/08-PLAYWRIGHT-E2E-PLAN.md:598:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:606:11. Click "Products" to return to the product list
specs/08-PLAYWRIGHT-E2E-PLAN.md:610:15. Click "Products" to return to the product list
specs/08-PLAYWRIGHT-E2E-PLAN.md:626:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:647:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:663:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:676:## Suite 4: Admin Order Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:678:**File:** `tests/Browser/Admin/OrderManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:906:## Suite 5: Admin Discount Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:908:**File:** `tests/Browser/Admin/DiscountManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:1037:## Suite 6: Admin Settings
specs/08-PLAYWRIGHT-E2E-PLAN.md:1039:**File:** `tests/Browser/Admin/SettingsTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:1185:## Suite 7: Storefront Browsing
specs/08-PLAYWRIGHT-E2E-PLAN.md:1187:**File:** `tests/Browser/Storefront/BrowsingTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:1191:### Storefront Page Map
specs/08-PLAYWRIGHT-E2E-PLAN.md:1195:    Home["/"] --> Collections["/collections"]
specs/08-PLAYWRIGHT-E2E-PLAN.md:1197:    Collections --> CollectionDetail["/collections/{handle}"]
specs/08-PLAYWRIGHT-E2E-PLAN.md:1198:    CollectionDetail --> Product
specs/08-PLAYWRIGHT-E2E-PLAN.md:1199:    Home --> Search["/search?q=..."]
specs/08-PLAYWRIGHT-E2E-PLAN.md:1200:    Search --> Product
specs/08-PLAYWRIGHT-E2E-PLAN.md:1423:**File:** `tests/Browser/Storefront/CartTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:1534:**Preconditions:** Products #1 and #2 exist
specs/08-PLAYWRIGHT-E2E-PLAN.md:1693:**File:** `tests/Browser/Storefront/CheckoutTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2080:**File:** `tests/Browser/Storefront/CustomerAccountTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2321:**File:** `tests/Browser/Storefront/InventoryTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2327:| Stock Level | Policy | Storefront Display | Add-to-Cart |
specs/08-PLAYWRIGHT-E2E-PLAN.md:2405:**File:** `tests/Browser/Storefront/TenantIsolationTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2414:        S1Products[Fashion Products]
specs/08-PLAYWRIGHT-E2E-PLAN.md:2419:        S2Products[Other Products]
specs/08-PLAYWRIGHT-E2E-PLAN.md:2423:    S1Products -.-x S2Products
specs/08-PLAYWRIGHT-E2E-PLAN.md:2442:- Products from other stores (e.g., electronics from Store 2) are absent
specs/08-PLAYWRIGHT-E2E-PLAN.md:2461:### Test 12.3: Admin cannot access other store data
specs/08-PLAYWRIGHT-E2E-PLAN.md:2468:3. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:2481:### Test 12.4: Search only returns current store products
specs/08-PLAYWRIGHT-E2E-PLAN.md:2516:**File:** `tests/Browser/Storefront/ResponsiveTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2524:| iPhone (mobile) | 375 | 812 | Storefront tests |
specs/08-PLAYWRIGHT-E2E-PLAN.md:2525:| iPad (tablet) | 768 | 1024 | Admin panel tests |
specs/08-PLAYWRIGHT-E2E-PLAN.md:2529:### Test 13.1: Storefront home works on mobile viewport
specs/08-PLAYWRIGHT-E2E-PLAN.md:2626:### Test 13.6: Admin login works on tablet viewport
specs/08-PLAYWRIGHT-E2E-PLAN.md:2643:### Test 13.7: Admin sidebar navigation works on tablet
specs/08-PLAYWRIGHT-E2E-PLAN.md:2651:4. Click "Products" in the sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:2652:5. Verify "Products" heading is visible
specs/08-PLAYWRIGHT-E2E-PLAN.md:2662:### Test 13.8: Collection page works on mobile with filters
specs/08-PLAYWRIGHT-E2E-PLAN.md:2672:- Products are visible
specs/08-PLAYWRIGHT-E2E-PLAN.md:2682:**File:** `tests/Browser/Storefront/AccessibilityTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2769:### Test 14.6: Admin login form has accessible labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2851:### Test 14.11: Search page has proper form labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2859:- Search input has a label or aria-label attribute
specs/08-PLAYWRIGHT-E2E-PLAN.md:2866:## Suite 15: Admin Collections Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2868:**File:** `tests/Browser/Admin/CollectionManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2899:5. Enter title: `E2E Test Collection`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2905:- After step 7: page displays "Collection saved", no JavaScript errors
specs/08-PLAYWRIGHT-E2E-PLAN.md:2906:- After step 8: page displays "E2E Test Collection" in the list
specs/08-PLAYWRIGHT-E2E-PLAN.md:2923:- Page displays "Collection saved"
specs/08-PLAYWRIGHT-E2E-PLAN.md:2930:## Suite 16: Admin Customer Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2932:**File:** `tests/Browser/Admin/CustomerManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2990:## Suite 17: Admin Pages Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2992:**File:** `tests/Browser/Admin/PageManagementTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:3052:## Suite 18: Admin Analytics Dashboard
specs/08-PLAYWRIGHT-E2E-PLAN.md:3054:**File:** `tests/Browser/Admin/AnalyticsTest.php`
specs/08-PLAYWRIGHT-E2E-PLAN.md:3123:| 2 - Admin Authentication | `tests/Browser/Admin/AuthenticationTest.php` | 10 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3124:| 3 - Admin Product Management | `tests/Browser/Admin/ProductManagementTest.php` | 7 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3125:| 4 - Admin Order Management | `tests/Browser/Admin/OrderManagementTest.php` | 7 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3126:| 5 - Admin Discount Management | `tests/Browser/Admin/DiscountManagementTest.php` | 6 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3127:| 6 - Admin Settings | `tests/Browser/Admin/SettingsTest.php` | 7 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3128:| 7 - Storefront Browsing | `tests/Browser/Storefront/BrowsingTest.php` | 15 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3129:| 8 - Cart Flow | `tests/Browser/Storefront/CartTest.php` | 12 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3130:| 9 - Checkout Flow | `tests/Browser/Storefront/CheckoutTest.php` | 8 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3131:| 10 - Customer Account | `tests/Browser/Storefront/CustomerAccountTest.php` | 12 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3132:| 11 - Inventory Enforcement | `tests/Browser/Storefront/InventoryTest.php` | 4 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3133:| 12 - Tenant Isolation | `tests/Browser/Storefront/TenantIsolationTest.php` | 5 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3134:| 13 - Responsive / Mobile | `tests/Browser/Storefront/ResponsiveTest.php` | 8 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3135:| 14 - Accessibility | `tests/Browser/Storefront/AccessibilityTest.php` | 11 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3136:| 15 - Admin Collections | `tests/Browser/Admin/CollectionManagementTest.php` | 3 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3137:| 16 - Admin Customers | `tests/Browser/Admin/CustomerManagementTest.php` | 3 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3138:| 17 - Admin Pages | `tests/Browser/Admin/PageManagementTest.php` | 3 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3139:| 18 - Admin Analytics | `tests/Browser/Admin/AnalyticsTest.php` | 3 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3150:| Run a specific suite (nested) | `php artisan test tests/Browser/Storefront/CartTest.php` |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3152:| Run admin auth tests | `php artisan test tests/Browser/Admin/AuthenticationTest.php` |
specs/08-PLAYWRIGHT-E2E-PLAN.md:3153:| Run checkout flow tests | `php artisan test tests/Browser/Storefront/CheckoutTest.php` |
specs/02-API-ROUTES.md:11:### 1.1 Admin Auth Routes
specs/02-API-ROUTES.md:17:| GET | `/admin/login` | Admin login page | `Livewire: Admin\Auth\Login` |
specs/02-API-ROUTES.md:20:| GET | `/admin/forgot-password` | Show forgot password form | `Livewire: Admin\Auth\ForgotPassword` |
specs/02-API-ROUTES.md:22:| GET | `/admin/reset-password/{token}` | Show reset password form | `Livewire: Admin\Auth\ResetPassword` |
specs/02-API-ROUTES.md:29:### 1.2 Admin Routes
specs/02-API-ROUTES.md:42:| GET | `/admin` | Dashboard with KPI tiles, orders chart, conversion funnel | `Admin\Dashboard` |
specs/02-API-ROUTES.md:44:#### Products
specs/02-API-ROUTES.md:48:| GET | `/admin/products` | Product list - searchable, filterable by status, bulk actions | `Admin\Products\Index` |
specs/02-API-ROUTES.md:49:| GET | `/admin/products/create` | Create product form | `Admin\Products\Create` |
specs/02-API-ROUTES.md:50:| GET | `/admin/products/{product}/edit` | Edit product form with variants, media, options | `Admin\Products\Edit` |
specs/02-API-ROUTES.md:56:| GET | `/admin/inventory` | Inventory management page | `Admin\Inventory\Index` |
specs/02-API-ROUTES.md:58:#### Collections
specs/02-API-ROUTES.md:62:| GET | `/admin/collections` | Collection list | `Admin\Collections\Index` |
specs/02-API-ROUTES.md:63:| GET | `/admin/collections/create` | Create collection form | `Admin\Collections\Create` |
specs/02-API-ROUTES.md:64:| GET | `/admin/collections/{collection}/edit` | Edit collection form | `Admin\Collections\Edit` |
specs/02-API-ROUTES.md:70:| GET | `/admin/orders` | Order list with status filters | `Admin\Orders\Index` |
specs/02-API-ROUTES.md:71:| GET | `/admin/orders/{order}` | Order detail with timeline, payments, fulfillments | `Admin\Orders\Show` |
specs/02-API-ROUTES.md:77:| GET | `/admin/customers` | Customer list | `Admin\Customers\Index` |
specs/02-API-ROUTES.md:78:| GET | `/admin/customers/{customer}` | Customer detail with order history, addresses | `Admin\Customers\Show` |
specs/02-API-ROUTES.md:84:| GET | `/admin/discounts` | Discount list | `Admin\Discounts\Index` |
specs/02-API-ROUTES.md:85:| GET | `/admin/discounts/create` | Create discount form with rules builder | `Admin\Discounts\Create` |
specs/02-API-ROUTES.md:86:| GET | `/admin/discounts/{discount}/edit` | Edit discount form | `Admin\Discounts\Edit` |
specs/02-API-ROUTES.md:92:| GET | `/admin/settings` | Store settings (tabs: General, Domains, Shipping, Taxes, Checkout, Notifications) | `Admin\Settings\Index` |
specs/02-API-ROUTES.md:93:| GET | `/admin/settings/shipping` | Shipping zones and rates configuration | `Admin\Settings\Shipping` |
specs/02-API-ROUTES.md:94:| GET | `/admin/settings/taxes` | Tax settings - mode, provider config, rates | `Admin\Settings\Taxes` |
specs/02-API-ROUTES.md:100:| GET | `/admin/themes` | Theme management - cards with actions (Customize, Preview, Publish, Duplicate, Delete) | `Admin\Themes\Index` |
specs/02-API-ROUTES.md:101:| GET | `/admin/themes/{theme}/editor` | Theme editor - left panel sections, center preview iframe, right panel settings | `Admin\Themes\Editor` |
specs/02-API-ROUTES.md:107:| GET | `/admin/pages` | Content pages list | `Admin\Pages\Index` |
specs/02-API-ROUTES.md:108:| GET | `/admin/pages/create` | Create content page | `Admin\Pages\Create` |
specs/02-API-ROUTES.md:109:| GET | `/admin/pages/{page}/edit` | Edit content page | `Admin\Pages\Edit` |
specs/02-API-ROUTES.md:115:| GET | `/admin/navigation` | Navigation menus management | `Admin\Navigation\Index` |
specs/02-API-ROUTES.md:121:| GET | `/admin/apps` | Apps directory - list installed and available apps | `Admin\Apps\Index` |
specs/02-API-ROUTES.md:122:| GET | `/admin/apps/{installation}` | Installed app detail - scopes, webhooks, usage | `Admin\Apps\Show` |
specs/02-API-ROUTES.md:128:| GET | `/admin/developers` | Developer settings - API keys/tokens, webhook management | `Admin\Developers\Index` |
specs/02-API-ROUTES.md:136:| GET | `/admin/analytics` | Analytics dashboard - sales, traffic, funnel, exports | `Admin\Analytics\Index` |
specs/02-API-ROUTES.md:138:#### Search Settings
specs/02-API-ROUTES.md:142:| GET | `/admin/search/settings` | Search settings - synonyms, stopwords, reindex | `Admin\Search\Settings` |
specs/02-API-ROUTES.md:146:### 1.3 Storefront Routes
specs/02-API-ROUTES.md:154:| GET | `/` | Home page | `Storefront\Home` |
specs/02-API-ROUTES.md:155:| GET | `/collections` | All collections listing | `Storefront\Collections\Index` |
specs/02-API-ROUTES.md:156:| GET | `/collections/{handle}` | Single collection page with product grid and filters | `Storefront\Collections\Show` |
specs/02-API-ROUTES.md:157:| GET | `/products/{handle}` | Product page - gallery, variant selector, add-to-cart | `Storefront\Products\Show` |
specs/02-API-ROUTES.md:158:| GET | `/cart` | Full cart page - line items, quantity controls, discount input, totals | `Storefront\Cart\Show` |
specs/02-API-ROUTES.md:159:| GET | `/search` | Search results page with filter panel, sort dropdown, product grid | `Storefront\Search\Index` |
specs/02-API-ROUTES.md:160:| GET | `/pages/{handle}` | Static content page (About, FAQ, etc.) | `Storefront\Pages\Show` |
specs/02-API-ROUTES.md:168:| GET | `/account` | Customer account overview | `Storefront\Account\Dashboard` |
specs/02-API-ROUTES.md:169:| GET | `/account/orders` | Order history list | `Storefront\Account\Orders\Index` |
specs/02-API-ROUTES.md:170:| GET | `/account/orders/{orderNumber}` | Order detail | `Storefront\Account\Orders\Show` |
specs/02-API-ROUTES.md:171:| GET | `/account/addresses` | Address book management | `Storefront\Account\Addresses\Index` |
specs/02-API-ROUTES.md:177:| GET | `/account/login` | Customer login page | `Storefront\Account\Auth\Login` |
specs/02-API-ROUTES.md:178:| GET | `/account/register` | Customer registration page | `Storefront\Account\Auth\Register` |
specs/02-API-ROUTES.md:179:| GET | `/forgot-password` | Forgot password page | `Storefront\Account\Auth\ForgotPassword` |
specs/02-API-ROUTES.md:181:| GET | `/reset-password/{token}` | Reset password form | `Storefront\Account\Auth\ResetPassword` |
specs/02-API-ROUTES.md:192:| GET | `/checkout/{checkoutId}` | Checkout page - stepper UI (Contact -> Shipping -> Payment) | `Storefront\Checkout\Show` |
specs/02-API-ROUTES.md:193:| GET | `/checkout/{checkoutId}/confirmation` | Order confirmation page - order number, items, totals | `Storefront\Checkout\Confirmation` |
specs/02-API-ROUTES.md:197:## 2. Storefront REST API
specs/02-API-ROUTES.md:422:    participant API as Storefront API
specs/02-API-ROUTES.md:1017:### 2.5 Search Endpoints
specs/02-API-ROUTES.md:1021:Search products within the current store.
specs/02-API-ROUTES.md:1030:| `q` | string | Yes | Search query. Min: 1, max: 200 characters. |
specs/02-API-ROUTES.md:1108:| `q` | string | Yes | Search prefix. Min: 1, max: 100 characters. |
specs/02-API-ROUTES.md:1206:## 3. Admin REST API
specs/02-API-ROUTES.md:1218:### 3.1 Platform Management (Super-Admin Only)
specs/02-API-ROUTES.md:1373:    "name": "Jane Admin",
specs/02-API-ROUTES.md:1393:### 3.2 Products
specs/02-API-ROUTES.md:1395:#### Admin Products Endpoint Summary
specs/02-API-ROUTES.md:1415:| `query` | string | No | Search by title, vendor, or SKU. |
specs/02-API-ROUTES.md:1516:| `collections` | array of integers | No | Collection IDs to add this product to. |
specs/02-API-ROUTES.md:1631:        "title": "Summer Collection",
specs/02-API-ROUTES.md:1674:Archive a product (soft delete). Products with existing orders cannot be hard-deleted.
specs/02-API-ROUTES.md:1736:### 3.3 Collections
specs/02-API-ROUTES.md:1738:#### Admin Collections Endpoint Summary
specs/02-API-ROUTES.md:1756:| `query` | string | No | Search by title. |
specs/02-API-ROUTES.md:1768:      "title": "Summer Collection",
specs/02-API-ROUTES.md:1797:  "title": "Winter Collection",
specs/02-API-ROUTES.md:1813:| `product_ids` | array of integers | No | Products to add to the collection. |
specs/02-API-ROUTES.md:1835:- `404` - Collection not found
specs/02-API-ROUTES.md:1850:  "message": "Collection deleted"
specs/02-API-ROUTES.md:1856:- `404` - Collection not found
specs/02-API-ROUTES.md:1862:#### Admin Orders Endpoint Summary
specs/02-API-ROUTES.md:1885:| `query` | string | No | Search by order number or customer email. |
specs/02-API-ROUTES.md:2134:#### Admin Discounts Endpoint Summary
specs/02-API-ROUTES.md:2280:#### Admin Shipping Endpoint Summary
specs/02-API-ROUTES.md:2416:#### Admin Tax Endpoint Summary
specs/02-API-ROUTES.md:2494:#### Admin Themes Endpoint Summary
specs/02-API-ROUTES.md:2600:#### Admin Pages Endpoint Summary
specs/02-API-ROUTES.md:2713:### 3.10 Search Admin
specs/02-API-ROUTES.md:2715:#### Admin Search Endpoint Summary
specs/02-API-ROUTES.md:2766:#### Admin Analytics Endpoint Summary
specs/02-API-ROUTES.md:3008:#### Admin
specs/02-API-ROUTES.md:3019:#### Storefront
specs/02-API-ROUTES.md:3027:#### API Storefront
specs/02-API-ROUTES.md:3036:#### API Admin
specs/02-API-ROUTES.md:3080:| `login` | 5 requests | 1 minute | IP address | Admin and customer login attempts |
specs/02-API-ROUTES.md:3081:| `api.admin` | 60 requests | 1 minute | Sanctum token ID | Admin REST API endpoints |
specs/02-API-ROUTES.md:3082:| `api.storefront` | 120 requests | 1 minute | IP address | Storefront REST API (carts, etc.) |
specs/02-API-ROUTES.md:3084:| `search` | 30 requests | 1 minute | IP address | Search and autocomplete endpoints |
specs/02-API-ROUTES.md:3171:- **Storefront API:** Versioned via URL path (`/api/storefront/v1/`). Breaking changes require a new version.
specs/02-API-ROUTES.md:3172:- **Admin API:** Versioned via URL path (`/api/admin/v1/`). Same strategy.


cmd: sed -n '376,740p' specs/04-STOREFRONT-UI.md


cmd: sed -n '1185,1265p' specs/08-PLAYWRIGHT-E2E-PLAN.md


cmd: sed -n '508,675p' specs/08-PLAYWRIGHT-E2E-PLAN.md


command:
/bin/zsh
-lc
sed -n '337,830p' specs/03-ADMIN-UI.md

type: read

cmd: sed -n '337,830p' specs/03-ADMIN-UI.md

aggregated_output:
## 3. Products List

**Route:** `GET /admin/products`

**Livewire component:** `App\Livewire\Admin\Products\Index`

**Blade view:** `resources/views/livewire/admin/products/index.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `search` | `string` | Search query, live-debounced at 300ms |
| `statusFilter` | `string` | Status filter: `all`, `draft`, `active`, `archived` |
| `typeFilter` | `string` | Product type filter |
| `selectedIds` | `array<int>` | Array of selected product IDs for bulk actions |
| `selectAll` | `bool` | Whether all visible rows are selected |
| `sortField` | `string` | Column to sort by (default: `updated_at`) |
| `sortDirection` | `string` | `asc` or `desc` |

| Action | Behavior |
|--------|----------|
| `updatedSearch()` | Resets pagination |
| `updatedStatusFilter()` | Resets pagination |
| `updatedTypeFilter()` | Resets pagination |
| `bulkArchive()` | Archives all selected products |
| `bulkDelete()` | Soft-deletes selected products (with confirmation) |
| `bulkSetActive()` | Sets selected products to active status |
| `sortBy(string $field)` | Toggles sort direction or changes sort field |
| `toggleSelectAll()` | Selects or deselects all visible product IDs |
| `confirmBulkDelete()` | Opens delete confirmation modal |

| Computed Property | Purpose |
|-------------------|---------|
| `products` | Paginated query result with search, filters, sorting applied. Eager loads `variants`, `media` (limit 1). Uses `withCount('variants')`. |
| `productTypes` | Distinct product types for the type filter dropdown |

### Wireframe

```
+------------------------------------------------------------------+
| Products                                    [+ Add product]       |
+------------------------------------------------------------------+
| [search icon] Search products...   [Status: All v] [Type: All v] |
+------------------------------------------------------------------+
| (shown when items selected)                                       |
| "3 products selected"  [Set Active]  [Archive]  [Delete]         |
+------------------------------------------------------------------+
| [x] | IMG | Title ^     | Status  | Inventory | Type | Vendor | Updated ^  |
|-----|-----|-------------|---------|-----------|------|--------|-----------|
| [ ] | img | Blue Shirt  | Active  | 45        | Tops | Nike   | 2h ago    |
| [ ] | img | Red Hat     | Draft   | 12        | Hats | Adidas | 1d ago    |
| [ ] | img | Sneakers    | Active  | 0         | Shoes| Nike   | 3d ago    |
| ...                                                              |
+------------------------------------------------------------------+
| < 1 2 3 ... 10 >  (pagination)                                  |
+------------------------------------------------------------------+
```

### Table Column Definitions

| Column | Sortable | Content |
|--------|----------|---------|
| Select | No | Checkbox for bulk selection |
| Image | No | 40x40 rounded thumbnail of first media item, or placeholder icon |
| Title | Yes | Product title as a link to the edit page (uses Livewire navigate) |
| Status | No | Flux badge: draft=zinc/gray, active=green, archived=red |
| Inventory | Yes | Sum of `inventory_items.quantity_on_hand` across all variants |
| Type | No | Product type text or "-" |
| Vendor | No | Vendor name text or "-" |
| Updated | Yes (default) | Relative timestamp (e.g., "2h ago") |

### Bulk Action Bar

Conditionally shown when `count($selectedIds) > 0`. Contains:
- Text showing "X products selected"
- "Set Active" button (ghost variant)
- "Archive" button (ghost variant)
- "Delete" button (danger variant) - opens confirmation modal

### Empty State

When no products exist (not filtered, genuinely empty):
- Centered container with a large muted placeholder icon (cube)
- Heading: "Add your first product"
- Text: "Start building your catalog by adding products."
- Primary button: "Add product" linking to the create page

### Delete Confirmation Modal

| Property | Value |
|----------|-------|
| Modal name | `confirm-bulk-delete` |
| Max width | md |
| Heading | "Delete products?" |
| Body text | "This will archive X product(s). Products with orders cannot be permanently deleted." |
| Cancel button | Ghost variant, closes modal |
| Confirm button | Danger variant, calls `bulkDelete` |

### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Page title | `heading` |
| Add product button | `button` (variant: primary) |
| Search field | `input` (icon: magnifying-glass) |
| Status filter | `select` |
| Type filter | `select` |
| Bulk action buttons | `button` (ghost/danger variants) |
| Selected count text | `text` |
| Row checkbox | `checkbox` |
| Status badges | `badge` |
| Cell text | `text` |
| Delete confirmation | `modal` |
| Pagination | Laravel default Tailwind pagination |

### View States

| State | Behavior |
|-------|----------|
| Loading | Ta…10478 chars truncated… (upload) | Progress bar shown in media section |
| Create mode | Empty form, no delete button, heading says "Add product" |
| Edit mode | Pre-filled form, delete button visible, heading shows product title |
| Validation error | Inline error messages below each invalid field |

---

## 5. Collections List and Edit

### 5.1 Collections List

**Route:** `GET /admin/collections`

**Livewire component:** `App\Livewire\Admin\Collections\Index`

**Blade view:** `resources/views/livewire/admin/collections/index.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `search` | `string` | Search query |
| `statusFilter` | `string` | `all`, `active`, `archived` |

| Action | Behavior |
|--------|----------|
| `updatedSearch()` | Resets pagination |
| `deleteCollection(int $id)` | Deletes a collection after confirmation |

| Computed Property | Purpose |
|-------------------|---------|
| `collections` | Paginated, filtered, searched. Includes `withCount('products')`. |

#### Layout

Same pattern as Products list:
- Heading "Collections" with "Add collection" primary button
- Search input
- Status filter dropdown

#### Table Columns

| Column | Content |
|--------|---------|
| Title | Link to edit page |
| Products count | Number of products in collection |
| Status | Flux badge |
| Updated date | Relative timestamp |

**Empty state:** "Create your first collection" with CTA button.

### 5.2 Collection Edit/Create

**Route:** `GET /admin/collections/create` and `GET /admin/collections/{collection}/edit`

**Livewire component:** `App\Livewire\Admin\Collections\Form`

**Blade view:** `resources/views/livewire/admin/collections/form.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `collection` | `?Collection` | The collection being edited |
| `title` | `string` | Collection title |
| `handle` | `string` | URL slug |
| `descriptionHtml` | `string` | Collection description |
| `status` | `string` | `active` or `archived` |
| `productSearch` | `string` | Search input for product assignment |
| `assignedProductIds` | `array<int>` | Ordered list of product IDs in this collection |

| Action | Behavior |
|--------|----------|
| `save()` | Validates and saves the collection with product assignments |
| `addProduct(int $productId)` | Adds a product to the collection |
| `removeProduct(int $productId)` | Removes a product from the collection |
| `reorderProducts(array $order)` | Updates product positions |

| Computed Property | Purpose |
|-------------------|---------|
| `searchResults` | Products matching `productSearch` that are not already assigned |
| `assignedProducts` | Ordered collection of assigned Product models |

#### Layout Wireframe

```
+------------------------------------------+-------------------+
|          LEFT COLUMN (2/3)               | RIGHT COLUMN (1/3)|
+------------------------------------------+-------------------+
|  Title: [Summer Collection         ]     | Status: [Active v] |
|  Handle: [summer-collection        ]     |                   |
|  Description:                            |                   |
|  [textarea...                      ]     |                   |
|                                          |                   |
|  PRODUCTS                                |                   |
|  Search: [Search products...       ]     |                   |
|  +----------------------------------+   |                   |
|  | Blue Shirt           [Add]       |   |                   |
|  | Red Hat              [Add]       |   |                   |
|  +----------------------------------+   |                   |
|                                          |                   |
|  Assigned products:                      |                   |
|  [drag] [img] Sneakers         [remove]  |                   |
|  [drag] [img] Blue Shirt       [remove]  |                   |
+------------------------------------------+-------------------+

+==================================================================+
| STICKY SAVE BAR                          [Discard]  [Save]       |
+==================================================================+
```

**Left column:**
- Title input
- Handle input
- Description textarea
- Products assignment section:
  - Search input with live debounce (300ms)
  - Search results dropdown (conditionally shown): list of matching products with "Add" button
  - Assigned products list: each row shows product title, thumbnail, and a remove button. Rows are sortable via drag-to-reorder.

**Right column:**
- Status: Flux select with Active / Archived
- Sticky save bar (same pattern as product form)

---

## 6. Inventory Management

**Route:** `GET /admin/inventory`

**Livewire component:** `App\Livewire\Admin\Inventory\Index`

**Blade view:** `resources/views/livewire/admin/inventory/index.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|

status: completed


output:
Chunk ID: db5744
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5120
Output:
## 3. Products List

**Route:** `GET /admin/products`

**Livewire component:** `App\Livewire\Admin\Products\Index`

**Blade view:** `resources/views/livewire/admin/products/index.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `search` | `string` | Search query, live-debounced at 300ms |
| `statusFilter` | `string` | Status filter: `all`, `draft`, `active`, `archived` |
| `typeFilter` | `string` | Product type filter |
| `selectedIds` | `array<int>` | Array of selected product IDs for bulk actions |
| `selectAll` | `bool` | Whether all visible rows are selected |
| `sortField` | `string` | Column to sort by (default: `updated_at`) |
| `sortDirection` | `string` | `asc` or `desc` |

| Action | Behavior |
|--------|----------|
| `updatedSearch()` | Resets pagination |
| `updatedStatusFilter()` | Resets pagination |
| `updatedTypeFilter()` | Resets pagination |
| `bulkArchive()` | Archives all selected products |
| `bulkDelete()` | Soft-deletes selected products (with confirmation) |
| `bulkSetActive()` | Sets selected products to active status |
| `sortBy(string $field)` | Toggles sort direction or changes sort field |
| `toggleSelectAll()` | Selects or deselects all visible product IDs |
| `confirmBulkDelete()` | Opens delete confirmation modal |

| Computed Property | Purpose |
|-------------------|---------|
| `products` | Paginated query result with search, filters, sorting applied. Eager loads `variants`, `media` (limit 1). Uses `withCount('variants')`. |
| `productTypes` | Distinct product types for the type filter dropdown |

### Wireframe

```
+------------------------------------------------------------------+
| Products                                    [+ Add product]       |
+------------------------------------------------------------------+
| [search icon] Search products...   [Status: All v] [Type: All v] |
+------------------------------------------------------------------+
| (shown when items selected)                                       |
| "3 products selected"  [Set Active]  [Archive]  [Delete]         |
+------------------------------------------------------------------+
| [x] | IMG | Title ^     | Status  | Inventory | Type | Vendor | Updated ^  |
|-----|-----|-------------|---------|-----------|------|--------|-----------|
| [ ] | img | Blue Shirt  | Active  | 45        | Tops | Nike   | 2h ago    |
| [ ] | img | Red Hat     | Draft   | 12        | Hats | Adidas | 1d ago    |
| [ ] | img | Sneakers    | Active  | 0         | Shoes| Nike   | 3d ago    |
| ...                                                              |
+------------------------------------------------------------------+
| < 1 2 3 ... 10 >  (pagination)                                  |
+------------------------------------------------------------------+
```

### Table Column Definitions

| Column | Sortable | Content |
|--------|----------|---------|
| Select | No | Checkbox for bulk selection |
| Image | No | 40x40 rounded thumbnail of first media item, or placeholder icon |
| Title | Yes | Product title as a link to the edit page (uses Livewire navigate) |
| Status | No | Flux badge: draft=zinc/gray, active=green, archived=red |
| Inventory | Yes | Sum of `inventory_items.quantity_on_hand` across all variants |
| Type | No | Product type text or "-" |
| Vendor | No | Vendor name text or "-" |
| Updated | Yes (default) | Relative timestamp (e.g., "2h ago") |

### Bulk Action Bar

Conditionally shown when `count($selectedIds) > 0`. Contains:
- Text showing "X products selected"
- "Set Active" button (ghost variant)
- "Archive" button (ghost variant)
- "Delete" button (danger variant) - opens confirmation modal

### Empty State

When no products exist (not filtered, genuinely empty):
- Centered container with a large muted placeholder icon (cube)
- Heading: "Add your first product"
- Text: "Start building your catalog by adding products."
- Primary button: "Add product" linking to the create page

### Delete Confirmation Modal

| Property | Value |
|----------|-------|
| Modal name | `confirm-bulk-delete` |
| Max width | md |
| Heading | "Delete products?" |
| Body text | "This will archive X product(s). Products with orders cannot be permanently deleted." |
| Cancel button | Ghost variant, closes modal |
| Confirm button | Danger variant, calls `bulkDelete` |

### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Page title | `heading` |
| Add product button | `button` (variant: primary) |
| Search field | `input` (icon: magnifying-glass) |
| Status filter | `select` |
| Type filter | `select` |
| Bulk action buttons | `button` (ghost/danger variants) |
| Selected count text | `text` |
| Row checkbox | `checkbox` |
| Status badges | `badge` |
| Cell text | `text` |
| Delete confirmation | `modal` |
| Pagination | Laravel default Tailwind pagination |

### View States

| State | Behavior |
|-------|----------|
| Loading | Table body shows reduced opacity |
| Empty (no products) | Empty state with illustration and CTA |
| Empty (filtered) | Table with "No products match your filters" message |
| Populated | Table with data rows and pagination |

---

## 4. Product Create/Edit

**Route:** `GET /admin/products/create` and `GET /admin/products/{product}/edit`

**Livewire component:** `App\Livewire\Admin\Products\Form`

**Blade view:** `resources/views/livewire/admin/products/form.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `product` | `?Product` | The product being edited, null for create |
| `title` | `string` | Product title |
| `descriptionHtml` | `string` | Product description (HTML) |
| `status` | `string` | `draft`, `active`, `archived` |
| `vendor` | `string` | Vendor name |
| `productType` | `string` | Product type string |
| `tags` | `string` | Comma-separated tags |
| `handle` | `string` | URL handle/slug |
| `publishedAt` | `?string` | Publish date (Y-m-d H:i) |
| `collectionIds` | `array<int>` | Selected collection IDs |
| `options` | `array` | Options array: `[{name: string, values: string[]}]` |
| `variants` | `array` | Variants array: `[{sku, price, compareAtPrice, quantity, requiresShipping, optionValues}]` |
| `media` | `array` | Existing media items: `[{id, url, alt_text, position}]` |
| `newMedia` | `array` | Temporary uploaded files |

| Action | Behavior |
|--------|----------|
| `mount(?Product $product)` | Loads product data into properties or sets defaults for create |
| `save()` | Validates and saves/creates the product, variants, options, and media |
| `addOption()` | Adds a new empty option `{name: '', values: []}` |
| `removeOption(int $index)` | Removes an option and regenerates variants |
| `addOptionValue(int $optionIndex)` | Adds a value to an option |
| `removeOptionValue(int $optionIndex, int $valueIndex)` | Removes a value |
| `generateVariants()` | Generates variant combinations from current options |
| `uploadMedia()` | Handles file upload via Livewire temporary upload |
| `removeMedia(int $mediaId)` | Removes a media item |
| `reorderMedia(array $order)` | Updates media positions |
| `updateMediaAlt(int $mediaId, string $alt)` | Updates alt text for a media item |
| `deleteProduct()` | Archives the product (with confirmation modal) |

| Computed Property | Purpose |
|-------------------|---------|
| `availableCollections` | All collections for the current store |
| `isEditing` | `bool` - whether editing or creating |

### Validation Rules

| Field | Rules |
|-------|-------|
| `title` | Required, string, max 255 |
| `descriptionHtml` | Nullable, string, max 65535 |
| `status` | Required, one of: draft, active, archived |
| `vendor` | Nullable, string, max 255 |
| `productType` | Nullable, string, max 255 |
| `tags` | Nullable, string |
| `handle` | Required, string, max 255, unique (excluding current product) |
| `variants.*.sku` | Nullable, string, max 255 |
| `variants.*.price` | Required, integer, min 0 |
| `variants.*.compareAtPrice` | Nullable, integer, min 0 |
| `variants.*.quantity` | Required, integer, min 0 |

### Two-Column Layout Wireframe

```
+------------------------------------------+-------------------+
|          LEFT COLUMN (2/3)               | RIGHT COLUMN (1/3)|
+------------------------------------------+-------------------+
|                                          |                   |
|  TITLE                                   |  STATUS CARD      |
|  +------------------------------------+  |  Status: [Draft v]|
|  | [Short Sleeve T-Shirt           ]  |  |                   |
|  +------------------------------------+  |  PUBLISHING CARD  |
|                                          |  Published at:    |
|  DESCRIPTION                             |  [datetime input]  |
|  +------------------------------------+  |                   |
|  | Describe your product...           |  |  ORGANIZATION     |
|  |                                    |  |  Vendor:          |
|  |                                    |  |  [Nike          ] |
|  |                                    |  |  Product type:    |
|  +------------------------------------+  |  [T-Shirts      ] |
|                                          |  Tags:            |
|  MEDIA                                   |  [summer, cotton ] |
|  +------------------------------------+  |  (comma-separated)|
|  | +--+ +--+ +--+ +--+               |  |                   |
|  | |  | |  | |  | |  |  (thumbnails) |  |  COLLECTIONS      |
|  | +--+ +--+ +--+ +--+               |  |  [x] Summer Sale  |
|  |                                    |  |  [ ] Winter       |
|  | [--- Drag & drop or click ---]    |  |  [x] New Arrivals |
|  +------------------------------------+  |                   |
|                                          |                   |
|  VARIANTS                                |                   |
|  Option name: [Size    ]                 |                   |
|  Values:      [S, M, L, XL         ]    |                   |
|  [trash]                                 |                   |
|                                          |                   |
|  [+ Add another option]                  |                   |
|                                          |                   |
|  Variant | SKU    | Price | Compare | Qty | Ship |          |
|  S / Red  | [   ] | [   ] | [     ] | [ ] | [x]  |          |
|  M / Red  | [   ] | [   ] | [     ] | [ ] | [x]  |          |
|  L / Red  | [   ] | [   ] | [     ] | [ ] | [x]  |          |
|                                          |                   |
|  SEO (collapsible)                       |                   |
|  > Search engine listing                 |                   |
|    URL handle: [short-sleeve-t-shirt]    |                   |
+------------------------------------------+-------------------+

+==================================================================+
| STICKY SAVE BAR (fixed bottom)                                    |
|                                      [Discard]  [Save]           |
+==================================================================+
```

### Left Column Sections

#### Title Input
- Flux field with label "Title"
- Flux input, placeholder "Short Sleeve T-Shirt"
- Flux error display for validation

#### Description
- Flux field with label "Description"
- Flux textarea, 8 rows, placeholder "Describe your product..."
- Future enhancement: WYSIWYG toolbar via Alpine.js; baseline is plain textarea

#### Media Section
A card with heading "Media" (size md).

**Upload area:** A dashed-border drop zone with upload icon and text "Drag and drop images or click to upload". A hidden file input (multiple, accept images) triggered by clicking the zone.

**Upload progress:** A progress bar shown during file upload.

**Media grid:** A 4-column grid (responsive: 2 on small, 3 on sm, 4 on lg) of thumbnails:
- Each item: square aspect ratio, object-cover, rounded
- On hover overlay shows: delete button (X icon, top-right), alt text edit button (pencil icon, bottom-left)
- Drag-to-reorder supported via Livewire sortable or Alpine.js Sortable

#### Variants Section
A card with heading "Variants" (size md).

**Options builder:** For each option, a row containing:
- "Option name" input field (placeholder: "Size")
- "Values" input field (placeholder: "S, M, L, XL" - comma-separated)
- Trash button to remove the option

Below options: "Add another option" ghost button with plus icon.

When options change, `generateVariants()` is called automatically via lifecycle hook.

**Variants table:** Shown when variants exist. Scrollable table with inline-editable fields:

| Column | Input Type | Description |
|--------|-----------|-------------|
| Variant | Read-only text | Combination name, e.g. "S / Red" |
| SKU | Text input (small) | Stock keeping unit |
| Price | Number input (small) | Price in major units |
| Compare at price | Number input (small) | Original price for sale display |
| Quantity | Number input (small) | On-hand inventory |
| Requires shipping | Checkbox | Whether variant needs shipping |

#### SEO Section
A collapsible section (collapsed by default, expands with animation):
- Toggle button: chevron icon + "Search engine listing" text
- When expanded: URL handle input field with placeholder "short-sleeve-t-shirt" and validation error display

### Right Column Sections

#### Status Card
- Flux field with label "Status"
- Flux select with options: Draft, Active, Archived

#### Publishing Card
- Flux field with label "Published at"
- Datetime-local input

#### Product Organization Card
- Vendor: Flux input, placeholder "Nike"
- Product type: Flux input, placeholder "T-Shirts"
- Tags: Flux input, placeholder "summer, cotton, sale" with description "Separate tags with commas"

#### Collections Card
- Flux field with label "Collections"
- For each available collection: a row with checkbox and collection title text
- Checkbox values bound to `collectionIds`

### Sticky Save Bar

Fixed at the bottom of the viewport. Appears when changes are detected.
- Left-aligned to account for sidebar width on desktop
- "Discard" button (ghost variant) - links back to products index
- "Save" button (primary variant) - calls `save()`, shows "Saving..." text during loading, disabled while loading

### Delete Confirmation Modal (Edit Only)

| Property | Value |
|----------|-------|
| Modal name | `confirm-delete-product` |
| Max width | md |
| Heading | "Delete this product?" |
| Body text | "This product will be archived. Products with existing orders cannot be permanently removed." |
| Cancel button | Ghost variant, closes modal |
| Confirm button | Danger variant, calls `deleteProduct` |

### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Page title | `heading` |
| Section titles | `heading` (size md) |
| All form labels | `field`, label via Flux |
| Text inputs | `input` |
| Textarea | `textarea` |
| Status/type selects | `select` |
| Checkboxes | `checkbox` |
| Validation errors | `field` error display |
| Tags description | `field` description |
| Save/discard buttons | `button` |
| Delete confirmation | `modal` |
| Section dividers | `separator` |
| Variant icons | `icon` |
| Status text | `text` |

### View States

| State | Behavior |
|-------|----------|
| Loading (save) | Save button disabled, text changes to "Saving..." |
| Loading (upload) | Progress bar shown in media section |
| Create mode | Empty form, no delete button, heading says "Add product" |
| Edit mode | Pre-filled form, delete button visible, heading shows product title |
| Validation error | Inline error messages below each invalid field |

---

## 5. Collections List and Edit

### 5.1 Collections List

**Route:** `GET /admin/collections`

**Livewire component:** `App\Livewire\Admin\Collections\Index`

**Blade view:** `resources/views/livewire/admin/collections/index.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `search` | `string` | Search query |
| `statusFilter` | `string` | `all`, `active`, `archived` |

| Action | Behavior |
|--------|----------|
| `updatedSearch()` | Resets pagination |
| `deleteCollection(int $id)` | Deletes a collection after confirmation |

| Computed Property | Purpose |
|-------------------|---------|
| `collections` | Paginated, filtered, searched. Includes `withCount('products')`. |

#### Layout

Same pattern as Products list:
- Heading "Collections" with "Add collection" primary button
- Search input
- Status filter dropdown

#### Table Columns

| Column | Content |
|--------|---------|
| Title | Link to edit page |
| Products count | Number of products in collection |
| Status | Flux badge |
| Updated date | Relative timestamp |

**Empty state:** "Create your first collection" with CTA button.

### 5.2 Collection Edit/Create

**Route:** `GET /admin/collections/create` and `GET /admin/collections/{collection}/edit`

**Livewire component:** `App\Livewire\Admin\Collections\Form`

**Blade view:** `resources/views/livewire/admin/collections/form.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `collection` | `?Collection` | The collection being edited |
| `title` | `string` | Collection title |
| `handle` | `string` | URL slug |
| `descriptionHtml` | `string` | Collection description |
| `status` | `string` | `active` or `archived` |
| `productSearch` | `string` | Search input for product assignment |
| `assignedProductIds` | `array<int>` | Ordered list of product IDs in this collection |

| Action | Behavior |
|--------|----------|
| `save()` | Validates and saves the collection with product assignments |
| `addProduct(int $productId)` | Adds a product to the collection |
| `removeProduct(int $productId)` | Removes a product from the collection |
| `reorderProducts(array $order)` | Updates product positions |

| Computed Property | Purpose |
|-------------------|---------|
| `searchResults` | Products matching `productSearch` that are not already assigned |
| `assignedProducts` | Ordered collection of assigned Product models |

#### Layout Wireframe

```
+------------------------------------------+-------------------+
|          LEFT COLUMN (2/3)               | RIGHT COLUMN (1/3)|
+------------------------------------------+-------------------+
|  Title: [Summer Collection         ]     | Status: [Active v] |
|  Handle: [summer-collection        ]     |                   |
|  Description:                            |                   |
|  [textarea...                      ]     |                   |
|                                          |                   |
|  PRODUCTS                                |                   |
|  Search: [Search products...       ]     |                   |
|  +----------------------------------+   |                   |
|  | Blue Shirt           [Add]       |   |                   |
|  | Red Hat              [Add]       |   |                   |
|  +----------------------------------+   |                   |
|                                          |                   |
|  Assigned products:                      |                   |
|  [drag] [img] Sneakers         [remove]  |                   |
|  [drag] [img] Blue Shirt       [remove]  |                   |
+------------------------------------------+-------------------+

+==================================================================+
| STICKY SAVE BAR                          [Discard]  [Save]       |
+==================================================================+
```

**Left column:**
- Title input
- Handle input
- Description textarea
- Products assignment section:
  - Search input with live debounce (300ms)
  - Search results dropdown (conditionally shown): list of matching products with "Add" button
  - Assigned products list: each row shows product title, thumbnail, and a remove button. Rows are sortable via drag-to-reorder.

**Right column:**
- Status: Flux select with Active / Archived
- Sticky save bar (same pattern as product form)

---

## 6. Inventory Management

**Route:** `GET /admin/inventory`

**Livewire component:** `App\Livewire\Admin\Inventory\Index`

**Blade view:** `resources/views/livewire/admin/inventory/index.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|


command: sed -n '376,740p' specs/04-STOREFRONT-UI.md

aggregated_output:
## 4. Collection Page (GET /collections/{handle})

**Livewire Component:** CollectionPage

### 4.1 Collection Header

| Element | Description |
|---|---|
| Breadcrumbs | Home > Collections > {Collection Title} |
| Title | H1, large, bold |
| Description | Rendered HTML from collection description, styled with prose/typography, constrained width |
| Spacing | Generous vertical padding |

### 4.2 Toolbar

Horizontal bar between the header and the product grid.

**Desktop:**

```
+--------------------------------------------------------------+
| [Filter toggle button]          [X products] [Sort dropdown]  |
+--------------------------------------------------------------+
```

**Mobile:**

```
+--------------------------------------------------------------+
| [Filter button]                           [Sort dropdown]     |
+--------------------------------------------------------------+
```

| Element | Description |
|---|---|
| Product count | Small muted text, e.g., "24 products" |
| Sort dropdown | Select element with live Livewire binding |

**Sort Options:**

| Option | Description |
|---|---|
| Featured | Default sort order |
| Price: Low to High | Ascending by price |
| Price: High to Low | Descending by price |
| Newest | Descending by creation date |
| Best Selling | Descending by sales count |

### 4.3 Filter Sidebar

**Desktop (large breakpoint and above):** Persistent sidebar on the left, approximately 256px wide.
**Mobile (below large breakpoint):** Slide-out drawer from the left, triggered by "Filter" button with filter icon.

**Filter Groups:**

Each filter group is a collapsible section with a heading and toggle chevron.

| Filter Group | Type | Binding | Description |
|---|---|---|---|
| Availability | Single checkbox | Live | "In stock" toggle |
| Price Range | Two number inputs | Live with 500ms debounce | "Min" and "Max" inputs with currency symbol prefix, displayed side by side |
| Product Type | Checkbox list | Live | Dynamically sourced from products in the collection |
| Vendor | Checkbox list | Live | Dynamically sourced from products in the collection |

**Clear All:**

- Link at the top of the filter sidebar: "Clear all filters"
- Only visible when at least one filter is active
- Small, blue, interactive text

**Active Filter Pills:**

- Displayed above the product grid (below toolbar) when filters are active
- Each pill: rounded tag with filter value text and a remove (X) button
- "Clear all" link at the end of the pills row

**Mobile Filter Drawer:**

| Attribute | Description |
|---|---|
| Position | Full-height overlay from left side |
| Header | "Filters" title + close button (X) |
| Content | Same filter groups as desktop, stacked vertically |
| Footer | Sticky "Apply" button at bottom that closes the drawer |
| Clear | "Clear all" link in header area |
| Focus | Trapped within drawer while open |

### 4.4 Product Grid

| Attribute | Description |
|---|---|
| Layout | Fills remaining width next to the sidebar |
| Columns | 2 on mobile, 3 on tablet, 3 on desktop (when sidebar visible). Without sidebar: 2 mobile, 3 tablet, 4 desktop |
| Loading state | Subtle opacity reduction on the grid while results update |

### 4.5 Product Card (Component)

The product card is a reusable component used on collection pages, search results, and featured products sections.

```
+---------------------------+
|  [Product Image]          |
|  1:1 aspect ratio         |
|  cover-fit, rounded       |
|  (hover: show 2nd image)  |
|                           |
|  [Sale badge]  [Sold out] |
+---------------------------+
|  [Product Title]          |
|  [Price]  [Compare price] |
|  [Quick Add / Options]    |
+---------------------------+
```

**Image Behavior:**

| Attribute | Description |
|---|---|
| Container | Square aspect ratio, rounded corners, overflow hidden, gray placeholder background |
| Primary image | Cover-fit, fills the container |
| Secondary image | On hover (desktop with hover capability only), crossfades to the second product image |
| Fallback | If no image, show a centered shopping bag placeholder icon |
| Loading | Lazy-loaded |

**Badges:**

| Badge | Condition | Position |
|---|---|---|
| "Sale" | compare_at_amount > price_amount | Top-left of image, stacked vertically |
| "Sold out" | All variants out of stock with deny policy | Top-left of image, stacked vertically |

**Text Content:**

| Element | Description |
|---|---|
| Title | H3 (or configurable heading level), small semi-bold text. Truncated to 2 lines |
| Price | Current price in small semi-bold text. Compare-at price shown with strikethrough if applicable |
| Quick Add | Single variant: "Add to cart" button. Multiple variants: "Choose options" link text. Hidden by default on desktop (shown on hover), always visible on mobile |

**Accessibility:**

- Card link wraps the entire card; title serves as the accessible name
- Badges have screen reader labels (e.g., "On sale")
- Price changes announced via parent live region…2838 chars truncated…nail strip | Horizontal row with overflow scroll, small gap between thumbnails |
| Each thumbnail | 64x64px, rounded, cover-fit, pointer cursor. Active thumbnail has a colored border |
| Variant images | When a variant is selected that has specific images, those images are shown |

**Mobile:**

| Attribute | Description |
|---|---|
| Gallery | Horizontal scrollable row with snap-scroll behavior |
| Each image | Full-width, square aspect ratio, rounded, cover-fit |
| Scroll indicators | Row of dots below the gallery. Active dot is dark (light in dark mode), inactive dots are gray |

**Accessibility:**

| Requirement | Description |
|---|---|
| Alt text | Main image has descriptive alt text from product media data |
| Thumbnails | Rendered as buttons with labels "View image X of Y" and current state indicator |
| Region | Gallery wrapped in a labeled region ("Product images") |

### 5.3 Product Info (Right Column)

#### Breadcrumbs

Home > {Primary Collection} > {Product Title}. Small, muted text with separator characters.

#### Product Title

H1, large, bold.

#### Price Display

| Element | Description |
|---|---|
| Current price | Large, bold |
| Compare-at price | Medium, muted, strikethrough (shown when set and higher than current price) |
| Sale badge | Inline badge next to the price |
| Currency | Formatted based on the store's default currency |
| Live updates | Price container is a live region, so price changes when variant changes are announced to screen readers |

#### Variant Selector

For each product option (e.g., Size, Color), render a selector group.

**Radio button style (for options with 6 or fewer values):**

```
Size
[S] [M] [L] [XL] [XXL]
```

| State | Visual Description |
|---|---|
| Available | Bordered pill shape, pointer cursor, border darkens on hover |
| Selected | Primary color border with subtle background tint and focus ring |
| Unavailable | Muted border, muted text, strikethrough, reduced opacity, not-allowed cursor |

**Select dropdown style:** Used when the option has more than 6 values.

**Color swatches (when option name is "Color"):**

| Attribute | Description |
|---|---|
| Shape | Circular, 32x32px |
| Color | Determined by value name mapped to a color lookup or inline style |
| Selected state | Ring with offset around the swatch |
| Tooltip | Shows color name on hover |

**Livewire behavior:**

- Selected options are a key-value map (e.g., Size = M, Color = Red)
- Selected variant is computed by matching all selected options to the variant option values
- On change: updates price, stock messaging, available images, and add-to-cart availability

#### Stock Messaging

Displayed below the variant selector.

| Condition | Message | Visual Style |
|---|---|---|
| In stock, quantity > 10 | "In stock" | Green text with check icon |
| In stock, quantity <= 10 | "Only X left in stock" | Amber text with warning icon |
| Out of stock, deny policy | "Out of stock" | Red text with X icon |
| Out of stock, continue policy | "Available on backorder" | Blue text with info icon |

Small text, icon + text inline. Wrapped in a live region for screen reader announcements on variant change.

#### Quantity Selector

Uses the quantity-selector component.

```
[-] [3] [+]
```

| Attribute | Description |
|---|---|
| Container | Inline flex, bordered, rounded |
| Decrease button | "-" icon, 40x40px. Disabled at minimum (1) |
| Input | Centered number input, 56px wide, 40px tall. Min = 1, Max = available stock (deny policy) or unlimited (continue policy) |
| Increase button | "+" icon, same size. Disabled at maximum |
| Disabled state | Reduced opacity, not-allowed cursor |
| Labels | Input labeled "Quantity", buttons labeled "Decrease quantity" / "Increase quantity" |

#### Add to Cart Button

| Attribute | Description |
|---|---|
| Width | Full width |
| Style | Primary button: blue background, white text, semi-bold, generous padding, rounded |
| Text | "Add to cart" |
| Loading state | Text changes to "Adding..." with spinner icon. Button disabled during loading |
| Sold out state | Gray background, muted text, not-allowed cursor. Text: "Sold out" |
| Spacing | Generous top margin |

**Livewire action (addToCart):**

1. Validates variant is selected and in stock
2. Adds to cart (creates cart if none exists in session)
3. Dispatches "cart-updated" browser event
4. Cart drawer opens automatically

#### Product Description

- Separated from above content by a horizontal rule with generous vertical spacing
- Rendered HTML styled with prose/typography styling

#### Tags

- Displayed below the description (if tags exist)
- Horizontal wrapping row with gap
- Each tag: rounded pill, gray background, small text

### 5.4 Accessibility Summary

| Requirement | Implementation |
|---|---|
| Variant radio buttons | Properly labeled with labels and grouped with fieldset/legend |
| Live regions | Price display, stock messaging, add-to-cart feedback |
| Image alt text | All images have meaningful alt text |


output:
Chunk ID: 9d7eda
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3210
Output:
## 4. Collection Page (GET /collections/{handle})

**Livewire Component:** CollectionPage

### 4.1 Collection Header

| Element | Description |
|---|---|
| Breadcrumbs | Home > Collections > {Collection Title} |
| Title | H1, large, bold |
| Description | Rendered HTML from collection description, styled with prose/typography, constrained width |
| Spacing | Generous vertical padding |

### 4.2 Toolbar

Horizontal bar between the header and the product grid.

**Desktop:**

```
+--------------------------------------------------------------+
| [Filter toggle button]          [X products] [Sort dropdown]  |
+--------------------------------------------------------------+
```

**Mobile:**

```
+--------------------------------------------------------------+
| [Filter button]                           [Sort dropdown]     |
+--------------------------------------------------------------+
```

| Element | Description |
|---|---|
| Product count | Small muted text, e.g., "24 products" |
| Sort dropdown | Select element with live Livewire binding |

**Sort Options:**

| Option | Description |
|---|---|
| Featured | Default sort order |
| Price: Low to High | Ascending by price |
| Price: High to Low | Descending by price |
| Newest | Descending by creation date |
| Best Selling | Descending by sales count |

### 4.3 Filter Sidebar

**Desktop (large breakpoint and above):** Persistent sidebar on the left, approximately 256px wide.
**Mobile (below large breakpoint):** Slide-out drawer from the left, triggered by "Filter" button with filter icon.

**Filter Groups:**

Each filter group is a collapsible section with a heading and toggle chevron.

| Filter Group | Type | Binding | Description |
|---|---|---|---|
| Availability | Single checkbox | Live | "In stock" toggle |
| Price Range | Two number inputs | Live with 500ms debounce | "Min" and "Max" inputs with currency symbol prefix, displayed side by side |
| Product Type | Checkbox list | Live | Dynamically sourced from products in the collection |
| Vendor | Checkbox list | Live | Dynamically sourced from products in the collection |

**Clear All:**

- Link at the top of the filter sidebar: "Clear all filters"
- Only visible when at least one filter is active
- Small, blue, interactive text

**Active Filter Pills:**

- Displayed above the product grid (below toolbar) when filters are active
- Each pill: rounded tag with filter value text and a remove (X) button
- "Clear all" link at the end of the pills row

**Mobile Filter Drawer:**

| Attribute | Description |
|---|---|
| Position | Full-height overlay from left side |
| Header | "Filters" title + close button (X) |
| Content | Same filter groups as desktop, stacked vertically |
| Footer | Sticky "Apply" button at bottom that closes the drawer |
| Clear | "Clear all" link in header area |
| Focus | Trapped within drawer while open |

### 4.4 Product Grid

| Attribute | Description |
|---|---|
| Layout | Fills remaining width next to the sidebar |
| Columns | 2 on mobile, 3 on tablet, 3 on desktop (when sidebar visible). Without sidebar: 2 mobile, 3 tablet, 4 desktop |
| Loading state | Subtle opacity reduction on the grid while results update |

### 4.5 Product Card (Component)

The product card is a reusable component used on collection pages, search results, and featured products sections.

```
+---------------------------+
|  [Product Image]          |
|  1:1 aspect ratio         |
|  cover-fit, rounded       |
|  (hover: show 2nd image)  |
|                           |
|  [Sale badge]  [Sold out] |
+---------------------------+
|  [Product Title]          |
|  [Price]  [Compare price] |
|  [Quick Add / Options]    |
+---------------------------+
```

**Image Behavior:**

| Attribute | Description |
|---|---|
| Container | Square aspect ratio, rounded corners, overflow hidden, gray placeholder background |
| Primary image | Cover-fit, fills the container |
| Secondary image | On hover (desktop with hover capability only), crossfades to the second product image |
| Fallback | If no image, show a centered shopping bag placeholder icon |
| Loading | Lazy-loaded |

**Badges:**

| Badge | Condition | Position |
|---|---|---|
| "Sale" | compare_at_amount > price_amount | Top-left of image, stacked vertically |
| "Sold out" | All variants out of stock with deny policy | Top-left of image, stacked vertically |

**Text Content:**

| Element | Description |
|---|---|
| Title | H3 (or configurable heading level), small semi-bold text. Truncated to 2 lines |
| Price | Current price in small semi-bold text. Compare-at price shown with strikethrough if applicable |
| Quick Add | Single variant: "Add to cart" button. Multiple variants: "Choose options" link text. Hidden by default on desktop (shown on hover), always visible on mobile |

**Accessibility:**

- Card link wraps the entire card; title serves as the accessible name
- Badges have screen reader labels (e.g., "On sale")
- Price changes announced via parent live region when filtering changes results

### 4.6 Pagination

| Attribute | Description |
|---|---|
| Style | Numbered pagination with previous/next arrow buttons |
| Current page | Highlighted with primary color background and white text |
| Other pages | Muted text, hover background |
| Disabled | Reduced opacity and not-allowed cursor on previous (at first page) or next (at last page) |
| Truncation | Ellipsis for large page counts |
| Mobile | Simplified: previous/next only with current page indicator |

### 4.7 Empty State

When no products match the current filters:

```
+--------------------------------------------------------------+
|  [Search icon - large, muted]                                 |
|  "No products found"                                          |
|  "Try adjusting your filters or browse our full collection."  |
|  [Clear filters button]                                       |
+--------------------------------------------------------------+
```

| Element | Description |
|---|---|
| Icon | Large, muted search icon |
| Heading | Medium, semi-bold |
| Subtext | Muted, descriptive guidance |
| Button | Secondary style, "Clear filters" |
| Position | Centered in the grid area with generous vertical padding |

---

## 5. Product Page (GET /products/{handle})

**Livewire Component:** ProductPage

### 5.1 Layout

**Desktop (large breakpoint and above):** Two-column, 50/50 split. Left column (images) is sticky while the right column (product info) scrolls.

**Mobile:** Single column, stacked. Images first, then product info.

```
Desktop:
+-------------------------------+-------------------------------+
|  [Image Gallery]              |  [Product Info]               |
|  (sticky while scrolling)     |  (scrollable)                 |
+-------------------------------+-------------------------------+

Mobile:
+--------------------------------------------------------------+
|  [Image Gallery - horizontal scroll]                          |
+--------------------------------------------------------------+
|  [Product Info - full width]                                  |
+--------------------------------------------------------------+
```

Container constrained to standard max-width with horizontal padding and vertical spacing.

### 5.2 Image Gallery (Left Column)

**Desktop:**

```
+-------------------------------+
|                               |
|  [Main Image - large]         |
|  1:1 aspect ratio, rounded    |
|                               |
+-------------------------------+
| [Thumb] [Thumb] [Thumb] ...  |
+-------------------------------+
```

| Attribute | Description |
|---|---|
| Main image | Square aspect ratio, large rounded corners, cover-fit. Gray placeholder background |
| Zoom on hover | Optional (theme setting): image scales to 150% and follows cursor position |
| Thumbnail strip | Horizontal row with overflow scroll, small gap between thumbnails |
| Each thumbnail | 64x64px, rounded, cover-fit, pointer cursor. Active thumbnail has a colored border |
| Variant images | When a variant is selected that has specific images, those images are shown |

**Mobile:**

| Attribute | Description |
|---|---|
| Gallery | Horizontal scrollable row with snap-scroll behavior |
| Each image | Full-width, square aspect ratio, rounded, cover-fit |
| Scroll indicators | Row of dots below the gallery. Active dot is dark (light in dark mode), inactive dots are gray |

**Accessibility:**

| Requirement | Description |
|---|---|
| Alt text | Main image has descriptive alt text from product media data |
| Thumbnails | Rendered as buttons with labels "View image X of Y" and current state indicator |
| Region | Gallery wrapped in a labeled region ("Product images") |

### 5.3 Product Info (Right Column)

#### Breadcrumbs

Home > {Primary Collection} > {Product Title}. Small, muted text with separator characters.

#### Product Title

H1, large, bold.

#### Price Display

| Element | Description |
|---|---|
| Current price | Large, bold |
| Compare-at price | Medium, muted, strikethrough (shown when set and higher than current price) |
| Sale badge | Inline badge next to the price |
| Currency | Formatted based on the store's default currency |
| Live updates | Price container is a live region, so price changes when variant changes are announced to screen readers |

#### Variant Selector

For each product option (e.g., Size, Color), render a selector group.

**Radio button style (for options with 6 or fewer values):**

```
Size
[S] [M] [L] [XL] [XXL]
```

| State | Visual Description |
|---|---|
| Available | Bordered pill shape, pointer cursor, border darkens on hover |
| Selected | Primary color border with subtle background tint and focus ring |
| Unavailable | Muted border, muted text, strikethrough, reduced opacity, not-allowed cursor |

**Select dropdown style:** Used when the option has more than 6 values.

**Color swatches (when option name is "Color"):**

| Attribute | Description |
|---|---|
| Shape | Circular, 32x32px |
| Color | Determined by value name mapped to a color lookup or inline style |
| Selected state | Ring with offset around the swatch |
| Tooltip | Shows color name on hover |

**Livewire behavior:**

- Selected options are a key-value map (e.g., Size = M, Color = Red)
- Selected variant is computed by matching all selected options to the variant option values
- On change: updates price, stock messaging, available images, and add-to-cart availability

#### Stock Messaging

Displayed below the variant selector.

| Condition | Message | Visual Style |
|---|---|---|
| In stock, quantity > 10 | "In stock" | Green text with check icon |
| In stock, quantity <= 10 | "Only X left in stock" | Amber text with warning icon |
| Out of stock, deny policy | "Out of stock" | Red text with X icon |
| Out of stock, continue policy | "Available on backorder" | Blue text with info icon |

Small text, icon + text inline. Wrapped in a live region for screen reader announcements on variant change.

#### Quantity Selector

Uses the quantity-selector component.

```
[-] [3] [+]
```

| Attribute | Description |
|---|---|
| Container | Inline flex, bordered, rounded |
| Decrease button | "-" icon, 40x40px. Disabled at minimum (1) |
| Input | Centered number input, 56px wide, 40px tall. Min = 1, Max = available stock (deny policy) or unlimited (continue policy) |
| Increase button | "+" icon, same size. Disabled at maximum |
| Disabled state | Reduced opacity, not-allowed cursor |
| Labels | Input labeled "Quantity", buttons labeled "Decrease quantity" / "Increase quantity" |

#### Add to Cart Button

| Attribute | Description |
|---|---|
| Width | Full width |
| Style | Primary button: blue background, white text, semi-bold, generous padding, rounded |
| Text | "Add to cart" |
| Loading state | Text changes to "Adding..." with spinner icon. Button disabled during loading |
| Sold out state | Gray background, muted text, not-allowed cursor. Text: "Sold out" |
| Spacing | Generous top margin |

**Livewire action (addToCart):**

1. Validates variant is selected and in stock
2. Adds to cart (creates cart if none exists in session)
3. Dispatches "cart-updated" browser event
4. Cart drawer opens automatically

#### Product Description

- Separated from above content by a horizontal rule with generous vertical spacing
- Rendered HTML styled with prose/typography styling

#### Tags

- Displayed below the description (if tags exist)
- Horizontal wrapping row with gap
- Each tag: rounded pill, gray background, small text

### 5.4 Accessibility Summary

| Requirement | Implementation |
|---|---|
| Variant radio buttons | Properly labeled with labels and grouped with fieldset/legend |
| Live regions | Price display, stock messaging, add-to-cart feedback |
| Image alt text | All images have meaningful alt text |


command: sed -n '508,675p' specs/08-PLAYWRIGHT-E2E-PLAN.md

aggregated_output:
## Suite 3: Admin Product Management

**File:** `tests/Browser/Admin/ProductManagementTest.php`

**Purpose:** Verify CRUD operations for products through the admin interface - listing, creating, editing, archiving, searching, and filtering by status.

### Product Lifecycle States

```mermaid
stateDiagram-v2
    [*] --> Draft: create product (default)
    Draft --> Active: set status to Active + Save
    Active --> Archived: set status to Archived + Save
    Draft --> Archived: set status to Archived + Save
    Archived --> Active: set status to Active + Save
    Active --> Draft: set status to Draft + Save
```

---

### Test 3.1: Shows the product list with seeded products

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Click "Products" in the sidebar

**Expected Results:**
- Page displays "Classic Cotton T-Shirt"
- Page displays "Premium Slim Fit Jeans"
- No JavaScript errors

---

### Test 3.2: Can create a new product

**Preconditions:** Logged in as admin

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin (email: `admin@acme.test`, password: `password`)
3. Click "Products" in the sidebar
4. Click "Add product"
5. Enter title: `Test Product Created by E2E`
6. Enter description: `This product was created by the E2E test suite.`
7. Enter vendor: `Test Vendor`
8. Enter product type: `T-Shirts`
9. Enter variant price (variants.0.price): `29.99`
10. Enter variant SKU (variants.0.sku): `E2E-TEST-001`
11. Enter variant quantity (variants.0.quantity): `50`
12. Click "Save"
13. Click "Products" to return to the product list

**Expected Results:**
- After step 12: page displays "Product saved", no JavaScript errors
- After step 13: page displays "Test Product Created by E2E" in the list

---

### Test 3.3: Can edit an existing product title

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Verify "Classic Cotton T-Shirt" is visible in the list
5. Click "Classic Cotton T-Shirt" to open the edit form
6. Clear the title field and enter: `Classic Cotton T-Shirt Updated`
7. Click "Save"
8. Click "Products" to return to the product list

**Expected Results:**
- After step 7: page displays "Product saved", no JavaScript errors
- After step 8: page displays "Classic Cotton T-Shirt Updated" in the list

---

### Test 3.4: Can archive a product

**Preconditions:** Logged in as admin

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Click "Add product"
5. Enter title: `Product To Archive`
6. Enter variant price: `19.99`
7. Enter variant SKU: `E2E-ARCHIVE-001`
8. Enter variant quantity: `10`
9. Click "Save"
10. Verify "Product saved" is displayed
11. Click "Products" to return to the product list
12. Click "Product To Archive" to open the edit form
13. Change status to "Archived" (click the Archived option)
14. Click "Save"
15. Click "Products" to return to the product list

**Expected Results:**
- After step 9: page displays "Product saved"
- After step 14: page displays "Product saved"
- After step 15: with default "Active" filter, the archived product should not appear in the list

---

### Test 3.5: Shows draft products only in admin, not storefront

**Preconditions:** Logged in as admin, Product #15 exists with draft status

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Verify Product #15 is visible in the admin list with a "Draft" badge
5. Open a new browser context / navigate to `/collections/t-shirts` (as guest)
6. Verify the draft product does NOT appear in the collection listing
7. Navigate to `/search?q=draft`
8. Verify the draft product does NOT appear in search results

**Expected Results:**
- Step 4: draft product visible in admin, no JavaScript errors
- Step 6: draft product absent from storefront collection, no JavaScript errors
- Step 8: draft product absent from search results, no JavaScript errors

---

### Test 3.6: Can search products in admin

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Enter "Cotton" in the search input field

**Expected Results:**
- Page displays "Classic Cotton T-Shirt" in filtered results
- No JavaScript errors

---

### Test 3.7: Can filter products by status in admin

**Preconditions:** Logged in as admin, seeded products including drafts

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Click the "Draft" status filter tab
5. Verify only draft products are visible
6. Click the "Active" status filter tab

**Expected Results:**
- After step 4: only draft products are visible, no JavaScript errors
- After step 6: "Classic Cotton T-Shirt" is visible, no JavaScript errors

**Total: 7 tests**

---