Input:
*** Begin Patch
*** Update File: app/Models/User.php
@@
 namespace App\Models;

 // use Illuminate\Contracts\Auth\MustVerifyEmail;
+use App\Enums\StoreUserRole;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
@@
         'name',
         'email',
-        'password',
+        'password_hash',
+        'status',
+        'last_login_at',
@@
-        'password',
+        'password_hash',
@@
             'email_verified_at' => 'datetime',
-            'password' => 'hashed',
+            'password_hash' => 'hashed',
+            'last_login_at' => 'datetime',
         ];
     }
+
+    public function getAuthPassword(): string
+    {
+        return $this->password_hash;
+    }
+
+    public function setPasswordAttribute(string $value): void
+    {
+        $this->attributes['password_hash'] = $value;
+    }
+
+    public function stores(): BelongsToMany
+    {
+        return $this->belongsToMany(Store::class, 'store_users')
+            ->using(StoreUser::class)
+            ->withPivot('role')
+            ->withTimestamps();
+    }
+
+    public function roleForStore(Store $store): ?StoreUserRole
+    {
+        $role = $this->stores()
+            ->whereKey($store->id)
+            ->first()
+            ?->pivot
+            ?->role;
+
+        return $role instanceof StoreUserRole ? $role : StoreUserRole::tryFrom((string) $role);
+    }
*** End Patch


Success. Updated the following files:
M app/Models/User.php

@@ -5,2 +5,4 @@
 // use Illuminate\Contracts\Auth\MustVerifyEmail;
+use App\Enums\StoreUserRole;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -24,3 +26,5 @@
         'email',
-        'password',
+        'password_hash',
+        'status',
+        'last_login_at',
     ];
@@ -33,3 +37,3 @@
     protected $hidden = [
-        'password',
+        'password_hash',
         'two_factor_secret',
@@ -48,3 +52,4 @@
             'email_verified_at' => 'datetime',
-            'password' => 'hashed',
+            'password_hash' => 'hashed',
+            'last_login_at' => 'datetime',
         ];
@@ -52,2 +57,31 @@

+    public function getAuthPassword(): string
+    {
+        return $this->password_hash;
+    }
+
+    public function setPasswordAttribute(string $value): void
+    {
+        $this->attributes['password_hash'] = $value;
+    }
+
+    public function stores(): BelongsToMany
+    {
+        return $this->belongsToMany(Store::class, 'store_users')
+            ->using(StoreUser::class)
+            ->withPivot('role')
+            ->withTimestamps();
+    }
+
+    public function roleForStore(Store $store): ?StoreUserRole
+    {
+        $role = $this->stores()
+            ->whereKey($store->id)
+            ->first()
+            ?->pivot
+            ?->role;
+
+        return $role instanceof StoreUserRole ? $role : StoreUserRole::tryFrom((string) $role);
+    }
+
     /**


Output: {"output":"Success. Updated the following files:\nM app/Models/User.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


Input:
*** Begin Patch
*** Add File: app/Enums/StoreStatus.php
+<?php
+
+namespace App\Enums;
+
+enum StoreStatus: string
+{
+    case Active = 'active';
+    case Suspended = 'suspended';
+}
+
*** Add File: app/Enums/StoreUserRole.php
+<?php
+
+namespace App\Enums;
+
+enum StoreUserRole: string
+{
+    case Owner = 'owner';
+    case Admin = 'admin';
+    case Staff = 'staff';
+    case Support = 'support';
+}
+
*** Add File: app/Enums/StoreDomainType.php
+<?php
+
+namespace App\Enums;
+
+enum StoreDomainType: string
+{
+    case Storefront = 'storefront';
+    case Admin = 'admin';
+    case Api = 'api';
+}
+
*** Add File: app/Enums/ProductStatus.php
+<?php
+
+namespace App\Enums;
+
+enum ProductStatus: string
+{
+    case Draft = 'draft';
+    case Active = 'active';
+    case Archived = 'archived';
+}
+
*** Add File: app/Enums/OrderStatus.php
+<?php
+
+namespace App\Enums;
+
+enum OrderStatus: string
+{
+    case Pending = 'pending';
+    case Paid = 'paid';
+    case PartiallyRefunded = 'partially_refunded';
+    case Refunded = 'refunded';
+    case Fulfilled = 'fulfilled';
+    case Cancelled = 'cancelled';
+}
+
*** Add File: app/Enums/PaymentStatus.php
+<?php
+
+namespace App\Enums;
+
+enum PaymentStatus: string
+{
+    case Pending = 'pending';
+    case Authorized = 'authorized';
+    case Paid = 'paid';
+    case Failed = 'failed';
+    case Refunded = 'refunded';
+}
+
*** Add File: app/Enums/CheckoutStatus.php
+<?php
+
+namespace App\Enums;
+
+enum CheckoutStatus: string
+{
+    case Started = 'started';
+    case Addressed = 'addressed';
+    case ShippingSelected = 'shipping_selected';
+    case PaymentSelected = 'payment_selected';
+    case Completed = 'completed';
+    case Expired = 'expired';
+}
+
*** Add File: app/Enums/DiscountType.php
+<?php
+
+namespace App\Enums;
+
+enum DiscountType: string
+{
+    case Percentage = 'percentage';
+    case FixedAmount = 'fixed_amount';
+    case FreeShipping = 'free_shipping';
+}
+
*** End Patch


Success. Updated the following files:
A app/Enums/StoreStatus.php
A app/Enums/StoreUserRole.php
A app/Enums/StoreDomainType.php
A app/Enums/ProductStatus.php
A app/Enums/OrderStatus.php
A app/Enums/PaymentStatus.php
A app/Enums/CheckoutStatus.php
A app/Enums/DiscountType.php

<?php

namespace App\Enums;

enum StoreUserRole: string
{
    case Owner = 'owner';
    case Admin = 'admin';
    case Staff = 'staff';
    case Support = 'support';
}

<?php

namespace App\Enums;

enum StoreDomainType: string
{
    case Storefront = 'storefront';
    case Admin = 'admin';
    case Api = 'api';
}

<?php

namespace App\Enums;

enum CheckoutStatus: string
{
    case Started = 'started';
    case Addressed = 'addressed';
    case ShippingSelected = 'shipping_selected';
    case PaymentSelected = 'payment_selected';
    case Completed = 'completed';
    case Expired = 'expired';
}

<?php

namespace App\Enums;

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
    case PartiallyRefunded = 'partially_refunded';
    case Refunded = 'refunded';
    case Fulfilled = 'fulfilled';
    case Cancelled = 'cancelled';
}

<?php

namespace App\Enums;

enum ProductStatus: string
{
    case Draft = 'draft';
    case Active = 'active';
    case Archived = 'archived';
}

<?php

namespace App\Enums;

enum DiscountType: string
{
    case Percentage = 'percentage';
    case FixedAmount = 'fixed_amount';
    case FreeShipping = 'free_shipping';
}

<?php

namespace App\Enums;

enum PaymentStatus: string
{
    case Pending = 'pending';
    case Authorized = 'authorized';
    case Paid = 'paid';
    case Failed = 'failed';
    case Refunded = 'refunded';
}

<?php

namespace App\Enums;

enum StoreStatus: string
{
    case Active = 'active';
    case Suspended = 'suspended';
}


Output: {"output":"Success. Updated the following files:\nA app/Enums/StoreStatus.php\nA app/Enums/StoreUserRole.php\nA app/Enums/StoreDomainType.php\nA app/Enums/ProductStatus.php\nA app/Enums/OrderStatus.php\nA app/Enums/PaymentStatus.php\nA app/Enums/CheckoutStatus.php\nA app/Enums/DiscountType.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


The password storage is now aligned with the spec’s `password_hash` column while keeping Laravel authentication compatible through `getAuthPassword()` and a password mutator. Next I’m adding the shop schema as a single ordered migration so SQLite foreign keys and tenant-scoped tables are created predictably.


Input:
*** Begin Patch
*** Add File: database/migrations/2026_04_25_000001_create_shop_domain_tables.php
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        DB::statement('PRAGMA foreign_keys = ON');
+
+        Schema::create('organizations', function (Blueprint $table): void {
+            $table->id();
+            $table->string('name');
+            $table->string('billing_email')->index();
+            $table->timestamps();
+        });
+
+        Schema::create('stores', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('organization_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->string('handle')->unique();
+            $table->string('status')->default('active')->index();
+            $table->string('default_currency', 3)->default('EUR');
+            $table->string('default_locale')->default('en');
+            $table->string('timezone')->default('UTC');
+            $table->timestamps();
+        });
+
+        Schema::create('store_domains', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('hostname')->unique();
+            $table->string('type')->default('storefront');
+            $table->boolean('is_primary')->default(false);
+            $table->string('tls_mode')->default('managed');
+            $table->timestamp('created_at')->nullable();
+            $table->index(['store_id', 'is_primary']);
+        });
+
+        Schema::create('store_users', function (Blueprint $table): void {
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+            $table->string('role')->default('staff');
+            $table->timestamps();
+            $table->primary(['store_id', 'user_id']);
+            $table->index(['store_id', 'role']);
+        });
+
+        Schema::create('store_settings', function (Blueprint $table): void {
+            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
+            $table->json('settings_json')->default('{}');
+            $table->timestamp('updated_at')->nullable();
+        });
+
+        Schema::create('products', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('title');
+            $table->string('handle');
+            $table->string('status')->default('draft');
+            $table->text('description_html')->nullable();
+            $table->string('vendor')->nullable();
+            $table->string('product_type')->nullable();
+            $table->json('tags')->default('[]');
+            $table->timestamp('published_at')->nullable();
+            $table->timestamps();
+            $table->unique(['store_id', 'handle']);
+            $table->index(['store_id', 'status']);
+            $table->index(['store_id', 'published_at']);
+            $table->index(['store_id', 'vendor']);
+            $table->index(['store_id', 'product_type']);
+        });
+
+        Schema::create('product_options', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->unsignedInteger('position')->default(0);
+            $table->unique(['product_id', 'position']);
+        });
+
+        Schema::create('product_option_values', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('product_option_id')->constrained()->cascadeOnDelete();
+            $table->string('value');
+            $table->unsignedInteger('position')->default(0);
+            $table->unique(['product_option_id', 'position']);
+        });
+
+        Schema::create('product_variants', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
+            $table->string('sku')->nullable()->index();
+            $table->string('barcode')->nullable()->index();
+            $table->unsignedInteger('price_amount')->default(0);
+            $table->unsignedInteger('compare_at_amount')->nullable();
+            $table->string('currency', 3)->default('EUR');
+            $table->unsignedInteger('weight_g')->nullable();
+            $table->boolean('requires_shipping')->default(true);
+            $table->boolean('is_default')->default(false);
+            $table->unsignedInteger('position')->default(0);
+            $table->string('status')->default('active');
+            $table->timestamps();
+            $table->index(['product_id', 'position']);
+            $table->index(['product_id', 'is_default']);
+        });
+
+        Schema::create('variant_option_values', function (Blueprint $table): void {
+            $table->foreignId('variant_id')->constrained('product_variants')->cascadeOnDelete();
+            $table->foreignId('product_option_value_id')->constrained()->cascadeOnDelete();
+            $table->primary(['variant_id', 'product_option_value_id'], 'variant_option_values_pk');
+        });
+
+        Schema::create('inventory_items', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('variant_id')->constrained('product_variants')->cascadeOnDelete();
+            $table->integer('quantity_available')->default(0);
+            $table->integer('quantity_reserved')->default(0);
+            $table->string('policy')->default('deny');
+            $table->timestamps();
+            $table->unique(['store_id', 'variant_id']);
+        });
+
+        Schema::create('collections', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('title');
+            $table->string('handle');
+            $table->text('description_html')->nullable();
+            $table->boolean('is_published')->default(true);
+            $table->timestamps();
+            $table->unique(['store_id', 'handle']);
+        });
+
+        Schema::create('collection_products', function (Blueprint $table): void {
+            $table->foreignId('collection_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
+            $table->unsignedInteger('position')->default(0);
+            $table->primary(['collection_id', 'product_id']);
+        });
+
+        Schema::create('product_media', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
+            $table->string('url');
+            $table->string('alt_text')->nullable();
+            $table->unsignedInteger('position')->default(0);
+            $table->timestamps();
+        });
+
+        Schema::create('themes', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->boolean('is_active')->default(false);
+            $table->json('settings_json')->default('{}');
+            $table->timestamps();
+        });
+
+        Schema::create('pages', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('title');
+            $table->string('handle');
+            $table->text('body_html');
+            $table->boolean('is_published')->default(true);
+            $table->timestamps();
+            $table->unique(['store_id', 'handle']);
+        });
+
+        Schema::create('navigation_menus', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('title');
+            $table->string('handle');
+            $table->timestamps();
+            $table->unique(['store_id', 'handle']);
+        });
+
+        Schema::create('navigation_items', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('navigation_menu_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('parent_id')->nullable()->constrained('navigation_items')->nullOnDelete();
+            $table->string('label');
+            $table->string('url');
+            $table->unsignedInteger('position')->default(0);
+            $table->timestamps();
+        });
+
+        Schema::create('customers', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('email');
+            $table->string('name');
+            $table->string('password_hash')->nullable();
+            $table->boolean('accepts_marketing')->default(false);
+            $table->timestamp('last_login_at')->nullable();
+            $table->timestamps();
+            $table->unique(['store_id', 'email']);
+        });
+
+        Schema::create('customer_addresses', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('customer_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->string('address1');
+            $table->string('address2')->nullable();
+            $table->string('city');
+            $table->string('postal_code');
+            $table->string('country_code', 2);
+            $table->boolean('is_default')->default(false);
+            $table->timestamps();
+        });
+
+        Schema::create('customer_password_reset_tokens', function (Blueprint $table): void {
+            $table->string('email');
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('token');
+            $table->timestamp('created_at')->nullable();
+            $table->primary(['store_id', 'email']);
+        });
+
+        Schema::create('carts', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
+            $table->string('currency', 3)->default('EUR');
+            $table->unsignedInteger('cart_version')->default(1);
+            $table->string('status')->default('active');
+            $table->string('discount_code')->nullable();
+            $table->timestamps();
+        });
+
+        Schema::create('cart_lines', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('cart_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('product_variant_id')->constrained('product_variants')->cascadeOnDelete();
+            $table->unsignedInteger('quantity');
+            $table->unsignedInteger('unit_price_amount');
+            $table->json('snapshot_json')->default('{}');
+            $table->timestamps();
+            $table->unique(['cart_id', 'product_variant_id']);
+        });
+
+        Schema::create('shipping_zones', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->json('countries')->default('[]');
+            $table->timestamps();
+        });
+
+        Schema::create('shipping_rates', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('shipping_zone_id')->constrained()->cascadeOnDelete();
+            $table->string('name');
+            $table->unsignedInteger('price_amount');
+            $table->unsignedInteger('min_order_amount')->nullable();
+            $table->timestamps();
+        });
+
+        Schema::create('tax_settings', function (Blueprint $table): void {
+            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
+            $table->boolean('prices_include_tax')->default(false);
+            $table->unsignedInteger('default_rate_bps')->default(1900);
+            $table->timestamp('updated_at')->nullable();
+        });
+
+        Schema::create('discounts', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('code');
+            $table->string('type');
+            $table->unsignedInteger('value_amount')->default(0);
+            $table->unsignedInteger('value_bps')->default(0);
+            $table->unsignedInteger('min_purchase_amount')->nullable();
+            $table->unsignedInteger('usage_limit')->nullable();
+            $table->unsignedInteger('used_count')->default(0);
+            $table->timestamp('starts_at')->nullable();
+            $table->timestamp('ends_at')->nullable();
+            $table->boolean('is_active')->default(true);
+            $table->timestamps();
+            $table->unique(['store_id', 'code']);
+        });
+
+        Schema::create('checkouts', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('cart_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
+            $table->string('status')->default('started');
+            $table->string('email')->nullable();
+            $table->json('shipping_address_json')->nullable();
+            $table->foreignId('shipping_rate_id')->nullable()->constrained()->nullOnDelete();
+            $table->string('payment_method')->nullable();
+            $table->foreignId('order_id')->nullable()->constrained()->nullOnDelete();
+            $table->json('totals_json')->default('{}');
+            $table->timestamps();
+        });
+
+        Schema::create('orders', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
+            $table->string('order_number');
+            $table->string('email');
+            $table->string('status')->default('pending');
+            $table->string('financial_status')->default('pending');
+            $table->string('fulfillment_status')->default('unfulfilled');
+            $table->string('currency', 3)->default('EUR');
+            $table->unsignedInteger('subtotal_amount')->default(0);
+            $table->unsignedInteger('discount_amount')->default(0);
+            $table->unsignedInteger('shipping_amount')->default(0);
+            $table->unsignedInteger('tax_amount')->default(0);
+            $table->unsignedInteger('total_amount')->default(0);
+            $table->json('shipping_address_json')->nullable();
+            $table->json('timeline_json')->default('[]');
+            $table->timestamps();
+            $table->unique(['store_id', 'order_number']);
+        });
+
+        Schema::create('order_lines', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('product_variant_id')->nullable()->constrained('product_variants')->nullOnDelete();
+            $table->string('title');
+            $table->string('sku')->nullable();
+            $table->unsignedInteger('quantity');
+            $table->unsignedInteger('unit_price_amount');
+            $table->unsignedInteger('total_amount');
+            $table->json('snapshot_json')->default('{}');
+            $table->timestamps();
+        });
+
+        Schema::create('payments', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
+            $table->string('provider')->default('mock');
+            $table->string('method');
+            $table->string('status');
+            $table->unsignedInteger('amount');
+            $table->string('reference')->nullable();
+            $table->text('raw_payload_encrypted')->nullable();
+            $table->timestamps();
+        });
+
+        Schema::create('refunds', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
+            $table->unsignedInteger('amount');
+            $table->string('reason')->nullable();
+            $table->boolean('restocked')->default(false);
+            $table->timestamps();
+        });
+
+        Schema::create('fulfillments', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
+            $table->string('status')->default('created');
+            $table->string('tracking_number')->nullable();
+            $table->timestamp('shipped_at')->nullable();
+            $table->timestamp('delivered_at')->nullable();
+            $table->timestamps();
+        });
+
+        Schema::create('fulfillment_lines', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('fulfillment_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('order_line_id')->constrained()->cascadeOnDelete();
+            $table->unsignedInteger('quantity');
+        });
+
+        Schema::create('search_settings', function (Blueprint $table): void {
+            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
+            $table->json('synonyms_json')->default('[]');
+            $table->json('stopwords_json')->default('[]');
+            $table->timestamp('updated_at')->nullable();
+        });
+
+        Schema::create('search_queries', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('query');
+            $table->unsignedInteger('results_count')->default(0);
+            $table->timestamp('created_at')->nullable();
+        });
+
+        Schema::create('analytics_events', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('event');
+            $table->json('payload_json')->default('{}');
+            $table->timestamp('created_at')->nullable();
+        });
+
+        Schema::create('analytics_daily', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->date('date');
+            $table->unsignedInteger('visitors')->default(0);
+            $table->unsignedInteger('orders_count')->default(0);
+            $table->unsignedInteger('sales_amount')->default(0);
+            $table->unique(['store_id', 'date']);
+        });
+
+        Schema::create('apps', function (Blueprint $table): void {
+            $table->id();
+            $table->string('name');
+            $table->string('handle')->unique();
+            $table->json('scopes')->default('[]');
+            $table->timestamps();
+        });
+
+        Schema::create('app_installations', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->foreignId('app_id')->constrained()->cascadeOnDelete();
+            $table->string('status')->default('installed');
+            $table->timestamps();
+        });
+
+        Schema::create('webhook_subscriptions', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
+            $table->string('topic');
+            $table->string('endpoint_url');
+            $table->string('secret');
+            $table->boolean('is_active')->default(true);
+            $table->timestamps();
+        });
+
+        Schema::create('webhook_deliveries', function (Blueprint $table): void {
+            $table->id();
+            $table->foreignId('webhook_subscription_id')->constrained()->cascadeOnDelete();
+            $table->string('status')->default('pending');
+            $table->unsignedInteger('attempts')->default(0);
+            $table->json('payload_json')->default('{}');
+            $table->timestamp('created_at')->nullable();
+        });
+    }
+
+    public function down(): void
+    {
+        foreach ([
+            'webhook_deliveries',
+            'webhook_subscriptions',
+            'app_installations',
+            'apps',
+            'analytics_daily',
+            'analytics_events',
+            'search_queries',
+            'search_settings',
+            'fulfillment_lines',
+            'fulfillments',
+            'refunds',
+            'payments',
+            'order_lines',
+            'orders',
+            'checkouts',
+            'discounts',
+            'tax_settings',
+            'shipping_rates',
+            'shipping_zones',
+            'cart_lines',
+            'carts',
+            'customer_password_reset_tokens',
+            'customer_addresses',
+            'customers',
+            'navigation_items',
+            'navigation_menus',
+            'pages',
+            'themes',
+            'product_media',
+            'collection_products',
+            'collections',
+            'inventory_items',
+            'variant_option_values',
+            'product_variants',
+            'product_option_values',
+            'product_options',
+            'products',
+            'store_settings',
+            'store_users',
+            'store_domains',
+            'stores',
+            'organizations',
+        ] as $table) {
+            Schema::dropIfExists($table);
+        }
+    }
+};
+
*** End Patch


Success. Updated the following files:
A database/migrations/2026_04_25_000001_create_shop_domain_tables.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        DB::statement('PRAGMA foreign_keys = ON');

        Schema::create('organizations', function (Blueprint $table): void {
            $table->id();
            $table->string('name');
            $table->string('billing_email')->index();
            $table->timestamps();
        });

        Schema::create('stores', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('organization_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->string('handle')->unique();
            $table->string('status')->default('active')->index();
            $table->string('default_currency', 3)->default('EUR');
            $table->string('default_locale')->default('en');
            $table->string('timezone')->default('UTC');
            $table->timestamps();
        });

        Schema::create('store_domains', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('hostname')->unique();
            $table->string('type')->default('storefront');
            $table->boolean('is_primary')->default(false);
            $table->string('tls_mode')->default('managed');
            $table->timestamp('created_at')->nullable();
            $table->index(['store_id', 'is_primary']);
        });

        Schema::create('store_users', function (Blueprint $table): void {
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('role')->default('staff');
            $table->timestamps();
            $table->primary(['store_id', 'user_id']);
            $table->index(['store_id', 'role']);
        });

        Schema::create('store_settings', function (Blueprint $table): void {
            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
            $table->json('settings_json')->default('{}');
            $table->timestamp('updated_at')->nullable();
        });

        Schema::create('products', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->string('handle');
            $table->string('status')->default('draft');
            $table->text('description_html')->nullable();
            $table->string('vendor')->nullable();
            $table->string('product_type')->nullable();
            $table->json('tags')->default('[]');
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
            $table->unique(['store_id', 'handle']);
            $table->index(['store_id', 'status']);
            $table->index(['store_id', 'published_at']);
            $table->index(['store_id', 'vendor']);
            $table->index(['store_id', 'product_type']);
        });

        Schema::create('product_options', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->unsignedInteger('position')->default(0);
            $table->unique(['product_id', 'position']);
        });

        Schema::create('product_option_values', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('product_option_id')->constrained()->cascadeOnDelete();
            $table->string('value');
            $table->unsignedInteger('position')->default(0);
            $table->unique(['product_option_id', 'position']);
        });

        Schema::create('product_variants', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
            $table->string('sku')->nullable()->index();
            $table->string('barcode')->nullable()->index();
            $table->unsignedInteger('price_amount')->default(0);
            $table->unsignedInteger('compare_at_amount')->nullable();
            $table->string('currency', 3)->default('EUR');
            $table->unsignedInteger('weight_g')->nullable();
            $table->boolean('requires_shipping')->default(true);
            $table->boolean('is_default')->default(false);
            $table->unsignedInteger('position')->default(0);
            $table->string('status')->default('active');
            $table->timestamps();
            $table->index(['product_id', 'position']);
            $table->index(['product_id', 'is_default']);
        });

        Schema::create('variant_option_values', function (Blueprint $table): void {
            $table->foreignId('variant_id')->constrained('product_variants')->cascadeOnDelete();
            $table->foreignId('product_option_value_id')->constrained()->cascadeOnDelete();
            $table->primary(['variant_id', 'product_option_value_id'], 'variant_option_values_pk');
        });

        Schema::create('inventory_items', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('variant_id')->constrained('product_variants')->cascadeOnDelete();
            $table->integer('quantity_available')->default(0);
            $table->integer('quantity_reserved')->default(0);
            $table->string('policy')->default('deny');
            $table->timestamps();
            $table->unique(['store_id', 'variant_id']);
        });

        Schema::create('collections', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->string('handle');
            $table->text('description_html')->nullable();
            $table->boolean('is_published')->default(true);
            $table->timestamps();
            $table->unique(['store_id', 'handle']);
        });

        Schema::create('collection_products', function (Blueprint $table): void {
            $table->foreignId('collection_id')->constrained()->cascadeOnDelete();
            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
            $table->unsignedInteger('position')->default(0);
            $table->primary(['collection_id', 'product_id']);
        });

        Schema::create('product_media', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('product_id')->constrained()->cascadeOnDelete();
            $table->string('url');
            $table->string('alt_text')->nullable();
            $table->unsignedInteger('position')->default(0);
            $table->timestamps();
        });

        Schema::create('themes', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->boolean('is_active')->default(false);
            $table->json('settings_json')->default('{}');
            $table->timestamps();
        });

        Schema::create('pages', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->string('handle');
            $table->text('body_html');
            $table->boolean('is_published')->default(true);
            $table->timestamps();
            $table->unique(['store_id', 'handle']);
        });

        Schema::create('navigation_menus', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->string('handle');
            $table->timestamps();
            $table->unique(['store_id', 'handle']);
        });

        Schema::create('navigation_items', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('navigation_menu_id')->constrained()->cascadeOnDelete();
            $table->foreignId('parent_id')->nullable()->constrained('navigation_items')->nullOnDelete();
            $table->string('label');
            $table->string('url');
            $table->unsignedInteger('position')->default(0);
            $table->timestamps();
        });

        Schema::create('customers', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('email');
            $table->string('name');
            $table->string('password_hash')->nullable();
            $table->boolean('accepts_marketing')->default(false);
            $table->timestamp('last_login_at')->nullable();
            $table->timestamps();
            $table->unique(['store_id', 'email']);
        });

        Schema::create('customer_addresses', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('customer_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->string('address1');
            $table->string('address2')->nullable();
            $table->string('city');
            $table->string('postal_code');
            $table->string('country_code', 2);
            $table->boolean('is_default')->default(false);
            $table->timestamps();
        });

        Schema::create('customer_password_reset_tokens', function (Blueprint $table): void {
            $table->string('email');
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('token');
            $table->timestamp('created_at')->nullable();
            $table->primary(['store_id', 'email']);
        });

        Schema::create('carts', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
            $table->string('currency', 3)->default('EUR');
            $table->unsignedInteger('cart_version')->default(1);
            $table->string('status')->default('active');
            $table->string('discount_code')->nullable();
            $table->timestamps();
        });

        Schema::create('cart_lines', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('cart_id')->constrained()->cascadeOnDelete();
            $table->foreignId('product_variant_id')->constrained('product_variants')->cascadeOnDelete();
            $table->unsignedInteger('quantity');
            $table->unsignedInteger('unit_price_amount');
            $table->json('snapshot_json')->default('{}');
            $table->timestamps();
            $table->unique(['cart_id', 'product_variant_id']);
        });

        Schema::create('shipping_zones', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->json('countries')->default('[]');
            $table->timestamps();
        });

        Schema::create('shipping_rates', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('shipping_zone_id')->constrained()->cascadeOnDelete();
            $table->string('name');
            $table->unsignedInteger('price_amount');
            $table->unsignedInteger('min_order_amount')->nullable();
            $table->timestamps();
        });

        Schema::create('tax_settings', function (Blueprint $table): void {
            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
            $table->boolean('prices_include_tax')->default(false);
            $table->unsignedInteger('default_rate_bps')->default(1900);
            $table->timestamp('updated_at')->nullable();
        });

        Schema::create('discounts', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('code');
            $table->string('type');
            $table->unsignedInteger('value_amount')->default(0);
            $table->unsignedInteger('value_bps')->default(0);
            $table->unsignedInteger('min_purchase_amount')->nullable();
            $table->unsignedInteger('usage_limit')->nullable();
            $table->unsignedInteger('used_count')->default(0);
            $table->timestamp('starts_at')->nullable();
            $table->timestamp('ends_at')->nullable();
            $table->boolean('is_active')->default(true);
            $table->timestamps();
            $table->unique(['store_id', 'code']);
        });

        Schema::create('checkouts', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('cart_id')->constrained()->cascadeOnDelete();
            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
            $table->string('status')->default('started');
            $table->string('email')->nullable();
            $table->json('shipping_address_json')->nullable();
            $table->foreignId('shipping_rate_id')->nullable()->constrained()->nullOnDelete();
            $table->string('payment_method')->nullable();
            $table->foreignId('order_id')->nullable()->constrained()->nullOnDelete();
            $table->json('totals_json')->default('{}');
            $table->timestamps();
        });

        Schema::create('orders', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('customer_id')->nullable()->constrained()->nullOnDelete();
            $table->string('order_number');
            $table->string('email');
            $table->string('status')->default('pending');
            $table->string('financial_status')->default('pending');
            $table->string('fulfillment_status')->default('unfulfilled');
            $table->string('currency', 3)->default('EUR');
            $table->unsignedInteger('subtotal_amount')->default(0);
            $table->unsignedInteger('discount_amount')->default(0);
            $table->unsignedInteger('shipping_amount')->default(0);
            $table->unsignedInteger('tax_amount')->default(0);
            $table->unsignedInteger('total_amount')->default(0);
            $table->json('shipping_address_json')->nullable();
            $table->json('timeline_json')->default('[]');
            $table->timestamps();
            $table->unique(['store_id', 'order_number']);
        });

        Schema::create('order_lines', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
            $table->foreignId('product_variant_id')->nullable()->constrained('product_variants')->nullOnDelete();
            $table->string('title');
            $table->string('sku')->nullable();
            $table->unsignedInteger('quantity');
            $table->unsignedInteger('unit_price_amount');
            $table->unsignedInteger('total_amount');
            $table->json('snapshot_json')->default('{}');
            $table->timestamps();
        });

        Schema::create('payments', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
            $table->string('provider')->default('mock');
            $table->string('method');
            $table->string('status');
            $table->unsignedInteger('amount');
            $table->string('reference')->nullable();
            $table->text('raw_payload_encrypted')->nullable();
            $table->timestamps();
        });

        Schema::create('refunds', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
            $table->unsignedInteger('amount');
            $table->string('reason')->nullable();
            $table->boolean('restocked')->default(false);
            $table->timestamps();
        });

        Schema::create('fulfillments', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('order_id')->constrained()->cascadeOnDelete();
            $table->string('status')->default('created');
            $table->string('tracking_number')->nullable();
            $table->timestamp('shipped_at')->nullable();
            $table->timestamp('delivered_at')->nullable();
            $table->timestamps();
        });

        Schema::create('fulfillment_lines', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('fulfillment_id')->constrained()->cascadeOnDelete();
            $table->foreignId('order_line_id')->constrained()->cascadeOnDelete();
            $table->unsignedInteger('quantity');
        });

        Schema::create('search_settings', function (Blueprint $table): void {
            $table->foreignId('store_id')->primary()->constrained()->cascadeOnDelete();
            $table->json('synonyms_json')->default('[]');
            $table->json('stopwords_json')->default('[]');
            $table->timestamp('updated_at')->nullable();
        });

        Schema::create('search_queries', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('query');
            $table->unsignedInteger('results_count')->default(0);
            $table->timestamp('created_at')->nullable();
        });

        Schema::create('analytics_events', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('event');
            $table->json('payload_json')->default('{}');
            $table->timestamp('created_at')->nullable();
        });

        Schema::create('analytics_daily', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->date('date');
            $table->unsignedInteger('visitors')->default(0);
            $table->unsignedInteger('orders_count')->default(0);
            $table->unsignedInteger('sales_amount')->default(0);
            $table->unique(['store_id', 'date']);
        });

        Schema::create('apps', function (Blueprint $table): void {
            $table->id();
            $table->string('name');
            $table->string('handle')->unique();
            $table->json('scopes')->default('[]');
            $table->timestamps();
        });

        Schema::create('app_installations', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->foreignId('app_id')->constrained()->cascadeOnDelete();
            $table->string('status')->default('installed');
            $table->timestamps();
        });

        Schema::create('webhook_subscriptions', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('store_id')->constrained()->cascadeOnDelete();
            $table->string('topic');
            $table->string('endpoint_url');
            $table->string('secret');
            $table->boolean('is_active')->default(true);
            $table->timestamps();
        });

        Schema::create('webhook_deliveries', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('webhook_subscription_id')->constrained()->cascadeOnDelete();
            $table->string('status')->default('pending');
            $table->unsignedInteger('attempts')->default(0);
            $table->json('payload_json')->default('{}');
            $table->timestamp('created_at')->nullable();
        });
    }

    public function down(): void
    {
        foreach ([
            'webhook_deliveries',
            'webhook_subscriptions',
            'app_installations',
            'apps',
            'analytics_daily',
            'analytics_events',
            'search_queries',
            'search_settings',
            'fulfillment_lines',
            'fulfillments',
            'refunds',
            'payments',
            'order_lines',
            'orders',
            'checkouts',
            'discounts',
            'tax_settings',
            'shipping_rates',
            'shipping_zones',
            'cart_lines',
            'carts',
            'customer_password_reset_tokens',
            'customer_addresses',
            'customers',
            'navigation_items',
            'navigation_menus',
            'pages',
            'themes',
            'product_media',
            'collection_products',
            'collections',
            'inventory_items',
            'variant_option_values',
            'product_variants',
            'product_option_values',
            'product_options',
            'products',
            'store_settings',
            'store_users',
            'store_domains',
            'stores',
            'organizations',
        ] as $table) {
            Schema::dropIfExists($table);
        }
    }
};


Output: {"output":"Success. Updated the following files:\nA database/migrations/2026_04_25_000001_create_shop_domain_tables.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


Input:
*** Begin Patch
*** Add File: app/Models/Scopes/StoreScope.php
+<?php
+
+namespace App\Models\Scopes;
+
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Scope;
+
+class StoreScope implements Scope
+{
+    public function apply(Builder $builder, Model $model): void
+    {
+        if (! app()->bound('current_store')) {
+            return;
+        }
+
+        $builder->where($model->getTable().'.store_id', app('current_store')->id);
+    }
+}
+
*** Add File: app/Models/Concerns/BelongsToStore.php
+<?php
+
+namespace App\Models\Concerns;
+
+use App\Models\Scopes\StoreScope;
+use App\Models\Store;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+trait BelongsToStore
+{
+    protected static function bootBelongsToStore(): void
+    {
+        static::addGlobalScope(new StoreScope);
+
+        static::creating(function ($model): void {
+            if (! $model->store_id && app()->bound('current_store')) {
+                $model->store_id = app('current_store')->id;
+            }
+        });
+    }
+
+    public function store(): BelongsTo
+    {
+        return $this->belongsTo(Store::class);
+    }
+}
+
*** Add File: app/Models/Organization.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class Organization extends Model
+{
+    use HasFactory;
+
+    protected $fillable = ['name', 'billing_email'];
+
+    public function stores(): HasMany
+    {
+        return $this->hasMany(Store::class);
+    }
+}
+
*** Add File: app/Models/Store.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\StoreStatus;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
+
+class Store extends Model
+{
+    use HasFactory;
+
+    protected $fillable = ['organization_id', 'name', 'handle', 'status', 'default_currency', 'default_locale', 'timezone'];
+
+    protected function casts(): array
+    {
+        return [
+            'status' => StoreStatus::class,
+        ];
+    }
+
+    public function organization(): BelongsTo
+    {
+        return $this->belongsTo(Organization::class);
+    }
+
+    public function domains(): HasMany
+    {
+        return $this->hasMany(StoreDomain::class);
+    }
+
+    public function users(): BelongsToMany
+    {
+        return $this->belongsToMany(User::class, 'store_users')
+            ->using(StoreUser::class)
+            ->withPivot('role')
+            ->withTimestamps();
+    }
+
+    public function settings(): HasOne
+    {
+        return $this->hasOne(StoreSettings::class);
+    }
+}
+
*** Add File: app/Models/StoreDomain.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\StoreDomainType;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class StoreDomain extends Model
+{
+    use HasFactory;
+
+    public const UPDATED_AT = null;
+
+    protected $fillable = ['store_id', 'hostname', 'type', 'is_primary', 'tls_mode'];
+
+    protected function casts(): array
+    {
+        return [
+            'type' => StoreDomainType::class,
+            'is_primary' => 'boolean',
+        ];
+    }
+
+    public function store(): BelongsTo
+    {
+        return $this->belongsTo(Store::class);
+    }
+}
+
*** Add File: app/Models/StoreSettings.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class StoreSettings extends Model
+{
+    public $incrementing = false;
+
+    public const CREATED_AT = null;
+
+    protected $primaryKey = 'store_id';
+
+    protected $fillable = ['store_id', 'settings_json'];
+
+    protected function casts(): array
+    {
+        return [
+            'settings_json' => 'array',
+        ];
+    }
+
+    public function store(): BelongsTo
+    {
+        return $this->belongsTo(Store::class);
+    }
+}
+
*** Add File: app/Models/StoreUser.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\StoreUserRole;
+use Illuminate\Database\Eloquent\Relations\Pivot;
+
+class StoreUser extends Pivot
+{
+    protected $table = 'store_users';
+
+    public $incrementing = false;
+
+    protected $fillable = ['store_id', 'user_id', 'role'];
+
+    protected function casts(): array
+    {
+        return [
+            'role' => StoreUserRole::class,
+        ];
+    }
+}
+
*** Add File: app/Models/Product.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\ProductStatus;
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
+
+class Product extends Model
+{
+    use BelongsToStore;
+    use HasFactory;
+
+    protected $fillable = ['store_id', 'title', 'handle', 'status', 'description_html', 'vendor', 'product_type', 'tags', 'published_at'];
+
+    protected function casts(): array
+    {
+        return [
+            'status' => ProductStatus::class,
+            'tags' => 'array',
+            'published_at' => 'datetime',
+        ];
+    }
+
+    public function variants(): HasMany
+    {
+        return $this->hasMany(ProductVariant::class);
+    }
+
+    public function defaultVariant(): HasOne
+    {
+        return $this->hasOne(ProductVariant::class)->where('is_default', true);
+    }
+
+    public function options(): HasMany
+    {
+        return $this->hasMany(ProductOption::class);
+    }
+
+    public function media(): HasMany
+    {
+        return $this->hasMany(ProductMedia::class)->orderBy('position');
+    }
+
+    public function collections(): BelongsToMany
+    {
+        return $this->belongsToMany(Collection::class, 'collection_products')->withPivot('position');
+    }
+}
+
*** Add File: app/Models/ProductVariant.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
+
+class ProductVariant extends Model
+{
+    use HasFactory;
+
+    protected $fillable = ['product_id', 'sku', 'barcode', 'price_amount', 'compare_at_amount', 'currency', 'weight_g', 'requires_shipping', 'is_default', 'position', 'status'];
+
+    protected function casts(): array
+    {
+        return [
+            'requires_shipping' => 'boolean',
+            'is_default' => 'boolean',
+        ];
+    }
+
+    public function product(): BelongsTo
+    {
+        return $this->belongsTo(Product::class);
+    }
+
+    public function inventoryItem(): HasOne
+    {
+        return $this->hasOne(InventoryItem::class, 'variant_id');
+    }
+
+    public function optionValues(): BelongsToMany
+    {
+        return $this->belongsToMany(ProductOptionValue::class, 'variant_option_values', 'variant_id', 'product_option_value_id');
+    }
+}
+
*** Add File: app/Models/ProductOption.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class ProductOption extends Model
+{
+    public $timestamps = false;
+
+    protected $fillable = ['product_id', 'name', 'position'];
+
+    public function product(): BelongsTo
+    {
+        return $this->belongsTo(Product::class);
+    }
+
+    public function values(): HasMany
+    {
+        return $this->hasMany(ProductOptionValue::class)->orderBy('position');
+    }
+}
+
*** Add File: app/Models/ProductOptionValue.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class ProductOptionValue extends Model
+{
+    public $timestamps = false;
+
+    protected $fillable = ['product_option_id', 'value', 'position'];
+
+    public function option(): BelongsTo
+    {
+        return $this->belongsTo(ProductOption::class, 'product_option_id');
+    }
+}
+
*** Add File: app/Models/InventoryItem.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class InventoryItem extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'variant_id', 'quantity_available', 'quantity_reserved', 'policy'];
+
+    public function variant(): BelongsTo
+    {
+        return $this->belongsTo(ProductVariant::class, 'variant_id');
+    }
+
+    public function availableForSale(): int
+    {
+        return max(0, $this->quantity_available - $this->quantity_reserved);
+    }
+}
+
*** Add File: app/Models/Collection.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+
+class Collection extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'title', 'handle', 'description_html', 'is_published'];
+
+    protected function casts(): array
+    {
+        return [
+            'is_published' => 'boolean',
+        ];
+    }
+
+    public function products(): BelongsToMany
+    {
+        return $this->belongsToMany(Product::class, 'collection_products')->withPivot('position')->orderByPivot('position');
+    }
+}
+
*** Add File: app/Models/ProductMedia.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class ProductMedia extends Model
+{
+    protected $fillable = ['product_id', 'url', 'alt_text', 'position'];
+
+    public function product(): BelongsTo
+    {
+        return $this->belongsTo(Product::class);
+    }
+}
+
*** End Patch


Success. Updated the following files:
A app/Models/Scopes/StoreScope.php
A app/Models/Concerns/BelongsToStore.php
A app/Models/Organization.php
A app/Models/Store.php
A app/Models/StoreDomain.php
A app/Models/StoreSettings.php
A app/Models/StoreUser.php
A app/Models/Product.php
A app/Models/ProductVariant.php
A app/Models/ProductOption.php
A app/Models/ProductOptionValue.php
A app/Models/InventoryItem.php
A app/Models/Collection.php
A app/Models/ProductMedia.php

<?php

namespace App\Models;

use App\Enums\StoreStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Store extends Model
{
    use HasFactory;

    protected $fillable = ['organization_id', 'name', 'handle', 'status', 'default_currency', 'default_locale', 'timezone'];

    protected function casts(): array
    {
        return [
            'status' => StoreStatus::class,
        ];
    }

    public function organization(): BelongsTo
    {
        return $this->belongsTo(Organization::class);
    }

    public function domains(): HasMany
    {
        return $this->hasMany(StoreDomain::class);
    }

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'store_users')
            ->using(StoreUser::class)
            ->withPivot('role')
            ->withTimestamps();
    }

    public function settings(): HasOne
    {
        return $this->hasOne(StoreSettings::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class ProductOptionValue extends Model
{
    public $timestamps = false;

    protected $fillable = ['product_option_id', 'value', 'position'];

    public function option(): BelongsTo
    {
        return $this->belongsTo(ProductOption::class, 'product_option_id');
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class InventoryItem extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'variant_id', 'quantity_available', 'quantity_reserved', 'policy'];

    public function variant(): BelongsTo
    {
        return $this->belongsTo(ProductVariant::class, 'variant_id');
    }

    public function availableForSale(): int
    {
        return max(0, $this->quantity_available - $this->quantity_reserved);
    }
}

<?php

namespace App\Models\Concerns;

use App\Models\Scopes\StoreScope;
use App\Models\Store;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

trait BelongsToStore
{
    protected static function bootBelongsToStore(): void
    {
        static::addGlobalScope(new StoreScope);

        static::creating(function ($model): void {
            if (! $model->store_id && app()->bound('current_store')) {
                $model->store_id = app('current_store')->id;
            }
        });
    }

    public function store(): BelongsTo
    {
        return $this->belongsTo(Store::class);
    }
}

<?php

namespace App\Models;

use App\Enums\StoreDomainType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class StoreDomain extends Model
{
    use HasFactory;

    public const UPDATED_AT = null;

    protected $fillable = ['store_id', 'hostname', 'type', 'is_primary', 'tls_mode'];

    protected function casts(): array
    {
        return [
            'type' => StoreDomainType::class,
            'is_primary' => 'boolean',
        ];
    }

    public function store(): BelongsTo
    {
        return $this->belongsTo(Store::class);
    }
}

<?php

namespace App\Models;

use App\Enums\StoreUserRole;
use Illuminate\Database\Eloquent\Relations\Pivot;

class StoreUser extends Pivot
{
    protected $table = 'store_users';

    public $incrementing = false;

    protected $fillable = ['store_id', 'user_id', 'role'];

    protected function casts(): array
    {
        return [
            'role' => StoreUserRole::class,
        ];
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class ProductVariant extends Model
{
    use HasFactory;

    protected $fillable = ['product_id', 'sku', 'barcode', 'price_amount', 'compare_at_amount', 'currency', 'weight_g', 'requires_shipping', 'is_default', 'position', 'status'];

    protected function casts(): array
    {
        return [
            'requires_shipping' => 'boolean',
            'is_default' => 'boolean',
        ];
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }

    public function inventoryItem(): HasOne
    {
        return $this->hasOne(InventoryItem::class, 'variant_id');
    }

    public function optionValues(): BelongsToMany
    {
        return $this->belongsToMany(ProductOptionValue::class, 'variant_option_values', 'variant_id', 'product_option_value_id');
    }
}

<?php

namespace App\Models\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class StoreScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        if (! app()->bound('current_store')) {
            return;
        }

        $builder->where($model->getTable().'.store_id', app('current_store')->id);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class ProductOption extends Model
{
    public $timestamps = false;

    protected $fillable = ['product_id', 'name', 'position'];

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }

    public function values(): HasMany
    {
        return $this->hasMany(ProductOptionValue::class)->orderBy('position');
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class ProductMedia extends Model
{
    protected $fillable = ['product_id', 'url', 'alt_text', 'position'];

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }
}

<?php

namespace App\Models;

use App\Enums\ProductStatus;
use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Product extends Model
{
    use BelongsToStore;
    use HasFactory;

    protected $fillable = ['store_id', 'title', 'handle', 'status', 'description_html', 'vendor', 'product_type', 'tags', 'published_at'];

    protected function casts(): array
    {
        return [
            'status' => ProductStatus::class,
            'tags' => 'array',
            'published_at' => 'datetime',
        ];
    }

    public function variants(): HasMany
    {
        return $this->hasMany(ProductVariant::class);
    }

    public function defaultVariant(): HasOne
    {
        return $this->hasOne(ProductVariant::class)->where('is_default', true);
    }

    public function options(): HasMany
    {
        return $this->hasMany(ProductOption::class);
    }

    public function media(): HasMany
    {
        return $this->hasMany(ProductMedia::class)->orderBy('position');
    }

    public function collections(): BelongsToMany
    {
        return $this->belongsToMany(Collection::class, 'collection_products')->withPivot('position');
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Collection extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'title', 'handle', 'description_html', 'is_published'];

    protected function casts(): array
    {
        return [
            'is_published' => 'boolean',
        ];
    }

    public function products(): BelongsToMany
    {
        return $this->belongsToMany(Product::class, 'collection_products')->withPivot('position')->orderByPivot('position');
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class StoreSettings extends Model
{
    public $incrementing = false;

    public const CREATED_AT = null;

    protected $primaryKey = 'store_id';

    protected $fillable = ['store_id', 'settings_json'];

    protected function casts(): array
    {
        return [
            'settings_json' => 'array',
        ];
    }

    public function store(): BelongsTo
    {
        return $this->belongsTo(Store::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Organization extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'billing_email'];

    public function stores(): HasMany
    {
        return $this->hasMany(Store::class);
    }
}


Output: {"output":"Success. Updated the following files:\nA app/Models/Scopes/StoreScope.php\nA app/Models/Concerns/BelongsToStore.php\nA app/Models/Organization.php\nA app/Models/Store.php\nA app/Models/StoreDomain.php\nA app/Models/StoreSettings.php\nA app/Models/StoreUser.php\nA app/Models/Product.php\nA app/Models/ProductVariant.php\nA app/Models/ProductOption.php\nA app/Models/ProductOptionValue.php\nA app/Models/InventoryItem.php\nA app/Models/Collection.php\nA app/Models/ProductMedia.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


Input:
*** Begin Patch
*** Add File: app/Models/Customer.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Auth\Authenticatable;
+
+class Customer extends Model implements AuthenticatableContract
+{
+    use Authenticatable;
+    use BelongsToStore;
+    use HasFactory;
+
+    protected $fillable = ['store_id', 'email', 'name', 'password_hash', 'accepts_marketing', 'last_login_at'];
+
+    protected $hidden = ['password_hash'];
+
+    protected function casts(): array
+    {
+        return [
+            'accepts_marketing' => 'boolean',
+            'last_login_at' => 'datetime',
+            'password_hash' => 'hashed',
+        ];
+    }
+
+    public function getAuthPassword(): string
+    {
+        return (string) $this->password_hash;
+    }
+
+    public function setPasswordAttribute(string $value): void
+    {
+        $this->attributes['password_hash'] = $value;
+    }
+
+    public function addresses(): HasMany
+    {
+        return $this->hasMany(CustomerAddress::class);
+    }
+
+    public function orders(): HasMany
+    {
+        return $this->hasMany(Order::class);
+    }
+}
+
*** Add File: app/Models/CustomerAddress.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class CustomerAddress extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'customer_id', 'name', 'address1', 'address2', 'city', 'postal_code', 'country_code', 'is_default'];
+
+    protected function casts(): array
+    {
+        return ['is_default' => 'boolean'];
+    }
+
+    public function customer(): BelongsTo
+    {
+        return $this->belongsTo(Customer::class);
+    }
+}
+
*** Add File: app/Models/Cart.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class Cart extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'customer_id', 'currency', 'cart_version', 'status', 'discount_code'];
+
+    public function lines(): HasMany
+    {
+        return $this->hasMany(CartLine::class);
+    }
+}
+
*** Add File: app/Models/CartLine.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class CartLine extends Model
+{
+    protected $fillable = ['cart_id', 'product_variant_id', 'quantity', 'unit_price_amount', 'snapshot_json'];
+
+    protected function casts(): array
+    {
+        return ['snapshot_json' => 'array'];
+    }
+
+    public function cart(): BelongsTo
+    {
+        return $this->belongsTo(Cart::class);
+    }
+
+    public function variant(): BelongsTo
+    {
+        return $this->belongsTo(ProductVariant::class, 'product_variant_id');
+    }
+}
+
*** Add File: app/Models/ShippingZone.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class ShippingZone extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'name', 'countries'];
+
+    protected function casts(): array
+    {
+        return ['countries' => 'array'];
+    }
+
+    public function rates(): HasMany
+    {
+        return $this->hasMany(ShippingRate::class);
+    }
+}
+
*** Add File: app/Models/ShippingRate.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class ShippingRate extends Model
+{
+    protected $fillable = ['shipping_zone_id', 'name', 'price_amount', 'min_order_amount'];
+
+    public function zone(): BelongsTo
+    {
+        return $this->belongsTo(ShippingZone::class, 'shipping_zone_id');
+    }
+}
+
*** Add File: app/Models/TaxSettings.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class TaxSettings extends Model
+{
+    public $incrementing = false;
+
+    public const CREATED_AT = null;
+
+    protected $primaryKey = 'store_id';
+
+    protected $fillable = ['store_id', 'prices_include_tax', 'default_rate_bps'];
+
+    protected function casts(): array
+    {
+        return ['prices_include_tax' => 'boolean'];
+    }
+}
+
*** Add File: app/Models/Discount.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\DiscountType;
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class Discount extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'code', 'type', 'value_amount', 'value_bps', 'min_purchase_amount', 'usage_limit', 'used_count', 'starts_at', 'ends_at', 'is_active'];
+
+    protected function casts(): array
+    {
+        return [
+            'type' => DiscountType::class,
+            'starts_at' => 'datetime',
+            'ends_at' => 'datetime',
+            'is_active' => 'boolean',
+        ];
+    }
+}
+
*** Add File: app/Models/Checkout.php
+<?php
+
+namespace App\Models;
+
+use App\Enums\CheckoutStatus;
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class Checkout extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'cart_id', 'customer_id', 'status', 'email', 'shipping_address_json', 'shipping_rate_id', 'payment_method', 'order_id', 'totals_json'];
+
+    protected function casts(): array
+    {
+        return [
+            'status' => CheckoutStatus::class,
+            'shipping_address_json' => 'array',
+            'totals_json' => 'array',
+        ];
+    }
+
+    public function cart(): BelongsTo
+    {
+        return $this->belongsTo(Cart::class);
+    }
+
+    public function order(): BelongsTo
+    {
+        return $this->belongsTo(Order::class);
+    }
+}
+
*** Add File: app/Models/Order.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class Order extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'customer_id', 'order_number', 'email', 'status', 'financial_status', 'fulfillment_status', 'currency', 'subtotal_amount', 'discount_amount', 'shipping_amount', 'tax_amount', 'total_amount', 'shipping_address_json', 'timeline_json'];
+
+    protected function casts(): array
+    {
+        return [
+            'shipping_address_json' => 'array',
+            'timeline_json' => 'array',
+        ];
+    }
+
+    public function customer(): BelongsTo
+    {
+        return $this->belongsTo(Customer::class);
+    }
+
+    public function lines(): HasMany
+    {
+        return $this->hasMany(OrderLine::class);
+    }
+
+    public function payments(): HasMany
+    {
+        return $this->hasMany(Payment::class);
+    }
+
+    public function fulfillments(): HasMany
+    {
+        return $this->hasMany(Fulfillment::class);
+    }
+}
+
*** Add File: app/Models/OrderLine.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class OrderLine extends Model
+{
+    protected $fillable = ['order_id', 'product_variant_id', 'title', 'sku', 'quantity', 'unit_price_amount', 'total_amount', 'snapshot_json'];
+
+    protected function casts(): array
+    {
+        return ['snapshot_json' => 'array'];
+    }
+
+    public function order(): BelongsTo
+    {
+        return $this->belongsTo(Order::class);
+    }
+}
+
*** Add File: app/Models/Payment.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class Payment extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'order_id', 'provider', 'method', 'status', 'amount', 'reference', 'raw_payload_encrypted'];
+
+    public function order(): BelongsTo
+    {
+        return $this->belongsTo(Order::class);
+    }
+}
+
*** Add File: app/Models/Refund.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class Refund extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'order_id', 'amount', 'reason', 'restocked'];
+
+    protected function casts(): array
+    {
+        return ['restocked' => 'boolean'];
+    }
+}
+
*** Add File: app/Models/Fulfillment.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class Fulfillment extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'order_id', 'status', 'tracking_number', 'shipped_at', 'delivered_at'];
+
+    protected function casts(): array
+    {
+        return [
+            'shipped_at' => 'datetime',
+            'delivered_at' => 'datetime',
+        ];
+    }
+
+    public function lines(): HasMany
+    {
+        return $this->hasMany(FulfillmentLine::class);
+    }
+}
+
*** Add File: app/Models/FulfillmentLine.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class FulfillmentLine extends Model
+{
+    public $timestamps = false;
+
+    protected $fillable = ['fulfillment_id', 'order_line_id', 'quantity'];
+}
+
*** Add File: app/Models/Page.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class Page extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'title', 'handle', 'body_html', 'is_published'];
+
+    protected function casts(): array
+    {
+        return ['is_published' => 'boolean'];
+    }
+}
+
*** Add File: app/Models/Theme.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class Theme extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'name', 'is_active', 'settings_json'];
+
+    protected function casts(): array
+    {
+        return [
+            'is_active' => 'boolean',
+            'settings_json' => 'array',
+        ];
+    }
+}
+
*** Add File: app/Models/NavigationMenu.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class NavigationMenu extends Model
+{
+    use BelongsToStore;
+
+    protected $fillable = ['store_id', 'title', 'handle'];
+
+    public function items(): HasMany
+    {
+        return $this->hasMany(NavigationItem::class)->orderBy('position');
+    }
+}
+
*** Add File: app/Models/NavigationItem.php
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+class NavigationItem extends Model
+{
+    protected $fillable = ['navigation_menu_id', 'parent_id', 'label', 'url', 'position'];
+}
+
*** Add File: app/Models/SearchQuery.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class SearchQuery extends Model
+{
+    use BelongsToStore;
+
+    public const UPDATED_AT = null;
+
+    protected $fillable = ['store_id', 'query', 'results_count'];
+}
+
*** Add File: app/Models/AnalyticsEvent.php
+<?php
+
+namespace App\Models;
+
+use App\Models\Concerns\BelongsToStore;
+use Illuminate\Database\Eloquent\Model;
+
+class AnalyticsEvent extends Model
+{
+    use BelongsToStore;
+
+    public const UPDATED_AT = null;
+
+    protected $fillable = ['store_id', 'event', 'payload_json'];
+
+    protected function casts(): array
+    {
+        return ['payload_json' => 'array'];
+    }
+}
+
*** End Patch


Success. Updated the following files:
A app/Models/Customer.php
A app/Models/CustomerAddress.php
A app/Models/Cart.php
A app/Models/CartLine.php
A app/Models/ShippingZone.php
A app/Models/ShippingRate.php
A app/Models/TaxSettings.php
A app/Models/Discount.php
A app/Models/Checkout.php
A app/Models/Order.php
A app/Models/OrderLine.php
A app/Models/Payment.php
A app/Models/Refund.php
A app/Models/Fulfillment.php
A app/Models/FulfillmentLine.php
A app/Models/Page.php
A app/Models/Theme.php
A app/Models/NavigationMenu.php
A app/Models/NavigationItem.php
A app/Models/SearchQuery.php
A app/Models/AnalyticsEvent.php

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class ShippingZone extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'name', 'countries'];

    protected function casts(): array
    {
        return ['countries' => 'array'];
    }

    public function rates(): HasMany
    {
        return $this->hasMany(ShippingRate::class);
    }
}

<?php

namespace App\Models;

use App\Enums\CheckoutStatus;
use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Checkout extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'cart_id', 'customer_id', 'status', 'email', 'shipping_address_json', 'shipping_rate_id', 'payment_method', 'order_id', 'totals_json'];

    protected function casts(): array
    {
        return [
            'status' => CheckoutStatus::class,
            'shipping_address_json' => 'array',
            'totals_json' => 'array',
        ];
    }

    public function cart(): BelongsTo
    {
        return $this->belongsTo(Cart::class);
    }

    public function order(): BelongsTo
    {
        return $this->belongsTo(Order::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class ShippingRate extends Model
{
    protected $fillable = ['shipping_zone_id', 'name', 'price_amount', 'min_order_amount'];

    public function zone(): BelongsTo
    {
        return $this->belongsTo(ShippingZone::class, 'shipping_zone_id');
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Auth\Authenticatable;

class Customer extends Model implements AuthenticatableContract
{
    use Authenticatable;
    use BelongsToStore;
    use HasFactory;

    protected $fillable = ['store_id', 'email', 'name', 'password_hash', 'accepts_marketing', 'last_login_at'];

    protected $hidden = ['password_hash'];

    protected function casts(): array
    {
        return [
            'accepts_marketing' => 'boolean',
            'last_login_at' => 'datetime',
            'password_hash' => 'hashed',
        ];
    }

    public function getAuthPassword(): string
    {
        return (string) $this->password_hash;
    }

    public function setPasswordAttribute(string $value): void
    {
        $this->attributes['password_hash'] = $value;
    }

    public function addresses(): HasMany
    {
        return $this->hasMany(CustomerAddress::class);
    }

    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Cart extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'customer_id', 'currency', 'cart_version', 'status', 'discount_code'];

    public function lines(): HasMany
    {
        return $this->hasMany(CartLine::class);
    }
}

<?php

namespace App\Models;

use App\Enums\DiscountType;
use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class Discount extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'code', 'type', 'value_amount', 'value_bps', 'min_purchase_amount', 'usage_limit', 'used_count', 'starts_at', 'ends_at', 'is_active'];

    protected function casts(): array
    {
        return [
            'type' => DiscountType::class,
            'starts_at' => 'datetime',
            'ends_at' => 'datetime',
            'is_active' => 'boolean',
        ];
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Payment extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'order_id', 'provider', 'method', 'status', 'amount', 'reference', 'raw_payload_encrypted'];

    public function order(): BelongsTo
    {
        return $this->belongsTo(Order::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class NavigationItem extends Model
{
    protected $fillable = ['navigation_menu_id', 'parent_id', 'label', 'url', 'position'];
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class Refund extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'order_id', 'amount', 'reason', 'restocked'];

    protected function casts(): array
    {
        return ['restocked' => 'boolean'];
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class CustomerAddress extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'customer_id', 'name', 'address1', 'address2', 'city', 'postal_code', 'country_code', 'is_default'];

    protected function casts(): array
    {
        return ['is_default' => 'boolean'];
    }

    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class AnalyticsEvent extends Model
{
    use BelongsToStore;

    public const UPDATED_AT = null;

    protected $fillable = ['store_id', 'event', 'payload_json'];

    protected function casts(): array
    {
        return ['payload_json' => 'array'];
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Order extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'customer_id', 'order_number', 'email', 'status', 'financial_status', 'fulfillment_status', 'currency', 'subtotal_amount', 'discount_amount', 'shipping_amount', 'tax_amount', 'total_amount', 'shipping_address_json', 'timeline_json'];

    protected function casts(): array
    {
        return [
            'shipping_address_json' => 'array',
            'timeline_json' => 'array',
        ];
    }

    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    public function lines(): HasMany
    {
        return $this->hasMany(OrderLine::class);
    }

    public function payments(): HasMany
    {
        return $this->hasMany(Payment::class);
    }

    public function fulfillments(): HasMany
    {
        return $this->hasMany(Fulfillment::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class TaxSettings extends Model
{
    public $incrementing = false;

    public const CREATED_AT = null;

    protected $primaryKey = 'store_id';

    protected $fillable = ['store_id', 'prices_include_tax', 'default_rate_bps'];

    protected function casts(): array
    {
        return ['prices_include_tax' => 'boolean'];
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class OrderLine extends Model
{
    protected $fillable = ['order_id', 'product_variant_id', 'title', 'sku', 'quantity', 'unit_price_amount', 'total_amount', 'snapshot_json'];

    protected function casts(): array
    {
        return ['snapshot_json' => 'array'];
    }

    public function order(): BelongsTo
    {
        return $this->belongsTo(Order::class);
    }
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class FulfillmentLine extends Model
{
    public $timestamps = false;

    protected $fillable = ['fulfillment_id', 'order_line_id', 'quantity'];
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class Theme extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'name', 'is_active', 'settings_json'];

    protected function casts(): array
    {
        return [
            'is_active' => 'boolean',
            'settings_json' => 'array',
        ];
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class NavigationMenu extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'title', 'handle'];

    public function items(): HasMany
    {
        return $this->hasMany(NavigationItem::class)->orderBy('position');
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Fulfillment extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'order_id', 'status', 'tracking_number', 'shipped_at', 'delivered_at'];

    protected function casts(): array
    {
        return [
            'shipped_at' => 'datetime',
            'delivered_at' => 'datetime',
        ];
    }

    public function lines(): HasMany
    {
        return $this->hasMany(FulfillmentLine::class);
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    use BelongsToStore;

    protected $fillable = ['store_id', 'title', 'handle', 'body_html', 'is_published'];

    protected function casts(): array
    {
        return ['is_published' => 'boolean'];
    }
}

<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Model;

class SearchQuery extends Model
{
    use BelongsToStore;

    public const UPDATED_AT = null;

    protected $fillable = ['store_id', 'query', 'results_count'];
}

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class CartLine extends Model
{
    protected $fillable = ['cart_id', 'product_variant_id', 'quantity', 'unit_price_amount', 'snapshot_json'];

    protected function casts(): array
    {
        return ['snapshot_json' => 'array'];
    }

    public function cart(): BelongsTo
    {
        return $this->belongsTo(Cart::class);
    }

    public function variant(): BelongsTo
    {
        return $this->belongsTo(ProductVariant::class, 'product_variant_id');
    }
}


Output: {"output":"Success. Updated the following files:\nA app/Models/Customer.php\nA app/Models/CustomerAddress.php\nA app/Models/Cart.php\nA app/Models/CartLine.php\nA app/Models/ShippingZone.php\nA app/Models/ShippingRate.php\nA app/Models/TaxSettings.php\nA app/Models/Discount.php\nA app/Models/Checkout.php\nA app/Models/Order.php\nA app/Models/OrderLine.php\nA app/Models/Payment.php\nA app/Models/Refund.php\nA app/Models/Fulfillment.php\nA app/Models/FulfillmentLine.php\nA app/Models/Page.php\nA app/Models/Theme.php\nA app/Models/NavigationMenu.php\nA app/Models/NavigationItem.php\nA app/Models/SearchQuery.php\nA app/Models/AnalyticsEvent.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}


Input:
*** Begin Patch
*** Update File: config/auth.php
@@
         'web' => [
             'driver' => 'session',
             'provider' => 'users',
         ],
+
+        'customer' => [
+            'driver' => 'session',
+            'provider' => 'customers',
+        ],
@@
         'users' => [
             'driver' => 'eloquent',
             'model' => env('AUTH_MODEL', App\Models\User::class),
         ],
+
+        'customers' => [
+            'driver' => 'eloquent',
+            'model' => App\Models\Customer::class,
+        ],
@@
         'users' => [
             'provider' => 'users',
             'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
             'expire' => 60,
             'throttle' => 60,
         ],
+
+        'customers' => [
+            'provider' => 'customers',
+            'table' => 'customer_password_reset_tokens',
+            'expire' => 60,
+            'throttle' => 60,
+        ],
*** End Patch


Success. Updated the following files:
M config/auth.php

@@ -42,2 +42,7 @@
         ],
+
+        'customer' => [
+            'driver' => 'session',
+            'provider' => 'customers',
+        ],
     ],
@@ -67,2 +72,7 @@

+        'customers' => [
+            'driver' => 'eloquent',
+            'model' => App\Models\Customer::class,
+        ],
+
         // 'users' => [
@@ -99,2 +109,9 @@
         ],
+
+        'customers' => [
+            'provider' => 'customers',
+            'table' => 'customer_password_reset_tokens',
+            'expire' => 60,
+            'throttle' => 60,
+        ],
     ],


Output: {"output":"Success. Updated the following files:\nM config/auth.php\n","metadata":{"exit_code":0,"duration_seconds":0.0}}