feat: add reusable gallery carousel and ranking feed infrastructure

This commit is contained in:
2026-02-28 07:56:25 +01:00
parent 67ef79766c
commit 6536d4ae78
36 changed files with 3177 additions and 373 deletions

View File

@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* App\Models\RankArtworkScore
*
* Materialised ranking scores for a single artwork.
* Rebuilt hourly by RankComputeArtworkScoresJob.
*
* @property int $artwork_id
* @property float $score_trending
* @property float $score_new_hot
* @property float $score_best
* @property string $model_version
* @property \Carbon\Carbon|null $computed_at
*/
class RankArtworkScore extends Model
{
protected $table = 'rank_artwork_scores';
/** Artwork_id is the primary key; no auto-increment. */
protected $primaryKey = 'artwork_id';
public $incrementing = false;
public $timestamps = false;
protected $fillable = [
'artwork_id',
'score_trending',
'score_new_hot',
'score_best',
'model_version',
'computed_at',
];
protected $casts = [
'artwork_id' => 'integer',
'score_trending' => 'float',
'score_new_hot' => 'float',
'score_best' => 'float',
'computed_at' => 'datetime',
];
// ── Relations ──────────────────────────────────────────────────────────
public function artwork(): BelongsTo
{
return $this->belongsTo(Artwork::class, 'artwork_id');
}
// ── Helpers ────────────────────────────────────────────────────────────
/**
* Map list_type string to the corresponding score column.
*/
public static function scoreColumn(string $listType): string
{
return match ($listType) {
'new_hot' => 'score_new_hot',
'best' => 'score_best',
default => 'score_trending',
};
}
}