Reconciles tier docs with `PlanSeeder` reality (basic has price_threshold
and score_alerts; schema is stripe_price_id_monthly + stripe_price_id_annual)
and introduces the display-name layer from pricing-plan.md v2.
- PlanTier::label() + Plan::displayName() + PlanFeatures::displayName()
expose user-facing names (Free/Daily/Smart/Pro); backend identifiers stay
basic/plus/pro so every call site, Stripe mapping, and test keeps working.
- push.frequency key added to features JSON (none/daily/triggered), mirroring
email.frequency so Daily's daily push is distinguishable from Smart/Pro's
triggered push. Seeder, factory, free-tier stubs, and Filament form updated.
- Homepage pricing cards renamed: Basic→Daily, Plus→Smart; badge
"Most Popular"→"Most pick this"; CTAs refreshed.
- docs/tiers.md change log records the full diff.
Fleet tier, 14-day trial copy, and Smart dark-card treatment deferred.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add comprehensive tier feature matrix spec defining Free/Basic/Plus/Pro capabilities across recommendations, predictions, history, logs, tools, and family sharing
- Add `stripe_price_id_annual` column to plans table and rename existing column to `stripe_price_id_monthly`
- Normalize legacy fuel type aliases (petrol→e10, diesel→b7_standard) in users table
- Implement BillingController with checkout, portal, success/cancel routes supporting monthly/annual cadence
- Add admin subscription assignment in Filament user edit page with admin-granted subscription support
- Add DowngradeUserOnSubscriptionDeleted listener to disable WhatsApp/SMS preferences on subscription cancellation
- Add MissedNotificationsOverview widget to Filament user detail page
- Add PollFuelPricesTest covering auto-refresh scenarios
- Add PriceReliability enum with reliability classification based on price age
- Add fuelTypes.js constants file exporting FUEL_TYPES from window global
- 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'
- BrentPriceFetcher owns ingestion (fetchFromEia / fetchFromFred, each throws on failure)
- BrentPricePredictor owns prediction and marks latest brent_prices row as generated
- oil:fetch command tries EIA, falls back to FRED, fails loudly if both fail
- oil:predict command prompts if latest price already has a prediction; --force bypasses
- add prediction_generated_at column to brent_prices
- delete OilPriceService (replaced by the two focused services)
OilPriceService no longer inlines per-provider fetch/transform/error logic.
EIA and FRED are now their own classes with a common shape; the service
just iterates and upserts the first successful result.
Adds authenticated endpoints for reading/updating fuel type preferences and managing saved stations, backed by new migrations and a SavedStation model.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enables stateful API via Sanctum so the Vue SPA can call /api/* routes
using cookie auth, without requiring an X-Api-Key header.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Implements PredictionRequest (fuel_type validation with ValueError→ValidationException), PredictionController delegating to NationalFuelPredictionService, and 5 feature tests. Also fixes LEAST() MySQL-only function to a CASE WHEN expression for SQLite test compatibility.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
User management resource with editable is_admin field, postcode support,
admin filter, and inline delete action. Includes list and edit pages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>