Task 1 Completion Report

Project: Monitoring Dashboard — Go-Parts Central
Task: Saved Filter Presets — Migration & Model
Completed: March 5, 2026
Environment: Production (central.go-parts.com)
✓ COMPLETED
Summary
Create database table and Eloquent model for saving per-user filter presets on the Monitoring Dashboard.
2 new files
None
Table exists & migration recorded in migrations table
Files Created
database/migrations/2026_03_05_000001_create_user_filter_presets_table.php CREATED

Laravel migration that creates the user_filter_presets table. Includes a foreign key to users.user_id with cascade delete, and a composite index on (user_id, page) for fast per-user, per-page queries.

Schema::create('user_filter_presets', function (Blueprint $table) {
    $table->id();
    $table->unsignedInteger('user_id');
    $table->string('page', 50);        // e.g. 'monitoring'
    $table->string('name', 100);        // user-given preset name
    $table->json('filters');              // saved filter state
    $table->tinyInteger('is_default')->default(0);
    $table->timestamps();
    $table->index(['user_id', 'page']);
    $table->foreign('user_id')->references('user_id')->on('users')->onDelete('cascade');
});
app/Models/UserFilterPreset.php CREATED

Eloquent model for the user_filter_presets table. The filters field auto-casts to/from PHP array. The is_default field auto-casts to boolean. Includes two query scopes for clean filtering in controllers.

class UserFilterPreset extends Model
{
    protected $fillable = ['user_id', 'page', 'name', 'filters', 'is_default'];

    protected $casts = [
        'filters'    => 'array',
        'is_default' => 'boolean',
    ];

    // Relationship
    public function user(): BelongsTo
        => $this->belongsTo(User::class, 'user_id', 'user_id');

    // Scopes
    public function scopeForPage($query, string $page)
        => $query->where('page', $page);

    public function scopeForUser($query, int $userId)
        => $query->where('user_id', $userId);
}
Database Table — user_filter_presets
Column Type Nullable Default Notes
idbigint unsignedNOPrimary key, auto-increment
user_idint unsignedNOFK → users.user_id (cascade delete)
pagevarchar(50)NOe.g. 'monitoring'
namevarchar(100)NOUser-given preset name
filtersjsonNOSaved filter state as JSON object
is_defaulttinyintNO01 = auto-load on page open
created_attimestampYESNULLLaravel timestamp
updated_attimestampYESNULLLaravel timestamp

Index: Composite index on (user_id, page) for fast per-user, per-page lookups.
Foreign Key: user_id → users.user_id ON DELETE CASCADE — presets are automatically deleted when a user is removed.

Acceptance Criteria — Verification Results
Criterion Result Verified By
Migration runs without error ✓ PASS Table confirmed present via DESCRIBE user_filter_presets
Model can be instantiated and saved ✓ PASS UserFilterPreset::save() executed, id=1 returned
filters field casts to/from array ✓ PASS Saved as JSON, retrieved as PHP array
is_default casts to boolean ✓ PASS Retrieved value confirmed as false (bool)
scopeForPage() filters correctly ✓ PASS Query returned correct record
scopeForUser() filters correctly ✓ PASS Query returned correct record
No other files modified ✓ PASS Only 2 new files created
What This Enables (Next Steps)