feat: add postcode resolution to /api/stations and Filament SearchResource
Extends NearbyStationsRequest to accept `postcode` (full or outcode) as an alternative to lat/lng. PostcodeService resolves it via postcodes.io and falls through to coordinates. Also adds SearchResource to the Filament admin panel for viewing logged search activity with fuel type filter and price/distance stats columns. Includes SQLite GREATEST/LEAST function polyfills in AppServiceProvider for test compatibility. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Enums\PredictionSource;
|
||||
use App\Enums\TrendDirection;
|
||||
use Database\Factories\PricePredictionFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
@@ -18,6 +19,8 @@ use Illuminate\Support\Carbon;
|
||||
* @property int $confidence
|
||||
* @property string|null $reasoning
|
||||
* @property Carbon $generated_at
|
||||
*
|
||||
* @method static Builder<PricePrediction> bestFirst()
|
||||
*/
|
||||
#[Fillable(['predicted_for', 'source', 'direction', 'confidence', 'reasoning', 'generated_at'])]
|
||||
class PricePrediction extends Model
|
||||
@@ -37,4 +40,21 @@ class PricePrediction extends Model
|
||||
'generated_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by source quality: llm_with_context → llm → ewma.
|
||||
* Use this whenever reading the "best" prediction for a given date.
|
||||
*
|
||||
* @param Builder<PricePrediction> $query
|
||||
* @return Builder<PricePrediction>
|
||||
*/
|
||||
public function scopeBestFirst(Builder $query): Builder
|
||||
{
|
||||
$priority = implode(', ', array_map(
|
||||
fn (string $v) => "'$v'",
|
||||
[PredictionSource::LlmWithContext->value, PredictionSource::Llm->value, PredictionSource::Ewma->value],
|
||||
));
|
||||
|
||||
return $query->orderByRaw("FIELD(source, $priority)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,14 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
#[Fillable(['name', 'email', 'password', 'is_admin', 'postcode'])]
|
||||
#[Hidden(['password', 'two_factor_secret', 'two_factor_recovery_codes', 'remember_token'])]
|
||||
class User extends Authenticatable implements FilamentUser
|
||||
{
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory, Notifiable, TwoFactorAuthenticatable;
|
||||
use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable;
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
|
||||
Reference in New Issue
Block a user