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.
62 lines
2.2 KiB
Markdown
62 lines
2.2 KiB
Markdown
# Livewire Components
|
|
|
|
## Classic two-file components only
|
|
|
|
Do NOT use Volt single-file syntax for new components.
|
|
Volt files created by the Livewire starter kit (auth screens) are left untouched.
|
|
|
|
## Component locations
|
|
|
|
```
|
|
app/Livewire/
|
|
├── Dashboard/
|
|
│ ├── FuelRecommendation.php # Main fill-up/wait card
|
|
│ ├── NearbyStations.php # Map + station list
|
|
│ └── PriceHistory.php # 14-day trend chart
|
|
├── Account/
|
|
│ ├── NotificationSettings.php # Channel prefs + WhatsApp OTP
|
|
│ ├── SubscriptionManager.php # Upgrade/downgrade UI
|
|
│ └── FuelPreferences.php # Fuel type, postcode
|
|
└── Public/
|
|
└── PriceWatchdog.php # Public-facing local price watchdog
|
|
```
|
|
|
|
## Component conventions
|
|
|
|
- Component properties that are shown in the view must be `public`
|
|
- Use `#[Computed]` attribute for derived values — not re-computed on every render
|
|
- Validate with `#[Validate]` attribute on properties, not in separate rules array
|
|
- Never put Service instantiation in the component — inject via method parameter or mount()
|
|
- Dispatch browser events with `$this->dispatch()` not `$this->emit()` (Livewire 3 syntax)
|
|
- Use `wire:loading` on all buttons that trigger server actions
|
|
|
|
## Alpine.js usage
|
|
|
|
Alpine.js handles local UI state only: dropdowns, modals, tab switching, copy-to-clipboard.
|
|
Do not replicate server state in Alpine — use Livewire for anything that needs PHP.
|
|
Alpine components stay inline in Blade (`x-data="{}"`), not in separate JS files unless reused 3+ times.
|
|
|
|
## Map (Leaflet.js)
|
|
|
|
Leaflet is a plain JS drop-in, not a Livewire component.
|
|
Station data is fetched from a dedicated Livewire endpoint and passed to Leaflet via Alpine:
|
|
```blade
|
|
<div
|
|
x-data="stationMap(@entangle('stations'))"
|
|
id="map"
|
|
style="height: 400px"
|
|
></div>
|
|
```
|
|
Map initialisation lives in `resources/js/maps/station-map.js`.
|
|
|
|
## Page routing
|
|
|
|
Livewire full-page components are mounted in `routes/web.php` using `Route::get()->component()`.
|
|
No separate view files for pages — the Livewire component IS the page.
|
|
|
|
---
|
|
paths:
|
|
- "app/Livewire/**/*.php"
|
|
- "resources/views/livewire/**/*.blade.php"
|
|
---
|