command: rg -n '^## |^### |^#### |^\| ' specs/01-DATABASE-SCHEMA.md specs/05-BUSINESS-LOGIC.md specs/06-AUTH-AND-SECURITY.md specs/07-SEEDERS-AND-TEST-DATA.md | head -520

cmd: rg -n '^## |''^### |''^#### |''^'"\\| " specs/01-DATABASE-SCHEMA.md specs/05-BUSINESS-LOGIC.md specs/06-AUTH-AND-SECURITY.md specs/07-SEEDERS-AND-TEST-DATA.md

stdout:
specs/06-AUTH-AND-SECURITY.md:7:## 1. Authentication
specs/06-AUTH-AND-SECURITY.md:11:### 1.1 Admin Authentication
specs/06-AUTH-AND-SECURITY.md:13:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:15:| Guard name | `web` (default Laravel guard) |
specs/06-AUTH-AND-SECURITY.md:16:| Provider name | `users` (Eloquent driver) |
specs/06-AUTH-AND-SECURITY.md:17:| Model | `App\Models\User` |
specs/06-AUTH-AND-SECURITY.md:18:| Driver | Session (cookie-based) |
specs/06-AUTH-AND-SECURITY.md:19:| Login route | `GET /admin/login` |
specs/06-AUTH-AND-SECURITY.md:20:| Login form | Livewire component `Admin\Auth\Login` |
specs/06-AUTH-AND-SECURITY.md:22:#### Admin Login Flow
specs/06-AUTH-AND-SECURITY.md:59:#### Remember Me
specs/06-AUTH-AND-SECURITY.md:66:#### Admin Password Reset Flow
specs/06-AUTH-AND-SECURITY.md:105:#### Admin Logout
specs/06-AUTH-AND-SECURITY.md:111:#### Session Lifetime
specs/06-AUTH-AND-SECURITY.md:113:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:115:| Lifetime | 120 minutes (configurable via `SESSION_LIFETIME` env var) |
specs/06-AUTH-AND-SECURITY.md:116:| Expire on close | No (session persists until lifetime expires) |
specs/06-AUTH-AND-SECURITY.md:120:### 1.2 Customer Authentication
specs/06-AUTH-AND-SECURITY.md:122:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:124:| Guard name | `customer` (custom guard) |
specs/06-AUTH-AND-SECURITY.md:125:| Provider name | `customers` (Eloquent driver) |
specs/06-AUTH-AND-SECURITY.md:126:| Model | `App\Models\Customer` |
specs/06-AUTH-AND-SECURITY.md:127:| Driver | Session (cookie-based) |
specs/06-AUTH-AND-SECURITY.md:128:| Login route | `GET /account/login` |
specs/06-AUTH-AND-SECURITY.md:129:| Registration route | `GET /account/register` |
specs/06-AUTH-AND-SECURITY.md:131:#### Customer Login Flow
specs/06-AUTH-AND-SECURITY.md:165:#### Customer Registration Flow
specs/06-AUTH-AND-SECURITY.md:179:| Field | Type | Required | Validation |
specs/06-AUTH-AND-SECURITY.md:181:| name | string | Y | max:255 |
specs/06-AUTH-AND-SECURITY.md:182:| email | string | Y | valid email, unique per store (composite unique on email + store_id) |
specs/06-AUTH-AND-SECURITY.md:183:| password | string | Y | min:8, confirmed |
specs/06-AUTH-AND-SECURITY.md:184:| password_confirmation | string | Y | must match password |
specs/06-AUTH-AND-SECURITY.md:185:| marketing_opt_in | boolean | N | defaults to false |
specs/06-AUTH-AND-SECURITY.md:187:#### Customer Store Scoping
specs/06-AUTH-AND-SECURITY.md:194:#### Customer Password Reset
specs/06-AUTH-AND-SECURITY.md:206:### 1.3 API Authentication (Sanctum)
specs/06-AUTH-AND-SECURITY.md:208:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:210:| Guard name | `sanctum` |
specs/06-AUTH-AND-SECURITY.md:211:| Provider | `users` (admin users only) |
specs/06-AUTH-AND-SECURITY.md:212:| Token type | Personal access tokens |
specs/06-AUTH-AND-SECURITY.md:213:| Token prefix | `shop_` |
specs/06-AUTH-AND-SECURITY.md:214:| Hashing | SHA-256 |
specs/06-AUTH-AND-SECURITY.md:215:| Default expiration | 1 year |
specs/06-AUTH-AND-SECURITY.md:216:| Storage | `personal_access_tokens` table |
specs/06-AUTH-AND-SECURITY.md:218:#### Token Lifecycle
specs/06-AUTH-AND-SECURITY.md:242:#### Token Abilities (Scopes)
specs/06-AUTH-AND-SECURITY.md:244:| Ability | Description |
specs/06-AUTH-AND-SECURITY.md:246:| `read-products` | List and view products |
specs/06-AUTH-AND-SECURITY.md:247:| `write-products` | Create, update, delete products |
specs/06-AUTH-AND-SECURITY.md:248:| `read-orders` | List and view orders |
specs/06-AUTH-AND-SECURITY.md:249:| `write-orders` | Update orders, create fulfillments |
specs/06-AUTH-AND-SECURITY.md:250:| `read-customers` | List and view customers |
specs/06-AUTH-AND-SECURITY.md:251:| `write-customers` | Update customers |
specs/06-AUTH-AND-SECURITY.md:252:| `read-collections` | List and view collections |
specs/06-AUTH-AND-SECURITY.md:253:| `write-collections` | Create, update, delete collections |
specs/06-AUTH-AND-SECURITY.md:254:| `read-discounts` | List and view discounts |
specs/06-AUTH-AND-SECURITY.md:255:| `write-discounts` | Create, update, delete discounts |
specs/06-AUTH-AND-SECURITY.md:256:| `read-analytics` | View analytics data |
specs/06-AUTH-AND-SECURITY.md:257:| `read-settings` | View store settings (general, shipping, taxes, checkout, notifications) |
specs/06-AUTH-AND-SECURITY.md:258:| `write-settings` | Update store settings (replaces the legacy `manage-store`, `manage-shipping`, `manage-taxes` scopes) |
specs/06-AUTH-AND-SECURITY.md:259:| `read-themes` | View themes and theme files |
specs/06-AUTH-AND-SECURITY.md:260:| `write-themes` | Create, update, delete, publish themes |
specs/06-AUTH-AND-SECURITY.md:261:| `read-content` | View pages and navigation menus |
specs/06-AUTH-AND-SECURITY.md:262:| `write-content` | Create, update, delete pages and navigation items |
specs/06-AUTH-AND-SECURITY.md:263:| `manage-platform` | Platform-level management (super-admin only) |
specs/06-AUTH-AND-SECURITY.md:269:### 1.4 Guard Configuration
specs/06-AUTH-AND-SECURITY.md:273:#### Guards Data Dictionary
specs/06-AUTH-AND-SECURITY.md:275:| Guard Name | Driver | Provider | Purpose |
specs/06-AUTH-AND-SECURITY.md:277:| `web` | session | `users` | Admin panel session auth (default guard) |
specs/06-AUTH-AND-SECURITY.md:278:| `customer` | session | `customers` | Storefront customer session auth |
specs/06-AUTH-AND-SECURITY.md:279:| `sanctum` | sanctum | `users` | Admin REST API token auth |
specs/06-AUTH-AND-SECURITY.md:281:#### Providers Data Dictionary
specs/06-AUTH-AND-SECURITY.md:283:| Provider Name | Driver | Model | Purpose |
specs/06-AUTH-AND-SECURITY.md:285:| `users` | eloquent | `App\Models\User` | Admin users |
specs/06-AUTH-AND-SECURITY.md:286:| `customers` | eloquent | `App\Models\Customer` | Storefront customers (store-scoped via custom provider) |
specs/06-AUTH-AND-SECURITY.md:288:#### Password Brokers Data Dictionary
specs/06-AUTH-AND-SECURITY.md:290:| Broker Name | Provider | Token Table | Expiry | Throttle |
specs/06-AUTH-AND-SECURITY.md:292:| `users` | `users` | `password_reset_tokens` | 60 min | 60 sec |
specs/06-AUTH-AND-SECURITY.md:293:| `customers` | `customers` | `customer_password_reset_tokens` | 60 min | 60 sec |
specs/06-AUTH-AND-SECURITY.md:299:## 2. Authorization
specs/06-AUTH-AND-SECURITY.md:301:### 2.1 Role Enum
specs/06-AUTH-AND-SECURITY.md:307:| Case | Stored Value | Description |
specs/06-AUTH-AND-SECURITY.md:309:| Owner | `'owner'` | Full access. Can transfer ownership, manage billing, delete store. One per store. |
specs/06-AUTH-AND-SECURITY.md:310:| Admin | `'admin'` | Near-full access. Cannot transfer ownership or delete store. |
specs/06-AUTH-AND-SECURITY.md:311:| Staff | `'staff'` | Operational access. Can manage products, orders, collections, discounts, pages. Cannot access settings, themes, staff management, or developers. |
specs/06-AUTH-AND-SECURITY.md:312:| Support | `'support'` | Read-only access to products, orders, and customers. For customer service agents. |
specs/06-AUTH-AND-SECURITY.md:322:### 2.2 Permission Matrix
specs/06-AUTH-AND-SECURITY.md:326:| Resource | Action | Owner | Admin | Staff | Support |
specs/06-AUTH-AND-SECURITY.md:328:| Store Settings | View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:329:| Store Settings | Update | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:330:| Store | Delete | Y | N | N | N |
specs/06-AUTH-AND-SECURITY.md:331:| Products | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:332:| Products | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:333:| Products | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:334:| Products | Delete / Archive | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:335:| Products | Restore | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:336:| Collections | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:337:| Collections | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:338:| Collections | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:339:| Collections | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:340:| Orders | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:341:| Orders | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:342:| Orders | Cancel | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:343:| Fulfillments | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:344:| Fulfillments | Update / Cancel | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:345:| Refunds | Create | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:346:| Customers | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:347:| Customers | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:348:| Discounts | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:349:| Discounts | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:350:| Discounts | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:351:| Discounts | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:352:| Themes | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:353:| Themes | Create / Upload | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:354:| Themes | Customize | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:355:| Themes | Publish | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:356:| Themes | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:357:| Pages | List / View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:358:| Pages | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:359:| Pages | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:360:| Pages | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:361:| Navigation | List / View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:362:| Navigation | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:363:| Apps | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:364:| Apps | Install / Remove | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:365:| Analytics | View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:366:| Developers / API | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:367:| Staff | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:368:| Staff | Invite | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:369:| Staff | Update Role | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:370:| Staff | Remove | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:371:| Shipping Zones | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:372:| Tax Settings | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:373:| Search Settings | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:375:#### Role Group Shorthand
specs/06-AUTH-AND-SECURITY.md:379:| Group Name | Roles Included | Used For |
specs/06-AUTH-AND-SECURITY.md:381:| OwnerOnly | Owner | Store deletion, ownership transfer |
specs/06-AUTH-AND-SECURITY.md:382:| OwnerOrAdmin | Owner, Admin | Settings, themes, staff, developers, navigation, apps, shipping, taxes, search, delete/archive actions |
specs/06-AUTH-AND-SECURITY.md:383:| OwnerAdminOrStaff | Owner, Admin, Staff | Create/update products, collections, discounts, pages, fulfillments, order updates |
specs/06-AUTH-AND-SECURITY.md:384:| AnyRole | Owner, Admin, Staff, Support | Read-only listing/viewing of products, orders, customers, collections, discounts |
specs/06-AUTH-AND-SECURITY.md:388:### 2.3 Role Checking Trait
specs/06-AUTH-AND-SECURITY.md:394:| Method | Parameters | Returns | Description |
specs/06-AUTH-AND-SECURITY.md:396:| `getStoreRole` | User, store_id (int) | StoreUserRole or null | Looks up the user's role for the given store via the `store_users` relationship. Returns null if the user has no role in that store. |
specs/06-AUTH-AND-SECURITY.md:397:| `hasRole` | User, store_id (int), roles (array of StoreUserRole) | bool | Returns true if the user's role for the store is in the provided list. Returns false if user has no role. |
specs/06-AUTH-AND-SECURITY.md:398:| `isOwnerOrAdmin` | User, store_id (int) | bool | Shorthand: checks if role is Owner or Admin. |
specs/06-AUTH-AND-SECURITY.md:399:| `isOwnerAdminOrStaff` | User, store_id (int) | bool | Shorthand: checks if role is Owner, Admin, or Staff. |
specs/06-AUTH-AND-SECURITY.md:400:| `isAnyRole` | User, store_id (int) | bool | Returns true if the user has any role at all in the store. |
specs/06-AUTH-AND-SECURITY.md:406:### 2.4 Laravel Policies
specs/06-AUTH-AND-SECURITY.md:415:#### ProductPolicy
specs/06-AUTH-AND-SECURITY.md:419:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:421:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:422:| `view(User, Product)` | Yes | AnyRole | product.store_id |
specs/06-AUTH-AND-SECURITY.md:423:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:424:| `update(User, Product)` | Yes | OwnerAdminOrStaff | product.store_id |
specs/06-AUTH-AND-SECURITY.md:425:| `delete(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:426:| `archive(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:427:| `restore(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:429:#### OrderPolicy
specs/06-AUTH-AND-SECURITY.md:433:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:435:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:436:| `view(User, Order)` | Yes | AnyRole | order.store_id |
specs/06-AUTH-AND-SECURITY.md:437:| `update(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:438:| `cancel(User, Order)` | Yes | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:439:| `createFulfillment(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:440:| `createRefund(User, Order)` | Yes | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:442:#### CollectionPolicy
specs/06-AUTH-AND-SECURITY.md:446:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:448:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:449:| `view(User, Collection)` | Yes | AnyRole | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:450:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:451:| `update(User, Collection)` | Yes | OwnerAdminOrStaff | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:452:| `delete(User, Collection)` | Yes | OwnerOrAdmin | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:454:#### DiscountPolicy
specs/06-AUTH-AND-SECURITY.md:458:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:460:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:461:| `view(User, Discount)` | Yes | AnyRole | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:462:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:463:| `update(User, Discount)` | Yes | OwnerAdminOrStaff | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:464:| `delete(User, Discount)` | Yes | OwnerOrAdmin | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:466:#### CustomerPolicy
specs/06-AUTH-AND-SECURITY.md:470:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:472:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:473:| `view(User, Customer)` | Yes | AnyRole | customer.store_id |
specs/06-AUTH-AND-SECURITY.md:474:| `update(User, Customer)` | Yes | OwnerAdminOrStaff | customer.store_id |
specs/06-AUTH-AND-SECURITY.md:476:#### ThemePolicy
specs/06-AUTH-AND-SECURITY.md:480:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:482:| `viewAny(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:483:| `view(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:484:| `create(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:485:| `update(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:486:| `delete(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:487:| `publish(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:489:#### PagePolicy
specs/06-AUTH-AND-SECURITY.md:493:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:495:| `viewAny(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:496:| `view(User, Page)` | Yes | OwnerAdminOrStaff | page.store_id |
specs/06-AUTH-AND-SECURITY.md:497:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:498:| `update(User, Page)` | Yes | OwnerAdminOrStaff | page.store_id |
specs/06-AUTH-AND-SECURITY.md:499:| `delete(User, Page)` | Yes | OwnerOrAdmin | page.store_id |
specs/06-AUTH-AND-SECURITY.md:501:#### StorePolicy
specs/06-AUTH-AND-SECURITY.md:505:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:507:| `viewSettings(User, Store)` | Yes | OwnerOrAdmin | store.id |
specs/06-AUTH-AND-SECURITY.md:508:| `updateSettings(User, Store)` | Yes | OwnerOrAdmin | store.id |
specs/06-AUTH-AND-SECURITY.md:509:| `delete(User, Store)` | Yes | OwnerOnly | store.id |
specs/06-AUTH-AND-SECURITY.md:511:#### FulfillmentPolicy
specs/06-AUTH-AND-SECURITY.md:515:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:517:| `create(User, Order)` | Yes (Order) | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:518:| `update(User, Fulfillment)` | Yes | OwnerAdminOrStaff | fulfillment -> order.store_id |
specs/06-AUTH-AND-SECURITY.md:519:| `cancel(User, Fulfillment)` | Yes | OwnerAdminOrStaff | fulfillment -> order.store_id |
specs/06-AUTH-AND-SECURITY.md:523:#### RefundPolicy
specs/06-AUTH-AND-SECURITY.md:527:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:529:| `create(User, Order)` | Yes (Order) | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:533:#### NavigationMenuPolicy
specs/06-AUTH-AND-SECURITY.md:537:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:539:| `viewAny(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:540:| `manage(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:544:### 2.5 Gates (Non-Model Operations)
specs/06-AUTH-AND-SECURITY.md:548:| Gate Name | Required Roles | Purpose |
specs/06-AUTH-AND-SECURITY.md:550:| `manage-store-settings` | Owner, Admin | Access store settings pages |
specs/06-AUTH-AND-SECURITY.md:551:| `manage-staff` | Owner, Admin | Invite, update, remove staff members |
specs/06-AUTH-AND-SECURITY.md:552:| `manage-developers` | Owner, Admin | Create/revoke API tokens, manage webhooks |
specs/06-AUTH-AND-SECURITY.md:553:| `view-analytics` | Owner, Admin, Staff | View analytics dashboard and reports |
specs/06-AUTH-AND-SECURITY.md:554:| `manage-shipping` | Owner, Admin | Manage shipping zones, rates, profiles |
specs/06-AUTH-AND-SECURITY.md:555:| `manage-taxes` | Owner, Admin | Manage tax settings and rates |
specs/06-AUTH-AND-SECURITY.md:556:| `manage-search-settings` | Owner, Admin | Configure search weights and synonyms |
specs/06-AUTH-AND-SECURITY.md:557:| `manage-navigation` | Owner, Admin | Create/edit/delete navigation menus |
specs/06-AUTH-AND-SECURITY.md:558:| `manage-apps` | Owner, Admin | Install and remove third-party apps |
specs/06-AUTH-AND-SECURITY.md:570:### 2.6 Policy and Gate Usage Patterns
specs/06-AUTH-AND-SECURITY.md:572:#### In Livewire Components
specs/06-AUTH-AND-SECURITY.md:578:#### In API Controllers
specs/06-AUTH-AND-SECURITY.md:584:#### In Blade Templates
specs/06-AUTH-AND-SECURITY.md:591:## 3. Middleware Stack
specs/06-AUTH-AND-SECURITY.md:593:### 3.1 Middleware Registration
specs/06-AUTH-AND-SECURITY.md:599:| Alias | Class | Purpose |
specs/06-AUTH-AND-SECURITY.md:601:| `store.resolve` | `App\Http\Middleware\ResolveStore` | Resolves current store from hostname or session |
specs/06-AUTH-AND-SECURITY.md:602:| `role.check` | `App\Http\Middleware\CheckStoreRole` | Checks user has required role for current store |
specs/06-AUTH-AND-SECURITY.md:603:| `auth:customer` | `App\Http\Middleware\CustomerAuthenticate` | Ensures customer is authenticated via customer guard |
specs/06-AUTH-AND-SECURITY.md:607:### 3.2 Route Middleware Groups
specs/06-AUTH-AND-SECURITY.md:609:| Route Group | Middleware Stack | Description |
specs/06-AUTH-AND-SECURITY.md:611:| Admin web (auth pages) | `web` | Login, forgot-password, reset-password |
specs/06-AUTH-AND-SECURITY.md:612:| Admin web (authenticated) | `web`, `auth`, `verified`, `store.resolve`, `role.check` | All admin panel pages |
specs/06-AUTH-AND-SECURITY.md:613:| Admin API | `api`, `auth:sanctum`, `store.resolve`, `throttle:api.admin` | REST API endpoints |
specs/06-AUTH-AND-SECURITY.md:614:| Storefront web (public) | `web`, `store.resolve` | Public store pages (catalog, product, cart) |
specs/06-AUTH-AND-SECURITY.md:615:| Storefront web (customer) | `web`, `store.resolve`, `auth:customer` | Customer account pages |
specs/06-AUTH-AND-SECURITY.md:616:| Storefront API | `api`, `store.resolve`, `throttle:api.storefront` | Cart and checkout API |
specs/06-AUTH-AND-SECURITY.md:617:| Webhook routes | `api`, `throttle:webhooks` | Reserved for outbound app webhooks (no inbound payment webhooks - Mock PSP is in-process) |
specs/06-AUTH-AND-SECURITY.md:621:### 3.3 Custom Middleware Specifications
specs/06-AUTH-AND-SECURITY.md:623:#### ResolveStore
specs/06-AUTH-AND-SECURITY.md:659:#### CheckStoreRole
specs/06-AUTH-AND-SECURITY.md:691:#### CustomerAuthenticate
specs/06-AUTH-AND-SECURITY.md:713:## 4. Security Controls
specs/06-AUTH-AND-SECURITY.md:715:### 4.1 CSRF Protection
specs/06-AUTH-AND-SECURITY.md:717:| Context | Mechanism |
specs/06-AUTH-AND-SECURITY.md:719:| Blade forms | Laravel's `@csrf` directive injects a hidden token field (automatic) |
specs/06-AUTH-AND-SECURITY.md:720:| Livewire actions | Livewire handles CSRF verification automatically on every request |
specs/06-AUTH-AND-SECURITY.md:721:| API routes (Sanctum token) | Exempt from CSRF (token-based auth replaces CSRF need) |
specs/06-AUTH-AND-SECURITY.md:722:| SPA clients | `GET /sanctum/csrf-cookie` sets XSRF-TOKEN cookie for session-based API calls |
specs/06-AUTH-AND-SECURITY.md:732:### 4.2 Rate Limiting
specs/06-AUTH-AND-SECURITY.md:736:| Limiter Name | Limit | Keyed By | Applied To |
specs/06-AUTH-AND-SECURITY.md:738:| `login` | 5 per minute | IP address | Admin login, customer login |
specs/06-AUTH-AND-SECURITY.md:739:| `api.admin` | 60 per minute | User ID (if authenticated), otherwise IP | Admin REST API endpoints |
specs/06-AUTH-AND-SECURITY.md:740:| `api.storefront` | 120 per minute | IP address | Public storefront API (cart, search) |
specs/06-AUTH-AND-SECURITY.md:741:| `checkout` | 10 per minute | Session ID | Checkout-related operations |
specs/06-AUTH-AND-SECURITY.md:742:| `search` | 30 per minute | IP address | Search queries |
specs/06-AUTH-AND-SECURITY.md:743:| `analytics` | 60 per minute | IP address | Analytics event ingestion |
specs/06-AUTH-AND-SECURITY.md:744:| `webhooks` | 100 per minute | IP address | Outbound app webhook endpoints (reserved; no inbound payment webhooks - Mock PSP is in-process) |
specs/06-AUTH-AND-SECURITY.md:748:| Header | Description |
specs/06-AUTH-AND-SECURITY.md:750:| `X-RateLimit-Limit` | Maximum requests allowed in the window |
specs/06-AUTH-AND-SECURITY.md:751:| `X-RateLimit-Remaining` | Requests remaining in the current window |
specs/06-AUTH-AND-SECURITY.md:752:| `Retry-After` | Seconds until the rate limit resets (only on 429 responses) |
specs/06-AUTH-AND-SECURITY.md:758:### 4.3 Encryption at Rest
specs/06-AUTH-AND-SECURITY.md:764:| Model | Column | Cast Type | Purpose |
specs/06-AUTH-AND-SECURITY.md:766:| OauthClient | `client_secret_encrypted` | `encrypted` | Third-party OAuth client secrets |
specs/06-AUTH-AND-SECURITY.md:767:| WebhookSubscription | `signing_secret_encrypted` | `encrypted` | Per-subscription signing secrets for outbound webhooks |
specs/06-AUTH-AND-SECURITY.md:768:| Payment | `raw_json` | `encrypted:array` | Full payment gateway response (may contain sensitive card/account data) |
specs/06-AUTH-AND-SECURITY.md:778:### 4.4 Input Validation
specs/06-AUTH-AND-SECURITY.md:782:#### Form Request Inventory
specs/06-AUTH-AND-SECURITY.md:784:| Form Request Class | Used By | Key Validation Rules |
specs/06-AUTH-AND-SECURITY.md:786:| `StoreProductRequest` | Create product | `title`: required, string, max:255. `description_html`: nullable, string. `status`: required, in:active,draft,archived. `vendor`: nullable, string. Price fields: required, integer, min:0. |
specs/06-AUTH-AND-SECURITY.md:787:| `UpdateProductRequest` | Update product | Same fields as StoreProductRequest but all optional (sometimes rule). |
specs/06-AUTH-AND-SECURITY.md:788:| `StoreCollectionRequest` | Create collection | `title`: required, string, max:255. `type`: required, in:manual,automated. `rules_json`: required_if:type,automated, valid JSON. |
specs/06-AUTH-AND-SECURITY.md:789:| `UpdateCollectionRequest` | Update collection | Same as StoreCollectionRequest, all optional. |
specs/06-AUTH-AND-SECURITY.md:790:| `StoreDiscountRequest` | Create discount | `type`: required, in:code,automatic. `code`: required_if:type,code, string, max:50, unique per store (case-insensitive). `value_type`: required, in:fixed,percent,free_shipping. `value_amount`: required_unless:value_type,free_shipping, integer, min:0; when value_type is `percent`, max:100. `minimum_order_amount`: nullable, integer, min:0. `usage_limit`: nullable, integer, min:1. `starts_at`: nullable, date, ISO-8601. `ends_at`: nullable, date, after:starts_at. |
specs/06-AUTH-AND-SECURITY.md:791:| `UpdateDiscountRequest` | Update discount | Same as StoreDiscountRequest, code unique ignoring self. |
specs/06-AUTH-AND-SECURITY.md:792:| `SetCheckoutAddressRequest` | Set shipping/billing address | `first_name`, `last_name`, `address1`, `city`, `country_code`: required. `province_code`: required when applicable. `postal_code`: required. `phone`: nullable. |
specs/06-AUTH-AND-SECURITY.md:793:| `ApplyDiscountRequest` | Apply discount to checkout | `code`: required, string, must exist in discounts table for current store. |
specs/06-AUTH-AND-SECURITY.md:794:| `CreateFulfillmentRequest` | Create fulfillment | `line_item_ids`: required, array of existing line item IDs. `tracking_company`: nullable, string. `tracking_number`: nullable, string. `tracking_url`: nullable, valid URL. |
specs/06-AUTH-AND-SECURITY.md:795:| `CreateRefundRequest` | Create refund | `line_items`: required, array with `id` and `quantity` per item. `reason`: required, string. `amount`: required, integer, min:0, max:original payment amount. |
specs/06-AUTH-AND-SECURITY.md:796:| `UpdateStoreSettingsRequest` | Update store settings | `name`: required, string. `default_currency`: in allowed currencies. `default_locale`: in allowed locales. `timezone`: valid timezone string. |
specs/06-AUTH-AND-SECURITY.md:797:| `InviteStaffRequest` | Invite staff member | `email`: required, valid email. `role`: required, in:admin,staff,support (not owner). |
specs/06-AUTH-AND-SECURITY.md:798:| `RegisterCustomerRequest` | Customer registration | `name`: required. `email`: required, email, unique per store (composite). `password`: required, min:8, confirmed. |
specs/06-AUTH-AND-SECURITY.md:799:| `LoginRequest` | Admin/customer login | `email`: required, email. `password`: required, string. |
specs/06-AUTH-AND-SECURITY.md:807:### 4.5 XSS Prevention
specs/06-AUTH-AND-SECURITY.md:809:| Context | Strategy |
specs/06-AUTH-AND-SECURITY.md:811:| Standard Blade output | Double-curly-brace syntax auto-escapes all output (Laravel default) |
specs/06-AUTH-AND-SECURITY.md:812:| Rich HTML output | Unescaped syntax used only for trusted HTML fields: product `description_html`, page `body_html` |
specs/06-AUTH-AND-SECURITY.md:813:| HTML input sanitization | Use HTMLPurifier (or equivalent) on save, before persisting to database |
specs/06-AUTH-AND-SECURITY.md:814:| Livewire properties | Auto-escaped by default when rendered in Blade |
specs/06-AUTH-AND-SECURITY.md:815:| JSON API responses | Laravel escapes JSON output by default |
specs/06-AUTH-AND-SECURITY.md:817:#### HTML Sanitization Requirements
specs/06-AUTH-AND-SECURITY.md:823:| Element | Allowed Attributes |
specs/06-AUTH-AND-SECURITY.md:825:| `p`, `br`, `strong`, `em`, `u` | none |
specs/06-AUTH-AND-SECURITY.md:826:| `ol`, `ul`, `li` | none |
specs/06-AUTH-AND-SECURITY.md:827:| `a` | `href` |
specs/06-AUTH-AND-SECURITY.md:828:| `img` | `src`, `alt` |
specs/06-AUTH-AND-SECURITY.md:829:| `h1` through `h6` | none |
specs/06-AUTH-AND-SECURITY.md:830:| `blockquote` | none |
specs/06-AUTH-AND-SECURITY.md:831:| `table`, `thead`, `tbody`, `tr`, `th`, `td` | none |
specs/06-AUTH-AND-SECURITY.md:832:| `div`, `span` | none |
specs/06-AUTH-AND-SECURITY.md:840:### 4.6 SQL Injection Prevention
specs/06-AUTH-AND-SECURITY.md:849:#### FTS5 Input Sanitization
specs/06-AUTH-AND-SECURITY.md:859:### 4.7 Mass Assignment Protection
specs/06-AUTH-AND-SECURITY.md:869:### 4.8 Password Security
specs/06-AUTH-AND-SECURITY.md:871:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:873:| Minimum length | 8 characters (for both admin and customer passwords) |
specs/06-AUTH-AND-SECURITY.md:874:| Hashing algorithm | Bcrypt (Laravel default) |
specs/06-AUTH-AND-SECURITY.md:875:| Password in logs | Never logged - use Laravel's built-in log redaction |
specs/06-AUTH-AND-SECURITY.md:876:| Password in API responses | Never returned - `password` and `remember_token` must be in the model's `$hidden` array |
specs/06-AUTH-AND-SECURITY.md:896:## 5. Session Configuration
specs/06-AUTH-AND-SECURITY.md:900:| Setting | Value | Rationale |
specs/06-AUTH-AND-SECURITY.md:902:| `driver` | `'file'` | Simple, no external dependencies. Compatible with SQLite-based stack without needing Redis. |
specs/06-AUTH-AND-SECURITY.md:903:| `lifetime` | 120 (minutes) | Configurable via `SESSION_LIFETIME` env var. |
specs/06-AUTH-AND-SECURITY.md:904:| `expire_on_close` | `false` | Session persists until lifetime expires, not on browser close. |
specs/06-AUTH-AND-SECURITY.md:905:| `encrypt` | `true` | Session data encrypted at rest on disk. |
specs/06-AUTH-AND-SECURITY.md:906:| `cookie` | `'shop_session'` | Custom name to avoid generic fingerprinting. Configurable via `SESSION_COOKIE` env var. |
specs/06-AUTH-AND-SECURITY.md:907:| `path` | `'/'` | Cookie available across entire domain. |
specs/06-AUTH-AND-SECURITY.md:908:| `domain` | `null` | Laravel determines from request. |
specs/06-AUTH-AND-SECURITY.md:909:| `secure` | `true` | HTTPS-only cookies in production. Configurable via `SESSION_SECURE_COOKIE` env var (set to false for local dev). |
specs/06-AUTH-AND-SECURITY.md:910:| `http_only` | `true` | Cookie inaccessible to JavaScript (mitigates XSS-based cookie theft). |
specs/06-AUTH-AND-SECURITY.md:911:| `same_site` | `'lax'` | Allows navigation-initiated requests while preventing CSRF from external origins. |
specs/06-AUTH-AND-SECURITY.md:912:| `partitioned` | `false` | Not needed for this use case. |
specs/06-AUTH-AND-SECURITY.md:916:## 6. CORS Configuration
specs/06-AUTH-AND-SECURITY.md:920:| Setting | Value | Rationale |
specs/06-AUTH-AND-SECURITY.md:922:| `paths` | `['api/*', 'sanctum/csrf-cookie']` | Only API and Sanctum CSRF cookie endpoints are CORS-enabled. Web routes are not. |
specs/06-AUTH-AND-SECURITY.md:923:| `allowed_methods` | `['*']` | All HTTP methods allowed for API. |
specs/06-AUTH-AND-SECURITY.md:924:| `allowed_origins` | `[FRONTEND_URL env var, default '*']` | Restrict to store domain in production. Wildcard for development. |
specs/06-AUTH-AND-SECURITY.md:925:| `allowed_origins_patterns` | `[]` | No pattern-based origin matching needed. |
specs/06-AUTH-AND-SECURITY.md:926:| `allowed_headers` | `['*']` | All headers allowed (Authorization, Content-Type, etc.). |
specs/06-AUTH-AND-SECURITY.md:927:| `exposed_headers` | `['X-RateLimit-Limit', 'X-RateLimit-Remaining', 'Retry-After']` | Expose rate limit headers so API clients can implement backoff. |
specs/06-AUTH-AND-SECURITY.md:928:| `max_age` | `0` | No preflight caching (conservative default). |
specs/06-AUTH-AND-SECURITY.md:929:| `supports_credentials` | `true` | Required for Sanctum SPA auth (cookies). |
specs/06-AUTH-AND-SECURITY.md:933:## 7. Webhook Signature Verification
specs/06-AUTH-AND-SECURITY.md:935:### 7.1 Inbound Payment Webhooks
specs/06-AUTH-AND-SECURITY.md:941:### 7.2 Platform Webhooks (Outbound)
specs/06-AUTH-AND-SECURITY.md:975:## 8. Audit Logging
specs/06-AUTH-AND-SECURITY.md:977:### 8.1 Logging Channel
specs/06-AUTH-AND-SECURITY.md:981:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:983:| Driver | `daily` (file-based, daily rotation) |
specs/06-AUTH-AND-SECURITY.md:984:| Path | `storage/logs/audit.log` |
specs/06-AUTH-AND-SECURITY.md:985:| Level | `info` |
specs/06-AUTH-AND-SECURITY.md:986:| Retention | 90 days |
specs/06-AUTH-AND-SECURITY.md:990:### 8.2 Log Entry Format
specs/06-AUTH-AND-SECURITY.md:994:| Field | Type | Required | Description |
specs/06-AUTH-AND-SECURITY.md:996:| `timestamp` | string (ISO-8601) | Y | When the event occurred |
specs/06-AUTH-AND-SECURITY.md:997:| `event` | string | Y | Event identifier (e.g., `product.updated`, `auth.login`) |
specs/06-AUTH-AND-SECURITY.md:998:| `user_id` | integer or null | N | ID of the admin user who triggered the event |
specs/06-AUTH-AND-SECURITY.md:999:| `store_id` | integer or null | N | ID of the store context |
specs/06-AUTH-AND-SECURITY.md:1000:| `resource_type` | string or null | N | Type of resource affected (e.g., `product`, `order`) |
specs/06-AUTH-AND-SECURITY.md:1001:| `resource_id` | integer or null | N | ID of the affected resource |
specs/06-AUTH-AND-SECURITY.md:1002:| `ip` | string | Y | Client IP address |
specs/06-AUTH-AND-SECURITY.md:1003:| `user_agent` | string | Y | Client user agent string |
specs/06-AUTH-AND-SECURITY.md:1004:| `changes` | object or null | N | For update events: object mapping field names to `[old_value, new_value]` tuples |
specs/06-AUTH-AND-SECURITY.md:1005:| (additional keys) | varies | N | Event-specific extra data |
specs/06-AUTH-AND-SECURITY.md:1009:### 8.3 Events to Log
specs/06-AUTH-AND-SECURITY.md:1011:#### Authentication Events
specs/06-AUTH-AND-SECURITY.md:1013:| Event ID | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1015:| `auth.login` | Successful admin login | user_id, ip, user_agent |
specs/06-AUTH-AND-SECURITY.md:1016:| `auth.logout` | Admin logout | user_id |
specs/06-AUTH-AND-SECURITY.md:1017:| `auth.failed_login` | Failed admin login attempt | email (never password), ip, user_agent |
specs/06-AUTH-AND-SECURITY.md:1018:| `customer.login` | Successful customer login | customer_id, store_id, ip |
specs/06-AUTH-AND-SECURITY.md:1019:| `customer.registered` | New customer registration | customer_id, store_id |
specs/06-AUTH-AND-SECURITY.md:1020:| `customer.failed_login` | Failed customer login attempt | email, store_id, ip |
specs/06-AUTH-AND-SECURITY.md:1022:#### Admin Resource Events
specs/06-AUTH-AND-SECURITY.md:1028:| Event Pattern | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1030:| `{resource}.created` | Resource created | resource_id, key attributes of the new resource |
specs/06-AUTH-AND-SECURITY.md:1031:| `{resource}.updated` | Resource updated | resource_id, `changes` object with old/new values for each changed field |
specs/06-AUTH-AND-SECURITY.md:1032:| `{resource}.deleted` | Resource soft-deleted or archived | resource_id |
specs/06-AUTH-AND-SECURITY.md:1033:| `{resource}.restored` | Resource restored from soft-delete | resource_id |
specs/06-AUTH-AND-SECURITY.md:1035:#### Security Events
specs/06-AUTH-AND-SECURITY.md:1037:| Event ID | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1039:| `api_token.created` | New API token issued | token_name, abilities list, user_id |
specs/06-AUTH-AND-SECURITY.md:1040:| `api_token.revoked` | API token revoked | token_name, user_id |
specs/06-AUTH-AND-SECURITY.md:1041:| `webhook.signature_invalid` | Outbound webhook delivery failed signature verification at subscriber | subscriber_url, ip |
specs/06-AUTH-AND-SECURITY.md:1042:| `store.settings_changed` | Store settings updated | changed fields with old/new values |
specs/06-AUTH-AND-SECURITY.md:1046:### 8.4 Audit Logger Service
specs/06-AUTH-AND-SECURITY.md:1054:| Parameter | Type | Required | Description |
specs/06-AUTH-AND-SECURITY.md:1056:| `event` | string | Y | Event identifier |
specs/06-AUTH-AND-SECURITY.md:1057:| `userId` | int or null | N | Acting user ID |
specs/06-AUTH-AND-SECURITY.md:1058:| `storeId` | int or null | N | Store context ID |
specs/06-AUTH-AND-SECURITY.md:1059:| `resourceType` | string or null | N | Affected resource type |
specs/06-AUTH-AND-SECURITY.md:1060:| `resourceId` | int or null | N | Affected resource ID |
specs/06-AUTH-AND-SECURITY.md:1061:| `extra` | associative array | N | Additional key-value pairs to include in the log entry |
specs/06-AUTH-AND-SECURITY.md:1071:### 8.5 Integration with Laravel Events
specs/06-AUTH-AND-SECURITY.md:1075:#### Auth Event Listeners
specs/06-AUTH-AND-SECURITY.md:1079:| Laravel Event | Audit Event ID | Data Captured |
specs/06-AUTH-AND-SECURITY.md:1081:| `Illuminate\Auth\Events\Login` | `auth.login` | user_id from event |
specs/06-AUTH-AND-SECURITY.md:1082:| `Illuminate\Auth\Events\Failed` | `auth.failed_login` | email from credentials (never password) |
specs/06-AUTH-AND-SECURITY.md:1083:| `Illuminate\Auth\Events\Logout` | `auth.logout` | user_id from event |
specs/06-AUTH-AND-SECURITY.md:1085:#### Model Observers
specs/06-AUTH-AND-SECURITY.md:1091:## 9. Security Checklist Summary
specs/06-AUTH-AND-SECURITY.md:1093:| # | Control | Implementation Approach | Priority |
specs/06-AUTH-AND-SECURITY.md:1095:| 1 | Session-based auth (admin) | Laravel `web` guard with bcrypt, session regeneration on login | Required |
specs/06-AUTH-AND-SECURITY.md:1096:| 2 | Session-based auth (customer) | Custom `customer` guard, store-scoped via custom user provider | Required |
specs/06-AUTH-AND-SECURITY.md:1097:| 3 | API token auth | Sanctum personal access tokens with per-token abilities | Required |
specs/06-AUTH-AND-SECURITY.md:1098:| 4 | Role-based access control | `StoreUserRole` enum, Laravel policies on all models, gates for non-model ops | Required |
specs/06-AUTH-AND-SECURITY.md:1099:| 5 | CSRF protection | `@csrf` on all session forms, Livewire auto-handles, API routes exempt | Required |
specs/06-AUTH-AND-SECURITY.md:1100:| 6 | Rate limiting | Seven named limiters (login, api.admin, api.storefront, checkout, search, analytics, webhooks) | Required |
specs/06-AUTH-AND-SECURITY.md:1101:| 7 | Input validation | Dedicated Form Request class for every write endpoint | Required |
specs/06-AUTH-AND-SECURITY.md:1102:| 8 | XSS prevention | Blade auto-escaping by default, HTMLPurifier for rich content fields | Required |
specs/06-AUTH-AND-SECURITY.md:1103:| 9 | SQL injection prevention | Eloquent ORM with parameterized queries, FTS5 input sanitization | Required |
specs/06-AUTH-AND-SECURITY.md:1104:| 10 | Mass assignment protection | `$fillable` on all models, always use `$request->validated()` | Required |
specs/06-AUTH-AND-SECURITY.md:1105:| 11 | Encryption at rest | Laravel `encrypted` cast for secrets and sensitive JSON columns | Required |
specs/06-AUTH-AND-SECURITY.md:1106:| 12 | Password security | Bcrypt, min 8 characters, `$hidden` on User and Customer models | Required |
specs/06-AUTH-AND-SECURITY.md:1107:| 13 | Session security | Encrypted sessions, HTTP-only cookies, secure flag, SameSite=Lax | Required |
specs/06-AUTH-AND-SECURITY.md:1108:| 14 | Webhook signature verification | HMAC-SHA256 for outbound platform webhooks (no inbound payment webhooks - Mock PSP is in-process) | Required |
specs/06-AUTH-AND-SECURITY.md:1109:| 15 | Audit logging | Structured JSON to dedicated daily-rotation log channel, 90-day retention | Required |
specs/06-AUTH-AND-SECURITY.md:1110:| 16 | CORS | Restricted to `api/*` paths, credentials supported, rate limit headers exposed | Required |
specs/07-SEEDERS-AND-TEST-DATA.md:7:## 1. DatabaseSeeder Orchestration
specs/07-SEEDERS-AND-TEST-DATA.md:13:| Step | Seeder Class | Depends On | Purpose |
specs/07-SEEDERS-AND-TEST-DATA.md:15:| 1 | OrganizationSeeder | (none) | Creates billing organizations |
specs/07-SEEDERS-AND-TEST-DATA.md:16:| 2 | StoreSeeder | Organizations | Creates stores under organizations |
specs/07-SEEDERS-AND-TEST-DATA.md:17:| 3 | StoreDomainSeeder | Stores | Attaches hostnames to stores |
specs/07-SEEDERS-AND-TEST-DATA.md:18:| 4 | UserSeeder | (none) | Creates admin/staff user accounts |
specs/07-SEEDERS-AND-TEST-DATA.md:19:| 5 | StoreUserSeeder | Stores, Users | Links users to stores with roles (pivot) |
specs/07-SEEDERS-AND-TEST-DATA.md:20:| 6 | StoreSettingsSeeder | Stores | Inserts per-store JSON settings |
specs/07-SEEDERS-AND-TEST-DATA.md:21:| 7 | TaxSettingsSeeder | Stores | Configures tax mode and rates |
specs/07-SEEDERS-AND-TEST-DATA.md:22:| 8 | ShippingSeeder | Stores | Creates shipping zones and rates |
specs/07-SEEDERS-AND-TEST-DATA.md:23:| 9 | CollectionSeeder | Stores | Creates product collections |
specs/07-SEEDERS-AND-TEST-DATA.md:24:| 10 | ProductSeeder | Stores, Collections | Creates products, options, variants, inventory, collection assignments |
specs/07-SEEDERS-AND-TEST-DATA.md:25:| 11 | DiscountSeeder | Stores | Creates discount codes |
specs/07-SEEDERS-AND-TEST-DATA.md:26:| 12 | CustomerSeeder | Stores | Creates customer accounts with addresses |
specs/07-SEEDERS-AND-TEST-DATA.md:27:| 13 | OrderSeeder | Stores, Customers, Products, Variants, Discounts | Creates orders with lines, payments, fulfillments, refunds |
specs/07-SEEDERS-AND-TEST-DATA.md:28:| 14 | ThemeSeeder | Stores | Creates themes with settings |
specs/07-SEEDERS-AND-TEST-DATA.md:29:| 15 | PageSeeder | Stores | Creates content pages |
specs/07-SEEDERS-AND-TEST-DATA.md:30:| 16 | NavigationSeeder | Stores, Collections, Pages | Creates menus linking to collections and pages |
specs/07-SEEDERS-AND-TEST-DATA.md:31:| 17 | AnalyticsSeeder | Stores, Customers | Creates daily aggregates and event stream |
specs/07-SEEDERS-AND-TEST-DATA.md:32:| 18 | SearchSettingsSeeder | Stores | Configures search synonyms and stop words |
specs/07-SEEDERS-AND-TEST-DATA.md:69:## 2. Factory Definitions
specs/07-SEEDERS-AND-TEST-DATA.md:75:### 2.1 OrganizationFactory
specs/07-SEEDERS-AND-TEST-DATA.md:81:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:83:| name | Faker company name |
specs/07-SEEDERS-AND-TEST-DATA.md:84:| billing_email | Faker company email |
specs/07-SEEDERS-AND-TEST-DATA.md:90:### 2.2 StoreFactory
specs/07-SEEDERS-AND-TEST-DATA.md:96:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:98:| organization_id | Creates a new Organization via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:99:| name | Faker company name + " Store" suffix |
specs/07-SEEDERS-AND-TEST-DATA.md:100:| handle | Faker unique slug (2 words) |
specs/07-SEEDERS-AND-TEST-DATA.md:101:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:102:| default_currency | "EUR" |
specs/07-SEEDERS-AND-TEST-DATA.md:103:| default_locale | "en" |
specs/07-SEEDERS-AND-TEST-DATA.md:104:| timezone | "Europe/Berlin" |
specs/07-SEEDERS-AND-TEST-DATA.md:108:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:110:| `suspended` | status = "suspended" |
specs/07-SEEDERS-AND-TEST-DATA.md:114:### 2.3 StoreDomainFactory
specs/07-SEEDERS-AND-TEST-DATA.md:120:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:122:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:123:| hostname | Faker unique domain name |
specs/07-SEEDERS-AND-TEST-DATA.md:124:| type | "storefront" |
specs/07-SEEDERS-AND-TEST-DATA.md:125:| is_primary | 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:126:| tls_mode | "managed" |
specs/07-SEEDERS-AND-TEST-DATA.md:130:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:132:| `admin` | type = "admin" |
specs/07-SEEDERS-AND-TEST-DATA.md:133:| `api` | type = "api" |
specs/07-SEEDERS-AND-TEST-DATA.md:134:| `secondary` | is_primary = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:138:### 2.4 UserFactory
specs/07-SEEDERS-AND-TEST-DATA.md:144:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:146:| email | Faker unique safe email |
specs/07-SEEDERS-AND-TEST-DATA.md:147:| password_hash | bcrypt of "password" |
specs/07-SEEDERS-AND-TEST-DATA.md:148:| name | Faker full name |
specs/07-SEEDERS-AND-TEST-DATA.md:149:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:150:| last_login_at | Random date within the last 30 days |
specs/07-SEEDERS-AND-TEST-DATA.md:154:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:156:| `disabled` | status = "disabled" |
specs/07-SEEDERS-AND-TEST-DATA.md:160:### 2.5 ProductFactory
specs/07-SEEDERS-AND-TEST-DATA.md:166:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:168:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:169:| title | Faker 3 random words joined |
specs/07-SEEDERS-AND-TEST-DATA.md:170:| handle | URL-slug of the title |
specs/07-SEEDERS-AND-TEST-DATA.md:171:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:172:| description_html | Faker 2 paragraphs wrapped in `<p>` tags |
specs/07-SEEDERS-AND-TEST-DATA.md:173:| vendor | Faker company name |
specs/07-SEEDERS-AND-TEST-DATA.md:174:| product_type | Random from: Shirts, Pants, Shoes, Accessories, Electronics, Books |
specs/07-SEEDERS-AND-TEST-DATA.md:175:| tags | JSON array of 1-3 random picks from: new, sale, trending, popular, limited |
specs/07-SEEDERS-AND-TEST-DATA.md:176:| published_at | Current timestamp |
specs/07-SEEDERS-AND-TEST-DATA.md:180:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:182:| `draft` | status = "draft", published_at = null |
specs/07-SEEDERS-AND-TEST-DATA.md:183:| `archived` | status = "archived" |
specs/07-SEEDERS-AND-TEST-DATA.md:187:| Hook Name | Behavior |
specs/07-SEEDERS-AND-TEST-DATA.md:189:| `withVariants(count)` | After creating the product, create `count` ProductVariant records associated with the product |
specs/07-SEEDERS-AND-TEST-DATA.md:190:| `withDefaultVariant(price)` | After creating the product, create one ProductVariant marked as default at the given price in EUR |
specs/07-SEEDERS-AND-TEST-DATA.md:194:### 2.6 ProductVariantFactory
specs/07-SEEDERS-AND-TEST-DATA.md:200:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:202:| product_id | Creates a new Product via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:203:| sku | Faker unique, pattern: "SKU-####-???" (digits and letters) |
specs/07-SEEDERS-AND-TEST-DATA.md:204:| barcode | Faker EAN-13 |
specs/07-SEEDERS-AND-TEST-DATA.md:205:| price_amount | Random integer 999-19999 (9.99 to 199.99 EUR) |
specs/07-SEEDERS-AND-TEST-DATA.md:206:| compare_at_amount | null |
specs/07-SEEDERS-AND-TEST-DATA.md:207:| currency | "EUR" |
specs/07-SEEDERS-AND-TEST-DATA.md:208:| weight_g | Random integer 100-5000 |
specs/07-SEEDERS-AND-TEST-DATA.md:209:| requires_shipping | 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:210:| is_default | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:211:| position | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:212:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:216:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:218:| `onSale` | compare_at_amount = random 20000-39999, price_amount = random 9999-19999 |
specs/07-SEEDERS-AND-TEST-DATA.md:219:| `digital` | requires_shipping = 0, weight_g = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:220:| `default` | is_default = 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:221:| `archived` | status = "archived" |
specs/07-SEEDERS-AND-TEST-DATA.md:225:### 2.7 InventoryItemFactory
specs/07-SEEDERS-AND-TEST-DATA.md:231:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:233:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:234:| variant_id | Creates a new ProductVariant via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:235:| quantity_on_hand | Random integer 0-100 |
specs/07-SEEDERS-AND-TEST-DATA.md:236:| quantity_reserved | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:237:| policy | "deny" |
specs/07-SEEDERS-AND-TEST-DATA.md:241:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:243:| `outOfStock` | quantity_on_hand = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:244:| `continuePolicy` | policy = "continue" |
specs/07-SEEDERS-AND-TEST-DATA.md:245:| `lowStock` | quantity_on_hand = random 1-3 |
specs/07-SEEDERS-AND-TEST-DATA.md:249:### 2.8 CollectionFactory

formatted_output:
Warning: truncated output (original token count: 12282)
Total output lines: 520

specs/06-AUTH-AND-SECURITY.md:7:## 1. Authentication
specs/06-AUTH-AND-SECURITY.md:11:### 1.1 Admin Authentication
specs/06-AUTH-AND-SECURITY.md:13:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:15:| Guard name | `web` (default Laravel guard) |
specs/06-AUTH-AND-SECURITY.md:16:| Provider name | `users` (Eloquent driver) |
specs/06-AUTH-AND-SECURITY.md:17:| Model | `App\Models\User` |
specs/06-AUTH-AND-SECURITY.md:18:| Driver | Session (cookie-based) |
specs/06-AUTH-AND-SECURITY.md:19:| Login route | `GET /admin/login` |
specs/06-AUTH-AND-SECURITY.md:20:| Login form | Livewire component `Admin\Auth\Login` |
specs/06-AUTH-AND-SECURITY.md:22:#### Admin Login Flow
specs/06-AUTH-AND-SECURITY.md:59:#### Remember Me
specs/06-AUTH-AND-SECURITY.md:66:#### Admin Password Reset Flow
specs/06-AUTH-AND-SECURITY.md:105:#### Admin Logout
specs/06-AUTH-AND-SECURITY.md:111:#### Session Lifetime
specs/06-AUTH-AND-SECURITY.md:113:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:115:| Lifetime | 120 minutes (configurable via `SESSION_LIFETIME` env var) |
specs/06-AUTH-AND-SECURITY.md:116:| Expire on close | No (session persists until lifetime expires) |
specs/06-AUTH-AND-SECURITY.md:120:### 1.2 Customer Authentication
specs/06-AUTH-AND-SECURITY.md:122:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:124:| Guard name | `customer` (custom guard) |
specs/06-AUTH-AND-SECURITY.md:125:| Provider name | `customers` (Eloquent driver) |
specs/06-AUTH-AND-SECURITY.md:126:| Model | `App\Models\Customer` |
specs/06-AUTH-AND-SECURITY.md:127:| Driver | Session (cookie-based) |
specs/06-AUTH-AND-SECURITY.md:128:| Login route | `GET /account/login` |
specs/06-AUTH-AND-SECURITY.md:129:| Registration route | `GET /account/register` |
specs/06-AUTH-AND-SECURITY.md:131:#### Customer Login Flow
specs/06-AUTH-AND-SECURITY.md:165:#### Customer Registration Flow
specs/06-AUTH-AND-SECURITY.md:179:| Field | Type | Required | Validation |
specs/06-AUTH-AND-SECURITY.md:181:| name | string | Y | max:255 |
specs/06-AUTH-AND-SECURITY.md:182:| email | string | Y | valid email, unique per store (composite unique on email + store_id) |
specs/06-AUTH-AND-SECURITY.md:183:| password | string | Y | min:8, confirmed |
specs/06-AUTH-AND-SECURITY.md:184:| password_confirmation | string | Y | must match password |
specs/06-AUTH-AND-SECURITY.md:185:| marketing_opt_in | boolean | N | defaults to false |
specs/06-AUTH-AND-SECURITY.md:187:#### Customer Store Scoping
specs/06-AUTH-AND-SECURITY.md:194:#### Customer Password Reset
specs/06-AUTH-AND-SECURITY.md:206:### 1.3 API Authentication (Sanctum)
specs/06-AUTH-AND-SECURITY.md:208:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:210:| Guard name | `sanctum` |
specs/06-AUTH-AND-SECURITY.md:211:| Provider | `users` (admin users only) |
specs/06-AUTH-AND-SECURITY.md:212:| Token type | Personal access tokens |
specs/06-AUTH-AND-SECURITY.md:213:| Token prefix | `shop_` |
specs/06-AUTH-AND-SECURITY.md:214:| Hashing | SHA-256 |
specs/06-AUTH-AND-SECURITY.md:215:| Default expiration | 1 year |
specs/06-AUTH-AND-SECURITY.md:216:| Storage | `personal_access_tokens` table |
specs/06-AUTH-AND-SECURITY.md:218:#### Token Lifecycle
specs/06-AUTH-AND-SECURITY.md:242:#### Token Abilities (Scopes)
specs/06-AUTH-AND-SECURITY.md:244:| Ability | Description |
specs/06-AUTH-AND-SECURITY.md:246:| `read-products` | List and view products |
specs/06-AUTH-AND-SECURITY.md:247:| `write-products` | Create, update, delete products |
specs/06-AUTH-AND-SECURITY.md:248:| `read-orders` | List and view orders |
specs/06-AUTH-AND-SECURITY.md:249:| `write-orders` | Update orders, create fulfillments |
specs/06-AUTH-AND-SECURITY.md:250:| `read-customers` | List and view customers |
specs/06-AUTH-AND-SECURITY.md:251:| `write-customers` | Update customers |
specs/06-AUTH-AND-SECURITY.md:252:| `read-collections` | List and view collections |
specs/06-AUTH-AND-SECURITY.md:253:| `write-collections` | Create, update, delete collections |
specs/06-AUTH-AND-SECURITY.md:254:| `read-discounts` | List and view discounts |
specs/06-AUTH-AND-SECURITY.md:255:| `write-discounts` | Create, update, delete discounts |
specs/06-AUTH-AND-SECURITY.md:256:| `read-analytics` | View analytics data |
specs/06-AUTH-AND-SECURITY.md:257:| `read-settings` | View store settings (general, shipping, taxes, checkout, notifications) |
specs/06-AUTH-AND-SECURITY.md:258:| `write-settings` | Update store settings (replaces the legacy `manage-store`, `manage-shipping`, `manage-taxes` scopes) |
specs/06-AUTH-AND-SECURITY.md:259:| `read-themes` | View themes and theme files |
specs/06-AUTH-AND-SECURITY.md:260:| `write-themes` | Create, update, delete, publish themes |
specs/06-AUTH-AND-SECURITY.md:261:| `read-content` | View pages and navigation menus |
specs/06-AUTH-AND-SECURITY.md:262:| `write-content` | Create, update, delete pages and navigation items |
specs/06-AUTH-AND-SECURITY.md:263:| `manage-platform` | Platform-level management (super-admin only) |
specs/06-AUTH-AND-SECURITY.md:269:### 1.4 Guard Configuration
specs/06-AUTH-AND-SECURITY.md:273:#### Guards Data Dictionary
specs/06-AUTH-AND-SECURITY.md:275:| Guard Name | Driver | Provider | Purpose |
specs/06-AUTH-AND-SECURITY.md:277:| `web` | session | `users` | Admin panel session auth (default guard) |
specs/06-AUTH-AND-SECURITY.md:278:| `customer` | session | `customers` | Storefront customer session auth |
specs/06-AUTH-AND-SECURITY.md:279:| `sanctum` | sanctum | `users` | Admin REST API token auth |
specs/06-AUTH-AND-SECURITY.md:281:#### Providers Data Dictionary
specs/06-AUTH-AND-SECURITY.md:283:| Provider Name | Driver | Model | Purpose |
specs/06-AUTH-AND-SECURITY.md:285:| `users` | eloquent | `App\Models\User` | Admin users |
specs/06-AUTH-AND-SECURITY.md:286:| `customers` | eloquent | `App\Models\Customer` | Storefront customers (store-scoped via custom provider) |
specs/06-AUTH-AND-SECURITY.md:288:#### Password Brokers Data Dictionary
specs/06-AUTH-AND-SECURITY.md:290:| Broker Name | Provider | Token Table | Expiry | Throttle |
specs/06-AUTH-AND-SECURITY.md:292:| `users` | `users` | `password_reset_tokens` | 60 min | 60 sec |
specs/06-AUTH-AND-SECURITY.md:293:| `customers` | `customers` | `customer_password_reset_tokens` | 60 min | 60 sec |
specs/06-AUTH-AND-SECURITY.md:299:## 2. Authorization
specs/06-AUTH-AND-SECURITY.md:301:### 2.1 Role Enum
specs/06-AUTH-AND-SECURITY.md:307:| Case | Stored Value | Description |
specs/06-AUTH-AND-SECURITY.md:309:| Owner | `'owner'` | Full access. Can transfer ownership, manage billing, delete store. One per store. |
specs/06-AUTH-AND-SECURITY.md:310:| Admin | `'admin'` | Near-full access. Cannot transfer ownership or delete store. |
specs/06-AUTH-AND-SECURITY.md:311:| Staff | `'staff'` | Operational access. Can manage products, orders, collections, discounts, pages. Cannot access settings, themes, staff management, or developers. |
specs/06-AUTH-AND-SECURITY.md:312:| Support | `'support'` | Read-only access to products, orders, and customers. For customer service agents. |
specs/06-AUTH-AND-SECURITY.md:322:### 2.2 Permission Matrix
specs/06-AUTH-AND-SECURITY.md:326:| Resource | Action | Owner | Admin | Staff | Support |
specs/06-AUTH-AND-SECURITY.md:328:| Store Settings | View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:329:| Store Settings | Update | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:330:| Store | Delete | Y | N | N | N |
specs/06-AUTH-AND-SECURITY.md:331:| Products | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:332:| Products | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:333:| Products | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:334:| Products | Delete / Archive | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:335:| Products | Restore | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:336:| Collections | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:337:| Collections | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:338:| Collections | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:339:| Collections | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:340:| Orders | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:341:| Orders | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:342:| Orders | Cancel | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:343:| Fulfillments | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:344:| Fulfillments | Update / Cancel | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:345:| Refunds | Create | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:346:| Customers | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:347:| Customers | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:348:| Discounts | List / View | Y | Y | Y | Y |
specs/06-AUTH-AND-SECURITY.md:349:| Discounts | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:350:| Discounts | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:351:| Discounts | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:352:| Themes | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:353:| Themes | Create / Upload | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:354:| Themes | Customize | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:355:| Themes | Publish | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:356:| Themes | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:357:| Pages | List / View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:358:| Pages | Create | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:359:| Pages | Update | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:360:| Pages | Delete | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:361:| Navigation | List / View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:362:| Navigation | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:363:| Apps | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:364:| Apps | Install / Remove | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:365:| Analytics | View | Y | Y | Y | N |
specs/06-AUTH-AND-SECURITY.md:366:| Developers / API | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:367:| Staff | List / View | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:368:| Staff | Invite | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:369:| Staff | Update Role | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:370:| Staff | Remove | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:371:| Shipping Zones | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:372:| Tax Settings | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:373:| Search Settings | Manage | Y | Y | N | N |
specs/06-AUTH-AND-SECURITY.md:375:#### Role Group Shorthand
specs/06-AUTH-AND-SECURITY.md:379:| Group Name | Roles Included | Used For |
specs/06-AUTH-AND-SECURITY.md:381:| OwnerOnly | Owner | Store deletion, ownership transfer |
specs/06-AUTH-AND-SECURITY.md:382:| OwnerOrAdmin | Owner, Admin | Settings, themes, staff, developers, navigation, apps, shipping, taxes, search, delete/archive actions |
specs/06-AUTH-AND-SECURITY.md:383:| OwnerAdminOrStaff | Owner, Admin, Staff | Create/update products, collections, discounts, pages, fulfillments, order updates |
specs/06-AUTH-AND-SECURITY.md:384:| AnyRole | Owner, Admin, Staff, Support | Read-only listing/viewing of products, orders, customers, collections, discounts |
specs/06-AUTH-AND-SECURITY.md:388:### 2.3 Role Checking Trait
specs/06-AUTH-AND-SECURITY.md:394:| Method | Parameters | Returns | Description |
specs/06-AUTH-AND-SECURITY.md:396:| `getStoreRole` | User, store_id (int) | StoreUserRole or null | Looks up the user's role for the given store via the `store_users` relationship. Returns null if the user has no role in that store. |
specs/06-AUTH-AND-SECURITY.md:397:| `hasRole` | User, store_id (int), roles (array of StoreUserRole) | bool | Returns true if the user's role for the store is in the provided list. Returns false if user has no role. |
specs/06-AUTH-AND-SECURITY.md:398:| `isOwnerOrAdmin` | User, store_id (int) | bool | Shorthand: checks if role is Owner or Admin. |
specs/06-AUTH-AND-SECURITY.md:399:| `isOwnerAdminOrStaff` | User, store_id (int) | bool | Shorthand: checks if role is Owner, Admin, or Staff. |
specs/06-AUTH-AND-SECURITY.md:400:| `isAnyRole` | User, store_id (int) | bool | Returns true if the user has any role at all in the store. |
specs/06-AUTH-AND-SECURITY.md:406:### 2.4 Laravel Policies
specs/06-AUTH-AND-SECURITY.md:415:#### ProductPolicy
specs/06-AUTH-AND-SECURITY.md:419:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:421:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:422:| `view(User, Product)` | Yes | AnyRole | product.store_id |
specs/06-AUTH-AND-SECURITY.md:423:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:424:| `update(User, Product)` | Yes | OwnerAdminOrStaff | product.store_id |
specs/06-AUTH-AND-SECURITY.md:425:| `delete(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:426:| `archive(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:427:| `restore(User, Product)` | Yes | OwnerOrAdmin | product.store_id |
specs/06-AUTH-AND-SECURITY.md:429:#### OrderPolicy
specs/06-AUTH-AND-SECURITY.md:433:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:435:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:436:| `view(User, Order)` | Yes | AnyRole | order.store_id |
specs/06-AUTH-AND-SECURITY.md:437:| `update(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:438:| `cancel(User, Order)` | Yes | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:439:| `createFulfillment(User, Order)` | Yes | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:440:| `createRefund(User, Order)` | Yes | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:442:#### CollectionPolicy
specs/06-AUTH-AND-SECURITY.md:446:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:448:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:449:| `view(User, Collection)` | Yes | AnyRole | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:450:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:451:| `update(User, Collection)` | Yes | OwnerAdminOrStaff | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:452:| `delete(User, Collection)` | Yes | OwnerOrAdmin | collection.store_id |
specs/06-AUTH-AND-SECURITY.md:454:#### DiscountPolicy
specs/06-AUTH-AND-SECURITY.md:458:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:460:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:461:| `view(User, Discount)` | Yes | AnyRole | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:462:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:463:| `update(User, Discount)` | Yes | OwnerAdminOrStaff | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:464:| `delete(User, Discount)` | Yes | OwnerOrAdmin | discount.store_id |
specs/06-AUTH-AND-SECURITY.md:466:#### CustomerPolicy
specs/06-AUTH-AND-SECURITY.md:470:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:472:| `viewAny(User)` | No | AnyRole | current_store |
specs/06-AUTH-AND-SECURITY.md:473:| `view(User, Customer)` | Yes | AnyRole | customer.store_id |
specs/06-AUTH-AND-SECURITY.md:474:| `update(User, Customer)` | Yes | OwnerAdminOrStaff | customer.store_id |
specs/06-AUTH-AND-SECURITY.md:476:#### ThemePolicy
specs/06-AUTH-AND-SECURITY.md:480:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:482:| `viewAny(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:483:| `view(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:484:| `create(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:485:| `update(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:486:| `delete(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:487:| `publish(User, Theme)` | Yes | OwnerOrAdmin | theme.store_id |
specs/06-AUTH-AND-SECURITY.md:489:#### PagePolicy
specs/06-AUTH-AND-SECURITY.md:493:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:495:| `viewAny(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:496:| `view(User, Page)` | Yes | OwnerAdminOrStaff | page.store_id |
specs/06-AUTH-AND-SECURITY.md:497:| `create(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:498:| `update(User, Page)` | Yes | OwnerAdminOrStaff | page.store_id |
specs/06-AUTH-AND-SECURITY.md:499:| `delete(User, Page)` | Yes | OwnerOrAdmin | page.store_id |
specs/06-AUTH-AND-SECURITY.md:501:#### StorePolicy
specs/06-AUTH-AND-SECURITY.md:505:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:507:| `viewSettings(User, Store)` | Yes | OwnerOrAdmin | store.id |
specs/06-AUTH-AND-SECURITY.md:508:| `updateSettings(User, Store)` | Yes | OwnerOrAdmin | store.id |
specs/06-AUTH-AND-SECURITY.md:509:| `delete(User, Store)` | Yes | OwnerOnly | store.id |
specs/06-AUTH-AND-SECURITY.md:511:#### FulfillmentPolicy
specs/06-AUTH-AND-SECURITY.md:515:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:517:| `create(User, Order)` | Yes (Order) | OwnerAdminOrStaff | order.store_id |
specs/06-AUTH-AND-SECURITY.md:518:| `update(User, Fulfillment)` | Yes | OwnerAdminOrStaff | fulfillment -> order.store_id |
specs/06-AUTH-AND-SECURITY.md:519:| `cancel(User, Fulfillment)` | Yes | OwnerAdminOrStaff | fulfillment -> order.store_id |
specs/06-AUTH-AND-SECURITY.md:523:#### RefundPolicy
specs/06-AUTH-AND-SECURITY.md:527:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:529:| `create(User, Order)` | Yes (Order) | OwnerOrAdmin | order.store_id |
specs/06-AUTH-AND-SECURITY.md:533:#### NavigationMenuPolicy
specs/06-AUTH-AND-SECURITY.md:537:| Method | Receives Model? | Required Roles | Store ID Source |
specs/06-AUTH-AND-SECURITY.md:539:| `viewAny(User)` | No | OwnerAdminOrStaff | current_store |
specs/06-AUTH-AND-SECURITY.md:540:| `manage(User)` | No | OwnerOrAdmin | current_store |
specs/06-AUTH-AND-SECURITY.md:544:### 2.5 Gates (Non-Model Operations)
specs/06-AUTH-AND-SECURITY.md:548:| Gate Name | Required Roles | Purpose |
specs/06-AUTH-AND-SECURITY.md:550:| `manage-store-settings` | Owner, Admin | Access store settings pages |
specs/06-AUTH-AND-SECURITY.md:551:| `manage-staff` | Owner, Admin | Invite, update, remove staff members |
specs/06-AUTH-AND-SECURITY.md:552:| `manage-developers` | Owner, Admin | Create/revoke API tokens, manage webhooks |
specs/06-AUTH-AND-SECURITY.md:553:| `view-analytics` | Owner, Admin, Staff | View analytics dashboard and reports |
specs/06-AUTH-AND-SECURITY.md:554:| `manage-shipping` | Owner, Admin | Manage shipping zones, rates, profiles |
specs/06-AUTH-AND-SECURITY.md:555:| `manage-taxes` | Owner, Admin | Manage tax settings and rates |
specs/06-AUTH-AND-SECURITY.md:556:| `manage-search-settings` | Owner, Admin | Configure search weights and synonyms |
specs/06-AUTH-AND-SECURITY.md:557:| `manage-navigation` | Owner, Admin | Create/edit/delete navigation menus |
specs/06-AUTH-AND-SECURITY.md:558:| `manage-apps` | Owner, Admin | Install and remove third-party apps |
specs/06-AUTH-AND-SECURITY.md:570:### 2.6 Policy and Gate Usage Patterns
specs/06-AUTH-AND-SECURITY.md:572:#### In Livewire Components
specs/06-AUTH-AND-SECURITY.md:578:#### In API Controllers
specs/06-AUTH-AND-SECURITY.md:584:#### In Blade T…2282 tokens truncated…0:| `blockquote` | none |
specs/06-AUTH-AND-SECURITY.md:831:| `table`, `thead`, `tbody`, `tr`, `th`, `td` | none |
specs/06-AUTH-AND-SECURITY.md:832:| `div`, `span` | none |
specs/06-AUTH-AND-SECURITY.md:840:### 4.6 SQL Injection Prevention
specs/06-AUTH-AND-SECURITY.md:849:#### FTS5 Input Sanitization
specs/06-AUTH-AND-SECURITY.md:859:### 4.7 Mass Assignment Protection
specs/06-AUTH-AND-SECURITY.md:869:### 4.8 Password Security
specs/06-AUTH-AND-SECURITY.md:871:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:873:| Minimum length | 8 characters (for both admin and customer passwords) |
specs/06-AUTH-AND-SECURITY.md:874:| Hashing algorithm | Bcrypt (Laravel default) |
specs/06-AUTH-AND-SECURITY.md:875:| Password in logs | Never logged - use Laravel's built-in log redaction |
specs/06-AUTH-AND-SECURITY.md:876:| Password in API responses | Never returned - `password` and `remember_token` must be in the model's `$hidden` array |
specs/06-AUTH-AND-SECURITY.md:896:## 5. Session Configuration
specs/06-AUTH-AND-SECURITY.md:900:| Setting | Value | Rationale |
specs/06-AUTH-AND-SECURITY.md:902:| `driver` | `'file'` | Simple, no external dependencies. Compatible with SQLite-based stack without needing Redis. |
specs/06-AUTH-AND-SECURITY.md:903:| `lifetime` | 120 (minutes) | Configurable via `SESSION_LIFETIME` env var. |
specs/06-AUTH-AND-SECURITY.md:904:| `expire_on_close` | `false` | Session persists until lifetime expires, not on browser close. |
specs/06-AUTH-AND-SECURITY.md:905:| `encrypt` | `true` | Session data encrypted at rest on disk. |
specs/06-AUTH-AND-SECURITY.md:906:| `cookie` | `'shop_session'` | Custom name to avoid generic fingerprinting. Configurable via `SESSION_COOKIE` env var. |
specs/06-AUTH-AND-SECURITY.md:907:| `path` | `'/'` | Cookie available across entire domain. |
specs/06-AUTH-AND-SECURITY.md:908:| `domain` | `null` | Laravel determines from request. |
specs/06-AUTH-AND-SECURITY.md:909:| `secure` | `true` | HTTPS-only cookies in production. Configurable via `SESSION_SECURE_COOKIE` env var (set to false for local dev). |
specs/06-AUTH-AND-SECURITY.md:910:| `http_only` | `true` | Cookie inaccessible to JavaScript (mitigates XSS-based cookie theft). |
specs/06-AUTH-AND-SECURITY.md:911:| `same_site` | `'lax'` | Allows navigation-initiated requests while preventing CSRF from external origins. |
specs/06-AUTH-AND-SECURITY.md:912:| `partitioned` | `false` | Not needed for this use case. |
specs/06-AUTH-AND-SECURITY.md:916:## 6. CORS Configuration
specs/06-AUTH-AND-SECURITY.md:920:| Setting | Value | Rationale |
specs/06-AUTH-AND-SECURITY.md:922:| `paths` | `['api/*', 'sanctum/csrf-cookie']` | Only API and Sanctum CSRF cookie endpoints are CORS-enabled. Web routes are not. |
specs/06-AUTH-AND-SECURITY.md:923:| `allowed_methods` | `['*']` | All HTTP methods allowed for API. |
specs/06-AUTH-AND-SECURITY.md:924:| `allowed_origins` | `[FRONTEND_URL env var, default '*']` | Restrict to store domain in production. Wildcard for development. |
specs/06-AUTH-AND-SECURITY.md:925:| `allowed_origins_patterns` | `[]` | No pattern-based origin matching needed. |
specs/06-AUTH-AND-SECURITY.md:926:| `allowed_headers` | `['*']` | All headers allowed (Authorization, Content-Type, etc.). |
specs/06-AUTH-AND-SECURITY.md:927:| `exposed_headers` | `['X-RateLimit-Limit', 'X-RateLimit-Remaining', 'Retry-After']` | Expose rate limit headers so API clients can implement backoff. |
specs/06-AUTH-AND-SECURITY.md:928:| `max_age` | `0` | No preflight caching (conservative default). |
specs/06-AUTH-AND-SECURITY.md:929:| `supports_credentials` | `true` | Required for Sanctum SPA auth (cookies). |
specs/06-AUTH-AND-SECURITY.md:933:## 7. Webhook Signature Verification
specs/06-AUTH-AND-SECURITY.md:935:### 7.1 Inbound Payment Webhooks
specs/06-AUTH-AND-SECURITY.md:941:### 7.2 Platform Webhooks (Outbound)
specs/06-AUTH-AND-SECURITY.md:975:## 8. Audit Logging
specs/06-AUTH-AND-SECURITY.md:977:### 8.1 Logging Channel
specs/06-AUTH-AND-SECURITY.md:981:| Setting | Value |
specs/06-AUTH-AND-SECURITY.md:983:| Driver | `daily` (file-based, daily rotation) |
specs/06-AUTH-AND-SECURITY.md:984:| Path | `storage/logs/audit.log` |
specs/06-AUTH-AND-SECURITY.md:985:| Level | `info` |
specs/06-AUTH-AND-SECURITY.md:986:| Retention | 90 days |
specs/06-AUTH-AND-SECURITY.md:990:### 8.2 Log Entry Format
specs/06-AUTH-AND-SECURITY.md:994:| Field | Type | Required | Description |
specs/06-AUTH-AND-SECURITY.md:996:| `timestamp` | string (ISO-8601) | Y | When the event occurred |
specs/06-AUTH-AND-SECURITY.md:997:| `event` | string | Y | Event identifier (e.g., `product.updated`, `auth.login`) |
specs/06-AUTH-AND-SECURITY.md:998:| `user_id` | integer or null | N | ID of the admin user who triggered the event |
specs/06-AUTH-AND-SECURITY.md:999:| `store_id` | integer or null | N | ID of the store context |
specs/06-AUTH-AND-SECURITY.md:1000:| `resource_type` | string or null | N | Type of resource affected (e.g., `product`, `order`) |
specs/06-AUTH-AND-SECURITY.md:1001:| `resource_id` | integer or null | N | ID of the affected resource |
specs/06-AUTH-AND-SECURITY.md:1002:| `ip` | string | Y | Client IP address |
specs/06-AUTH-AND-SECURITY.md:1003:| `user_agent` | string | Y | Client user agent string |
specs/06-AUTH-AND-SECURITY.md:1004:| `changes` | object or null | N | For update events: object mapping field names to `[old_value, new_value]` tuples |
specs/06-AUTH-AND-SECURITY.md:1005:| (additional keys) | varies | N | Event-specific extra data |
specs/06-AUTH-AND-SECURITY.md:1009:### 8.3 Events to Log
specs/06-AUTH-AND-SECURITY.md:1011:#### Authentication Events
specs/06-AUTH-AND-SECURITY.md:1013:| Event ID | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1015:| `auth.login` | Successful admin login | user_id, ip, user_agent |
specs/06-AUTH-AND-SECURITY.md:1016:| `auth.logout` | Admin logout | user_id |
specs/06-AUTH-AND-SECURITY.md:1017:| `auth.failed_login` | Failed admin login attempt | email (never password), ip, user_agent |
specs/06-AUTH-AND-SECURITY.md:1018:| `customer.login` | Successful customer login | customer_id, store_id, ip |
specs/06-AUTH-AND-SECURITY.md:1019:| `customer.registered` | New customer registration | customer_id, store_id |
specs/06-AUTH-AND-SECURITY.md:1020:| `customer.failed_login` | Failed customer login attempt | email, store_id, ip |
specs/06-AUTH-AND-SECURITY.md:1022:#### Admin Resource Events
specs/06-AUTH-AND-SECURITY.md:1028:| Event Pattern | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1030:| `{resource}.created` | Resource created | resource_id, key attributes of the new resource |
specs/06-AUTH-AND-SECURITY.md:1031:| `{resource}.updated` | Resource updated | resource_id, `changes` object with old/new values for each changed field |
specs/06-AUTH-AND-SECURITY.md:1032:| `{resource}.deleted` | Resource soft-deleted or archived | resource_id |
specs/06-AUTH-AND-SECURITY.md:1033:| `{resource}.restored` | Resource restored from soft-delete | resource_id |
specs/06-AUTH-AND-SECURITY.md:1035:#### Security Events
specs/06-AUTH-AND-SECURITY.md:1037:| Event ID | Trigger | Extra Data |
specs/06-AUTH-AND-SECURITY.md:1039:| `api_token.created` | New API token issued | token_name, abilities list, user_id |
specs/06-AUTH-AND-SECURITY.md:1040:| `api_token.revoked` | API token revoked | token_name, user_id |
specs/06-AUTH-AND-SECURITY.md:1041:| `webhook.signature_invalid` | Outbound webhook delivery failed signature verification at subscriber | subscriber_url, ip |
specs/06-AUTH-AND-SECURITY.md:1042:| `store.settings_changed` | Store settings updated | changed fields with old/new values |
specs/06-AUTH-AND-SECURITY.md:1046:### 8.4 Audit Logger Service
specs/06-AUTH-AND-SECURITY.md:1054:| Parameter | Type | Required | Description |
specs/06-AUTH-AND-SECURITY.md:1056:| `event` | string | Y | Event identifier |
specs/06-AUTH-AND-SECURITY.md:1057:| `userId` | int or null | N | Acting user ID |
specs/06-AUTH-AND-SECURITY.md:1058:| `storeId` | int or null | N | Store context ID |
specs/06-AUTH-AND-SECURITY.md:1059:| `resourceType` | string or null | N | Affected resource type |
specs/06-AUTH-AND-SECURITY.md:1060:| `resourceId` | int or null | N | Affected resource ID |
specs/06-AUTH-AND-SECURITY.md:1061:| `extra` | associative array | N | Additional key-value pairs to include in the log entry |
specs/06-AUTH-AND-SECURITY.md:1071:### 8.5 Integration with Laravel Events
specs/06-AUTH-AND-SECURITY.md:1075:#### Auth Event Listeners
specs/06-AUTH-AND-SECURITY.md:1079:| Laravel Event | Audit Event ID | Data Captured |
specs/06-AUTH-AND-SECURITY.md:1081:| `Illuminate\Auth\Events\Login` | `auth.login` | user_id from event |
specs/06-AUTH-AND-SECURITY.md:1082:| `Illuminate\Auth\Events\Failed` | `auth.failed_login` | email from credentials (never password) |
specs/06-AUTH-AND-SECURITY.md:1083:| `Illuminate\Auth\Events\Logout` | `auth.logout` | user_id from event |
specs/06-AUTH-AND-SECURITY.md:1085:#### Model Observers
specs/06-AUTH-AND-SECURITY.md:1091:## 9. Security Checklist Summary
specs/06-AUTH-AND-SECURITY.md:1093:| # | Control | Implementation Approach | Priority |
specs/06-AUTH-AND-SECURITY.md:1095:| 1 | Session-based auth (admin) | Laravel `web` guard with bcrypt, session regeneration on login | Required |
specs/06-AUTH-AND-SECURITY.md:1096:| 2 | Session-based auth (customer) | Custom `customer` guard, store-scoped via custom user provider | Required |
specs/06-AUTH-AND-SECURITY.md:1097:| 3 | API token auth | Sanctum personal access tokens with per-token abilities | Required |
specs/06-AUTH-AND-SECURITY.md:1098:| 4 | Role-based access control | `StoreUserRole` enum, Laravel policies on all models, gates for non-model ops | Required |
specs/06-AUTH-AND-SECURITY.md:1099:| 5 | CSRF protection | `@csrf` on all session forms, Livewire auto-handles, API routes exempt | Required |
specs/06-AUTH-AND-SECURITY.md:1100:| 6 | Rate limiting | Seven named limiters (login, api.admin, api.storefront, checkout, search, analytics, webhooks) | Required |
specs/06-AUTH-AND-SECURITY.md:1101:| 7 | Input validation | Dedicated Form Request class for every write endpoint | Required |
specs/06-AUTH-AND-SECURITY.md:1102:| 8 | XSS prevention | Blade auto-escaping by default, HTMLPurifier for rich content fields | Required |
specs/06-AUTH-AND-SECURITY.md:1103:| 9 | SQL injection prevention | Eloquent ORM with parameterized queries, FTS5 input sanitization | Required |
specs/06-AUTH-AND-SECURITY.md:1104:| 10 | Mass assignment protection | `$fillable` on all models, always use `$request->validated()` | Required |
specs/06-AUTH-AND-SECURITY.md:1105:| 11 | Encryption at rest | Laravel `encrypted` cast for secrets and sensitive JSON columns | Required |
specs/06-AUTH-AND-SECURITY.md:1106:| 12 | Password security | Bcrypt, min 8 characters, `$hidden` on User and Customer models | Required |
specs/06-AUTH-AND-SECURITY.md:1107:| 13 | Session security | Encrypted sessions, HTTP-only cookies, secure flag, SameSite=Lax | Required |
specs/06-AUTH-AND-SECURITY.md:1108:| 14 | Webhook signature verification | HMAC-SHA256 for outbound platform webhooks (no inbound payment webhooks - Mock PSP is in-process) | Required |
specs/06-AUTH-AND-SECURITY.md:1109:| 15 | Audit logging | Structured JSON to dedicated daily-rotation log channel, 90-day retention | Required |
specs/06-AUTH-AND-SECURITY.md:1110:| 16 | CORS | Restricted to `api/*` paths, credentials supported, rate limit headers exposed | Required |
specs/07-SEEDERS-AND-TEST-DATA.md:7:## 1. DatabaseSeeder Orchestration
specs/07-SEEDERS-AND-TEST-DATA.md:13:| Step | Seeder Class | Depends On | Purpose |
specs/07-SEEDERS-AND-TEST-DATA.md:15:| 1 | OrganizationSeeder | (none) | Creates billing organizations |
specs/07-SEEDERS-AND-TEST-DATA.md:16:| 2 | StoreSeeder | Organizations | Creates stores under organizations |
specs/07-SEEDERS-AND-TEST-DATA.md:17:| 3 | StoreDomainSeeder | Stores | Attaches hostnames to stores |
specs/07-SEEDERS-AND-TEST-DATA.md:18:| 4 | UserSeeder | (none) | Creates admin/staff user accounts |
specs/07-SEEDERS-AND-TEST-DATA.md:19:| 5 | StoreUserSeeder | Stores, Users | Links users to stores with roles (pivot) |
specs/07-SEEDERS-AND-TEST-DATA.md:20:| 6 | StoreSettingsSeeder | Stores | Inserts per-store JSON settings |
specs/07-SEEDERS-AND-TEST-DATA.md:21:| 7 | TaxSettingsSeeder | Stores | Configures tax mode and rates |
specs/07-SEEDERS-AND-TEST-DATA.md:22:| 8 | ShippingSeeder | Stores | Creates shipping zones and rates |
specs/07-SEEDERS-AND-TEST-DATA.md:23:| 9 | CollectionSeeder | Stores | Creates product collections |
specs/07-SEEDERS-AND-TEST-DATA.md:24:| 10 | ProductSeeder | Stores, Collections | Creates products, options, variants, inventory, collection assignments |
specs/07-SEEDERS-AND-TEST-DATA.md:25:| 11 | DiscountSeeder | Stores | Creates discount codes |
specs/07-SEEDERS-AND-TEST-DATA.md:26:| 12 | CustomerSeeder | Stores | Creates customer accounts with addresses |
specs/07-SEEDERS-AND-TEST-DATA.md:27:| 13 | OrderSeeder | Stores, Customers, Products, Variants, Discounts | Creates orders with lines, payments, fulfillments, refunds |
specs/07-SEEDERS-AND-TEST-DATA.md:28:| 14 | ThemeSeeder | Stores | Creates themes with settings |
specs/07-SEEDERS-AND-TEST-DATA.md:29:| 15 | PageSeeder | Stores | Creates content pages |
specs/07-SEEDERS-AND-TEST-DATA.md:30:| 16 | NavigationSeeder | Stores, Collections, Pages | Creates menus linking to collections and pages |
specs/07-SEEDERS-AND-TEST-DATA.md:31:| 17 | AnalyticsSeeder | Stores, Customers | Creates daily aggregates and event stream |
specs/07-SEEDERS-AND-TEST-DATA.md:32:| 18 | SearchSettingsSeeder | Stores | Configures search synonyms and stop words |
specs/07-SEEDERS-AND-TEST-DATA.md:69:## 2. Factory Definitions
specs/07-SEEDERS-AND-TEST-DATA.md:75:### 2.1 OrganizationFactory
specs/07-SEEDERS-AND-TEST-DATA.md:81:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:83:| name | Faker company name |
specs/07-SEEDERS-AND-TEST-DATA.md:84:| billing_email | Faker company email |
specs/07-SEEDERS-AND-TEST-DATA.md:90:### 2.2 StoreFactory
specs/07-SEEDERS-AND-TEST-DATA.md:96:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:98:| organization_id | Creates a new Organization via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:99:| name | Faker company name + " Store" suffix |
specs/07-SEEDERS-AND-TEST-DATA.md:100:| handle | Faker unique slug (2 words) |
specs/07-SEEDERS-AND-TEST-DATA.md:101:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:102:| default_currency | "EUR" |
specs/07-SEEDERS-AND-TEST-DATA.md:103:| default_locale | "en" |
specs/07-SEEDERS-AND-TEST-DATA.md:104:| timezone | "Europe/Berlin" |
specs/07-SEEDERS-AND-TEST-DATA.md:108:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:110:| `suspended` | status = "suspended" |
specs/07-SEEDERS-AND-TEST-DATA.md:114:### 2.3 StoreDomainFactory
specs/07-SEEDERS-AND-TEST-DATA.md:120:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:122:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:123:| hostname | Faker unique domain name |
specs/07-SEEDERS-AND-TEST-DATA.md:124:| type | "storefront" |
specs/07-SEEDERS-AND-TEST-DATA.md:125:| is_primary | 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:126:| tls_mode | "managed" |
specs/07-SEEDERS-AND-TEST-DATA.md:130:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:132:| `admin` | type = "admin" |
specs/07-SEEDERS-AND-TEST-DATA.md:133:| `api` | type = "api" |
specs/07-SEEDERS-AND-TEST-DATA.md:134:| `secondary` | is_primary = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:138:### 2.4 UserFactory
specs/07-SEEDERS-AND-TEST-DATA.md:144:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:146:| email | Faker unique safe email |
specs/07-SEEDERS-AND-TEST-DATA.md:147:| password_hash | bcrypt of "password" |
specs/07-SEEDERS-AND-TEST-DATA.md:148:| name | Faker full name |
specs/07-SEEDERS-AND-TEST-DATA.md:149:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:150:| last_login_at | Random date within the last 30 days |
specs/07-SEEDERS-AND-TEST-DATA.md:154:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:156:| `disabled` | status = "disabled" |
specs/07-SEEDERS-AND-TEST-DATA.md:160:### 2.5 ProductFactory
specs/07-SEEDERS-AND-TEST-DATA.md:166:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:168:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:169:| title | Faker 3 random words joined |
specs/07-SEEDERS-AND-TEST-DATA.md:170:| handle | URL-slug of the title |
specs/07-SEEDERS-AND-TEST-DATA.md:171:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:172:| description_html | Faker 2 paragraphs wrapped in `<p>` tags |
specs/07-SEEDERS-AND-TEST-DATA.md:173:| vendor | Faker company name |
specs/07-SEEDERS-AND-TEST-DATA.md:174:| product_type | Random from: Shirts, Pants, Shoes, Accessories, Electronics, Books |
specs/07-SEEDERS-AND-TEST-DATA.md:175:| tags | JSON array of 1-3 random picks from: new, sale, trending, popular, limited |
specs/07-SEEDERS-AND-TEST-DATA.md:176:| published_at | Current timestamp |
specs/07-SEEDERS-AND-TEST-DATA.md:180:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:182:| `draft` | status = "draft", published_at = null |
specs/07-SEEDERS-AND-TEST-DATA.md:183:| `archived` | status = "archived" |
specs/07-SEEDERS-AND-TEST-DATA.md:187:| Hook Name | Behavior |
specs/07-SEEDERS-AND-TEST-DATA.md:189:| `withVariants(count)` | After creating the product, create `count` ProductVariant records associated with the product |
specs/07-SEEDERS-AND-TEST-DATA.md:190:| `withDefaultVariant(price)` | After creating the product, create one ProductVariant marked as default at the given price in EUR |
specs/07-SEEDERS-AND-TEST-DATA.md:194:### 2.6 ProductVariantFactory
specs/07-SEEDERS-AND-TEST-DATA.md:200:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:202:| product_id | Creates a new Product via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:203:| sku | Faker unique, pattern: "SKU-####-???" (digits and letters) |
specs/07-SEEDERS-AND-TEST-DATA.md:204:| barcode | Faker EAN-13 |
specs/07-SEEDERS-AND-TEST-DATA.md:205:| price_amount | Random integer 999-19999 (9.99 to 199.99 EUR) |
specs/07-SEEDERS-AND-TEST-DATA.md:206:| compare_at_amount | null |
specs/07-SEEDERS-AND-TEST-DATA.md:207:| currency | "EUR" |
specs/07-SEEDERS-AND-TEST-DATA.md:208:| weight_g | Random integer 100-5000 |
specs/07-SEEDERS-AND-TEST-DATA.md:209:| requires_shipping | 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:210:| is_default | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:211:| position | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:212:| status | "active" |
specs/07-SEEDERS-AND-TEST-DATA.md:216:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:218:| `onSale` | compare_at_amount = random 20000-39999, price_amount = random 9999-19999 |
specs/07-SEEDERS-AND-TEST-DATA.md:219:| `digital` | requires_shipping = 0, weight_g = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:220:| `default` | is_default = 1 |
specs/07-SEEDERS-AND-TEST-DATA.md:221:| `archived` | status = "archived" |
specs/07-SEEDERS-AND-TEST-DATA.md:225:### 2.7 InventoryItemFactory
specs/07-SEEDERS-AND-TEST-DATA.md:231:| Field | Generation Rule |
specs/07-SEEDERS-AND-TEST-DATA.md:233:| store_id | Creates a new Store via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:234:| variant_id | Creates a new ProductVariant via its factory |
specs/07-SEEDERS-AND-TEST-DATA.md:235:| quantity_on_hand | Random integer 0-100 |
specs/07-SEEDERS-AND-TEST-DATA.md:236:| quantity_reserved | 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:237:| policy | "deny" |
specs/07-SEEDERS-AND-TEST-DATA.md:241:| State Name | Overrides |
specs/07-SEEDERS-AND-TEST-DATA.md:243:| `outOfStock` | quantity_on_hand = 0 |
specs/07-SEEDERS-AND-TEST-DATA.md:244:| `continuePolicy` | policy = "continue" |
specs/07-SEEDERS-AND-TEST-DATA.md:245:| `lowStock` | quantity_on_hand = random 1-3 |
specs/07-SEEDERS-AND-TEST-DATA.md:249:### 2.8 CollectionFactory


type: CommandExecution

command: php artisan route:list --except-vendor --json

type: unknown

status: completed

account.logout

method: POST

uri: account/logout

action: Closure

middleware: web App\Http\Middleware\ResolveStore

admin.logout

uri: admin/logout

method: GET|HEAD

method: PUT

method: DELETE

dashboard

uri: dashboard

action: Illuminate\Routing\ViewController

oauth.authorize

uri: oauth/authorize

oauth.token

uri: oauth/token

method: GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS

uri: settings

action: Illuminate\Routing\RedirectController