Input:
*** Begin Patch
*** Update File: /Users/fabianwesner/Herd/shop/specs/progress.md
@@
-- Active slice: Phase 2 - Catalog data layer, seed graph, and media processing
+- Active slice: Phase 3 - Storefront content/theme data and cart foundation
@@
-| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 routes exist: `/`, `/admin`, `/admin/login`, `/admin/logout`, `/account/login`, `/account/register`, `/account`. API routes are still missing. |
-| Admin UI | `specs/03-ADMIN-UI.md` | missing | Starter dashboard/settings only. |
-| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront home still starter welcome; customer login/register/account placeholders exist. |
+| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 auth routes plus catalog UI routes exist: `/`, `/collections`, `/collections/{handle}`, `/products/{handle}`, `/search`, `/pages/{handle}`, `/admin/products`, `/admin/products/create`, `/admin/products/{product}/edit`, `/admin/collections`, `/admin/collections/create`, `/admin/collections/{collection}/edit`, `/admin/inventory`. API routes are still missing. |
+| Admin UI | `specs/03-ADMIN-UI.md` | partial | Flux/Livewire admin catalog shell now includes product index/form, collection index/form, and inventory list with auth protection, filtering, pagination, status changes, SKU uniqueness checks, and collection assignment. Order/customer/content/settings admin pages are still missing. |
+| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront layout, home, collections index/detail, product detail, search, breadcrumbs, price display, product cards, and static about/faq pages render seeded catalog data. Cart interaction is currently a UI dispatch only. |
@@
-| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | missing | No browser tests yet. |
-| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, and seed graph are implemented; admin catalog CRUD and storefront catalog browsing are still pending. |
+| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | partial | Manual Playwright MCP smoke coverage has verified storefront catalog browsing, product detail, search, static page, admin product/collection/inventory pages, and auth flows without console warnings/errors. Automated browser tests are still missing. |
+| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, seed graph, admin catalog CRUD, and storefront catalog browsing are implemented with known media/option-matrix UI gaps. |
@@
 - 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after the Phase 2 seed update.
 - 2026-05-03: Boost schema summary confirmed Phase 2 catalog tables. Boost query counts after fresh seed: stores 2, products 25, variants 127, inventory_items 127, collections 6, product_media 0, variant_option_values 206.
+- 2026-05-03: `mcp__laravel_boost__.search_docs` consulted Livewire 4 full-page component routing/testing docs and Flux UI form/input/select/checkbox/button docs before catalog UI changes.
+- 2026-05-03: `php artisan route:list --path=admin` showed 10 admin routes including product, collection, and inventory catalog pages. `php artisan route:list --path=collections`, `--path=products`, `--path=search`, and `--path=pages` showed storefront catalog/content routes.
+- 2026-05-03: `php artisan test --compact tests/Feature/Catalog/CatalogUiTest.php` passed: 4 tests, 44 assertions.
+- 2026-05-03: `php artisan test --compact tests/Feature/Catalog` passed: 23 tests, 115 assertions.
+- 2026-05-03: `php artisan test --compact` passed: 68 tests, 236 assertions.
+- 2026-05-03: `vendor/bin/pint --dirty --format agent` passed after formatting catalog UI changes.
+- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after catalog UI test changes.
+- 2026-05-03: `npm run build` passed with Vite production assets generated under ignored `public/build`.
+- 2026-05-03: Playwright MCP verified `http://shop.test/`, `/collections/t-shirts`, `/products/classic-cotton-t-shirt`, `/search?q=Cotton`, `/pages/about`, `/admin/products`, `/admin/products/create`, `/admin/collections`, and `/admin/inventory` render with no console warnings/errors.
@@
 - Child catalog models without a `store_id` column are tenant-scoped through their parent product relationship. Inventory keeps its denormalized `store_id` and enforces that it matches the variant product store at save time.
+- Static storefront content currently ships as code-backed placeholder pages until the content/page schema slice is implemented.
+- The catalog admin form intentionally blocks active products without a priced variant and duplicate in-store SKUs during UI edits, mirroring service-layer invariants where the current CRUD surface touches product variants directly.
@@
-- Phase 2 catalog UI is still missing: no admin product/collection CRUD routes or storefront product/collection browsing routes have been implemented yet.
+- Phase 2 media upload/admin UI is still missing, even though the media schema/job layer exists.
+- Product options can be displayed and edited as text in the admin form, but full option matrix generation and option-value reassignment UI are not complete.
+- Storefront product detail "Add to cart" currently dispatches a browser event only; cart persistence and checkout are still pending later roadmap phases.
+- Automated browser tests from Spec 08 are still missing; current browser coverage is manual Playwright MCP smoke verification.
 - SQLite enum/check constraints from the schema spec are not yet explicitly enforced as database `CHECK` constraints; enum validation is currently enforced through casts/services/model invariants.
-- Product media processing now validates and resizes image uploads with GD and cleans predictable generated paths, but browser/admin upload UI is still pending.
+- Product media processing now validates and resizes image uploads with GD and cleans predictable generated paths, but browser/admin upload UI is still pending.
@@
-Not complete. Phase 1 foundation is committed and the Phase 2 catalog data layer is implemented enough to support admin/storefront catalog UI work, with known auth/token, UI route, API, and database CHECK constraint gaps tracked above.
+Not complete. Phase 1 foundation and Phase 2 catalog data/UI surfaces are implemented enough to support cart, checkout, and richer storefront content work, with known auth/token, media UI, API, browser-test, and database CHECK constraint gaps tracked above.
*** End Patch


Success. Updated the following files:
M /Users/fabianwesner/Herd/shop/specs/progress.md

@@ -9,3 +9,3 @@
 - Status: in progress
-- Active slice: Phase 2 - Catalog data layer, seed graph, and media processing
+- Active slice: Phase 3 - Storefront content/theme data and cart foundation
 - Started from: Laravel Livewire/Fortify starter kit with no shop domain tables or models present
@@ -29,5 +29,5 @@
 | Database schema | `specs/01-DATABASE-SCHEMA.md` | partial | Phase 1 tenancy/auth tables plus Phase 2 catalog tables implemented: products, product_options, product_option_values, product_variants, variant_option_values, inventory_items, collections, collection_products, product_media. Boost schema confirmed these tables after `migrate:fresh --seed`. |
-| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 routes exist: `/`, `/admin`, `/admin/login`, `/admin/logout`, `/account/login`, `/account/register`, `/account`. API routes are still missing. |
-| Admin UI | `specs/03-ADMIN-UI.md` | missing | Starter dashboard/settings only. |
-| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront home still starter welcome; customer login/register/account placeholders exist. |
+| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 auth routes plus catalog UI routes exist: `/`, `/collections`, `/collections/{handle}`, `/products/{handle}`, `/search`, `/pages/{handle}`, `/admin/products`, `/admin/products/create`, `/admin/products/{product}/edit`, `/admin/collections`, `/admin/collections/create`, `/admin/collections/{collection}/edit`, `/admin/inventory`. API routes are still missing. |
+| Admin UI | `specs/03-ADMIN-UI.md` | partial | Flux/Livewire admin catalog shell now includes product index/form, collection index/form, and inventory list with auth protection, filtering, pagination, status changes, SKU uniqueness checks, and collection assignment. Order/customer/content/settings admin pages are still missing. |
+| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront layout, home, collections index/detail, product detail, search, breadcrumbs, price display, product cards, and static about/faq pages render seeded catalog data. Cart interaction is currently a UI dispatch only. |
 | Business logic | `specs/05-BUSINESS-LOGIC.md` | partial | `ResolveStore`, `BelongsToStore`, `StoreScope`, role checks, customer guard provider, catalog product lifecycle transitions, SKU uniqueness, variant matrix rebuilding, inventory reserve/release/commit/restock, automatic variant inventory, variant option mapping, and media resize/cleanup job implemented. Cart/checkout/order services still missing. |
@@ -35,4 +35,4 @@
 | Seed/test data | `specs/07-SEEDERS-AND-TEST-DATA.md` | partial | Seeders create Acme Fashion and Acme Electronics stores/domains/settings/admin access, 6 collections, 25 products, 127 variants, 127 inventory rows, 206 variant option pivots, and no product media. Order/discount/theme/content seed data still missing. |
-| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | missing | No browser tests yet. |
-| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, and seed graph are implemented; admin catalog CRUD and storefront catalog browsing are still pending. |
+| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | partial | Manual Playwright MCP smoke coverage has verified storefront catalog browsing, product detail, search, static page, admin product/collection/inventory pages, and auth flows without console warnings/errors. Automated browser tests are still missing. |
+| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, seed graph, admin catalog CRUD, and storefront catalog browsing are implemented with known media/option-matrix UI gaps. |

@@ -57,2 +57,11 @@
 - 2026-05-03: Boost schema summary confirmed Phase 2 catalog tables. Boost query counts after fresh seed: stores 2, products 25, variants 127, inventory_items 127, collections 6, product_media 0, variant_option_values 206.
+- 2026-05-03: `mcp__laravel_boost__.search_docs` consulted Livewire 4 full-page component routing/testing docs and Flux UI form/input/select/checkbox/button docs before catalog UI changes.
+- 2026-05-03: `php artisan route:list --path=admin` showed 10 admin routes including product, collection, and inventory catalog pages. `php artisan route:list --path=collections`, `--path=products`, `--path=search`, and `--path=pages` showed storefront catalog/content routes.
+- 2026-05-03: `php artisan test --compact tests/Feature/Catalog/CatalogUiTest.php` passed: 4 tests, 44 assertions.
+- 2026-05-03: `php artisan test --compact tests/Feature/Catalog` passed: 23 tests, 115 assertions.
+- 2026-05-03: `php artisan test --compact` passed: 68 tests, 236 assertions.
+- 2026-05-03: `vendor/bin/pint --dirty --format agent` passed after formatting catalog UI changes.
+- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after catalog UI test changes.
+- 2026-05-03: `npm run build` passed with Vite production assets generated under ignored `public/build`.
+- 2026-05-03: Playwright MCP verified `http://shop.test/`, `/collections/t-shirts`, `/products/classic-cotton-t-shirt`, `/search?q=Cotton`, `/pages/about`, `/admin/products`, `/admin/products/create`, `/admin/collections`, and `/admin/inventory` render with no console warnings/errors.

@@ -68,2 +77,4 @@
 - Child catalog models without a `store_id` column are tenant-scoped through their parent product relationship. Inventory keeps its denormalized `store_id` and enforces that it matches the variant product store at save time.
+- Static storefront content currently ships as code-backed placeholder pages until the content/page schema slice is implemented.
+- The catalog admin form intentionally blocks active products without a priced variant and duplicate in-store SKUs during UI edits, mirroring service-layer invariants where the current CRUD surface touches product variants directly.

@@ -76,3 +87,6 @@
 - `php artisan route:list --except-vendor` hides Livewire full-page routes because their controller is vendor-provided; path-filtered route-list commands are used as evidence for those routes.
-- Phase 2 catalog UI is still missing: no admin product/collection CRUD routes or storefront product/collection browsing routes have been implemented yet.
+- Phase 2 media upload/admin UI is still missing, even though the media schema/job layer exists.
+- Product options can be displayed and edited as text in the admin form, but full option matrix generation and option-value reassignment UI are not complete.
+- Storefront product detail "Add to cart" currently dispatches a browser event only; cart persistence and checkout are still pending later roadmap phases.
+- Automated browser tests from Spec 08 are still missing; current browser coverage is manual Playwright MCP smoke verification.
 - SQLite enum/check constraints from the schema spec are not yet explicitly enforced as database `CHECK` constraints; enum validation is currently enforced through casts/services/model invariants.
@@ -82,2 +96,2 @@

-Not complete. Phase 1 foundation is committed and the Phase 2 catalog data layer is implemented enough to support admin/storefront catalog UI work, with known auth/token, UI route, API, and database CHECK constraint gaps tracked above.
+Not complete. Phase 1 foundation and Phase 2 catalog data/UI surfaces are implemented enough to support cart, checkout, and richer storefront content work, with known auth/token, media UI, API, browser-test, and database CHECK constraint gaps tracked above.


Output: {"output":"Success. Updated the following files:\nM /Users/fabianwesner/Herd/shop/specs/progress.md\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


/bin/zsh
-lc
sed -n '1,220p' specs/progress.md

# Shop Build Progress

## Objective

Build a complete, self-contained Laravel shop system from `specs/*`, with implemented acceptance criteria mapped to evidence, passing automated checks, verified browser flows, independent QA, and meaningful commits.

## Current Status

- Status: in progress
- Active slice: Phase 3 - Storefront content/theme data and cart foundation
- Started from: Laravel Livewire/Fortify starter kit with no shop domain tables or models present
- Last updated: 2026-05-03

## Phased Plan

1. Foundation: SQLite config, tenancy tables/models/factories/seeders, store resolution middleware, store scoping, admin/customer auth foundations, policies, and Phase 1 tests.
2. Catalog: product, variant, inventory, collection, media schema/models/services, admin catalog CRUD, storefront browsing, and tests.
3. Storefront theme/layout: theme/page/navigation data, storefront layout, product/collection/search/page views, and smoke browser verification.
4. Cart/checkout/pricing: cart API/UI, discount, shipping, tax, checkout state machine, and tests.
5. Payments/orders/fulfillment: mock PSP, order creation, refunds, fulfillments, customer account order views, and tests.
6. Admin panel: dashboard and all admin list/form/detail pages from Spec 03, with Livewire/Flux interactions.
7. Search/analytics/apps/webhooks: SQLite search, event aggregation, developer token/webhook UI, delivery jobs, and tests.
8. Final verification: full Pest suite, Pint, frontend build, Playwright MCP customer/admin flows, independent QA, fixes, and completion audit.

## Acceptance Checklist

| Area | Criteria Source | Status | Evidence |
| --- | --- | --- | --- |
| Database schema | `specs/01-DATABASE-SCHEMA.md` | partial | Phase 1 tenancy/auth tables plus Phase 2 catalog tables implemented: products, product_options, product_option_values, product_variants, variant_option_values, inventory_items, collections, collection_products, product_media. Boost schema confirmed these tables after `migrate:fresh --seed`. |
| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 auth routes plus catalog UI routes exist: `/`, `/collections`, `/collections/{handle}`, `/products/{handle}`, `/search`, `/pages/{handle}`, `/admin/products`, `/admin/products/create`, `/admin/products/{product}/edit`, `/admin/collections`, `/admin/collections/create`, `/admin/collections/{collection}/edit`, `/admin/inventory`. API routes are still missing. |
| Admin UI | `specs/03-ADMIN-UI.md` | partial | Flux/Livewire admin catalog shell now includes product index/form, collection index/form, and inventory list with auth protection, filtering, pagination, status changes, SKU uniqueness checks, and collection assignment. Order/customer/content/settings admin pages are still missing. |
| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront layout, home, collections index/detail, product detail, search, breadcrumbs, price display, product cards, and static about/faq pages render seeded catalog data. Cart interaction is currently a UI dispatch only. |
| Business logic | `specs/05-BUSINESS-LOGIC.md` | partial | `ResolveStore`, `BelongsToStore`, `StoreScope`, role checks, customer guard provider, catalog product lifecycle transitions, SKU uniqueness, variant matrix rebuilding, inventory reserve/release/commit/restock, automatic variant inventory, variant option mapping, and media resize/cleanup job implemented. Cart/checkout/order services still missing. |
| Auth/security | `specs/06-AUTH-AND-SECURITY.md` | partial | Admin Livewire login/logout, customer guard/provider, customer login/register, login rate limiting, session hardening, and resource policies implemented. Customer password reset and Sanctum token auth still missing. |
| Seed/test data | `specs/07-SEEDERS-AND-TEST-DATA.md` | partial | Seeders create Acme Fashion and Acme Electronics stores/domains/settings/admin access, 6 collections, 25 products, 127 variants, 127 inventory rows, 206 variant option pivots, and no product media. Order/discount/theme/content seed data still missing. |
| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | partial | Manual Playwright MCP smoke coverage has verified storefront catalog browsing, product detail, search, static page, admin product/collection/inventory pages, and auth flows without console warnings/errors. Automated browser tests are still missing. |
| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, seed graph, admin catalog CRUD, and storefront catalog browsing are implemented with known media/option-matrix UI gaps. |

## Verification Evidence

- 2026-05-03: `mcp__laravel_boost__.application_info` confirmed PHP 8.4, Laravel 12.51.0, Livewire 4.1.4, Flux 2.12.0, Pest 4.3.2, SQLite.
- 2026-05-03: `mcp__laravel_boost__.database_schema(summary: true)` returned no tables for the current configured database.
- 2026-05-03: `git status --short` sh…2627 chars truncated…on docs before catalog UI changes.
- 2026-05-03: `php artisan route:list --path=admin` showed 10 admin routes including product, collection, and inventory catalog pages. `php artisan route:list --path=collections`, `--path=products`, `--path=search`, and `--path=pages` showed storefront catalog/content routes.
- 2026-05-03: `php artisan test --compact tests/Feature/Catalog/CatalogUiTest.php` passed: 4 tests, 44 assertions.
- 2026-05-03: `php artisan test --compact tests/Feature/Catalog` passed: 23 tests, 115 assertions.
- 2026-05-03: `php artisan test --compact` passed: 68 tests, 236 assertions.
- 2026-05-03: `vendor/bin/pint --dirty --format agent` passed after formatting catalog UI changes.
- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after catalog UI test changes.
- 2026-05-03: `npm run build` passed with Vite production assets generated under ignored `public/build`.
- 2026-05-03: Playwright MCP verified `http://shop.test/`, `/collections/t-shirts`, `/products/classic-cotton-t-shirt`, `/search?q=Cotton`, `/pages/about`, `/admin/products`, `/admin/products/create`, `/admin/collections`, and `/admin/inventory` render with no console warnings/errors.

## Decisions

- Follow the roadmap order strictly. Phase 1 is required before catalog, checkout, admin, storefront, and QA flows can be meaningfully implemented.
- Preserve the starter Fortify conventions where they do not conflict with the shop specs.
- Use integer minor units for all money columns and JSON text columns cast through Eloquent as specified.
- Keep `password_hash` as the database column for admin users and customers while exposing `password`/`getAuthPassword()` at the model layer for Fortify/Laravel auth compatibility.
- Seed both `shop.test` and `acme-fashion.test` as storefront domains for the first store so the goal URL and E2E spec URL can both resolve.
- Customer Livewire auth components persist `storeId` from the initial storefront request because Livewire update requests do not run through the original storefront route middleware.
- The seed specification contains an arithmetic conflict: Acme Fashion's per-product variant table sums to 117 variants, while the prose says 107. The implementation follows the concrete per-product table, resulting in 117 Fashion variants and 10 Electronics variants, 127 total.
- Child catalog models without a `store_id` column are tenant-scoped through their parent product relationship. Inventory keeps its denormalized `store_id` and enforces that it matches the variant product store at save time.
- Static storefront content currently ships as code-backed placeholder pages until the content/page schema slice is implemented.
- The catalog admin form intentionally blocks active products without a priced variant and duplicate in-store SKUs during UI edits, mirroring service-layer invariants where the current CRUD surface touches product variants directly.

## Open Issues

- Composer does not currently include Sanctum, while Spec 06 requires Sanctum personal access tokens. This will need either an approved dependency addition or a documented compatible alternative before final completion.
- The Herd app URL in the goal is `http://shop.test/`, while the E2E spec also references `http://acme-fashion.test`; domain handling must support seeded store domains and Herd verification.
- Phase 1 still lacks admin/customer password reset at the spec paths and a custom customer password reset token repository that scopes by store_id.
- Policy classes for later resources use generic object parameters until the concrete catalog/order/content models exist.
- `php artisan route:list --except-vendor` hides Livewire full-page routes because their controller is vendor-provided; path-filtered route-list commands are used as evidence for those routes.
- Phase 2 media upload/admin UI is still missing, even though the media schema/job layer exists.
- Product options can be displayed and edited as text in the admin form, but full option matrix generation and option-value reassignment UI are not complete.
- Storefront product detail "Add to cart" currently dispatches a browser event only; cart persistence and checkout are still pending later roadmap phases.
- Automated browser tests from Spec 08 are still missing; current browser coverage is manual Playwright MCP smoke verification.
- SQLite enum/check constraints from the schema spec are not yet explicitly enforced as database `CHECK` constraints; enum validation is currently enforced through casts/services/model invariants.
- Product media processing now validates and resizes image uploads with GD and cleans predictable generated paths, but browser/admin upload UI is still pending.

## Completion Summary

Not complete. Phase 1 foundation and Phase 2 catalog data/UI surfaces are implemented enough to support cart, checkout, and richer storefront content work, with known auth/token, media UI, API, browser-test, and database CHECK constraint gaps tracked above.


Output:
Chunk ID: bf38cf
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1550
Output:
 D .playwright-mcp/console-2026-04-18T07-42-21-973Z.log
 D .playwright-mcp/console-2026-04-18T07-42-29-697Z.log
 D .playwright-mcp/console-2026-04-18T07-42-33-348Z.log
 D .playwright-mcp/console-2026-04-18T07-42-37-846Z.log
 D .playwright-mcp/console-2026-04-18T07-43-07-589Z.log
 D .playwright-mcp/console-2026-04-18T07-43-15-408Z.log
 D .playwright-mcp/console-2026-04-18T07-43-17-415Z.log
 D .playwright-mcp/console-2026-04-18T07-43-21-810Z.log
 D .playwright-mcp/console-2026-04-18T07-43-24-813Z.log
 D .playwright-mcp/console-2026-04-18T08-04-27-959Z.log
 D .playwright-mcp/console-2026-04-18T08-04-43-558Z.log
 D .playwright-mcp/console-2026-04-18T08-04-48-155Z.log
 D .playwright-mcp/console-2026-04-18T08-04-54-091Z.log
 D .playwright-mcp/console-2026-04-18T08-06-02-803Z.log
 D .playwright-mcp/console-2026-04-18T08-06-32-813Z.log
 D .playwright-mcp/console-2026-04-18T08-07-33-682Z.log
 D .playwright-mcp/console-2026-04-18T08-07-51-938Z.log
 D .playwright-mcp/console-2026-04-18T08-07-58-376Z.log
 D .playwright-mcp/console-2026-04-18T08-18-52-998Z.log
 D .playwright-mcp/console-2026-04-18T08-26-52-212Z.log
 D .playwright-mcp/console-2026-04-18T08-27-08-697Z.log
 D .playwright-mcp/console-2026-04-18T08-27-49-983Z.log
 D .playwright-mcp/console-2026-04-18T08-27-52-992Z.log
 D .playwright-mcp/console-2026-04-18T08-39-15-591Z.log
 D .playwright-mcp/console-2026-04-18T08-41-52-531Z.log
 D .playwright-mcp/console-2026-04-18T08-42-02-646Z.log
 D .playwright-mcp/console-2026-04-18T08-43-55-862Z.log
 D .playwright-mcp/console-2026-04-18T08-44-17-066Z.log
 D .playwright-mcp/console-2026-04-18T08-44-45-330Z.log
 D .playwright-mcp/console-2026-04-18T08-44-53-484Z.log
 D .playwright-mcp/console-2026-04-18T08-45-34-419Z.log
 D .playwright-mcp/console-2026-04-18T08-45-49-887Z.log
 D .playwright-mcp/console-2026-04-18T08-46-24-044Z.log
 D .playwright-mcp/console-2026-04-18T08-46-55-981Z.log
 D .playwright-mcp/console-2026-04-18T08-47-07-970Z.log
 D .playwright-mcp/console-2026-04-18T08-47-18-512Z.log
 D .playwright-mcp/console-2026-04-18T08-47-22-997Z.log
 D .playwright-mcp/page-2026-04-18T07-42-22-458Z.yml
 D .playwright-mcp/page-2026-04-18T07-42-29-798Z.yml
 D .playwright-mcp/page-2026-04-18T07-42-33-517Z.yml
 D .playwright-mcp/page-2026-04-18T07-42-38-652Z.yml
 D .playwright-mcp/page-2026-04-18T07-43-07-708Z.yml
 D .playwright-mcp/page-2026-04-18T07-43-15-507Z.yml
 D .playwright-mcp/page-2026-04-18T07-43-17-578Z.yml
 D .playwright-mcp/page-2026-04-18T07-43-21-920Z.yml
 D .playwright-mcp/page-2026-04-18T07-43-24-950Z.yml
 D .playwright-mcp/page-2026-04-18T08-04-28-270Z.yml
 D .playwright-mcp/page-2026-04-18T08-04-43-675Z.yml
 D .playwright-mcp/page-2026-04-18T08-04-48-300Z.yml
 D .playwright-mcp/page-2026-04-18T08-04-54-210Z.yml
 D .playwright-mcp/page-2026-04-18T08-05-12-101Z.yml
 D .playwright-mcp/page-2026-04-18T08-06-02-997Z.yml
 D .playwright-mcp/page-2026-04-18T08-06-09-558Z.yml
 D .playwright-mcp/page-2026-04-18T08-06-32-938Z.yml
 D .playwright-mcp/page-2026-04-18T08-06-42-016Z.yml
 D .playwright-mcp/page-2026-04-18T08-07-33-859Z.yml
 D .playwright-mcp/page-2026-04-18T08-07-43-009Z.yml
 D .playwright-mcp/page-2026-04-18T08-07-52-099Z.yml
 D .playwright-mcp/page-2026-04-18T08-07-58-525Z.yml
 D .playwright-mcp/page-2026-04-18T08-18-53-378Z.yml
 D .playwright-mcp/page-2026-04-18T08-26-52-503Z.yml
 D .playwright-mcp/page-2026-04-18T08-27-08-803Z.yml
 D .playwright-mcp/page-2026-04-18T08-27-41-204Z.yml
 D .playwright-mcp/page-2026-04-18T08-27-50-110Z.yml
 D .playwright-mcp/page-2026-04-18T08-27-53-108Z.yml
 D .playwright-mcp/page-2026-04-18T08-39-15-903Z.yml
 D .playwright-mcp/page-2026-04-18T08-39-24-839Z.yml
 D .playwright-mcp/page-2026-04-18T08-39-31-590Z.yml
 D .playwright-mcp/page-2026-04-18T08-39-45-003Z.yml
 D .playwright-mcp/page-2026-04-18T08-40-17-855Z.yml
 D .playwright-mcp/page-2026-04-18T08-41-52-664Z.yml
 D .playwright-mcp/page-2026-04-18T08-41-59-687Z.yml
 D .playwright-mcp/page-2026-04-18T08-42-02-779Z.yml
 D .playwright-mcp/page-2026-04-18T08-42-25-068Z.yml
 D .playwright-mcp/page-2026-04-18T08-42-33-505Z.yml
 D .playwright-mcp/page-2026-04-18T08-42-45-519Z.yml
 D .playwright-mcp/page-2026-04-18T08-43-11-472Z.yml
 D .playwright-mcp/page-2026-04-18T08-43-21-769Z.yml
 D .playwright-mcp/page-2026-04-18T08-43-55-970Z.yml
 D .playwright-mcp/page-2026-04-18T08-44-17-187Z.yml
 D .playwright-mcp/page-2026-04-18T08-44-45-492Z.yml
 D .playwright-mcp/page-2026-04-18T08-44-53-597Z.yml
 D .playwright-mcp/page-2026-04-18T08-45-20-872Z.yml
 D .playwright-mcp/page-2026-04-18T08-45-29-103Z.yml
 D .playwright-mcp/page-2026-04-18T08-45-34-547Z.yml
 D .playwright-mcp/page-2026-04-18T08-45-49-992Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-01-203Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-07-518Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-19-920Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-24-184Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-40-422Z.yml
 D .playwright-mcp/page-2026-04-18T08-46-56-113Z.yml
 D .playwright-mcp/page-2026-04-18T08-47-08-093Z.yml
 D .playwright-mcp/page-2026-04-18T08-47-18-629Z.yml
 D .playwright-mcp/page-2026-04-18T08-47-23-095Z.yml
 D .playwright-mcp/page-2026-04-18T10-59-02-335Z.yml
 M app/Providers/AppServiceProvider.php
 M resources/views/components/app-logo.blade.php
 M resources/views/layouts/app/sidebar.blade.php
 M routes/web.php
 M specs/progress.md
?? app/Livewire/Admin/Collections/
?? app/Livewire/Admin/Inventory/
?? app/Livewire/Admin/Products/
?? app/Livewire/Storefront/Collections/
?? app/Livewire/Storefront/Home.php
?? app/Livewire/Storefront/Pages/
?? app/Livewire/Storefront/Products/
?? app/Livewire/Storefront/Search/
?? app/Support/Money.php
?? resources/views/components/storefront/
?? resources/views/layouts/storefront.blade.php
?? resources/views/livewire/admin/collections/
?? resources/views/livewire/admin/inventory/
?? resources/views/livewire/admin/products/
?? resources/views/livewire/storefront/collections/
?? resources/views/livewire/storefront/home.blade.php
?? resources/views/livewire/storefront/pages/
?? resources/views/livewire/storefront/products/
?? resources/views/livewire/storefront/search/
?? tests/Feature/Catalog/CatalogUiTest.php


Output:
Chunk ID: a70fa4
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1632
Output:
 .../console-2026-04-18T07-42-21-973Z.log           |   2 -
 .../console-2026-04-18T07-42-29-697Z.log           |   1 -
 .../console-2026-04-18T07-42-33-348Z.log           |   1 -
 .../console-2026-04-18T07-42-37-846Z.log           |   6 -
 .../console-2026-04-18T07-43-07-589Z.log           |   2 -
 .../console-2026-04-18T07-43-15-408Z.log           |   1 -
 .../console-2026-04-18T07-43-17-415Z.log           |   1 -
 .../console-2026-04-18T07-43-21-810Z.log           |   1 -
 .../console-2026-04-18T07-43-24-813Z.log           |   2 -
 .../console-2026-04-18T08-04-27-959Z.log           |   2 -
 .../console-2026-04-18T08-04-43-558Z.log           |   1 -
 .../console-2026-04-18T08-04-48-155Z.log           |   1 -
 .../console-2026-04-18T08-04-54-091Z.log           |   4 -
 .../console-2026-04-18T08-06-02-803Z.log           |   4 -
 .../console-2026-04-18T08-06-32-813Z.log           |   4 -
 .../console-2026-04-18T08-07-33-682Z.log           |   3 -
 .../console-2026-04-18T08-07-51-938Z.log           |   1 -
 .../console-2026-04-18T08-07-58-376Z.log           |   1 -
 .../console-2026-04-18T08-18-52-998Z.log           |   3 -
 .../console-2026-04-18T08-26-52-212Z.log           |   6 -
 .../console-2026-04-18T08-27-08-697Z.log           |   4 -
 .../console-2026-04-18T08-27-49-983Z.log           |   1 -
 .../console-2026-04-18T08-27-52-992Z.log           |   1 -
 .../console-2026-04-18T08-39-15-591Z.log           |   5 -
 .../console-2026-04-18T08-41-52-531Z.log           |   3 -
 .../console-2026-04-18T08-42-02-646Z.log           |   3 -
 .../console-2026-04-18T08-43-55-862Z.log           |   1 -
 .../console-2026-04-18T08-44-17-066Z.log           |   2 -
 .../console-2026-04-18T08-44-45-330Z.log           |   1 -
 .../console-2026-04-18T08-44-53-484Z.log           |   2 -
 .../console-2026-04-18T08-45-34-419Z.log           |   1 -
 .../console-2026-04-18T08-45-49-887Z.log           |   2 -
 .../console-2026-04-18T08-46-24-044Z.log           |   1 -
 .../console-2026-04-18T08-46-55-981Z.log           |   1 -
 .../console-2026-04-18T08-47-07-970Z.log           |   1 -
 .../console-2026-04-18T08-47-18-512Z.log           |   1 -
 .../console-2026-04-18T08-47-22-997Z.log           |   1 -
 .playwright-mcp/page-2026-04-18T07-42-22-458Z.yml  |  42 ----
 .playwright-mcp/page-2026-04-18T07-42-29-798Z.yml  |  33 ----
 .playwright-mcp/page-2026-04-18T07-42-33-517Z.yml  |  51 -----
 .playwright-mcp/page-2026-04-18T07-42-38-652Z.yml  | 212 ---------------------
 .playwright-mcp/page-2026-04-18T07-43-07-708Z.yml  |  56 ------
 .playwright-mcp/page-2026-04-18T07-43-15-507Z.yml  |  32 ----
 .playwright-mcp/page-2026-04-18T07-43-17-578Z.yml  |  35 ----
 .playwright-mcp/page-2026-04-18T07-43-21-920Z.yml  |  37 ----
 .playwright-mcp/page-2026-04-18T07-43-24-950Z.yml  |   6 -
 .playwright-mcp/page-2026-04-18T08-04-28-270Z.yml  |  54 ------
 .playwright-mcp/page-2026-04-18T08-04-43-675Z.yml  |  50 -----
 .playwright-mcp/page-2026-04-18T08-04-48-300Z.yml  |  68 -------
 .playwright-mcp/page-2026-04-18T08-04-54-210Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-05-12-101Z.yml  |  81 --------
 .playwright-mcp/page-2026-04-18T08-06-02-997Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-06-09-558Z.yml  |  81 --------
 .playwright-mcp/page-2026-04-18T08-06-32-938Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-06-42-016Z.yml  |  81 --------
 .playwright-mcp/page-2026-04-18T08-07-33-859Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-07-43-009Z.yml  |  94 ---------
 .playwright-mcp/page-2026-04-18T08-07-52-099Z.yml  | 117 ------------
 .playwright-mcp/page-2026-04-18T08-07-58-525Z.yml  | 148 --------------
 .playwright-mcp/page-2026-04-18T08-18-53-378Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-26-52-503Z.yml  |   6 -
 .playwright-mcp/page-2026-04-18T08-27-08-803Z.yml  |  56 ------
 .playwright-mcp/page-2026-04-18T08-27-41-204Z.yml  |  52 -----
 .playwright-mcp/page-2026-04-18T08-27-50-110Z.yml  |  58 ------
 .playwright-mcp/page-2026-04-18T08-27-53-108Z.yml  |  58 ------
 .playwright-mcp/page-2026-04-18T08-39-15-903Z.yml  |  59 ------
 .playwright-mcp/page-2026-04-18T08-39-24-839Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-39-31-590Z.yml  |  94 ---------
 .playwright-mcp/page-2026-04-18T08-39-45-003Z.yml  | 148 --------------
 .playwright-mcp/page-2026-04-18T08-40-17-855Z.yml  | 148 --------------
 .playwright-mcp/page-2026-04-18T08-41-52-664Z.yml  |  73 -------
 .playwright-mcp/page-2026-04-18T08-41-59-687Z.yml  |  94 ---------
 .playwright-mcp/page-2026-04-18T08-42-02-779Z.yml  | 151 ---------------
 .playwright-mcp/page-2026-04-18T08-42-25-068Z.yml  | 151 ---------------
 .playwright-mcp/page-2026-04-18T08-42-33-505Z.yml  | 155 ---------------
 .playwright-mcp/page-2026-04-18T08-42-45-519Z.yml  | 155 ---------------
 .playwright-mcp/page-2026-04-18T08-43-11-472Z.yml  | 155 ---------------
 .playwright-mcp/page-2026-04-18T08-43-21-769Z.yml  | 155 ---------------
 .playwright-mcp/page-2026-04-18T08-43-55-970Z.yml  |  44 -----
 .playwright-mcp/page-2026-04-18T08-44-17-187Z.yml  |  75 --------
 .playwright-mcp/page-2026-04-18T08-44-45-492Z.yml  |  75 --------
 .playwright-mcp/page-2026-04-18T08-44-53-597Z.yml  |  56 ------
 .playwright-mcp/page-2026-04-18T08-45-20-872Z.yml  |  52 -----
 .playwright-mcp/page-2026-04-18T08-45-29-103Z.yml  |  52 -----
 .playwright-mcp/page-2026-04-18T08-45-34-547Z.yml  |  58 ------
 .playwright-mcp/page-2026-04-18T08-45-49-992Z.yml  |  16 --
 .playwright-mcp/page-2026-04-18T08-46-01-203Z.yml  |  16 --
 .playwright-mcp/page-2026-04-18T08-46-07-518Z.yml  |  16 --
 .playwright-mcp/page-2026-04-18T08-46-19-920Z.yml  |  83 --------
 .playwright-mcp/page-2026-04-18T08-46-24-184Z.yml  |  99 ----------
 .playwright-mcp/page-2026-04-18T08-46-40-422Z.yml  |  99 ----------
 .playwright-mcp/page-2026-04-18T08-46-56-113Z.yml  |  90 ---------
 .playwright-mcp/page-2026-04-18T08-47-08-093Z.yml  | 104 ----------
 .playwright-mcp/page-2026-04-18T08-47-18-629Z.yml  |  60 ------
 .playwright-mcp/page-2026-04-18T08-47-23-095Z.yml  |  69 -------
 .playwright-mcp/page-2026-04-18T10-59-02-335Z.yml  |  59 ------
 app/Providers/AppServiceProvider.php               |  13 ++
 resources/views/components/app-logo.blade.php      |   4 +-
 resources/views/layouts/app/sidebar.blade.php      |  18 +-
 routes/web.php                                     |  33 +++-
 specs/progress.md                                  |  30 ++-
 101 files changed, 80 insertions(+), 4703 deletions(-)


Output:
Chunk ID: 1d036c
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3157
Output:
# Shop Build Progress

## Objective

Build a complete, self-contained Laravel shop system from `specs/*`, with implemented acceptance criteria mapped to evidence, passing automated checks, verified browser flows, independent QA, and meaningful commits.

## Current Status

- Status: in progress
- Active slice: Phase 3 - Storefront content/theme data and cart foundation
- Started from: Laravel Livewire/Fortify starter kit with no shop domain tables or models present
- Last updated: 2026-05-03

## Phased Plan

1. Foundation: SQLite config, tenancy tables/models/factories/seeders, store resolution middleware, store scoping, admin/customer auth foundations, policies, and Phase 1 tests.
2. Catalog: product, variant, inventory, collection, media schema/models/services, admin catalog CRUD, storefront browsing, and tests.
3. Storefront theme/layout: theme/page/navigation data, storefront layout, product/collection/search/page views, and smoke browser verification.
4. Cart/checkout/pricing: cart API/UI, discount, shipping, tax, checkout state machine, and tests.
5. Payments/orders/fulfillment: mock PSP, order creation, refunds, fulfillments, customer account order views, and tests.
6. Admin panel: dashboard and all admin list/form/detail pages from Spec 03, with Livewire/Flux interactions.
7. Search/analytics/apps/webhooks: SQLite search, event aggregation, developer token/webhook UI, delivery jobs, and tests.
8. Final verification: full Pest suite, Pint, frontend build, Playwright MCP customer/admin flows, independent QA, fixes, and completion audit.

## Acceptance Checklist

| Area | Criteria Source | Status | Evidence |
| --- | --- | --- | --- |
| Database schema | `specs/01-DATABASE-SCHEMA.md` | partial | Phase 1 tenancy/auth tables plus Phase 2 catalog tables implemented: products, product_options, product_option_values, product_variants, variant_option_values, inventory_items, collections, collection_products, product_media. Boost schema confirmed these tables after `migrate:fresh --seed`. |
| Routes/API | `specs/02-API-ROUTES.md` | partial | Phase 1 auth routes plus catalog UI routes exist: `/`, `/collections`, `/collections/{handle}`, `/products/{handle}`, `/search`, `/pages/{handle}`, `/admin/products`, `/admin/products/create`, `/admin/products/{product}/edit`, `/admin/collections`, `/admin/collections/create`, `/admin/collections/{collection}/edit`, `/admin/inventory`. API routes are still missing. |
| Admin UI | `specs/03-ADMIN-UI.md` | partial | Flux/Livewire admin catalog shell now includes product index/form, collection index/form, and inventory list with auth protection, filtering, pagination, status changes, SKU uniqueness checks, and collection assignment. Order/customer/content/settings admin pages are still missing. |
| Storefront UI | `specs/04-STOREFRONT-UI.md` | partial | Storefront layout, home, collections index/detail, product detail, search, breadcrumbs, price display, product cards, and static about/faq pages render seeded catalog data. Cart interaction is currently a UI dispatch only. |
| Business logic | `specs/05-BUSINESS-LOGIC.md` | partial | `ResolveStore`, `BelongsToStore`, `StoreScope`, role checks, customer guard provider, catalog product lifecycle transitions, SKU uniqueness, variant matrix rebuilding, inventory reserve/release/commit/restock, automatic variant inventory, variant option mapping, and media resize/cleanup job implemented. Cart/checkout/order services still missing. |
| Auth/security | `specs/06-AUTH-AND-SECURITY.md` | partial | Admin Livewire login/logout, customer guard/provider, customer login/register, login rate limiting, session hardening, and resource policies implemented. Customer password reset and Sanctum token auth still missing. |
| Seed/test data | `specs/07-SEEDERS-AND-TEST-DATA.md` | partial | Seeders create Acme Fashion and Acme Electronics stores/domains/settings/admin access, 6 collections, 25 products, 127 variants, 127 inventory rows, 206 variant option pivots, and no product media. Order/discount/theme/content seed data still missing. |
| Browser E2E plan | `specs/08-PLAYWRIGHT-E2E-PLAN.md` | partial | Manual Playwright MCP smoke coverage has verified storefront catalog browsing, product detail, search, static page, admin product/collection/inventory pages, and auth flows without console warnings/errors. Automated browser tests are still missing. |
| Roadmap phases | `specs/09-IMPLEMENTATION-ROADMAP.md` | in progress | Phase 1 foundation committed. Phase 2 catalog data layer, business services, media job, seed graph, admin catalog CRUD, and storefront catalog browsing are implemented with known media/option-matrix UI gaps. |

## Verification Evidence

- 2026-05-03: `mcp__laravel_boost__.application_info` confirmed PHP 8.4, Laravel 12.51.0, Livewire 4.1.4, Flux 2.12.0, Pest 4.3.2, SQLite.
- 2026-05-03: `mcp__laravel_boost__.database_schema(summary: true)` returned no tables for the current configured database.
- 2026-05-03: `git status --short` showed no current worktree changes before implementation.
- 2026-05-03: `mcp__laravel_boost__.search_docs` consulted Laravel 12 middleware/auth/authorization/migration docs plus Livewire 4 and Pest 4 docs before code changes.
- 2026-05-03: Planning challenger sub-agent found the repo was still a starter kit and produced the acceptance checklist by vertical slice. Risks added here: missing Sanctum dependency, password_hash/Fortify coordination, route/API absence, and E2E count inconsistencies.
- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed on real `database/database.sqlite` after creating the missing SQLite file.
- 2026-05-03: `php artisan test --compact` passed: 45 tests, 121 assertions.
- 2026-05-03: `vendor/bin/pint --dirty --format agent` passed after formatting changes.
- 2026-05-03: `php artisan route:list --path=admin` showed `/admin`, `/admin/login`, `/admin/logout`; `php artisan route:list --path=account` showed `/account`, `/account/login`, `/account/register`.
- 2026-05-03: Boost schema summary confirmed Phase 1 tables: organizations, stores, store_domains, store_users, store_settings, customers, customer_password_reset_tokens, users with password_hash.
- 2026-05-03: Playwright MCP verified `http://shop.test/` loads, `http://shop.test/admin/login` renders, admin login with `admin@acme.test` / `password` reaches `/admin`, `http://shop.test/account/login` renders with no console warnings/errors after the Livewire layout fix, and customer login with `customer@acme.test` / `password` reaches `/account`.
- 2026-05-03: Independent Phase 2 QA agents reported no critical findings. High findings on lifecycle bypass, child tenant scoping, inventory store mismatch, variant option mapping, simplified seed data, and media status-only processing were addressed in the catalog data layer.
- 2026-05-03: `php artisan test --compact tests/Feature/Catalog` passed: 19 tests, 71 assertions.
- 2026-05-03: `php artisan test --compact` passed: 64 tests, 192 assertions.
- 2026-05-03: `vendor/bin/pint --dirty --format agent` fixed import/order/spacing, followed by passing catalog and full Pest suites.
- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after the Phase 2 seed update.
- 2026-05-03: Boost schema summary confirmed Phase 2 catalog tables. Boost query counts after fresh seed: stores 2, products 25, variants 127, inventory_items 127, collections 6, product_media 0, variant_option_values 206.
- 2026-05-03: `mcp__laravel_boost__.search_docs` consulted Livewire 4 full-page component routing/testing docs and Flux UI form/input/select/checkbox/button docs before catalog UI changes.
- 2026-05-03: `php artisan route:list --path=admin` showed 10 admin routes including product, collection, and inventory catalog pages. `php artisan route:list --path=collections`, `--path=products`, `--path=search`, and `--path=pages` showed storefront catalog/content routes.
- 2026-05-03: `php artisan test --compact tests/Feature/Catalog/CatalogUiTest.php` passed: 4 tests, 44 assertions.
- 2026-05-03: `php artisan test --compact tests/Feature/Catalog` passed: 23 tests, 115 assertions.
- 2026-05-03: `php artisan test --compact` passed: 68 tests, 236 assertions.
- 2026-05-03: `vendor/bin/pint --dirty --format agent` passed after formatting catalog UI changes.
- 2026-05-03: `php artisan migrate:fresh --seed --no-interaction` passed after catalog UI test changes.
- 2026-05-03: `npm run build` passed with Vite production assets generated under ignored `public/build`.
- 2026-05-03: Playwright MCP verified `http://shop.test/`, `/collections/t-shirts`, `/products/classic-cotton-t-shirt`, `/search?q=Cotton`, `/pages/about`, `/admin/products`, `/admin/products/create`, `/admin/collections`, and `/admin/inventory` render with no console warnings/errors.

## Decisions

- Follow the roadmap order strictly. Phase 1 is required before catalog, checkout, admin, storefront, and QA flows can be meaningfully implemented.
- Preserve the starter Fortify conventions where they do not conflict with the shop specs.
- Use integer minor units for all money columns and JSON text columns cast through Eloquent as specified.
- Keep `password_hash` as the database column for admin users and customers while exposing `password`/`getAuthPassword()` at the model layer for Fortify/Laravel auth compatibility.
- Seed both `shop.test` and `acme-fashion.test` as storefront domains for the first store so the goal URL and E2E spec URL can both resolve.
- Customer Livewire auth components persist `storeId` from the initial storefront request because Livewire update requests do not run through the original storefront route middleware.
- The seed specification contains an arithmetic conflict: Acme Fashion's per-product variant table sums to 117 variants, while the prose says 107. The implementation follows the concrete per-product table, resulting in 117 Fashion variants and 10 Electronics variants, 127 total.
- Child catalog models without a `store_id` column are tenant-scoped through their parent product relationship. Inventory keeps its denormalized `store_id` and enforces that it matches the variant product store at save time.
- Static storefront content currently ships as code-backed placeholder pages until the content/page schema slice is implemented.
- The catalog admin form intentionally blocks active products without a priced variant and duplicate in-store SKUs during UI edits, mirroring service-layer invariants where the current CRUD surface touches product variants directly.

## Open Issues

- Composer does not currently include Sanctum, while Spec 06 requires Sanctum personal access tokens. This will need either an approved dependency addition or a documented compatible alternative before final completion.
- The Herd app URL in the goal is `http://shop.test/`, while the E2E spec also references `http://acme-fashion.test`; domain handling must support seeded store domains and Herd verification.
- Phase 1 still lacks admin/customer password reset at the spec paths and a custom customer password reset token repository that scopes by store_id.
- Policy classes for later resources use generic object parameters until the concrete catalog/order/content models exist.
- `php artisan route:list --except-vendor` hides Livewire full-page routes because their controller is vendor-provided; path-filtered route-list commands are used as evidence for those routes.
- Phase 2 media upload/admin UI is still missing, even though the media schema/job layer exists.
- Product options can be displayed and edited as text in the admin form, but full option matrix generation and option-value reassignment UI are not complete.
- Storefront product detail "Add to cart" currently dispatches a browser event only; cart persistence and checkout are still pending later roadmap phases.
- Automated browser tests from Spec 08 are still missing; current browser coverage is manual Playwright MCP smoke verification.
- SQLite enum/check constraints from the schema spec are not yet explicitly enforced as database `CHECK` constraints; enum validation is currently enforced through casts/services/model invariants.
- Product media processing now validates and resizes image uploads with GD and cleans predictable generated paths, but browser/admin upload UI is still pending.

## Completion Summary

Not complete. Phase 1 foundation and Phase 2 catalog data/UI surfaces are implemented enough to support cart, checkout, and richer storefront content work, with known auth/token, media UI, API, browser-test, and database CHECK constraint gaps tracked above.


I accidentally removed older tracked `.playwright-mcp` fixtures while cleaning today’s generated files. I’m restoring that directory from `HEAD` now so the commit only contains the shop work.


/bin/zsh
-lc
git restore .playwright-mcp


Output:
Chunk ID: d67c4b
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 0
Output:


git status --ignored --short public/build .playwright-mcp | sed -n '1,80p'


 M app/Providers/AppServiceProvider.php
 M resources/views/components/app-logo.blade.php
 M resources/views/layouts/app/sidebar.blade.php
 M routes/web.php
 M specs/progress.md
?? app/Livewire/Admin/Collections/
?? app/Livewire/Admin/Inventory/
?? app/Livewire/Admin/Products/
?? app/Livewire/Storefront/Collections/
?? app/Livewire/Storefront/Home.php
?? app/Livewire/Storefront/Pages/
?? app/Livewire/Storefront/Products/
?? app/Livewire/Storefront/Search/
?? app/Support/Money.php
?? resources/views/components/storefront/
?? resources/views/layouts/storefront.blade.php
?? resources/views/livewire/admin/collections/
?? resources/views/livewire/admin/inventory/
?? resources/views/livewire/admin/products/
?? resources/views/livewire/storefront/collections/
?? resources/views/livewire/storefront/home.blade.php
?? resources/views/livewire/storefront/pages/
?? resources/views/livewire/storefront/products/
?? resources/views/livewire/storefront/search/
?? tests/Feature/Catalog/CatalogUiTest.php


Output:
Chunk ID: 5e0802
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 251
Output:
 M app/Providers/AppServiceProvider.php
 M resources/views/components/app-logo.blade.php
 M resources/views/layouts/app/sidebar.blade.php
 M routes/web.php
 M specs/progress.md
?? app/Livewire/Admin/Collections/
?? app/Livewire/Admin/Inventory/
?? app/Livewire/Admin/Products/
?? app/Livewire/Storefront/Collections/
?? app/Livewire/Storefront/Home.php
?? app/Livewire/Storefront/Pages/
?? app/Livewire/Storefront/Products/
?? app/Livewire/Storefront/Search/
?? app/Support/Money.php
?? resources/views/components/storefront/
?? resources/views/layouts/storefront.blade.php
?? resources/views/livewire/admin/collections/
?? resources/views/livewire/admin/inventory/
?? resources/views/livewire/admin/products/
?? resources/views/livewire/storefront/collections/
?? resources/views/livewire/storefront/home.blade.php
?? resources/views/livewire/storefront/pages/
?? resources/views/livewire/storefront/products/
?? resources/views/livewire/storefront/search/
?? tests/Feature/Catalog/CatalogUiTest.php


 app/Providers/AppServiceProvider.php          | 13 +++++++++++
 resources/views/components/app-logo.blade.php |  4 ++--
 resources/views/layouts/app/sidebar.blade.php | 18 +++++++++++++--
 routes/web.php                                | 33 ++++++++++++++++++++++-----
 specs/progress.md                             | 30 +++++++++++++++++-------
 5 files changed, 80 insertions(+), 18 deletions(-)


Output:
Chunk ID: 7a2f0b
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 100
Output:
 app/Providers/AppServiceProvider.php          | 13 +++++++++++
 resources/views/components/app-logo.blade.php |  4 ++--
 resources/views/layouts/app/sidebar.blade.php | 18 +++++++++++++--
 routes/web.php                                | 33 ++++++++++++++++++++++-----
 specs/progress.md                             | 30 +++++++++++++++++-------
 5 files changed, 80 insertions(+), 18 deletions(-)


Output:
Chunk ID: 372044
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5
Output:
!! public/build/


The tracked Playwright fixtures are back, and only the intended catalog UI files remain dirty. I’m staging this slice now and checking the staged diff before committing it.


git add app/Providers/AppServiceProvider.php resources/views/components/app-logo.blade.php resources/views/layouts/app/sidebar.blade.php routes/web.php specs/progress.md app/Livewire/Admin/Collections app/Livewire/Admin/Inventory app/Livewire/Admin/Products app/Livewire/Storefront/Collections app/Livewire/Storefront/Home.php app/Livewire/Storefront/Pages app/Livewire/Storefront/Products app/Livewire/Storefront/Search app/Support/Money.php resources/views/components/storefront resources/views/layouts/storefront.blade.php resources/views/livewire/admin/collections resources/views/livewire/admin/inventory resources/views/livewire/admin/products resources/views/livewire/storefront/collections resources/views/livewire/storefront/home.blade.php resources/views/livewire/storefront/pages resources/views/livewire/storefront/products resources/views/livewire/storefront/search tests/Feature/Catalog/CatalogUiTest.php


Output:
Chunk ID: 56df78
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 0
Output:


A  app/Livewire/Admin/Collections/Form.php
A  app/Livewire/Admin/Collections/Index.php
A  app/Livewire/Admin/Inventory/Index.php
A  app/Livewire/Admin/Products/Form.php
A  app/Livewire/Admin/Products/Index.php
A  app/Livewire/Storefront/Collections/Index.php
A  app/Livewire/Storefront/Collections/Show.php
A  app/Livewire/Storefront/Home.php
A  app/Livewire/Storefront/Pages/Show.php
A  app/Livewire/Storefront/Products/Show.php
A  app/Livewire/Storefront/Search/Index.php
M  app/Providers/AppServiceProvider.php
A  app/Support/Money.php
M  resources/views/components/app-logo.blade.php
A  resources/views/components/storefront/breadcrumbs.blade.php
A  resources/views/components/storefront/price.blade.php
A  resources/views/components/storefront/product-card.blade.php
M  resources/views/layouts/app/sidebar.blade.php
A  resources/views/layouts/storefront.blade.php
A  resources/views/livewire/admin/collections/form.blade.php
A  resources/views/livewire/admin/collections/index.blade.php
A  resources/views/livewire/admin/inventory/index.blade.php
A  resources/views/livewire/admin/products/form.blade.php
A  resources/views/livewire/admin/products/index.blade.php
A  resources/views/livewire/storefront/collections/index.blade.php
A  resources/views/livewire/storefront/collections/show.blade.php
A  resources/views/livewire/storefront/home.blade.php
A  resources/views/livewire/storefront/pages/show.blade.php
A  resources/views/livewire/storefront/products/show.blade.php
A  resources/views/livewire/storefront/search/index.blade.php
M  routes/web.php
M  specs/progress.md
A  tests/Feature/Catalog/CatalogUiTest.php


Output:
Chunk ID: 52599f
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 406
Output:
A  app/Livewire/Admin/Collections/Form.php
A  app/Livewire/Admin/Collections/Index.php
A  app/Livewire/Admin/Inventory/Index.php
A  app/Livewire/Admin/Products/Form.php
A  app/Livewire/Admin/Products/Index.php
A  app/Livewire/Storefront/Collections/Index.php
A  app/Livewire/Storefront/Collections/Show.php
A  app/Livewire/Storefront/Home.php
A  app/Livewire/Storefront/Pages/Show.php
A  app/Livewire/Storefront/Products/Show.php
A  app/Livewire/Storefront/Search/Index.php
M  app/Providers/AppServiceProvider.php
A  app/Support/Money.php
M  resources/views/components/app-logo.blade.php
A  resources/views/components/storefront/breadcrumbs.blade.php
A  resources/views/components/storefront/price.blade.php
A  resources/views/components/storefront/product-card.blade.php
M  resources/views/layouts/app/sidebar.blade.php
A  resources/views/layouts/storefront.blade.php
A  resources/views/livewire/admin/collections/form.blade.php
A  resources/views/livewire/admin/collections/index.blade.php
A  resources/views/livewire/admin/inventory/index.blade.php
A  resources/views/livewire/admin/products/form.blade.php
A  resources/views/livewire/admin/products/index.blade.php
A  resources/views/livewire/storefront/collections/index.blade.php
A  resources/views/livewire/storefront/collections/show.blade.php
A  resources/views/livewire/storefront/home.blade.php
A  resources/views/livewire/storefront/pages/show.blade.php
A  resources/views/livewire/storefront/products/show.blade.php
A  resources/views/livewire/storefront/search/index.blade.php
M  routes/web.php
M  specs/progress.md
A  tests/Feature/Catalog/CatalogUiTest.php


 app/Livewire/Admin/Collections/Form.php            | 162 +++++++++
 app/Livewire/Admin/Collections/Index.php           |  56 +++
 app/Livewire/Admin/Inventory/Index.php             |  56 +++
 app/Livewire/Admin/Products/Form.php               | 375 +++++++++++++++++++++
 app/Livewire/Admin/Products/Index.php              | 145 ++++++++
 app/Livewire/Storefront/Collections/Index.php      |  30 ++
 app/Livewire/Storefront/Collections/Show.php       | 130 +++++++
 app/Livewire/Storefront/Home.php                   |  53 +++
 app/Livewire/Storefront/Pages/Show.php             |  29 ++
 app/Livewire/Storefront/Products/Show.php          | 148 ++++++++
 app/Livewire/Storefront/Search/Index.php           |  57 ++++
 app/Providers/AppServiceProvider.php               |  13 +
 app/Support/Money.php                              |  20 ++
 resources/views/components/app-logo.blade.php      |   4 +-
 .../components/storefront/breadcrumbs.blade.php    |  15 +
 .../views/components/storefront/price.blade.php    |  13 +
 .../components/storefront/product-card.blade.php   |  40 +++
 resources/views/layouts/app/sidebar.blade.php      |  18 +-
 resources/views/layouts/storefront.blade.php       |  71 ++++
 .../livewire/admin/collections/form.blade.php      |  95 ++++++
 .../livewire/admin/collections/index.blade.php     |  80 +++++
 .../views/livewire/admin/inventory/index.blade.php |  57 ++++
 .../views/livewire/admin/products/form.blade.php   | 145 ++++++++
 .../views/livewire/admin/products/index.blade.php  | 118 +++++++
 .../storefront/collections/index.blade.php         |  20 ++
 .../livewire/storefront/collections/show.blade.php |  84 +++++
 resources/views/livewire/storefront/home.blade.php |  63 ++++
 .../views/livewire/storefront/pages/show.blade.php |  15 +
 .../livewire/storefront/products/show.blade.php    | 102 ++++++
 .../livewire/storefront/search/index.blade.php     |  38 +++
 routes/web.php                                     |  33 +-
 specs/progress.md                                  |  30 +-
 tests/Feature/Catalog/CatalogUiTest.php            | 172 ++++++++++
 33 files changed, 2469 insertions(+), 18 deletions(-)


Output:
Chunk ID: 75dbb0
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 539
Output:
 app/Livewire/Admin/Collections/Form.php            | 162 +++++++++
 app/Livewire/Admin/Collections/Index.php           |  56 +++
 app/Livewire/Admin/Inventory/Index.php             |  56 +++
 app/Livewire/Admin/Products/Form.php               | 375 +++++++++++++++++++++
 app/Livewire/Admin/Products/Index.php              | 145 ++++++++
 app/Livewire/Storefront/Collections/Index.php      |  30 ++
 app/Livewire/Storefront/Collections/Show.php       | 130 +++++++
 app/Livewire/Storefront/Home.php                   |  53 +++
 app/Livewire/Storefront/Pages/Show.php             |  29 ++
 app/Livewire/Storefront/Products/Show.php          | 148 ++++++++
 app/Livewire/Storefront/Search/Index.php           |  57 ++++
 app/Providers/AppServiceProvider.php               |  13 +
 app/Support/Money.php                              |  20 ++
 resources/views/components/app-logo.blade.php      |   4 +-
 .../components/storefront/breadcrumbs.blade.php    |  15 +
 .../views/components/storefront/price.blade.php    |  13 +
 .../components/storefront/product-card.blade.php   |  40 +++
 resources/views/layouts/app/sidebar.blade.php      |  18 +-
 resources/views/layouts/storefront.blade.php       |  71 ++++
 .../livewire/admin/collections/form.blade.php      |  95 ++++++
 .../livewire/admin/collections/index.blade.php     |  80 +++++
 .../views/livewire/admin/inventory/index.blade.php |  57 ++++
 .../views/livewire/admin/products/form.blade.php   | 145 ++++++++
 .../views/livewire/admin/products/index.blade.php  | 118 +++++++
 .../storefront/collections/index.blade.php         |  20 ++
 .../livewire/storefront/collections/show.blade.php |  84 +++++
 resources/views/livewire/storefront/home.blade.php |  63 ++++
 .../views/livewire/storefront/pages/show.blade.php |  15 +
 .../livewire/storefront/products/show.blade.php    | 102 ++++++
 .../livewire/storefront/search/index.blade.php     |  38 +++
 routes/web.php                                     |  33 +-
 specs/progress.md                                  |  30 +-
 tests/Feature/Catalog/CatalogUiTest.php            | 172 ++++++++++
 33 files changed, 2469 insertions(+), 18 deletions(-)


Output:
Chunk ID: 923c05
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 0
Output:


git status --short --untracked-files=all | sed -n '1,120p'


Output:
Chunk ID: e45c03
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 406
Output:
A  app/Livewire/Admin/Collections/Form.php
A  app/Livewire/Admin/Collections/Index.php
A  app/Livewire/Admin/Inventory/Index.php
A  app/Livewire/Admin/Products/Form.php
A  app/Livewire/Admin/Products/Index.php
A  app/Livewire/Storefront/Collections/Index.php
A  app/Livewire/Storefront/Collections/Show.php
A  app/Livewire/Storefront/Home.php
A  app/Livewire/Storefront/Pages/Show.php
A  app/Livewire/Storefront/Products/Show.php
A  app/Livewire/Storefront/Search/Index.php
M  app/Providers/AppServiceProvider.php
A  app/Support/Money.php
M  resources/views/components/app-logo.blade.php
A  resources/views/components/storefront/breadcrumbs.blade.php
A  resources/views/components/storefront/price.blade.php
A  resources/views/components/storefront/product-card.blade.php
M  resources/views/layouts/app/sidebar.blade.php
A  resources/views/layouts/storefront.blade.php
A  resources/views/livewire/admin/collections/form.blade.php
A  resources/views/livewire/admin/collections/index.blade.php
A  resources/views/livewire/admin/inventory/index.blade.php
A  resources/views/livewire/admin/products/form.blade.php
A  resources/views/livewire/admin/products/index.blade.php
A  resources/views/livewire/storefront/collections/index.blade.php
A  resources/views/livewire/storefront/collections/show.blade.php
A  resources/views/livewire/storefront/home.blade.php
A  resources/views/livewire/storefront/pages/show.blade.php
A  resources/views/livewire/storefront/products/show.blade.php
A  resources/views/livewire/storefront/search/index.blade.php
M  routes/web.php
M  specs/progress.md
A  tests/Feature/Catalog/CatalogUiTest.php


The staged diff is clean: 33 intended files, no whitespace issues, and no stray artifacts. I’m committing the catalog UI slice now.


git commit -m "Build catalog UI surface"


git commit -m "Build catalog UI surface"

[2026-05-04-codex-5-5-goal 60a486f7] Build catalog UI surface
 33 files changed, 2469 insertions(+), 18 deletions(-)
 create mode 100644 app/Livewire/Admin/Collections/Form.php
 create mode 100644 app/Livewire/Admin/Collections/Index.php
 create mode 100644 app/Livewire/Admin/Inventory/Index.php
 create mode 100644 app/Livewire/Admin/Products/Form.php
 create mode 100644 app/Livewire/Admin/Products/Index.php
 create mode 100644 app/Livewire/Storefront/Collections/Index.php
 create mode 100644 app/Livewire/Storefront/Collections/Show.php
 create mode 100644 app/Livewire/Storefront/Home.php
 create mode 100644 app/Livewire/Storefront/Pages/Show.php
 create mode 100644 app/Livewire/Storefront/Products/Show.php
 create mode 100644 app/Livewire/Storefront/Search/Index.php
 create mode 100644 app/Support/Money.php
 create mode 100644 resources/views/components/storefront/breadcrumbs.blade.php
 create mode 100644 resources/views/components/storefront/price.blade.php
 create mode 100644 resources/views/components/storefront/product-card.blade.php
 create mode 100644 resources/views/layouts/storefront.blade.php
 create mode 100644 resources/views/livewire/admin/collections/form.blade.php
 create mode 100644 resources/views/livewire/admin/collections/index.blade.php
 create mode 100644 resources/views/livewire/admin/inventory/index.blade.php
 create mode 100644 resources/views/livewire/admin/products/form.blade.php
 create mode 100644 resources/views/livewire/admin/products/index.blade.php
 create mode 100644 resources/views/livewire/storefront/collections/index.blade.php
 create mode 100644 resources/views/livewire/storefront/collections/show.blade.php
 create mode 100644 resources/views/livewire/storefront/home.blade.php
 create mode 100644 resources/views/livewire/storefront/pages/show.blade.php
 create mode 100644 resources/views/livewire/storefront/products/show.blade.php
 create mode 100644 resources/views/livewire/storefront/search/index.blade.php
 create mode 100644 tests/Feature/Catalog/CatalogUiTest.php


Output:
Chunk ID: 6231a9
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 510
Output:
[2026-05-04-codex-5-5-goal 60a486f7] Build catalog UI surface
 33 files changed, 2469 insertions(+), 18 deletions(-)
 create mode 100644 app/Livewire/Admin/Collections/Form.php
 create mode 100644 app/Livewire/Admin/Collections/Index.php
 create mode 100644 app/Livewire/Admin/Inventory/Index.php
 create mode 100644 app/Livewire/Admin/Products/Form.php
 create mode 100644 app/Livewire/Admin/Products/Index.php
 create mode 100644 app/Livewire/Storefront/Collections/Index.php
 create mode 100644 app/Livewire/Storefront/Collections/Show.php
 create mode 100644 app/Livewire/Storefront/Home.php
 create mode 100644 app/Livewire/Storefront/Pages/Show.php
 create mode 100644 app/Livewire/Storefront/Products/Show.php
 create mode 100644 app/Livewire/Storefront/Search/Index.php
 create mode 100644 app/Support/Money.php
 create mode 100644 resources/views/components/storefront/breadcrumbs.blade.php
 create mode 100644 resources/views/components/storefront/price.blade.php
 create mode 100644 resources/views/components/storefront/product-card.blade.php
 create mode 100644 resources/views/layouts/storefront.blade.php
 create mode 100644 resources/views/livewire/admin/collections/form.blade.php
 create mode 100644 resources/views/livewire/admin/collections/index.blade.php
 create mode 100644 resources/views/livewire/admin/inventory/index.blade.php
 create mode 100644 resources/views/livewire/admin/products/form.blade.php
 create mode 100644 resources/views/livewire/admin/products/index.blade.php
 create mode 100644 resources/views/livewire/storefront/collections/index.blade.php
 create mode 100644 resources/views/livewire/storefront/collections/show.blade.php
 create mode 100644 resources/views/livewire/storefront/home.blade.php
 create mode 100644 resources/views/livewire/storefront/pages/show.blade.php
 create mode 100644 resources/views/livewire/storefront/products/show.blade.php
 create mode 100644 resources/views/livewire/storefront/search/index.blade.php
 create mode 100644 tests/Feature/Catalog/CatalogUiTest.php


The catalog UI slice is committed as `60a486f7 Build catalog UI surface`. I’m moving to the next roadmap slice now and rereading the relevant specs so the next commit lands on the planned build order instead of drifting.


sed -n '1,260p' specs/09-IMPLEMENTATION-ROADMAP.md


sed -n '1,260p' specs/04-STOREFRONT-UI.md


sed -n '1,260p' specs/05-BUSINESS-LOGIC.md


sed -n '1,260p' specs/01-DATABASE-SCHEMA.md


sed -n '1,260p' specs/09-IMPLEMENTATION-ROADMAP.md

# 09 - Implementation Roadmap and Pest Test Specification

> E-commerce platform - Step-by-step build order and exhaustive test plan for Laravel 12 + Livewire v4 + Flux UI Free + SQLite + Tailwind CSS v4

---

## 1. Technology Decisions (Final)

These decisions adapt the original PDF spec for a self-contained, benchmarkable Laravel application. All decisions are final and must not be revisited.

| Concern | PDF Default | Our Decision | Rationale |
|---------|-------------|--------------|-----------|
| Database | PostgreSQL | SQLite | Self-contained, no external DB, zero config |
| Cache | Redis | File (Array for tests) | No Redis dependency |
| Session | Redis | File | No Redis dependency |
| Queue | Redis + Horizon | Sync (dev) / Database (prod) | No Redis dependency, sync for immediate feedback |
| Search | Elasticsearch + Scout | SQLite FTS5 | Self-contained, no external service |
| Storage | S3 | Local filesystem (storage/app/public) | No AWS dependency |
| Admin UI | React/Vue SPA | Livewire v4 + Flux UI Free | Server-rendered, matches project stack |
| Storefront | Blade SSR + Vite | Blade + Livewire + Tailwind v4 | Server-rendered, matches project stack |
| Auth (admin) | Sanctum SPA | Laravel session auth | Standard Livewire auth pattern |
| Auth (API) | Sanctum tokens | Sanctum personal access tokens | For programmatic API access |
| Auth (customer) | Separate guard | Custom `customer` guard | Storefront customer auth |
| OAuth (apps) | Passport | Deferred/Stubbed | Simplifies initial build, can add later |
| Payments | Stripe + PayPal | Mock PSP (in-process) | No external API calls. MockPaymentProvider handles credit card, PayPal, bank transfer with magic card numbers for testing. |
| Email | SMTP/SES | Log driver (dev) / SMTP | Log for benchmark, SMTP configurable |
| Monitoring | OpenTelemetry | Laravel Log (structured JSON) | Simplified for benchmark |
| CI/CD | GitHub Actions | Not implemented | Out of scope for one-shot benchmark |
| Docker | Multi-stage | Not implemented | App served by Laravel Herd locally |

---

## 2. Implementation Phases (Build Order)

Each phase builds on the previous. A coding agent should execute these in strict sequential order. Tests are written alongside each phase (see Section 3 for the full test specification).

### Phase Dependency Graph

```mermaid
flowchart TD
    P1[Phase 1: Foundation]
    P2[Phase 2: Catalog]
    P3[Phase 3: Themes and Storefront Layout]
    P4[Phase 4: Cart, Checkout, Discounts, Shipping, Taxes]
    P5[Phase 5: Payments, Orders, Fulfillment]
    P6[Phase 6: Customer Accounts]
    P7[Phase 7: Admin Panel]
    P8[Phase 8: Search]
    P9[Phase 9: Analytics]
    P10[Phase 10: Apps and Webhooks]
    P11[Phase 11: Polish]
    P12[Phase 12: Full Test Suite]

    P1 --> P2
    P1 --> P3
    P2 --> P4
    P3 --> P4
    P4 --> P5
    P5 --> P6
    P5 --> P7
    P2 --> P8
    P5 --> P9
    P5 --> P10
    P6 --> P11
    P7 --> P11
    P8 --> P11
    P9 --> P11
    P10 --> P11
    P11 --> P12
```

---

### Phase 1: Foundation (Migrations, Models, Middleware, Auth)

**Priority:** CRITICAL - everything depends on this.

#### Step 1.1: Environment and Config

| Config File | Setting | Value | Purpose |
|-------------|---------|-------|---------|
| `.env` | `DB_CONNECTION` | `sqlite` | Use SQLite as database |
| `.env` | `DB_DATABASE` | `database/database.sqlite` | SQLite database file path |
| `.env` | `CACHE_STORE` | `file` | File-based caching |
| `.env` | `SESSION_DRIVER` | `file` | File-based sessions |
| `.env` | `QUEUE_CONNECTION` | `sync` | Synchronous queue for dev |
| `.env` | `MAIL_MAILER` | `log` | Log-based mail for dev |
| `.env` | `FILESYSTEM_DISK` | `local` | Local filesystem storage |
| `config/database.php` | SQLite connection | WAL mode, foreign keys enabled, busy_timeout=5000, synchronous=normal | Optimized SQLite configuration |
| `config/session.php` | `driver` | `file` | Session driver |
| `config/session.php` | `lifetime` | `120` | Session lifetime in minutes |
| `config/cache.php` | `default` | `file` | Cache driver |
| `config/queue.php` | `default` | `sync` | Queue driver |
| `config/auth.php` | Guards | Add `customer` guard with `customers` provider | Customer storefront authentication |
| `config/auth.php` | Providers | Add `customers` provider pointing to Customer model | Customer user provider |
| `config/auth.php` | Passwords | Add `customers` password broker | Customer password reset |
| `config/filesystems.php` | `public` disk | Ensure configured for local storage | Media file storage |
| `config/logging.php` | Channels | Add structured JSON channel | Structured logging |

#### Step 1.2: Core Migrations (Batch 1-2)

Create in this dependency order:

1. `create_organizations_table` - no dependencies
2. `create_stores_table` - FK: `organization_id`
3. `create_store_domains_table` - FK: `store_id`
4. Modify default `users` migration - add `status`, `last_login_at`, `two_factor_*` columns; rename `password` to `password_hash`…1704 chars truncated…
|------|--------|
| `StoreStatus` | `Active`, `Suspended` |
| `StoreUserRole` | `Owner`, `Admin`, `Staff`, `Support` |
| `StoreDomainType` | `Storefront`, `Admin`, `Api` |

#### Step 1.5: Tenant Resolution Middleware

**File to create:** `App\Http\Middleware\ResolveStore`

Requirements:
1. Storefront routes: extract hostname from the request, look up `store_domains`, cache hostname-to-store_id for 5 minutes, bind `Store` as singleton via container instance `current_store`
2. Admin routes: read `current_store_id` from session, verify user has `store_users` record
3. Return 404 if hostname not found
4. Return 503 for suspended stores on storefront routes

**Registration in `bootstrap/app.php`:**
- Register middleware group `storefront` containing `ResolveStore`
- Register middleware group `admin` containing `ResolveStore`

#### Step 1.6: BelongsToStore Trait and Global Scope

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Trait | `App\Models\Concerns\BelongsToStore` | Applies StoreScope and auto-sets store_id on creating event |
| Scope | `App\Models\Scopes\StoreScope` | Applies `where('store_id', app('current_store')->id)` to all queries |

Applied on: products, collections, customers, orders, carts, checkouts, discounts, shipping_zones, themes, pages, navigation_menus, analytics_events, analytics_daily, webhook_subscriptions, inventory_items, search_queries.

#### Step 1.7: Authentication

**Admin auth requirements:**

| Component | Description |
|-----------|-------------|
| Livewire component `Admin\Auth\Login` | Admin login form |
| Livewire component `Admin\Auth\Logout` | Admin logout action |
| Auth mechanism | Standard Laravel session auth via `Auth::guard('web')->attempt()` |
| Rate limiting | 5 attempts per minute per IP via `RateLimiter::for('login')` |
| Password reset | Standard Laravel flow with `Password::broker('users')` |

**Customer auth requirements:**

| Component | Description |
|-----------|-------------|
| Custom guard | `customer` guard with `customers` provider |
| Custom user provider | `CustomerUserProvider` that injects `store_id` into queries |
| Livewire component `Storefront\Account\Auth\Login` | Customer login form |
| Livewire component `Storefront\Account\Auth\Register` | Customer registration form |
| Uniqueness | Customer email unique per store, not globally |
| Rate limiting | 5 attempts per minute per IP |

**Rate limiter registration:**
- Register rate limiters in `AppServiceProvider::boot()` for login (5 per minute per IP)

#### Step 1.8: Authorization

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Policy | `ProductPolicy` | Product authorization based on store role |
| Policy | `OrderPolicy` | Order authorization based on store role |
| Policy | `CollectionPolicy` | Collection authorization based on store role |
| Policy | `DiscountPolicy` | Discount authorization based on store role |
| Policy | `CustomerPolicy` | Customer authorization based on store role |
| Policy | `StorePolicy` | Store authorization based on store role |
| Policy | `PagePolicy` | Page authorization based on store role |
| Policy | `ThemePolicy` | Theme authorization based on store role |
| Policy | `FulfillmentPolicy` | Fulfillment authorization based on store role |
| Policy | `RefundPolicy` | Refund authorization based on store role |

Each policy checks user role via `store_users` pivot for the current store. Helper on User model: `roleForStore(Store $store): ?StoreUserRole`. Register policies via auto-discovery or explicit binding in `AppServiceProvider`.

**Permission Matrix:**

| Permission | Owner | Admin | Staff | Support |
|------------|:-----:|:-----:|:-----:|:-------:|
| Manage store settings | Y | Y | N | N |
| Delete store | Y | N | N | N |
| Manage staff | Y | Y | N | N |
| Manage products (CRUD) | Y | Y | Y | N |
| Delete/archive products | Y | Y | N | N |
| Manage orders | Y | Y | Y | Read-only |
| Process refunds | Y | Y | N | N |
| Create fulfillments | Y | Y | Y | N |
| Manage discounts | Y | Y | Y | N |
| Manage themes | Y | Y | N | N |
| Manage apps | Y | Y | N | N |
| View analytics | Y | Y | Y | N |
| Manage shipping/tax | Y | Y | N | N |
| View customers | Y | Y | Y | Y |
| Update customers | Y | Y | Y | N |

---

### Phase 2: Catalog (Products, Variants, Inventory, Collections, Media)

**Priority:** HIGH - storefront and orders depend on this.

#### Step 2.1: Migrations (Batch 3-5)

Create in dependency order:

1. `create_products_table` - FK: `store_id`
2. `create_product_options_table` - FK: `product_id`
3. `create_product_option_values_table` - FK: `product_option_id`
4. `create_product_variants_table` - FK: `product_id`
5. `create_variant_option_values_table` - composite PK: `variant_id` + `product_option_value_id`
6. `create_inventory_items_table` - FK: `store_id`, `variant_id`
7. `create_collections_table` - FK: `store_id`
8. `create_collection_products_table` - composite PK: `collection_id` + `product_id`


sed -n '1,260p' specs/04-STOREFRONT-UI.md

# 04 - Storefront UI/UX Specification

> E-commerce platform - Customer-facing storefront UI/UX requirements

---

## Conventions

| Convention | Detail |
|---|---|
| CSS Framework | Tailwind CSS v4, mobile-first design, dark mode support |
| Interactivity | Livewire v4 for all dynamic UI (cart, filters, checkout) |
| Templating | Blade templates with reusable storefront-prefixed components |
| Accessibility | WCAG 2.2 AA compliance throughout |
| Responsive | Mobile-first with progressive enhancement at small, medium, large, and extra-large breakpoints |
| Currency | All prices stored as integers (cents), formatted with locale-aware helpers |
| Images | Lazy-loaded, with proper alt text and maintained aspect ratios |

---

## Currency Formatting

All monetary amounts are stored as integers in minor units (cents) and must be formatted for display according to these rules:

| Setting | Value |
|---------|-------|
| Decimal separator | `.` (period) |
| Thousands separator | `,` (comma) |
| Currency symbol | After amount with space (e.g., `24.99 EUR`) |
| Decimal places | Always 2 |
| Free amounts | Display as `0.00 EUR` |
| Negative amounts (refunds) | Prefix with `-` (e.g., `-12.50 EUR`) |

**Helper:** Use a shared Blade component or helper (e.g., `<x-price :amount="$amount" :currency="$currency" />`) to ensure consistent formatting across all storefront pages.

**Examples:**
- 2499 cents -> `24.99 EUR`
- 0 cents -> `0.00 EUR`
- 149900 cents -> `1,499.00 EUR`

---

## 1. Theme System Architecture

### 1.1 View Organization

The storefront views are organized into the following categories:

| Category | Purpose | Views |
|---|---|---|
| Layouts | Master page shell | app (master layout) |
| Pages | Core storefront pages | home, collection, product, cart, search, page (static CMS) |
| Checkout | Purchase flow | checkout index, order confirmation |
| Account | Customer area | login, register, dashboard, orders (list + detail), addresses |
| Errors | Error states | 404, 503 |
| Components | Reusable UI elements | product-card, price, badge, quantity-selector, address-form, order-summary, breadcrumbs, pagination |

### 1.2 Layout Hierarchy

All storefront pages extend a single master layout, which provides the full page shell including header, footer, cart drawer, and global Livewire listeners. Individual page templates fill the main content section.

### 1.3 Theme Settings

Theme settings are stored in the database as JSON (keyed by theme ID). A singleton service loads and caches the active theme settings for the current store. Settings control:

- Announcement bar visibility, text, link, and background color
- Sticky header toggle
- Home page section order and visibility
- Color palette overrides (primary, secondary, accent)
- Typography scale
- Footer content and social links
- Dark mode behavior (system preference, toggle, or forced)

### 1.4 Section-Based Architecture

Each page is composed of configurable sections. Sections are Blade includes or Livewire components receiving configuration from theme settings.

| Section | Description | Used On |
|---|---|---|
| Hero | Full-width banner with heading, subheading, call-to-action | Home |
| Featured Collections | Grid of collection cards | Home |
| Featured Products | Grid of product cards (lazy-loaded) | Home |
| Newsletter | Email signup form | Home, Footer |
| Rich Text | Customizable content block | Home, Pages |

### 1.5 Blade Components

All reusable UI elements are implemented as Blade components with a storefront prefix. See Section 16 for the full component library reference.

---

## 2. Base Layout

### 2.1 Document Head

The document head includes:

| Element | Description |
|---|---|
| Character encoding | UTF-8 |
| Viewport | Width = device width, initial scale 1 |
| Meta description | Page-specific, yielded from child templates |
| Title | Page-specific title appended with the app name |
| Stylesheets | Compiled CSS via Vite |
| Scripts | Compiled JS via Vite |
| Livewire styles | Injected by Livewire |
| Language attribute | Set on the HTML element from application locale |
| Scroll behavior | Smooth scrolling enabled globally |

### 2.2 Skip Link

A visually hidden "Skip to main content" link is the first element in the body. It becomes visible on keyboard focus, positioned fixed at top-left with a clear visual treatment (solid background, shadow, focus ring). Supports dark mode.

**Accessibility:** Allows keyboard users to bypass the header navigation and jump directly to the main content area.

### 2.3 Announcement Bar

Optional, controlled by theme settings. Renders a full-width bar above the header.

| Attribute | Description |
|---|---|
| Position | Full-width, above the header |
| Background | Configurable color, defaults to dark background (light text) / inverted in dark mode |
| Text | Centered, small size, configurable content |
| Link | Optional, underlined, opens in same tab |
| Dismiss | Close button (X icon) on the right side; dismis…880 chars truncated…rt Icon | Right group | Button that opens the cart drawer. Displays item count badge (small circular indicator, primary color background, white text) |
| Account Icon | Right group | Link to account dashboard (logged in) or login page (guest) |

**Mobile Layout (below large breakpoint):**

```
+--------------------------------------------------------------+
| [Hamburger]           [Logo]                            [Cart]|
+--------------------------------------------------------------+
```

| Element | Position | Description |
|---|---|---|
| Hamburger menu | Left | Toggle button for mobile navigation drawer |
| Logo | Center | Same as desktop but horizontally centered |
| Cart icon | Right | Same as desktop |

**Sticky Header (optional):**

When enabled in theme settings, the header sticks to the top of the viewport with a semi-transparent background and backdrop blur. A subtle bottom border appears on scroll.

**Mobile Navigation Drawer:**

| Attribute | Description |
|---|---|
| Animation | Slides in from the left side |
| Height | Full viewport height |
| Backdrop | Semi-transparent dark overlay behind the drawer |
| Close button | X icon at the top-right of the drawer |
| Navigation items | Vertical stack with comfortable tap targets |
| Submenus | Collapsible accordion pattern with chevron icons |
| Account link | Positioned at the bottom of the navigation list |
| Focus behavior | Focus is trapped within the drawer while open |
| ARIA | Labeled as "Mobile navigation" |

### 2.5 Main Content Area

The main content area is a landmark element with a unique ID for skip-link targeting. It occupies at least the full viewport height.

### 2.6 Footer

The footer is a content-info landmark.

**Layout:**

```
+--------------------------------------------------------------+
| [Column 1: Links]  [Column 2: Links]  [Column 3: Store Info] |
|                                                               |
| [Social Icons]                                                |
| [Copyright] [Payment Icons]                                   |
+--------------------------------------------------------------+
```

| Element | Description |
|---|---|
| Link columns | Responsive grid: 2 columns on mobile, 3 on tablet, up to 4 on desktop. Links sourced from "footer-menu" navigation menu. Each column has an uppercase heading and a list of links |
| Store info column | Store name, address (if configured), contact email |
| Social links | Row of icon links (Facebook, Instagram, Twitter/X, TikTok, YouTube) configured in theme settings. Each with screen reader label. Icons are 20x20, muted color with hover to full contrast |
| Copyright line | Small muted text: "(c) {year} {store name}. All rights reserved." |
| Payment method icons | Row of SVG icons for accepted payment methods (Visa, Mastercard, Amex, PayPal, etc.). Slightly reduced opacity |
| Spacing | Generous vertical padding, content constrained to max-width container with horizontal padding |
| Background | Light gray (dark: very dark gray), top border separator |

### 2.7 Cart Drawer (Livewire)

The cart drawer is always present in the layout as a global Livewire component. It listens for the "cart-updated" browser event to refresh and open. See Section 6 for full specification.

### 2.8 Dark Mode

Dark mode is implemented via Tailwind's dark variant. The behavior is controlled by theme settings:

| Mode | Implementation |
|---|---|
| System preference (default) | Follows OS-level dark mode preference automatically |
| Toggle | User-controlled toggle button in header/footer; preference stored in localStorage |
| Forced light/dark | Applied at server render time on the HTML element |

**Color Token Patterns:**

| Token | Light Mode | Dark Mode |
|---|---|---|
| Page background | White | Near-black |
| Card/section background | Light gray | Very dark gray |
| Heading text | Near-black | White |
| Body text | Medium gray | Light gray |
| Borders | Light gray | Medium-dark gray |
| Primary actions | Blue, darkens on hover | Slightly lighter blue, lightens on hover |

---

## 3. Home Page (GET /)

The home page renders sections in the order defined by theme settings. Each section can be toggled on/off and reordered. Default section order:

1. Hero Banner
2. Featured Collections
3. Featured Products
4. Newsletter Signup
5. Rich Text

### 3.1 Hero Banner Section

**Layout:** Full-width container (no max-width on the outer wrapper). Inner content constrained to standard max-width.

**Desktop (large breakpoint and above):**

```
+--------------------------------------------------------------+
|                                                               |
|  [Background Image / Gradient]                                |
|                                                               |
|       [Heading - very large, bold]                            |
|       [Subheading - medium, regular weight]                   |
|       [CTA Button - primary, large]                           |


Output:
Chunk ID: 70d6fe
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 0
Output: