- Add AdminPanelProvider mounting panel at `/admin` with `is_admin` auth guard - Add `is_admin` boolean column to users table - Add brent_prices and price_predictions tables with appropriate indexes - Add comprehensive admin design spec covering resources, dashboard, navigation, and build order - Configure default panel with amber primary color and standard middleware stack - Add compiled Filament assets (actions.js, app.css)
2.8 KiB
2.8 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, 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/.