Includes verified API authentication flow, correct base URL, all DB table schemas for stations, current prices, history, and archive. Fuel types corrected to match live API (B7_STANDARD, B7_PREMIUM). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.4 KiB
2.4 KiB
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, 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
└── 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/.