Remove obsolete Livewire fuel search components and consolidate pricing tiers
- Delete unused Livewire Search test and fuel type select Blade component - Move subscription webhook listener from EventServiceProvider to AppServiceProvider - Add FUEL_TYPES global config to app layout for client-side use - Add Billable trait to User model and include email_verified_at in fillable - Implement monthly/annual cadence toggle with pricing display and smart CTA routing on homepage - Update VerifyApiKeyMiddlewareTest to use e10 instead of petrol - Refactor PollFuelPrices to auto-refresh stale stations based on last_seen_at - Add incremental polling with cached timestamp and effective-start-timestamp param to FuelPriceService - Normalize amenities/fuel_types from API objects to flat arrays, skip stations missing required fields - Log response body on API failures in ApiLogger - Default homepage sort to 'reliable' instead of 'price'
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
- Base URL: `https://www.fuel-finder.service.gov.uk/api/v1/`
|
||||
- Returns: all UK station prices + station metadata (~14,500 stations)
|
||||
- Update frequency: stations report within 30 minutes of price change
|
||||
- Our polling interval: every 15 minutes via scheduler (incremental), full refresh once daily
|
||||
- Our polling interval: every 30 minutes via scheduler (incremental using `effective-start-timestamp`), station metadata auto-refreshed once per day on the first poll after midnight
|
||||
|
||||
### Authentication
|
||||
|
||||
@@ -35,24 +35,34 @@ Content-Type: application/json
|
||||
- Include token in every API request: `Authorization: Bearer {token}`
|
||||
|
||||
#### Endpoints
|
||||
- `GET /api/v1/pfs/fuel-prices?batch-number` — all/incremental station prices
|
||||
- `GET /api/v1/pfs?batch-number` — all/incremental station metadata
|
||||
- `GET /api/v1/pfs/fuel-prices?batch-number={n}` — all station prices (500 stations per batch)
|
||||
- `GET /api/v1/pfs/fuel-prices?batch-number={n}&effective-start-timestamp=YYYY-MM-DD HH:MM:SS` — incremental, only prices changed since timestamp
|
||||
- `GET /api/v1/pfs?batch-number={n}` — all station metadata (500 per batch)
|
||||
- `GET /api/v1/pfs?batch-number={n}&effective-start-timestamp=YYYY-MM-DD HH:MM:SS` — incremental station metadata
|
||||
|
||||
**Fuel prices response fields** (array of stations):
|
||||
- `node_id` — station identifier
|
||||
- `trading_name` — station name
|
||||
- `node_id`, `public_phone_number`, `trading_name` — station identifiers
|
||||
- `fuel_prices[]` — array of `{fuel_type, price, price_last_updated, price_change_effective_timestamp}`
|
||||
- Fuel types: `E5`, `E10`, `B7_STANDARD`, `B7_PREMIUM`, `B10`, `HVO`
|
||||
- Fuel types (API casing): `E5`, `E10`, `B7_Standard`, `B7_Premium`, `B10`, `HVO` — lowercased on ingest via `FuelType::fromApiValue()`
|
||||
- Price is a float (e.g. `159.9` = 159.9p) — multiply × 100 and store as integer pence
|
||||
|
||||
**Station metadata response fields** (array of stations):
|
||||
- `node_id`, `trading_name`, `brand_name`
|
||||
- `node_id`, `trading_name`, `brand_name`, `is_same_trading_and_brand_name`, `public_phone_number`
|
||||
- `is_supermarket_service_station`, `is_motorway_service_station`
|
||||
- `temporary_closure`, `permanent_closure`
|
||||
- `location` — `{address_line_1, city, postcode, latitude, longitude}`
|
||||
- `amenities` — string array (e.g. `car_wash`, `adblue_pumps`)
|
||||
- `fuel_types` — string array of available fuel types
|
||||
- `opening_times` — per-day open/close times (not used in scoring)
|
||||
- `temporary_closure`, `permanent_closure`, `permanent_closure_date`
|
||||
- `location` — `{address_line_1, address_line_2, city, county, country, postcode, latitude, longitude}`
|
||||
- `amenities` — **OBJECT** with boolean flags: `{adblue_pumps, adblue_packaged, lpg_pumps, car_wash, air_pump_or_screenwash, water_filling, twenty_four_hour_fuel, customer_toilets}`. Normalised at ingest to a flat array of enabled keys.
|
||||
- `fuel_types` — **OBJECT** with boolean flags: `{E10, E5, B7_Standard, B7_Premium, B10, HVO}`. Normalised at ingest to a flat array of enabled keys.
|
||||
- `opening_times` — `usual_days.{monday..sunday}.{open, close, is_24_hours}` + `bank_holidays.type.{open_time, close_time, is_24_hours}`. Stored as raw JSON, not used in scoring.
|
||||
|
||||
### Required-field validation
|
||||
Stations missing any of `node_id`, `trading_name`, `location.postcode`, `location.latitude`, `location.longitude` are dropped at ingest with a warning. Price rows missing any of `fuel_type`, `price`, `price_last_updated`, `price_change_effective_timestamp` are skipped silently.
|
||||
|
||||
### Incremental polling (FuelPriceService::pollPrices)
|
||||
On each successful poll the wall-clock start time is cached under `fuel_finder_last_price_poll_at` (forever). The next poll sends this as `effective-start-timestamp`. Cold start (cache miss) performs a full fetch.
|
||||
|
||||
### FK safety
|
||||
Price batches are filtered against the `stations` table before insert — any station not yet in `stations` is skipped and logged. This guards against new stations appearing in the prices endpoint before the next metadata refresh picks them up.
|
||||
|
||||
### FuelPriceService responsibilities
|
||||
1. Fetch OAuth token (cache it)
|
||||
|
||||
Reference in New Issue
Block a user