# Architecture

## Core principle: fat Services, thin everything else

All business logic lives in Service classes. Controllers, Livewire components,
and console commands are thin orchestrators — they call Services and return results.
This keeps the app API-extractable later without a rewrite.

## Directory structure

```
app/
├── Console/Commands/       # Scheduler commands (PollFuelPrices, PredictOilPrices, RunScoringEngine)
├── Http/Controllers/       # Minimal — auth + Stripe webhook only
├── Livewire/               # Classic two-file Livewire components
├── Models/                 # Eloquent models
├── Notifications/          # Laravel Notification classes (multi-channel)
├── Services/               # ALL business logic lives here
│   ├── FuelPriceService.php        # Fuel Finder API polling + storage
│   ├── AlertScoringService.php     # Fill-up timing recommendation engine
│   ├── StationTaggingService.php   # Supermarket brand detection
│   ├── NotificationDispatchService.php  # Tier-aware notification routing
│   ├── SubscriptionService.php    # Cashier/tier helpers
│   ├── PostcodeService.php         # Resolves postcodes/outcodes/place names → lat/lng
│   ├── OilPriceService.php         # FRED fetch + EWMA/LLM Brent crude prediction
│   ├── LocationResult.php          # DTO returned by PostcodeService
│   └── ApiLogger.php               # Wraps all outbound HTTP calls, logs to api_logs
└── Jobs/                   # Queued jobs (dispatch notifications per user)

resources/views/
├── livewire/               # Livewire Blade templates
└── emails/                 # Mailable templates

routes/
├── web.php                 # All web routes (Livewire pages)
└── api.php                 # Empty for now — API added later if needed
```

## Service class conventions

- Constructor injection only — no facade usage inside Services
- Services are bound in AppServiceProvider if they need interfaces
- Each Service has one responsibility — do not merge concerns
- Return typed DTOs or Eloquent collections — never raw arrays from Services
- Services never dispatch jobs directly — that's the controller/command's job

## No API yet

`routes/api.php` stays empty for v1. Do not create API controllers or Sanctum
token auth. The app is Livewire-only until subscriber count justifies a native app.
When the API is added later, it will reuse the same Service classes.

## Livewire components (classic only)

Use two-file classic Livewire components. Do NOT use Volt single-file syntax.
Volt files from the starter kit (auth screens) are left as-is — do not convert them.
New components go in `app/Livewire/` with corresponding Blade in `resources/views/livewire/`.
