Below is a solid Laravel 10/11-style Eloquent model set for the Phase 1 schema in `searchmercials_v2.sql`. It follows the `sm_` table names and foreign keys shown in the file. 

I’m assuming:

* models live under `App\Models`
* timestamps are enabled
* integer PKs are default
* `uuid` is just a normal attribute, not the route key yet
* JSON columns are cast
* enums are left as strings for now

## Base notes

A few relationship truths from the schema:

* `Tenant -> hasMany Accounts, Categories, Domains, Vendors, Listings, Sessions, SearchQueries, SourceImportBatches, JobQueue`
* `Account -> hasMany Users`, and may own `Vendors`
* `Vendor -> hasMany VendorLocations, Listings, VendorCategoryMap, VendorSourceMap, ClaimRequests`
* `Listing -> belongsTo Vendor, Tenant, Category, PrimaryLocation`
* `SearchQuery -> belongsTo Session/User/Tenant/Category`
* `EventImpression` and `EventClick` hang off `Session`, optionally `SearchQuery` and `Listing`
* job tables chain `JobDefinition -> JobQueue -> JobRuns -> JobErrors` 

---

# 1. Core models

## `app/Models/Tenant.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Tenant extends Model
{
    protected $table = 'sm_tenants';

    protected $fillable = [
        'uuid',
        'name',
        'slug',
        'status',
        'settings_json',
    ];

    protected $casts = [
        'settings_json' => 'array',
    ];

    public function accounts(): HasMany
    {
        return $this->hasMany(Account::class, 'tenant_id');
    }

    public function domains(): HasMany
    {
        return $this->hasMany(Domain::class, 'tenant_id');
    }

    public function vendors(): HasMany
    {
        return $this->hasMany(Vendor::class, 'tenant_id');
    }

    public function categories(): HasMany
    {
        return $this->hasMany(Category::class, 'tenant_id');
    }

    public function listings(): HasMany
    {
        return $this->hasMany(Listing::class, 'tenant_id');
    }

    public function sessions(): HasMany
    {
        return $this->hasMany(Session::class, 'tenant_id');
    }

    public function searchQueries(): HasMany
    {
        return $this->hasMany(SearchQuery::class, 'tenant_id');
    }

    public function importBatches(): HasMany
    {
        return $this->hasMany(SourceImportBatch::class, 'tenant_id');
    }

    public function jobQueue(): HasMany
    {
        return $this->hasMany(JobQueue::class, 'tenant_id');
    }
}
```

## `app/Models/Account.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Account extends Model
{
    protected $table = 'sm_accounts';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'account_type',
        'name',
        'legal_name',
        'email',
        'phone',
        'website',
        'status',
        'lifecycle_stage',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function users(): HasMany
    {
        return $this->hasMany(User::class, 'account_id');
    }

    public function primaryVendors(): HasMany
    {
        return $this->hasMany(Vendor::class, 'primary_account_id');
    }

    public function sessions(): HasMany
    {
        return $this->hasMany(Session::class, 'account_id');
    }
}
```

## `app/Models/User.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class User extends Authenticatable
{
    protected $table = 'sm_users';

    protected $fillable = [
        'uuid',
        'account_id',
        'first_name',
        'last_name',
        'email',
        'email_verified_at',
        'password_hash',
        'remember_token',
        'phone',
        'status',
        'last_login_at',
    ];

    protected $hidden = [
        'password_hash',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
        'last_login_at' => 'datetime',
    ];

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

    public function account(): BelongsTo
    {
        return $this->belongsTo(Account::class, 'account_id');
    }

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(
            Role::class,
            'sm_user_role_map',
            'user_id',
            'role_id'
        )->withPivot('tenant_id', 'created_at');
    }

    public function roleMappings(): HasMany
    {
        return $this->hasMany(UserRoleMap::class, 'user_id');
    }

    public function searchQueries(): HasMany
    {
        return $this->hasMany(SearchQuery::class, 'user_id');
    }

    public function sessions(): HasMany
    {
        return $this->hasMany(Session::class, 'user_id');
    }

    public function initiatedImportBatches(): HasMany
    {
        return $this->hasMany(SourceImportBatch::class, 'initiated_by_user_id');
    }

    public function resolvedClaimRequests(): HasMany
    {
        return $this->hasMany(ClaimRequest::class, 'resolved_by_user_id');
    }
}
```

## `app/Models/Role.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Role extends Model
{
    protected $table = 'sm_roles';

    protected $fillable = [
        'code',
        'name',
        'description',
    ];

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(
            User::class,
            'sm_user_role_map',
            'role_id',
            'user_id'
        )->withPivot('tenant_id', 'created_at');
    }

    public function mappings(): HasMany
    {
        return $this->hasMany(UserRoleMap::class, 'role_id');
    }
}
```

## `app/Models/UserRoleMap.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class UserRoleMap extends Model
{
    protected $table = 'sm_user_role_map';

    public $timestamps = false;

    protected $fillable = [
        'user_id',
        'role_id',
        'tenant_id',
        'created_at',
    ];

    protected $casts = [
        'created_at' => 'datetime',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function role(): BelongsTo
    {
        return $this->belongsTo(Role::class, 'role_id');
    }

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }
}
```

## `app/Models/Domain.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Domain extends Model
{
    protected $table = 'sm_domains';

    protected $fillable = [
        'tenant_id',
        'domain',
        'is_primary',
        'ssl_status',
        'status',
    ];

    protected $casts = [
        'is_primary' => 'boolean',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }
}
```

---

# 2. Vendor graph models

## `app/Models/Vendor.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Vendor extends Model
{
    protected $table = 'sm_vendors';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'primary_account_id',
        'canonical_name',
        'legal_name',
        'display_name',
        'description_short',
        'description_long',
        'website',
        'email',
        'phone',
        'claim_status',
        'verification_status',
        'source_confidence_score',
        'enrichment_status',
        'active_status',
    ];

    protected $casts = [
        'source_confidence_score' => 'decimal:2',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function primaryAccount(): BelongsTo
    {
        return $this->belongsTo(Account::class, 'primary_account_id');
    }

    public function locations(): HasMany
    {
        return $this->hasMany(VendorLocation::class, 'vendor_id');
    }

    public function listings(): HasMany
    {
        return $this->hasMany(Listing::class, 'vendor_id');
    }

    public function categoryMappings(): HasMany
    {
        return $this->hasMany(VendorCategoryMap::class, 'vendor_id');
    }

    public function sourceMappings(): HasMany
    {
        return $this->hasMany(VendorSourceMap::class, 'vendor_id');
    }

    public function claimRequests(): HasMany
    {
        return $this->hasMany(ClaimRequest::class, 'vendor_id');
    }
}
```

## `app/Models/VendorLocation.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class VendorLocation extends Model
{
    protected $table = 'sm_vendor_locations';

    protected $fillable = [
        'uuid',
        'vendor_id',
        'location_name',
        'address1',
        'address2',
        'city',
        'state',
        'postal_code',
        'country_code',
        'latitude',
        'longitude',
        'phone',
        'email',
        'is_primary',
        'service_area_json',
        'geo_hash',
        'active_status',
    ];

    protected $casts = [
        'latitude' => 'decimal:7',
        'longitude' => 'decimal:7',
        'is_primary' => 'boolean',
        'service_area_json' => 'array',
    ];

    public function vendor(): BelongsTo
    {
        return $this->belongsTo(Vendor::class, 'vendor_id');
    }

    public function primaryForListings(): HasMany
    {
        return $this->hasMany(Listing::class, 'primary_location_id');
    }
}
```

## `app/Models/Category.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Category extends Model
{
    protected $table = 'sm_categories';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'parent_id',
        'slug',
        'name',
        'full_path',
        'level_depth',
        'description',
        'status',
        'sort_order',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function parent(): BelongsTo
    {
        return $this->belongsTo(Category::class, 'parent_id');
    }

    public function children(): HasMany
    {
        return $this->hasMany(Category::class, 'parent_id');
    }

    public function vendorMappings(): HasMany
    {
        return $this->hasMany(VendorCategoryMap::class, 'category_id');
    }

    public function listings(): HasMany
    {
        return $this->hasMany(Listing::class, 'primary_category_id');
    }

    public function searchQueries(): HasMany
    {
        return $this->hasMany(SearchQuery::class, 'category_id');
    }
}
```

## `app/Models/VendorCategoryMap.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class VendorCategoryMap extends Model
{
    protected $table = 'sm_vendor_category_map';

    public $timestamps = false;

    protected $fillable = [
        'vendor_id',
        'category_id',
        'is_primary',
        'source',
        'confidence_score',
        'created_at',
    ];

    protected $casts = [
        'is_primary' => 'boolean',
        'confidence_score' => 'decimal:2',
        'created_at' => 'datetime',
    ];

    public function vendor(): BelongsTo
    {
        return $this->belongsTo(Vendor::class, 'vendor_id');
    }

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class, 'category_id');
    }
}
```

## `app/Models/Listing.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Listing extends Model
{
    protected $table = 'sm_listings';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'vendor_id',
        'primary_location_id',
        'listing_type',
        'title',
        'subtitle',
        'slug',
        'summary',
        'body_content',
        'primary_category_id',
        'listing_status',
        'verification_status',
        'ranking_score',
        'quality_score',
        'completeness_score',
        'review_score',
        'review_count',
        'image_count',
        'video_count',
        'claimed_at',
        'published_at',
    ];

    protected $casts = [
        'ranking_score' => 'decimal:4',
        'quality_score' => 'decimal:4',
        'completeness_score' => 'decimal:4',
        'review_score' => 'decimal:2',
        'claimed_at' => 'datetime',
        'published_at' => 'datetime',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function vendor(): BelongsTo
    {
        return $this->belongsTo(Vendor::class, 'vendor_id');
    }

    public function primaryLocation(): BelongsTo
    {
        return $this->belongsTo(VendorLocation::class, 'primary_location_id');
    }

    public function primaryCategory(): BelongsTo
    {
        return $this->belongsTo(Category::class, 'primary_category_id');
    }

    public function media(): HasMany
    {
        return $this->hasMany(ListingMedia::class, 'listing_id');
    }

    public function attributes(): HasMany
    {
        return $this->hasMany(ListingAttribute::class, 'listing_id');
    }

    public function searchResults(): HasMany
    {
        return $this->hasMany(SearchResult::class, 'listing_id');
    }

    public function impressionEvents(): HasMany
    {
        return $this->hasMany(EventImpression::class, 'listing_id');
    }

    public function clickEvents(): HasMany
    {
        return $this->hasMany(EventClick::class, 'listing_id');
    }

    public function claimRequests(): HasMany
    {
        return $this->hasMany(ClaimRequest::class, 'listing_id');
    }
}
```

## `app/Models/ListingMedia.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class ListingMedia extends Model
{
    protected $table = 'sm_listing_media';

    protected $fillable = [
        'listing_id',
        'media_type',
        'storage_disk',
        'storage_path',
        'mime_type',
        'title',
        'alt_text',
        'sort_order',
        'status',
    ];

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }
}
```

## `app/Models/ListingAttribute.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class ListingAttribute extends Model
{
    protected $table = 'sm_listing_attributes';

    protected $fillable = [
        'listing_id',
        'attribute_key',
        'attribute_value',
        'attribute_type',
        'source',
    ];

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }
}
```

---

# 3. Source ingestion models

## `app/Models/Source.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Source extends Model
{
    protected $table = 'sm_sources';

    protected $fillable = [
        'code',
        'name',
        'source_type',
        'status',
        'config_json',
    ];

    protected $casts = [
        'config_json' => 'array',
    ];

    public function importBatches(): HasMany
    {
        return $this->hasMany(SourceImportBatch::class, 'source_id');
    }

    public function sourceRecords(): HasMany
    {
        return $this->hasMany(SourceRecord::class, 'source_id');
    }

    public function vendorMappings(): HasMany
    {
        return $this->hasMany(VendorSourceMap::class, 'source_id');
    }
}
```

## `app/Models/SourceImportBatch.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class SourceImportBatch extends Model
{
    protected $table = 'sm_source_import_batches';

    public $timestamps = false;

    protected $fillable = [
        'uuid',
        'source_id',
        'tenant_id',
        'initiated_by_user_id',
        'import_type',
        'search_term',
        'search_geo',
        'status',
        'total_records',
        'processed_records',
        'created_at',
        'completed_at',
    ];

    protected $casts = [
        'created_at' => 'datetime',
        'completed_at' => 'datetime',
    ];

    public function source(): BelongsTo
    {
        return $this->belongsTo(Source::class, 'source_id');
    }

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function initiatedByUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'initiated_by_user_id');
    }

    public function sourceRecords(): HasMany
    {
        return $this->hasMany(SourceRecord::class, 'batch_id');
    }
}
```

## `app/Models/SourceRecord.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class SourceRecord extends Model
{
    protected $table = 'sm_source_records';

    protected $fillable = [
        'source_id',
        'batch_id',
        'external_record_id',
        'external_url',
        'raw_payload_json',
        'normalized_payload_json',
        'dedupe_hash',
        'processing_status',
    ];

    protected $casts = [
        'raw_payload_json' => 'array',
        'normalized_payload_json' => 'array',
    ];

    public function source(): BelongsTo
    {
        return $this->belongsTo(Source::class, 'source_id');
    }

    public function batch(): BelongsTo
    {
        return $this->belongsTo(SourceImportBatch::class, 'batch_id');
    }
}
```

## `app/Models/VendorSourceMap.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class VendorSourceMap extends Model
{
    protected $table = 'sm_vendor_source_map';

    protected $fillable = [
        'vendor_id',
        'source_id',
        'external_record_id',
        'external_place_id',
        'source_url',
        'confidence_score',
        'is_primary_source',
        'last_seen_at',
    ];

    protected $casts = [
        'confidence_score' => 'decimal:2',
        'is_primary_source' => 'boolean',
        'last_seen_at' => 'datetime',
    ];

    public function vendor(): BelongsTo
    {
        return $this->belongsTo(Vendor::class, 'vendor_id');
    }

    public function source(): BelongsTo
    {
        return $this->belongsTo(Source::class, 'source_id');
    }
}
```

---

# 4. Search and event models

## `app/Models/SearchQuery.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class SearchQuery extends Model
{
    protected $table = 'sm_search_queries';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'session_id',
        'user_id',
        'raw_query',
        'normalized_query',
        'detected_location',
        'category_id',
        'latitude',
        'longitude',
        'radius_miles',
        'intent_type',
        'result_count',
        'search_source',
        'searched_at',
    ];

    protected $casts = [
        'latitude' => 'decimal:7',
        'longitude' => 'decimal:7',
        'radius_miles' => 'decimal:2',
        'searched_at' => 'datetime',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function session(): BelongsTo
    {
        return $this->belongsTo(Session::class, 'session_id');
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class, 'category_id');
    }

    public function results(): HasMany
    {
        return $this->hasMany(SearchResult::class, 'search_query_id');
    }

    public function impressionEvents(): HasMany
    {
        return $this->hasMany(EventImpression::class, 'search_query_id');
    }

    public function clickEvents(): HasMany
    {
        return $this->hasMany(EventClick::class, 'search_query_id');
    }
}
```

## `app/Models/SearchResult.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class SearchResult extends Model
{
    protected $table = 'sm_search_results';

    public $timestamps = false;

    protected $fillable = [
        'search_query_id',
        'listing_id',
        'rank_position',
        'ranking_score',
        'was_promoted',
        'promotion_source',
        'shown_at',
        'created_at',
    ];

    protected $casts = [
        'ranking_score' => 'decimal:4',
        'was_promoted' => 'boolean',
        'shown_at' => 'datetime',
        'created_at' => 'datetime',
    ];

    public function searchQuery(): BelongsTo
    {
        return $this->belongsTo(SearchQuery::class, 'search_query_id');
    }

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }
}
```

## `app/Models/Session.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class Session extends Model
{
    protected $table = 'sm_sessions';

    protected $fillable = [
        'uuid',
        'tenant_id',
        'user_id',
        'account_id',
        'session_source',
        'ip_address',
        'user_agent',
        'referrer',
        'device_type',
        'geo_json',
        'started_at',
        'last_seen_at',
    ];

    protected $casts = [
        'geo_json' => 'array',
        'started_at' => 'datetime',
        'last_seen_at' => 'datetime',
    ];

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function account(): BelongsTo
    {
        return $this->belongsTo(Account::class, 'account_id');
    }

    public function searchQueries(): HasMany
    {
        return $this->hasMany(SearchQuery::class, 'session_id');
    }

    public function impressionEvents(): HasMany
    {
        return $this->hasMany(EventImpression::class, 'session_id');
    }

    public function clickEvents(): HasMany
    {
        return $this->hasMany(EventClick::class, 'session_id');
    }
}
```

## `app/Models/EventImpression.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class EventImpression extends Model
{
    protected $table = 'sm_event_impressions';

    public $timestamps = false;

    protected $fillable = [
        'session_id',
        'search_query_id',
        'listing_id',
        'position',
        'context_type',
        'occurred_at',
        'created_at',
    ];

    protected $casts = [
        'occurred_at' => 'datetime',
        'created_at' => 'datetime',
    ];

    public function session(): BelongsTo
    {
        return $this->belongsTo(Session::class, 'session_id');
    }

    public function searchQuery(): BelongsTo
    {
        return $this->belongsTo(SearchQuery::class, 'search_query_id');
    }

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }
}
```

## `app/Models/EventClick.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class EventClick extends Model
{
    protected $table = 'sm_event_clicks';

    public $timestamps = false;

    protected $fillable = [
        'session_id',
        'search_query_id',
        'listing_id',
        'click_type',
        'destination_url',
        'fraud_score',
        'occurred_at',
        'created_at',
    ];

    protected $casts = [
        'fraud_score' => 'decimal:2',
        'occurred_at' => 'datetime',
        'created_at' => 'datetime',
    ];

    public function session(): BelongsTo
    {
        return $this->belongsTo(Session::class, 'session_id');
    }

    public function searchQuery(): BelongsTo
    {
        return $this->belongsTo(SearchQuery::class, 'search_query_id');
    }

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }
}
```

---

# 5. Claim models

## `app/Models/ClaimRequest.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class ClaimRequest extends Model
{
    protected $table = 'sm_claim_requests';

    protected $fillable = [
        'uuid',
        'vendor_id',
        'listing_id',
        'requester_name',
        'requester_email',
        'requester_phone',
        'requester_role',
        'business_email',
        'submitted_payload_json',
        'verification_method',
        'status',
        'submitted_at',
        'resolved_at',
        'resolved_by_user_id',
    ];

    protected $casts = [
        'submitted_payload_json' => 'array',
        'submitted_at' => 'datetime',
        'resolved_at' => 'datetime',
    ];

    public function vendor(): BelongsTo
    {
        return $this->belongsTo(Vendor::class, 'vendor_id');
    }

    public function listing(): BelongsTo
    {
        return $this->belongsTo(Listing::class, 'listing_id');
    }

    public function resolvedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'resolved_by_user_id');
    }

    public function verifications(): HasMany
    {
        return $this->hasMany(ClaimVerification::class, 'claim_request_id');
    }
}
```

## `app/Models/ClaimVerification.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class ClaimVerification extends Model
{
    protected $table = 'sm_claim_verifications';

    protected $fillable = [
        'claim_request_id',
        'verification_type',
        'verification_target',
        'verification_code',
        'status',
        'evidence_json',
        'verified_at',
    ];

    protected $casts = [
        'evidence_json' => 'array',
        'verified_at' => 'datetime',
    ];

    public function claimRequest(): BelongsTo
    {
        return $this->belongsTo(ClaimRequest::class, 'claim_request_id');
    }
}
```

---

# 6. Job models

## `app/Models/JobDefinition.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class JobDefinition extends Model
{
    protected $table = 'sm_job_definitions';

    protected $fillable = [
        'job_code',
        'job_name',
        'job_domain',
        'queue_name',
        'retry_limit',
        'timeout_seconds',
        'is_active',
    ];

    protected $casts = [
        'is_active' => 'boolean',
    ];

    public function queuedJobs(): HasMany
    {
        return $this->hasMany(JobQueue::class, 'job_definition_id');
    }
}
```

## `app/Models/JobQueue.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class JobQueue extends Model
{
    protected $table = 'sm_job_queue';

    protected $fillable = [
        'uuid',
        'job_definition_id',
        'tenant_id',
        'related_type',
        'related_id',
        'parent_job_id',
        'priority',
        'scheduled_for',
        'payload_json',
        'status',
        'attempt_count',
        'max_attempts',
    ];

    protected $casts = [
        'scheduled_for' => 'datetime',
        'payload_json' => 'array',
    ];

    public function definition(): BelongsTo
    {
        return $this->belongsTo(JobDefinition::class, 'job_definition_id');
    }

    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class, 'tenant_id');
    }

    public function parentJob(): BelongsTo
    {
        return $this->belongsTo(JobQueue::class, 'parent_job_id');
    }

    public function childJobs(): HasMany
    {
        return $this->hasMany(JobQueue::class, 'parent_job_id');
    }

    public function runs(): HasMany
    {
        return $this->hasMany(JobRun::class, 'job_queue_id');
    }
}
```

## `app/Models/JobRun.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class JobRun extends Model
{
    protected $table = 'sm_job_runs';

    public $timestamps = false;

    protected $fillable = [
        'job_queue_id',
        'run_number',
        'worker_name',
        'started_at',
        'finished_at',
        'status',
        'output_json',
        'metrics_json',
        'error_message',
        'created_at',
    ];

    protected $casts = [
        'started_at' => 'datetime',
        'finished_at' => 'datetime',
        'output_json' => 'array',
        'metrics_json' => 'array',
        'created_at' => 'datetime',
    ];

    public function jobQueue(): BelongsTo
    {
        return $this->belongsTo(JobQueue::class, 'job_queue_id');
    }

    public function errors(): HasMany
    {
        return $this->hasMany(JobError::class, 'job_run_id');
    }
}
```

## `app/Models/JobError.php`

```php
<?php

declare(strict_types=1);

namespace App\Models;

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

class JobError extends Model
{
    protected $table = 'sm_job_errors';

    public $timestamps = false;

    protected $fillable = [
        'job_run_id',
        'error_code',
        'error_class',
        'error_message',
        'stack_trace',
        'context_json',
        'created_at',
    ];

    protected $casts = [
        'context_json' => 'array',
        'created_at' => 'datetime',
    ];

    public function jobRun(): BelongsTo
    {
        return $this->belongsTo(JobRun::class, 'job_run_id');
    }
}
```

---

# 7. Suggested eager-loading bundles

These will help a lot.

## Listing detail bundle

```php
Listing::with([
    'tenant',
    'vendor',
    'primaryLocation',
    'primaryCategory',
    'media',
    'attributes',
])->findOrFail($id);
```

## Search results bundle

```php
SearchResult::with([
    'listing.vendor',
    'listing.primaryLocation',
    'listing.primaryCategory',
])->where('search_query_id', $queryId)->get();
```

## Vendor admin bundle

```php
Vendor::with([
    'tenant',
    'primaryAccount',
    'locations',
    'listings',
    'categoryMappings.category',
    'sourceMappings.source',
    'claimRequests.verifications',
])->findOrFail($id);
```

---

# 8. Recommended next improvements

Before coding controllers, I would add:

* `HasFactory` to every model
* `SoftDeletes` only where needed later, not everywhere
* route binding by `uuid` for public-facing models
* scoped query helpers like `forTenant($tenantId)`
* enums as PHP backed enums for `claim_status`, `listing_status`, `click_type`, job statuses

The next best step is a **Laravel migration plan + model factory/seed plan** aligned to these models and the schema file.
