type: CollabAgentToolCall

agent_nickname: Faraday

completed:
## Audit verdict

The repo at `d3efee4e` does not satisfy `specs/03-ADMIN-UI.md` or `specs/04-STOREFRONT-UI.md`. It contains a functional commerce slice, but most specified UI components, interactions, theme behavior, and accessibility requirements are incomplete.

I inspected both specifications in full, current routes/classes/views, Tailwind markup, and a read-only HTTP render. No files were edited. Playwright could not be reattached because its existing browser session was locked, so runtime-only responsive assertions remain unverified.

## Admin UI gaps

### Layout shell

- Required `Admin\Layout\Sidebar` and `Admin\Layout\TopBar` classes/views are missing.
- The shell is hard-coded inline in [`resources/views/layouts/admin.blade.php:4`](/Users/wesner/Herd/shop/resources/views/layouts/admin.blade.php:4).
- No collapsed state, `toggle()`, mobile drawer, backdrop, hamburger, store selector, notifications, profile dropdown, or `switchStore()`.
- No Flux components are used in the target admin views.
- No breadcrumbs on admin pages.
- No global toast listener or `toast` event system.
- No admin dark-mode classes, system preference handling, `localStorage` persistence, or flash-prevention script.

### Dashboard

[`app/Livewire/Admin/Dashboard.php:9`](/Users/wesner/Herd/shop/app/Livewire/Admin/Dashboard.php:9) and [`resources/views/livewire/admin/dashboard.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/dashboard.blade.php:1):

- Missing date-range state and custom date inputs.
- Missing visitors, period comparisons, chart data, top-products data, and conversion-funnel data.
- No Chart.js chart, loading overlays, empty/error states, or trend badges.
- Displays product count instead of the required visitors KPI.

### Products list and form

[`app/Livewire/Admin/Products/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Products/Index.php), [`resources/views/livewire/admin/products/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/products/index.blade.php:1), [`app/Livewire/Admin/Products/Form.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Products/Form.php), and [`resources/views/livewire/admin/products/form.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/products/form.blade.php:1):

- Missing type filter, selected IDs, select-all, sortable columns, bulk archive/delete/activate actions, and confirmation modal.
- Missing image, inventory, type, vendor, updated columns and required status badges.
- Form lacks handle, tags, publish date, collections, options, variant matrix, media uploads/reordering/alt text, SEO section, sticky save bar, discard/delete actions, and loading states.
- Uses a single default price instead of editable variants.
- No Flux field/input/select/modal mapping required by the spec.

### Collections

[`app/Livewire/Admin/Collections/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Collections/Index.php), [`Create.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Collections/Create.php), [`Edit.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Collections/Edit.php), and [`resources/views/livewire/admin/collections/`](/Users/wesner/Herd/shop/resources/views/livewire/admin/collections/):

- `Index`, `Create`, and `Edit` only inherit the generic placeholder [`app/Livewire/Admin/Section.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Section.php).
- Required `Admin\Collections\Form` class/view is absent.
- No search/filter, pagination, deletion modal, product assignment, product search, ordering, or save behavior.

### Inventory

[`app/Livewire/Admin/Inventory/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Inventory/Index.php) and [`resources/views/livewire/admin/inventory/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/inventory/index.blade.php:1):

- Placeholder only.
- No search, stock filter, pagination, inline quantity editing, reserved quantity, policy badge, or actions.

### Orders

[`app/Livewire/Admin/Orders/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Orders/Index.php), [`resources/views/livewire/admin/orders/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/orders/index.blade.php:1), [`app/Livewire/Admin/Orders/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Orders/Show.php), and [`resources/views/livewire/admin/orders/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/orders/show.blade.php:1):

- List lacks search, required status tabs, correct status taxonomy, sorting, fulfillment status, and responsive table behavior.
- Detail lacks timeline, addresses, payment details, fulfillment tracking fields, fulfillment/refund modals, line selection, partial quantities, shipped/delivered actions, and required callouts.
- Required action names such as `createFulfillment()`, `markAsShipped()`, `markAsDelivered()`, and `createRefund()` are absent.
- Current fulfillment action fulfills every order line at once.

### Customers

[`app/Livewire/Admin/Customers/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Customers/Index.php), [`resources/views/livewire/admin/customers/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/customers/index.blade.php:1), [`app/Livewire/Admin/Customers/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Customers/Show.php), and [`resources/views/livewire/admin/customers/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/customers/show.blade.php:1):

- Missing total spent aggregate and required table columns.
- Detail lacks customer information card, marketing status, paginated order history, address CRUD, address modal, default-address action, edit/delete controls, and responsive layout.

### Discounts

[`app/Livewire/Admin/Discounts/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Discounts/Index.php), [`resources/views/livewire/admin/discounts/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/discounts/index.blade.php:1), [`app/Livewire/Admin/Discounts/Form.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Discounts/Form.php), and [`resources/views/livewire/admin/discounts/form.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/discounts/form.blade.php:1):

- List lacks search, status filter, pagination, type, usage, and date columns.
- Form lacks automatic/code selection, generate-code action, minimum purchase, product/collection eligibility, usage limits, one-per-customer, dates, active toggle, and search selectors.
- No sticky save bar, discard action, or confirmation behavior.

### Settings

[`app/Livewire/Admin/Settings/General.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Settings/General.php), [`Shipping.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Settings/Shipping.php), [`Taxes.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Settings/Taxes.php), and their views:

- General settings only edit store name; currency, locale, timezone, and immutable handle are absent.
- Required `Admin\Settings\Domains` class/view is missing.
- Required General/Domains/Shipping/Taxes/Checkout/Notifications tab UI is missing.
- Shipping lacks zone/rate CRUD, country checklist, dynamic rate configuration, active toggles, modals, deletion, and test-address tool.
- Taxes lacks manual/provider modes, provider/API fields, manual-rate rows, and tax-inclusive toggle.

### Themes, pages, navigation, apps, developers, analytics, search

These routes point to placeholder components:

[`app/Livewire/Admin/Section.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Section.php), [`resources/views/livewire/admin/section.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/section.blade.php:1), and the following classes/views:

- Themes: [`app/Livewire/Admin/Themes/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Themes/Index.php), [`Editor.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Themes/Editor.php)
- Pages: [`app/Livewire/Admin/Pages/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Pages/Index.php), [`Create.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Pages/Create.php), [`Edit.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Pages/Edit.php)
- Navigation: [`app/Livewire/Admin/Navigation/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Navigation/Index.php)
- Apps: [`app/Livewire/Admin/Apps/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Apps/Index.php), [`Show.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Apps/Show.php)
- Developers: [`app/Livewire/Admin/Developers/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Developers/Index.php)
- Analytics: [`app/Livewire/Admin/Analytics/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Analytics/Index.php)
- Search settings: [`app/Livewire/Admin/Search/Settings.php`](/Users/wesner/Herd/shop/app/Livewire/Admin/Search/Settings.php)

All lack the specified properties, actions, forms, tables, modals, loading states, and data interactions.

### Admin route mismatches

[`routes/web.php:117-131`](/Users/wesner/Herd/shop/routes/web.php:117):

- Spec names such as `admin.collections.index`, `admin.inventory.index`, `admin.themes.index`, `admin.pages.index`, `admin.navigation.index`, `admin.apps.index`, `admin.analytics.index`, and `admin.developers.index` are not used.
- Current names are `admin.collections`, `admin.inventory`, `admin.themes`, `admin.pages`, `admin.navigation`, `admin.apps`, `admin.analytics`, and `admin.developers`.

## Storefront UI gaps

### Architecture, theme, and currency

[`resources/views/layouts/storefront.blade.php`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php), [`app/Livewire/Storefront/Home.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Home.php), and [`resources/views/livewire/storefront/home.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/home.blade.php):

- No active-theme settings service, cache, section schema, or configurable section order/visibility.
- Announcement, header, footer, palette, typography, sticky-header, dark-mode, and social settings are hard-coded.
- No shared currency/price helper. Prices are hard-coded as `€` with `number_format()` in multiple views instead of locale-aware `24.99 EUR` formatting.
- Only [`resources/views/components/storefront/product-card.blade.php`](/Users/wesner/Herd/shop/resources/views/components/storefront/product-card.blade.php) exists from the required reusable component library.

### Base layout

[`resources/views/layouts/storefront.blade.php:1-41`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php):

- No page-specific meta description, app-name title suffix, Open Graph tags, JSON-LD, or smooth-scroll behavior.
- `lang="en"` is hard-coded.
- Skip link says “Skip to content” rather than the specified “Skip to main content.”
- Announcement bar is always visible, hard-coded, has no configured link, dismiss control, or `localStorage` persistence.
- Desktop navigation is hard-coded and has no theme-driven menu or dropdown submenus.
- Mobile navigation has no hamburger, drawer, backdrop, close behavior, accordion submenus, focus trap, or account placement.
- Cart is a normal link; there is no cart count badge or drawer trigger.
- Search is a normal link; `Search\Modal` is not mounted in the layout.
- Footer lacks configured footer menus, social links, payment icons, address/contact details, and Organization structured data.
- No dark-mode toggle, persistence, system-preference initialization, or forced theme mode.

### Home page

[`app/Livewire/Storefront/Home.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Home.php) and [`resources/views/livewire/storefront/home.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/home.blade.php):

- Sections are fixed inline rather than theme-configurable.
- No `FeaturedProducts` lazy-loading component or skeleton state.
- No `NewsletterSignup` Livewire component; the form posts to `#` and has no success/error/loading behavior.
- Hero has no configured background image/gradient/overlay and does not implement the specified responsive heights.
- Collection cards lack images, 3:4 aspect ratio, overlays, and configured card content.
- Rich-text section is missing.
- No theme-driven sanitized rich content.

### Collections and product cards

[`app/Livewire/Storefront/Collections/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Collections/Show.php), [`resources/views/livewire/storefront/collections/show.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/collections/show.blade.php), and [`resources/views/components/storefront/product-card.blade.php`](/Users/wesner/Herd/shop/resources/views/components/storefront/product-card.blade.php):

- Collection filters only support sort and in-stock; price, product type, vendor, filter pills, clear-all logic, and filter drawer/sidebar are missing.
- No best-selling sort or pagination.
- Collection description is plain text rather than configured sanitized prose.
- Product cards lack secondary hover images, quick add/choose-options behavior, proper fallback icon, heading-level prop, shared price/badge components, and complete accessibility labels.
- Sale/compare-at handling is not fully spec-compliant.

### Product page

[`app/Livewire/Storefront/Products/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Products/Show.php) and [`resources/views/livewire/storefront/products/show.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/products/show.blade.php):

- Missing breadcrumbs, sticky image column, image zoom, thumbnail selection, variant-specific media, mobile gallery scrolling, dots, and labeled image region.
- Thumbnails are buttons but do not change the selected image or expose current state.
- Variant matching uses `str_contains()` against variant titles rather than an option matrix.
- No selected/unavailable option states, color swatches, large-option select fallback, or live variant mapping.
- Missing compare-at price, sale badge, in-stock/low-stock messaging, live price/stock regions, and tags.
- Quantity selector lacks increment/decrement buttons, max logic, and policy-aware limits.
- Add-to-cart lacks loading text/spinner and only dispatches `cart-updated` without the specified payload.
- Product description is not rendered with the required prose/sanitization behavior.

### Cart drawer and cart page

[`app/Livewire/Storefront/Cart/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Cart/Show.php), [`resources/views/livewire/storefront/cart/show.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/cart/show.blade.php), and the layout:

- Required `CartDrawer` component is absent.
- No global drawer, backdrop, slide animation, scroll lock, focus trap, Escape handling, focus restoration, or browser-event listeners.
- Full cart lacks product thumbnails, proper desktop table headers, discount totals, discount removal, loading states, and responsive card/table variants.
- Quantity buttons are only 32px (`h-8 w-8`), below the 44px touch-target requirement.
- Cart totals display subtotal as total and do not render the required discount breakdown.

### Checkout

[`app/Livewire/Storefront/Checkout/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Checkout/Show.php) and [`resources/views/livewire/storefront/checkout/show.blade.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Checkout/Show.php):

- Contact and address are combined; email is not rendered as a checkout field.
- No collapsible step state, completed/future states, edit links, or focus movement.
- Address lacks line 2, phone, billing address, saved addresses, country-dependent regions, labels, required attributes, and blur validation.
- Shipping options lack delivery estimates, accessible fieldset/legend, no-method warning, and full summary updates.
- Payment UI only supports a card number; cardholder, expiry, CVC, PayPal content, and bank-transfer content are missing.
- No payment-specific button text, formatting, validation, processing state, or inline decline callout.
- Order summary lacks discount input, subtotal/discount/shipping/tax rows, mobile collapse, and sticky desktop behavior.
- Most inputs use placeholders without associated labels.

### Confirmation

[`app/Livewire/Storefront/Checkout/Confirmation.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Checkout/Confirmation.php) and [`resources/views/livewire/storefront/checkout/confirmation.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/checkout/confirmation.blade.php):

- Only order number, total, payment status, and continue-shopping link are shown.
- Missing email notice, line-item summary, thumbnails, shipping/billing address, payment method details, view-order link, and bank-transfer instructions.

### Customer accounts

Current routes exist in [`routes/web.php:71-88`](/Users/wesner/Herd/shop/routes/web.php:71), but the implementations are partial:

- Login lacks autocomplete attributes and a general error callout.
- Registration lacks marketing opt-in, labels, and complete inline validation.
- Dashboard lacks quick-link descriptions, recent orders, status badges, and order actions.
- Order history is unpaginated, lacks mobile cards, action links, status badges, and table scopes.
- Order detail lacks breadcrumbs, placed date, addresses, payment information, totals breakdown, and fulfillment tracking.
- Address book only creates addresses; edit, delete, default selection, modal behavior, full fields, and reusable address form are missing.

Relevant files include [`resources/views/livewire/storefront/account/auth/login.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/login.blade.php), [`register.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php), [`dashboard.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/dashboard.blade.php), [`orders/index.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/orders/index.blade.php), [`orders/show.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/orders/show.blade.php), and [`addresses/index.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/addresses/index.blade.php).

### Search

[`app/Livewire/Storefront/Search/Modal.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Search/Modal.php), [`resources/views/livewire/storefront/search/modal.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/search/modal.blade.php), and [`app/Livewire/Storefront/Search/Index.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Search/Index.php):

- Modal is not included in the global layout.
- Results contain products only; collections, grouping, max-five limits, “view all,” skeletons, no-results text, listbox semantics, arrow-key navigation, Enter selection, Escape behavior, and focus trap are missing.
- Search results page lacks collection-page filters, sort controls, active filter pills, and the required empty-state wording.

### Content and errors

- [`resources/views/livewire/storefront/pages/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/pages/show.blade.php:1) renders HTML with `{!! !!}` and has no breadcrumbs, dynamic metadata, or verified sanitized `body_html` contract.
- No `resources/views/errors/404.blade.php`.
- No `resources/views/errors/503.blade.php`.
- [`resources/views/livewire/storefront/home-fallback.blade.php`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/home-fallback.blade.php) is only a generic Laravel fallback.

## Global responsive/accessibility failures

Across [`resources/views/layouts/admin.blade.php`](/Users/wesner/Herd/shop/resources/views/layouts/admin.blade.php), [`resources/views/layouts/storefront.blade.php`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php), and the target Livewire views:

- No complete mobile navigation/drawer implementations.
- No filter, cart, search, address, fulfillment, refund, or admin confirmation focus traps.
- No reliable Escape/Arrow-key interaction implementations.
- No `aria-current` navigation state.
- No `aria-describedby`, `aria-invalid`, required markers, or systematic validation-to-field links.
- No table `scope` headers in account/admin tables.
- No live regions for product counts, prices, stock, cart updates, totals, or search results.
- No global loading states; `wire:loading` is absent from target admin/storefront UI.
- Visible focus styling is not consistently supplied on custom buttons/links.
- Several controls are below the 44px mobile target.
- Small-screen tables are not wrapped in horizontal scrolling containers.
- Several page forms rely on placeholders instead of labels.
- Admin and storefront dark-mode implementations are inconsistent and incomplete.

## Missing storefront component library

The following specified components have no corresponding Blade component:

- `storefront-price`
- `storefront-badge`
- `storefront-quantity-selector`
- `storefront-address-form`
- `storefront-order-summary`
- `storefront-breadcrumbs`
- `storefront-pagination`

Only `storefront-product-card` exists.

## SEO and browser-event gaps

- No page-specific title/description system.
- No product Open Graph metadata.
- No Product, BreadcrumbList, or Organization JSON-LD.
- Required browser events are not implemented/listened to globally. The only relevant dispatch found is `cart-updated` in [`app/Livewire/Storefront/Products/Show.php:38`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Products/Show.php:38).
- No required toast messages are rendered through a shared toast system.

An independent read-only audit reached the same conclusion about placeholder admin sections, missing global storefront components, and incomplete theme/accessibility behavior.


status: completed

agent_nickname: Linnaeus

completed:
# Audit result

The implementation is not acceptance-ready. Core happy paths and tenancy basics exist, but the specifications require substantially broader functionality, security controls, fixtures, and browser coverage.

No files were edited.

Test status:

- Baseline Pest run: 67 tests passed, 175 assertions.
- A fresh run during this audit currently fails before completion with `Cannot redeclare App\Models\User::stores()` in a temporary merge worktree. The visible `User` model currently has one declaration, so this appears related to concurrent uncommitted worktree changes.
- No `tests/Browser`, Playwright config, `.env.testing`, or browser fixture infrastructure exists.

## Critical security findings

| Severity | Finding |
|---|---|
| Critical | Admin API is session-authenticated, not Sanctum-authenticated. `composer.json` has no Sanctum dependency; `config/auth.php` only defines `web` and `customer` guards; API routes use `StartSession` and `auth`. The `personal_access_tokens` table is inert. See [routes/api.php](/Users/wesner/Herd/shop/routes/api.php:26), [config/auth.php](/Users/wesner/Herd/shop/config/auth.php:38), and [composer.json](/Users/wesner/Herd/shop/composer.json:10). |
| High | Session-authenticated admin API mutations have no explicit CSRF middleware. This is especially problematic because the intended bearer-token API has not been implemented. |
| High | Checkout creation does not verify cart ownership. `POST /checkouts` loads any current-store cart by numeric ID and immediately returns its contents. A known cart ID can disclose another guest’s cart. See [StorefrontCheckoutController.php](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontCheckoutController.php:23). |
| High | Guest cart and checkout identifiers are sequential integers, contrary to the opaque-token requirement. Later ownership checks reduce exposure but do not satisfy the required token model. |
| High | Livewire’s custom update route only applies `web` and `store.resolve`; it does not apply authentication or role middleware. Several settings actions also lack action-level authorization. See [AppServiceProvider.php](/Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php:43) and [General.php](/Users/wesner/Herd/shop/app/Livewire/Admin/Settings/General.php:20). |
| High | Role restrictions are inconsistent. Themes allow every store role to view; broad admin routes allow Support/Staff into themes, apps, developers, analytics, search settings, and navigation. `ThemePolicy` uses `StoreUserRole::cases()`. See [ThemePolicy.php](/Users/wesner/Herd/shop/app/Policies/ThemePolicy.php:14) and [routes/web.php](/Users/wesner/Herd/shop/routes/web.php:117). |
| High | Customer password-reset tokens have a `store_id` column, but Laravel’s standard password broker is not shown populating or validating it. The token table is keyed only by email. This can create cross-store reset ambiguity for identical email addresses. See [config/auth.php](/Users/wesner/Herd/shop/config/auth.php:101) and the token migration. |
| High | Session encryption defaults to false, the cookie name is generic, and secure-cookie behavior is unset by default. These contradict the required production settings. See [config/session.php](/Users/wesner/Herd/shop/config/session.php:50). |
| High | Rich HTML is rendered unescaped, while sanitization is incomplete. The sanitizer allows only a subset of required tags and does not robustly validate URL schemes such as `data:`, `vbscript:`, malformed/unquoted attributes, or encoded payloads. See [HtmlSanitizer.php](/Users/wesner/Herd/shop/app/Support/HtmlSanitizer.php:7) and [page output](/Users/wesner/Herd/shop/resources/views/livewire/storefront/pages/show.blade.php:1). |
| Medium | Required `search` and `webhooks` rate limiters are missing. The Livewire login update path also lacks the intended login limiter. See [AppServiceProvider.php](/Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php:43). |
| Medium | No dedicated audit channel, `AuditLogger`, auth listeners, or model observers exist. Required authentication, admin mutation, security, and failed-login events are therefore not auditable. |
| Medium | No `config/cors.php` exists despite the required CORS/Sanctum configuration. |

The requirements for these controls are explicitly described in [06-AUTH-AND-SECURITY.md](/Users/wesner/Herd/shop/specs/06-AUTH-AND-SECURITY.md:206), [06-AUTH-AND-SECURITY.md](/Users/wesner/Herd/shop/specs/06-AUTH-AND-SECURITY.md:732), and [06-AUTH-AND-SECURITY.md](/Users/wesner/Herd/shop/specs/06-AUTH-AND-SECURITY.md:896).

## Business-logic gaps

### Catalog and inventory

- SKU has only a normal index, not the required unique `(store_id, sku)` constraint. See the schema migration around `product_variants.sku`.
- Variant-matrix orphan handling leaves variants active when order history exists; the specification requires archiving them.
- There is no complete guarantee that every variant has exactly one inventory row.
- Media processing does not implement resize, WebP conversion, dimensions, storage metadata, or cleanup.
- Product/catalog actions are incomplete for handle management, SKU collision validation, and full lifecycle edge cases.

### Cart and checkout

- Cart expiration marks carts abandoned but does not comprehensively release reservations associated with abandoned active checkouts.
- Checkout expiry is driven by `expires_at`, not the specified inactivity/`updated_at` rule.
- Required checkout events such as address, shipping selection, payment selection, completion, and expiration are not consistently dispatched.
- Checkout state transitions are not fully enforced in the service layer.
- Guest checkout does not create/link a guest customer as required.
- Customer registration does not implement the specified single `name` field and marketing opt-in.
- Customer address management supports adding addresses but not the required edit flow.
- Bank-transfer confirmation lacks the full required instructions and reference details.

### Pricing, discounts, tax, and shipping

- Automatic discounts and stacking rules are not implemented; only code discounts are handled.
- Discount usage increment is case-sensitive even though discount lookup is case-insensitive, allowing usage-count inconsistencies.
- Discount validation and pricing calculation do not consistently revalidate all minimum-order and applicability rules.
- Required tax-provider abstractions (`TaxProvider`, manual provider, Stripe Tax stub, request/result value objects) are missing.
- Pricing result serialization uses snake-case keys such as `tax_lines` and `tax`, while the specification requires fields such as `taxLines` and `taxTotal`.
- Shipping zone selection does not implement the required most-specific-zone selection and tie-break behavior.
- Weight-based, price-based, carrier, and unavailable-rate behavior is incomplete.

### Payments and orders

- Order numbering hardcodes `#` and ignores the configurable store prefix.
- Cancelling an order changes the order status but does not fully update financial/payment status as required.
- Bank-transfer confirmation does not auto-fulfill all-digital orders.
- There is no order-export endpoint.
- Refunds do not track refund quantities per order line. Repeated partial refunds can refund the same line quantity more than once.
- Refunds do not adequately verify that the selected payment belongs to the order and is refundable/captured.
- Payment/refund statuses are not fully synchronized.
- Fulfillment shipment/delivery actions update only part of the required order state and lack the specified events and notifications.
- The admin order UI lacks the complete shipped/delivered/refund workflows.

### Webhooks and analytics

- Webhook signatures are calculated over the raw JSON body only. The specification requires signing `"{timestamp}.{json_body}"`. See [WebhookService.php](/Users/wesner/Herd/shop/app/Services/WebhookService.php:26) and [DeliverWebhook.php](/Users/wesner/Herd/shop/app/Jobs/DeliverWebhook.php:31).
- Domain events do not appear to dispatch webhook deliveries automatically; current tests invoke the webhook service directly.
- The required signing-secret column naming and payment raw-response cast do not match the specification exactly.
- Analytics ingestion accepts one top-level event, not the required `events[]` batch structure, and ignores client-provided `session_id` and `occurred_at`. See [StorefrontAnalyticsController.php](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontAnalyticsController.php:14).
- Analytics aggregation derives orders/revenue from the orders table rather than checkout-completed event properties, and counts page views rather than distinct sessions. See [AggregateAnalytics.php](/Users/wesner/Herd/shop/app/Jobs/AggregateAnalytics.php:27).
- Search logging and autocomplete behavior are only partial; the required search limiter is absent.

## Seeder and fixture gaps

The specification requires a strict multi-seeder orchestration, but [DatabaseSeeder.php](/Users/wesner/Herd/shop/database/seeders/DatabaseSeeder.php:12) calls only `ShopSeeder`.

The current seed data is far smaller and materially different:

- One organization instead of the required organization data.
- One store instead of Acme Fashion plus Acme Electronics.
- Missing electronics domain and tenant-isolation data.
- Five products instead of 20 fashion products plus electronics products.
- Missing exact products #15–#20, including draft, archived, sold-out, backorder, digital, and expensive products.
- One admin user and one customer instead of the required role matrix, staff/support users, and multiple customers.
- Customer name is `Jamie Customer`, not the required `John Doe`.
- One order instead of the required order corpus through #1015, including delivered, partial fulfillment, refunds, bank transfer, PayPal, digital, and discount cases.
- Only one shipping zone/rate and one tax configuration.
- Only two collections, one page, one navigation menu, and minimal theme data.
- No analytics event/daily aggregate seed data.
- Order-line snapshots are incomplete in the seed path.
- Required factories are missing for carts lines, checkouts, order lines, payments, refunds, fulfillments, addresses, shipping, themes, pages, navigation, and analytics.

See [ShopSeeder.php](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:35) and the required fixture matrix in [07-SEEDERS-AND-TEST-DATA.md](/Users/wesner/Herd/shop/specs/07-SEEDERS-AND-TEST-DATA.md:743).

## Pest coverage gaps

The current tests cover useful basics:

- Standard admin authentication, password reset, email verification, 2FA, and profile settings.
- Store resolution and a limited role/policy set.
- Guest cart behavior, optimistic cart versions, card decline, and bank-transfer reservation.
- Basic product/collection admin API behavior.
- Basic search, analytics idempotency, and webhook delivery.
- Customer session authentication.

They do not cover:

- Sanctum token creation, hashing, expiry, revocation, or abilities.
- CSRF, CORS, session-cookie security, rate limits, or security headers.
- Store-scoped customer password resets.
- XSS payloads and sanitizer bypasses.
- Audit logging.
- Complete role matrix for every admin resource.
- Livewire action authorization.
- SKU uniqueness and full variant matrix transitions.
- Cart/checkout ownership attacks and opaque-token behavior.
- All checkout state transitions and required events.
- PayPal, insufficient-funds, bank-transfer instructions, cancellation, export, refunds, fulfillment state transitions, or digital auto-fulfillment.
- Shipping-zone specificity and weight/price calculations.
- Inclusive-tax rounding and provider abstraction behavior.
- Automatic discounts and discount stacking.
- Media processing/cleanup.
- Webhook timestamp signatures, retries, pause thresholds, and event listeners.
- Batch analytics ingestion and event-based aggregation.
- Scheduled job behavior.
- Seeder counts, fixture integrity, snapshots, or tenant-isolation corpus.
- Any browser, responsive, accessibility, or JavaScript-console acceptance tests.

One current webhook test specifically verifies the implementation’s raw-payload signature behavior, not the timestamped signature required by the specification. Likewise, the analytics test validates the current aggregation implementation rather than the event-based aggregation contract.

## Playwright acceptance gaps

[08-PLAYWRIGHT-E2E-PLAN.md](/Users/wesner/Herd/shop/specs/08-PLAYWRIGHT-E2E-PLAN.md:3118) defines 18 browser test files covering smoke, admin, catalog, orders, discounts, checkout, accounts, inventory, tenant isolation, responsive behavior, accessibility, collections, customers, pages, and analytics.

None of those tests exist in the repository.

The plan itself also has inconsistent counts: its summary claims 143 tests, while the detailed sections report different counts for at least Suites 4 and 9. This should be reconciled before using it as an acceptance baseline.

The implementation progress file currently overstates completion by marking browser acceptance and resource-aware admin sections complete, while later acknowledging those areas remain incomplete. See [specs/progress.md](/Users/wesner/Herd/shop/specs/progress.md:3) and [specs/progress.md](/Users/wesner/Herd/shop/specs/progress.md:25).

## Overall release blockers

1. Fix the current test/worktree fatal and establish a reliable green baseline.
2. Implement Sanctum/token abilities and CSRF-safe API authentication.
3. Close the cart/checkout ownership and opaque-token issues.
4. Enforce the full role matrix at both route and Livewire-action levels.
5. Replace the minimal seeder with the deterministic multi-tenant fixture corpus.
6. Implement the missing order/refund/fulfillment, tax/shipping, analytics, webhook, and media rules.
7. Add the missing security, domain, job, fixture, and browser acceptance tests.


agent_nickname: Boyle

completed:
Read-only audit completed. No files were edited.

## Priority 0 — launch-blocking gaps

### Admin UI

- The admin shell is not implemented as specified.
  - Missing Livewire `Admin\Layout\Sidebar` and `TopBar`.
  - No mobile sidebar toggle/drawer, store switcher, notification bell, profile dropdown, active-route state, breadcrumbs, toast system, or persisted dark mode.
  - Evidence: [`resources/views/layouts/admin.blade.php:1-5`](/Users/wesner/Herd/shop/resources/views/layouts/admin.blade.php:1).

- Most admin sections are generic placeholders rather than functional screens.
  - Collections, inventory, themes, pages, navigation, apps, developers, analytics, and search settings components all extend `Admin\Section`.
  - The inherited renderer displays generic summary rows only.
  - Evidence: [`app/Livewire/Admin/Section.php:16-57`](/Users/wesner/Herd/shop/app/Livewire/Admin/Section.php:16), [`app/Livewire/Admin/Collections/Index.php:5-7`](/Users/wesner/Herd/shop/app/Livewire/Admin/Collections/Index.php:5), and equivalent classes under `app/Livewire/Admin/{Inventory,Themes,Pages,Navigation,Apps,Developers,Analytics,Search}`.

- Admin product management is substantially incomplete.
  - The list lacks bulk selection/actions, type filter, sorting, inventory/type/vendor/updated columns, delete confirmation, and required empty/loading states.
  - The form only supports title, plain description, vendor, type, one price, and status. It lacks handles, publishing, collections, options, variant matrix, media upload/reordering/alt text, SEO, and delete confirmation.
  - Evidence: [`app/Livewire/Admin/Products/Index.php:12-30`](/Users/wesner/Herd/shop/app/Livewire/Admin/Products/Index.php:12), [`resources/views/livewire/admin/products/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/products/index.blade.php:1), [`app/Livewire/Admin/Products/Form.php:12-60`](/Users/wesner/Herd/shop/app/Livewire/Admin/Products/Form.php:12), [`resources/views/livewire/admin/products/form.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/products/form.blade.php:1).

- Dashboard requirements are missing.
  - No date-range controls, period comparisons, visitors KPI, chart, top-products table, conversion funnel, or loading/error states.
  - Current implementation only calculates sales, order count, product count, and AOV.
  - Evidence: [`app/Livewire/Admin/Dashboard.php:11-17`](/Users/wesner/Herd/shop/app/Livewire/Admin/Dashboard.php:11), [`resources/views/livewire/admin/dashboard.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/dashboard.blade.php:1).

- Order management lacks the specified workflow UI.
  - No search, sorting, required status filters, badges, fulfillment line selection, tracking fields, timeline, customer/address cards, or structured refund modal.
  - The fulfillment action blindly submits every line at full quantity.
  - Evidence: [`app/Livewire/Admin/Orders/Index.php:10-16`](/Users/wesner/Herd/shop/app/Livewire/Admin/Orders/Index.php:10), [`app/Livewire/Admin/Orders/Show.php:10-43`](/Users/wesner/Herd/shop/app/Livewire/Admin/Orders/Show.php:10), [`resources/views/livewire/admin/orders/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/admin/orders/show.blade.php:1).

### Storefront UI

- The required global cart drawer does not exist.
  - There is no `CartDrawer` component, no drawer mounted in the layout, and the header’s cart link navigates directly to `/cart`.
  - Evidence: [`resources/views/layouts/storefront.blade.php:15-40`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php:15). Only [`app/Livewire/Storefront/Cart/Show.php`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Cart/Show.php) exists.

- Theme-driven storefront architecture is not implemented.
  - Announcement text, navigation, footer, hero, section order, colors, logo, social links, and dark-mode behavior are hard-coded.
  - No theme settings service or configurable section rendering is used.
  - Evidence: [`resources/views/layouts/storefront.blade.php:12-38`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php:12), [`resources/views/livewire/storefront/home.blade.php:2-17`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/home.blade.php:2).

- Collection filtering/pagination is incomplete.
  - Only sort and “in stock” are supported.
  - Missing price range, product type, vendor, filter sidebar/drawer, active filter pills, best-selling sort, pagination, and live result announcements.
  - Products are loaded into memory rather than paginated.
  - Evidence: [`app/Livewire/Storefront/Collections/Show.php:12-33`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Collections/Show.php:12), [`resources/views/livewire/storefront/collections/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/collections/show.blade.php:1).

- Product option selection is incorrect for multi-option variants.
  - It searches variant titles with `str_contains()` and selects the first matching variant, rather than maintaining an option matrix.
  - No active selection state, proper radio behavior, stock/price live regions, gallery state, tags, or rich description rendering.
  - Evidence: [`resources/views/livewire/storefront/products/show.blade.php:1-3`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/products/show.blade.php:1), [`app/Livewire/Storefront/Products/Show.php:41-46`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Products/Show.php:41).

- Checkout is not the specified four-step flow.
  - Contact email is absent from the form, steps are not collapsible/stateful, validation messages are not associated with fields, and payment fields omit cardholder, expiry, and CVC.
  - No loading state, payment-specific instructions, accessible fieldsets, or complete subtotal/discount/shipping/tax breakdown.
  - The component ships with a test card number as the default value.
  - Evidence: [`app/Livewire/Storefront/Checkout/Show.php:15-25`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Checkout/Show.php:15), [`resources/views/livewire/storefront/checkout/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/checkout/show.blade.php:1).

- Confirmation is incomplete.
  - Missing item list, thumbnails, addresses, detailed totals, payment-method display, bank-transfer instructions, account order link, and fulfillment information.
  - Evidence: [`resources/views/livewire/storefront/checkout/confirmation.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/checkout/confirmation.blade.php:1).

## Priority 1 — major functional/UI gaps

### Admin

- Collections list/create/edit are absent; the required `Collections\Form` component does not exist.
- Inventory management has no editable quantity, reserved quantity, policy, stock filter, or search UI.
- Customer list lacks total-spent data; customer detail lacks address CRUD, default-address handling, address modal, marketing status, and paginated order history.
  - Evidence: [`app/Livewire/Admin/Customers/Index.php:10-16`](/Users/wesner/Herd/shop/app/Livewire/Admin/Customers/Index.php:10), [`app/Livewire/Admin/Customers/Show.php:10-16`](/Users/wesner/Herd/shop/app/Livewire/Admin/Customers/Show.php:10).
- Discounts lack search/status filters, pagination, usage/date columns, automatic-discount support, minimum purchase, restrictions, usage limits, customer limit, dates, and active toggle.
  - Evidence: [`app/Livewire/Admin/Discounts/Index.php:10-14`](/Users/wesner/Herd/shop/app/Livewire/Admin/Discounts/Index.php:10), [`app/Livewire/Admin/Discounts/Form.php:12-37`](/Users/wesner/Herd/shop/app/Livewire/Admin/Discounts/Form.php:12).
- Settings are reduced to one store-name field, a single shipping zone/rate form, and one scalar tax rate. Domains, tax modes/providers/inclusive pricing, shipping CRUD/test tool, and settings tabs are missing.
- Themes, pages, navigation, apps, developers, analytics, and search settings have no functional CRUD/actions.
- Admin views do not use the required Flux components, breadcrumbs, confirmation modals, toast events, or loading states.
- Several route names differ from the spec contract, e.g. `admin.collections` instead of `admin.collections.index`, `admin.inventory` instead of `admin.inventory.index`, and similar section routes.
  - Evidence: [`routes/web.php:117-131`](/Users/wesner/Herd/shop/routes/web.php:117).

### Storefront

- Only one storefront Blade component exists: `product-card`.
  - Missing shared price, badge, quantity selector, address form, order summary, breadcrumbs, and pagination components.
  - Evidence: `resources/views/components/storefront/` contains only [`product-card.blade.php`](/Users/wesner/Herd/shop/resources/views/components/storefront/product-card.blade.php).

- Product cards lack quick add/choose-options behavior, secondary-image hover, configurable heading level, shared price formatting, and proper badge/accessibility treatment.
  - Evidence: [`resources/views/components/storefront/product-card.blade.php:1-19`](/Users/wesner/Herd/shop/resources/views/components/storefront/product-card.blade.php:1).

- Home page lacks the required configurable rich-text section, lazy-loaded featured-products component, skeleton state, collection imagery/overlays, and functional newsletter Livewire behavior.
  - Evidence: [`resources/views/livewire/storefront/home.blade.php:12-17`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/home.blade.php:12).

- Search modal is not globally mounted and only returns product titles.
  - Missing collection results, prices/thumbnails, result grouping, “view all,” loading/no-result states, keyboard navigation, focus trapping, and listbox semantics.
  - Evidence: [`app/Livewire/Storefront/Search/Modal.php:10-28`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Search/Modal.php:10), [`resources/views/livewire/storefront/search/modal.blade.php:1-9`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/search/modal.blade.php:1).

- Search results lack collection-style filters, sorting, breadcrumbs, dynamic result heading, and the specified empty-state search affordance.
  - Evidence: [`app/Livewire/Storefront/Search/Index.php:17-21`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Search/Index.php:17), [`resources/views/livewire/storefront/search/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/search/index.blade.php:1).

- Account dashboard, order history/detail, and address book are only partial.
  - Missing recent orders, mobile card layout, pagination, edit/delete/set-default address actions, modal editing, address fields, fulfillment tracking, shipping/billing/payment panels, and totals breakdown.
  - Evidence: [`app/Livewire/Storefront/Account/Addresses/Index.php:9-29`](/Users/wesner/Herd/shop/app/Livewire/Storefront/Account/Addresses/Index.php:9), [`resources/views/livewire/storefront/account/addresses/index.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/addresses/index.blade.php:1), [`resources/views/livewire/storefront/account/orders/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/orders/show.blade.php:1).

- Content pages render `$page->content`, while the specification calls for `body_html` and theme-configurable width.
  - Evidence: [`resources/views/livewire/storefront/pages/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/pages/show.blade.php:1).

## Priority 2 — accessibility, consistency, and polish

- Storefront prices are hard-coded as `€` with `number_format()` throughout instead of a shared locale-aware price component.
  - Evidence: [`resources/views/components/storefront/product-card.blade.php:16`](/Users/wesner/Herd/shop/resources/views/components/storefront/product-card.blade.php:16), [`resources/views/livewire/storefront/cart/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/cart/show.blade.php:1).

- Storefront layout has no page-specific meta description, Open Graph tags, JSON-LD, or breadcrumb structured data.
  - Evidence: [`resources/views/layouts/storefront.blade.php:3-8`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php:3).

- Header/footer content is not sourced from navigation/theme settings; mobile navigation is absent.
  - Evidence: [`resources/views/layouts/storefront.blade.php:15-38`](/Users/wesner/Herd/shop/resources/views/layouts/storefront.blade.php:15).

- Many form inputs have placeholders but no associated labels, including registration, checkout, address, and search controls.
  - Evidence: [`resources/views/livewire/storefront/account/auth/register.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/account/auth/register.blade.php:1), [`resources/views/livewire/storefront/checkout/show.blade.php:1`](/Users/wesner/Herd/shop/resources/views/livewire/storefront/checkout/show.blade.php:1).

- Required ARIA live regions, focus management, focus traps, keyboard interactions, `aria-current`, loading indicators, and error-to-field associations are broadly absent.

- Admin does not include dark-mode variants, despite the specification requiring admin dark mode.
  - Evidence: [`resources/views/layouts/admin.blade.php:2-4`](/Users/wesner/Herd/shop/resources/views/layouts/admin.blade.php:2).

## Test coverage gap

There are no dedicated admin/storefront UI test suites for these requirements:

- No `tests/Browser` directory.
- No component tests for admin CRUD, storefront filters, cart drawer, checkout steps, search modal, address CRUD, or responsive/accessibility behavior.
- Existing relevant coverage is primarily API/domain flow and customer login:
  - [`tests/Feature/CommerceFlowTest.php`](/Users/wesner/Herd/shop/tests/Feature/CommerceFlowTest.php)
  - [`tests/Feature/AdminApiTest.php`](/Users/wesner/Herd/shop/tests/Feature/AdminApiTest.php)
  - [`tests/Feature/Storefront/CustomerAuthenticationTest.php`](/Users/wesner/Herd/shop/tests/Feature/Storefront/CustomerAuthenticationTest.php)

Overall assessment: the routes and a basic catalog/cart/checkout skeleton exist, but the implementation is not close to satisfying either UI specification. The highest-value next work is replacing the generic admin section shell, implementing the global storefront shell/cart drawer/theme system, and adding UI-focused Pest/browser coverage.


agent_nickname: Huygens

completed:
## Audit result

The implementation is not compliant with the three requested specs. The highest-priority blockers are the missing Sanctum API security layer, incomplete API surface, cross-store password-reset risk, and substantial schema contract drift.

### P0 blockers

- **Admin REST API is not Sanctum-authenticated.**
  Spec requires `auth:sanctum`, personal tokens, `shop_` prefix, abilities, expiry, creation/revocation UI, and 403 ability checks ([06-AUTH-AND-SECURITY.md:206](/Users/wesner/Herd/shop/specs/06-AUTH-AND-SECURITY.md:206)).
  Actual routes use session middleware and the default web guard: [routes/api.php:26](/Users/wesner/Herd/shop/routes/api.php:26). `config/auth.php` has no `sanctum` guard ([config/auth.php:38](/Users/wesner/Herd/shop/config/auth.php:38)), `User` does not use `HasApiTokens`, and `composer.json` does not directly require Sanctum. The token table exists but is unused ([2026_08_20_220000_add_search_and_auth_support.php:12](/Users/wesner/Herd/shop/database/migrations/2026_08_20_220000_add_search_and_auth_support.php:12)).

- **Admin API session authentication is also CSRF-exposed.**
  The admin API explicitly starts sessions and authenticates with `auth`, but is outside CSRF protection ([routes/api.php:26](/Users/wesner/Herd/shop/routes/api.php:26)). This is unsafe for cookie-authenticated mutations.

- **Customer password resets are not reliably store-scoped.**
  `/forgot-password` and `/reset-password` can proceed without a resolved store ([ResolveStore.php:36](/Users/wesner/Herd/shop/app/Http/Middleware/ResolveStore.php:36), [ResolveStore.php:104](/Users/wesner/Herd/shop/app/Http/Middleware/ResolveStore.php:104)). `CustomerUserProvider` only adds the store filter when `current_store` is bound ([CustomerUserProvider.php:21](/Users/wesner/Herd/shop/app/Auth/CustomerUserProvider.php:21)). The reset table has `email` as its primary key and nullable `store_id`, rather than the required composite `(store_id, email)` key ([2026_08_20_220000_add_search_and_auth_support.php:23](/Users/wesner/Herd/shop/database/migrations/2026_08_20_220000_add_search_and_auth_support.php:23), [2026_08_20_223045_add_remaining_schema_contract_columns.php:19](/Users/wesner/Herd/shop/database/migrations/2026_08_20_223045_add_remaining_schema_contract_columns.php:19)).

- **The database schema has major contract mismatches.**

  - `users` retains required Laravel `password`, while the required `password_hash` is nullable ([create_shop_schema.php:45](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:45), [add_remaining_schema_contract_columns.php:12](/Users/wesner/Herd/shop/database/migrations/2026_08_20_223045_add_remaining_schema_contract_columns.php:12)).
  - `collections` lacks required `type` and `description_html` columns ([create_shop_schema.php:143](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:143), spec [01:297](/Users/wesner/Herd/shop/specs/01-DATABASE-SCHEMA.md:297)).
  - `theme_settings` is a multi-row `id/theme_id/key/value` table, but the spec requires one row per theme keyed by `theme_id` with `settings_json` ([create_shop_schema.php:199](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:199)).
  - `navigation_menus` uses `name`, while the spec requires `title`; `navigation_items.menu_id` is only a nullable alias without the required foreign key ([create_shop_schema.php:220](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:220), [add_remaining_schema_contract_columns.php:46](/Users/wesner/Herd/shop/database/migrations/2026_08_20_223045_add_remaining_schema_contract_columns.php:46)).
  - `search_queries` lacks required `filters_json` ([create_shop_schema.php:250](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:250)).
  - `customers` uses required `first_name`/`last_name` and lacks `name` and `marketing_opt_in` ([create_shop_schema.php:313](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:313)).
  - `order_lines.title_snapshot` and `total_amount` remain nullable, contrary to the required non-null snapshots ([create_shop_schema.php:414](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:414), [add_remaining_schema_contract_columns.php:59](/Users/wesner/Herd/shop/database/migrations/2026_08_20_223045_add_remaining_schema_contract_columns.php:59)).
  - `refunds.payment_id` is nullable with `SET NULL`; the spec requires non-null with cascade deletion ([create_shop_schema.php:447](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:447)).
  - OAuth tables use different relationships and column names: `oauth_clients` is store-scoped instead of app-scoped, and `oauth_tokens` lacks the specified installation/access-token/refresh-token fields ([create_shop_schema.php:528](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:528)).
  - Webhook compatibility columns are nullable aliases without foreign keys; the signing-secret and delivery contract does not match the spec ([create_shop_schema.php:549](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:549), [add_remaining_schema_contract_columns.php:81](/Users/wesner/Herd/shop/database/migrations/2026_08_20_223045_add_remaining_schema_contract_columns.php:81)).

### P1 API gaps

- **Large portions of the specified API are absent.**
  Actual API routes contain only catalog, collections, orders/customers/discount reads, cart, checkout, pay, and one analytics endpoint ([routes/api.php:10](/Users/wesner/Herd/shop/routes/api.php:10), [routes/api.php:26](/Users/wesner/Herd/shop/routes/api.php:26)).

  Missing or incomplete areas include:

  - Storefront order lookup with signed token.
  - Storefront search and autocomplete endpoints.
  - Batch analytics ingestion.
  - Checkout discount removal.
  - Admin platform organizations/stores/invites/me.
  - Product media upload.
  - Order fulfillment and refund mutations.
  - Discount create/update/delete.
  - Shipping zones/rates.
  - Tax settings.
  - Themes.
  - Pages.
  - Search reindex/status.
  - Analytics summary and exports.
  - OAuth and app endpoints.

- **Storefront API validation and response contracts diverge.**
  Analytics accepts one event rather than the required batch payload ([StorefrontAnalyticsController.php:14](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontAnalyticsController.php:14)). Payment card fields are nullable and `card_holder` is not validated ([StorefrontCheckoutController.php:83](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontCheckoutController.php:83)). Business errors use `code`, while the spec requires `error_code` and specific status mappings ([StorefrontCartController.php:45](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontCartController.php:45)).

- **Rate limiting is incomplete.**
  Only `login`, `api.storefront`, `api.admin`, and `checkout` are defined ([AppServiceProvider.php:48](/Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php:48)). Required `search`, `analytics`, and `webhooks` limiters are missing. Analytics incorrectly uses `api.storefront` ([routes/api.php:23](/Users/wesner/Herd/shop/routes/api.php:23)).

- **Admin route authorization is too broad.**
  The parent admin group allows every role ([routes/web.php:102](/Users/wesner/Herd/shop/routes/web.php:102)); themes, apps, navigation, and developers have no stricter route middleware. `ThemePolicy` and `PagePolicy` also permit all roles for read operations, contrary to the matrix ([ThemePolicy.php:14](/Users/wesner/Herd/shop/app/Policies/ThemePolicy.php:14), [PagePolicy.php:14](/Users/wesner/Herd/shop/app/Policies/PagePolicy.php:14)). `NavigationMenuPolicy` is absent.

- **Secondary admin routes are largely placeholder implementations.**
  Inventory, collections, themes, pages, navigation, apps, developers, analytics, and search components simply extend the generic `Section` component ([Inventory/Index.php:5](/Users/wesner/Herd/shop/app/Livewire/Admin/Inventory/Index.php:5), [Section.php:16](/Users/wesner/Herd/shop/app/Livewire/Admin/Section.php:16)). They expose summary rows, not the specified management workflows.

### P1 authentication/security gaps

- No dedicated `CustomerAuthenticate` middleware exists; account routes use Laravel’s generic `auth:customer` ([routes/web.php:83](/Users/wesner/Herd/shop/routes/web.php:83)). The required intended-URL redirect behavior is not implemented.
- Admin/customer login messages are “These credentials do not match our records,” not the specified generic “Invalid credentials” ([Admin Login.php:20](/Users/wesner/Herd/shop/app/Livewire/Admin/Auth/Login.php:20)).
- Login attempts do not explicitly reject disabled users.
- The `login` limiter is redefined by Fortify as email+IP rather than IP-only ([FortifyServiceProvider.php:66](/Users/wesner/Herd/shop/app/Providers/FortifyServiceProvider.php:66)).
- No Form Request classes exist. Controllers and Livewire components use inline validation; this fails the required Form Request inventory and authorization-before-validation design.
- Sanitization is implemented in `HtmlSanitizer`, but it is not the specified action and its allowed tag list omits several required tags such as `img`, tables, `div`, and `span` ([HtmlSanitizer.php:13](/Users/wesner/Herd/shop/app/Support/HtmlSanitizer.php:13)).
- Webhook signatures are incorrect: the implementation signs only the JSON body, while the spec requires signing `timestamp.json_body` ([WebhookService.php:26](/Users/wesner/Herd/shop/app/Services/WebhookService.php:26), [DeliverWebhook.php:33](/Users/wesner/Herd/shop/app/Jobs/DeliverWebhook.php:33)).
- Required audit logging is absent: no `audit` channel, `AuditLogger`, auth listeners, or resource observers ([config/logging.php:53](/Users/wesner/Herd/shop/config/logging.php:53)).
- Session settings diverge: encryption is disabled by default and the cookie defaults to `laravel-session`, not `shop_session` ([config/session.php:35](/Users/wesner/Herd/shop/config/session.php:35), [config/session.php:50](/Users/wesner/Herd/shop/config/session.php:50), [config/session.php:130](/Users/wesner/Herd/shop/config/session.php:130)).
- `config/cors.php` is missing, so the required CORS policy and exposed rate-limit headers are not explicitly configured.

### Schema/index completeness

The live SQLite schema also lacks several indexes explicitly required by the spec, including standalone indexes for product options, variants, collections, media, pages, navigation menus, payments, refunds, fulfillments, app installations, OAuth tokens, and webhook delivery retry timestamps. The migration generally uses plain `foreignId()` without adding the required indexes ([create_shop_schema.php:88](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:88), [create_shop_schema.php:414](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:414), [create_shop_schema.php:561](/Users/wesner/Herd/shop/database/migrations/2026_08_20_000000_create_shop_schema.php:561)).

SQLite connection settings are mostly present—foreign keys, WAL, busy timeout, synchronous mode, and deferred transactions ([config/database.php:34](/Users/wesner/Herd/shop/config/database.php:34))—but the required `cache_size=-20000` pragma is not configured.

### Test evidence

The suite contains tests for the basic commerce flow, tenancy, customer login, and only two admin API behaviors ([AdminApiTest.php:17](/Users/wesner/Herd/shop/tests/Feature/AdminApiTest.php:17)). There are no tests for Sanctum tokens/abilities, most specified endpoints, CORS, audit logging, role matrix coverage, OAuth, reset-token tenant isolation, or webhook timestamp signing.

During this audit, `php artisan test --compact` did not produce a green baseline; repeated runs emitted `Cannot redeclare App\Models\User::stores()`, and an isolated Fortify login test failed with an unresolvable `LoginViewResponse` binding.


agent_nickname: Gauss

completed:
# Audit result

The implementation is a partial happy-path build, not yet compliant with specs 05, 07, or 08. The largest risks are incorrect payment/fulfillment state transitions, incomplete seed fixtures, absent browser tests, and unwired event-driven behavior.

## Critical gaps

### Business logic — payment, order, fulfillment

- Creating a pending fulfillment can immediately mark an order as fulfilled because fulfillment lines are counted regardless of shipment status. This violates the requirement that orders become fulfilled only after shipment.
  Evidence: [FulfillmentService.php:18](/Users/wesner/Herd/shop/app/Services/FulfillmentService.php:18), [FulfillmentService.php:82](/Users/wesner/Herd/shop/app/Services/FulfillmentService.php:82)

- `markAsDelivered()` unconditionally sets the order status to `fulfilled`, even when other order lines remain unfulfilled. It also does not update `fulfillment_status`.
  Evidence: [FulfillmentService.php:61](/Users/wesner/Herd/shop/app/Services/FulfillmentService.php:61)

- Bank-transfer cancellation only changes the order status and releases inventory. It does not set financial status to `voided` or payment status to `failed`, as required.
  Evidence: [OrderService.php:110](/Users/wesner/Herd/shop/app/Services/OrderService.php:110), [CancelUnpaidBankTransferOrders.php:17](/Users/wesner/Herd/shop/app/Jobs/CancelUnpaidBankTransferOrders.php:17)

- Confirming a bank transfer commits inventory but does not auto-fulfill all-digital orders.
  Evidence: [OrderService.php:129](/Users/wesner/Herd/shop/app/Services/OrderService.php:129)

- Refunds do not update the payment record to `refunded`; line-level refund quantities are not tracked across previous refunds, allowing repeated refunds/restocks for the same line quantity.
  Evidence: [RefundService.php:21](/Users/wesner/Herd/shop/app/Services/RefundService.php:21), [RefundService.php:61](/Users/wesner/Herd/shop/app/Services/RefundService.php:61)

- Order line tax snapshots contain the entire checkout tax-line array for every line instead of line-specific tax allocations.
  Evidence: [OrderService.php:57](/Users/wesner/Herd/shop/app/Services/OrderService.php:57)

- Order numbering always uses `#` and ignores the configurable prefix requirement.
  Evidence: [OrderService.php:103](/Users/wesner/Herd/shop/app/Services/OrderService.php:103)

### Event/listener architecture is largely absent

The spec requires listeners for checkout events, order events, product events, fulfillment events, webhooks, emails, analytics, and inventory side effects. There is no `app/Listeners` directory, and the existing events are dispatched directly without registered side effects.

Examples:

- Checkout address/shipping/completion/expiration events are not dispatched from [CheckoutService.php:29](/Users/wesner/Herd/shop/app/Services/CheckoutService.php:29).
- Webhooks are not automatically triggered by domain events; they require manual calls to [WebhookService.php:11](/Users/wesner/Herd/shop/app/Services/WebhookService.php:11).
- Webhook delivery uses the encrypted secret value directly and omits required headers such as `Content-Type`.
  Evidence: [DeliverWebhook.php:28](/Users/wesner/Herd/shop/app/Jobs/DeliverWebhook.php:28)

### Analytics API contract is incorrect

The spec requires batches of events with `type`, `session_id`, `client_event_id`, `occurred_at`, and `properties`. The controller accepts one event only and does not validate or store the required client session/timestamp fields.

- Evidence: [StorefrontAnalyticsController.php:14](/Users/wesner/Herd/shop/app/Http/Controllers/Api/StorefrontAnalyticsController.php:14)
- The configured storefront limit is 120 requests/minute, not the required 60.
  Evidence: [AppServiceProvider.php:48](/Users/wesner/Herd/shop/app/Providers/AppServiceProvider.php:48)
- Aggregation counts page views rather than distinct sessions and derives orders/revenue from the orders table rather than `checkout_completed` event properties.
  Evidence: [AggregateAnalytics.php:21](/Users/wesner/Herd/shop/app/Jobs/AggregateAnalytics.php:21)

### Media processing is a stub

`ProcessMediaUpload` only changes the media status to `ready`; it does not resize images, generate WebP variants, populate dimensions/byte size, preserve originals, or enforce the required retry behavior.

Evidence: [ProcessMediaUpload.php:18](/Users/wesner/Herd/shop/app/Jobs/ProcessMediaUpload.php:18)

## High-priority business logic gaps

- Product creation creates variants but does not automatically create inventory records.
  Evidence: [ProductService.php:19](/Users/wesner/Herd/shop/app/Services/ProductService.php:19), [ProductVariant.php:11](/Users/wesner/Herd/shop/app/Models/ProductVariant.php:11)

- Variant matrix rebuild leaves orphaned variants with order history untouched instead of archiving them.
  Evidence: [VariantMatrixService.php:38](/Users/wesner/Herd/shop/app/Services/VariantMatrixService.php:38)

- Cart cleanup marks carts abandoned but does not release reservations from active checkouts.
  Evidence: [CleanupAbandonedCarts.php:15](/Users/wesner/Herd/shop/app/Jobs/CleanupAbandonedCarts.php:15)

- Guest-cart merge clears only the store-specific session key, not the required plain `cart_id` key.
  Evidence: [CartService.php:154](/Users/wesner/Herd/shop/app/Services/CartService.php:154)

- Shipping-zone matching does not implement specificity or lowest-ID tie-breaking. Its `OR` conditions can return rates from unrelated zones.
  Evidence: [ShippingCalculator.php:13](/Users/wesner/Herd/shop/app/Services/ShippingCalculator.php:13)

- Unmatched weight/price ranges fall back to the rate base price instead of making the rate unavailable.
  Evidence: [ShippingCalculator.php:43](/Users/wesner/Herd/shop/app/Services/ShippingCalculator.php:43)

- Discount usage increment is case-sensitive even though validation is case-insensitive.
  Evidence: [PaymentService.php:48](/Users/wesner/Herd/shop/app/Services/PaymentService.php:48)

- No `TaxProvider` contract, manual provider, or Stripe Tax stub exists; tax is implemented directly in `TaxCalculator`.
  Evidence: [TaxCalculator.php:9](/Users/wesner/Herd/shop/app/Services/TaxCalculator.php:9)

## Seeders and test data

The required fixture dataset is not present.

- `DatabaseSeeder` calls only `ShopSeeder`; the other required seeders are empty.
  Evidence: [DatabaseSeeder.php:12](/Users/wesner/Herd/shop/database/seeders/DatabaseSeeder.php:12), [OrganizationSeeder.php:12](/Users/wesner/Herd/shop/database/seeders/OrganizationSeeder.php:12)

- `ShopSeeder` creates approximately:
  - 1 store instead of 2
  - 5 products instead of 20
  - 1 customer instead of 10
  - 1 order instead of 15
  - 1 page instead of 5
  - 1 shipping zone instead of domestic/international coverage
  - no analytics events/daily aggregates
  - no search settings
  - no electronics tenant

  Evidence: [ShopSeeder.php:35](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:35), [ShopSeeder.php:57](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:57), [ShopSeeder.php:75](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:75)

- Seed values contradict the specification:
  - Customer is “Jamie Customer” instead of John Doe.
  - `WELCOME10` starts with usage count 0 instead of 3.
  - `MAXED` uses limit/count 1/1 instead of 5/5.
  - `FREESHIP` usage count is 0 instead of 1.
  - Seeded order `#1001` totals 2998 with zero tax instead of 5497 with tax.

  Evidence: [ShopSeeder.php:53](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:53), [ShopSeeder.php:65](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:72), [ShopSeeder.php:75](/Users/wesner/Herd/shop/database/seeders/ShopSeeder.php:75)

- Required factories are missing for cart lines, checkouts, order lines, payments, refunds, fulfillments, fulfillment lines, addresses, shipping zones/rates, themes, pages, navigation, and analytics events.

- Existing factories lack most required states. For example, `ProductFactory` only has `draft`, and `ProductVariantFactory` has no digital, sale, archived, or default states.
  Evidence: [ProductFactory.php:13](/Users/wesner/Herd/shop/database/factories/ProductFactory.php:13), [ProductVariantFactory.php:12](/Users/wesner/Herd/shop/database/factories/ProductVariantFactory.php:12)

## Playwright/Pest E2E plan

The required browser suite is not implemented.

- `tests/Browser` does not exist.
- `phpunit.xml` registers only Unit and Feature suites.
  Evidence: [phpunit.xml:7](/Users/wesner/Herd/shop/phpunit.xml:7)
- There is no `.env.testing` with the browser configuration described by the spec.
- None of the 18 suites / 143 browser tests are present.

The browser-facing routes exist for many smoke pages, but the implementation cannot satisfy the planned interactions:

- Admin order UI has buttons for confirm payment, create fulfillment, and refund, but no “Mark as shipped” or “Mark as delivered” actions.
  Evidence: [Show.php:24](/Users/wesner/Herd/shop/app/Livewire/Admin/Orders/Show.php:24), [show.blade.php:1](/Users/wesner/Herd/shop/resources/views/livewire/admin/orders/show.blade.php:1)

- Collections, pages, themes, navigation, analytics, apps, developers, and search settings mostly render a generic read-only `Section` placeholder.
  Evidence: [Section.php:16](/Users/wesner/Herd/shop/app/Livewire/Admin/Section.php:16), [Index.php:7](/Users/wesner/Herd/shop/app/Livewire/Admin/Collections/Index.php:7)

- Product option selection chooses the first variant whose title contains a value, rather than selecting a valid cartesian option combination.
  Evidence: [products/show.blade.php:3](/Users/wesner/Herd/shop/resources/views/livewire/storefront/products/show.blade.php:3)

- The storefront does not render compare-at pricing, a cart drawer, theme-driven content, or the complete checkout/payment form required by the plan.
  Evidence: [products/show.blade.php:3](/Users/wesner/Herd/shop/resources/views/livewire/storefront/products/show.blade.php:3), [checkout/show.blade.php:1](/Users/wesner/Herd/shop/resources/views/livewire/storefront/checkout/show.blade.php:1)

## Verification note

I did not edit files. `git status` remained limited to the pre-existing `boost.json` and `.playwright-mcp/` entries.

A full Pest run was not a reliable source verdict because the generated Composer autoloader points to `/private/tmp/shop-merge.XZmomj` rather than this checkout. It loaded a different source snapshot and produced redeclaration errors. Independently, the repository still has zero browser test files, which is an unambiguous spec gap.