Add comprehensive project documentation and architecture guidelines
Establishes core rules and conventions for the FuelAlert Laravel application: architecture patterns (fat services, thin controllers), database schema with partitioned station_prices table, multi-tier notification system with Vonage and OneSignal, 4-signal scoring engine for fuel price recommendations, Stripe subscription tiers, Livewire classic component structure, and Pest testing standards.
This commit is contained in:
68
api-data.md
Normal file
68
api-data.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# External API & Data Sources
|
||||
|
||||
## UK Fuel Finder API (gov.uk) — PRIMARY SOURCE
|
||||
|
||||
- Base URL: `https://api.fuel-finder.service.gov.uk/`
|
||||
- Auth: OAuth 2.0 client credentials (client_id + client_secret → Bearer token)
|
||||
- Token stored in cache with TTL matching expiry minus 60 seconds
|
||||
- Returns: all UK station prices + station metadata
|
||||
- Update frequency: stations report within 30 minutes of price change
|
||||
- Our polling interval: every 15 minutes via scheduler
|
||||
|
||||
### FuelPriceService responsibilities
|
||||
1. Fetch OAuth token (cache it)
|
||||
2. GET all station prices
|
||||
3. Upsert `stations` table with metadata
|
||||
4. Insert new rows into `station_prices` only when price has changed for that station+fuel combo
|
||||
5. Call StationTaggingService to set `is_supermarket` and `brand`
|
||||
6. Dispatch `PricesUpdatedEvent` for downstream processing
|
||||
|
||||
### Deduplication
|
||||
Only insert a new `station_prices` row if price differs from the most recent stored price
|
||||
for that `(station_id, fuel_type)` combination. Avoids row explosion on unchanged prices.
|
||||
|
||||
### Credentials in .env
|
||||
```
|
||||
FUEL_FINDER_CLIENT_ID=
|
||||
FUEL_FINDER_CLIENT_SECRET=
|
||||
FUEL_FINDER_BASE_URL=https://api.fuel-finder.service.gov.uk
|
||||
```
|
||||
|
||||
## Postcodes.io — postcode → lat/lng
|
||||
|
||||
- URL: `https://api.postcodes.io/postcodes/{postcode}`
|
||||
- Free, no API key required
|
||||
- Called once on user registration / when postcode changes
|
||||
- Store resolved `lat` + `lng` on `users` table
|
||||
- Cache postcode lookups for 30 days (postcodes rarely change coordinates)
|
||||
|
||||
## FRED API (St. Louis Fed) — Brent crude direction
|
||||
|
||||
- Series: `DCOILBRENTEU` (daily Brent spot price)
|
||||
- URL: `https://api.stlouisfed.org/fred/series/observations?series_id=DCOILBRENTEU&api_key={key}&sort_order=desc&limit=10&file_type=json`
|
||||
- Free API key required — stored as `FRED_API_KEY` in .env
|
||||
- Fetched once daily via scheduler at 7am
|
||||
- Stored in `brent_prices` table: `(date DATE, price_usd DECIMAL(8,2))`
|
||||
- Only the 5-day trend direction is used by the scoring engine
|
||||
|
||||
## OneSignal — push notifications
|
||||
|
||||
- REST API: `https://oapi.onesignal.com/notifications`
|
||||
- App ID + REST API key stored in .env as `ONESIGNAL_APP_ID`, `ONESIGNAL_API_KEY`
|
||||
- Target by `player_id` (stored in `users.push_token`)
|
||||
- No official Laravel package needed — use Laravel HTTP client (`Http::post(...)`)
|
||||
- Free plan: 10,000 subscribers — sufficient for v1
|
||||
|
||||
## Vonage — WhatsApp + SMS
|
||||
|
||||
- Package: `vonage/client-core` via Composer
|
||||
- Credentials: `VONAGE_KEY`, `VONAGE_SECRET`, `VONAGE_WHATSAPP_FROM` in .env
|
||||
- WhatsApp: Messages API, utility template category (pre-approved)
|
||||
- SMS: SMS API, alphanumeric sender ID "FuelAlert"
|
||||
- All Vonage calls go through NotificationDispatchService — never call Vonage directly from components
|
||||
|
||||
## HTTP client
|
||||
|
||||
Use Laravel's built-in `Http` facade for all external API calls.
|
||||
Always set a timeout: `Http::timeout(10)->get(...)`.
|
||||
Wrap in try/catch — log failures, never let a failed API call crash the scheduler.
|
||||
Reference in New Issue
Block a user