- 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)
161 lines
5.7 KiB
Markdown
161 lines
5.7 KiB
Markdown
# Filament Admin Panel — Design Spec
|
||
|
||
**Date:** 2026-04-04
|
||
**Stack:** Laravel 11, Filament v5, Livewire v4
|
||
**Scope:** Admin panel for FuelAlert — internal tooling only, no user-facing exposure
|
||
|
||
---
|
||
|
||
## 1. Access & Auth
|
||
|
||
- Filament panel mounted at `/admin`
|
||
- Protected by `is_admin` boolean on `users` table
|
||
- Migration adds `is_admin TINYINT(1) DEFAULT 0` to `users`
|
||
- `AdminPanelProvider` uses `->authGuard('web')` (same guard as the main app — no separate admin users table)
|
||
- `canAccessPanel()` check: `$user->is_admin === true`
|
||
- `uovidiu@sent.com` seeded as admin via a dedicated `AdminSeeder` (idempotent — safe to re-run)
|
||
- No self-registration on the admin panel — access is granted only via the `is_admin` flag
|
||
|
||
---
|
||
|
||
## 2. Dashboard Page
|
||
|
||
Default landing page. Four `StatsOverviewWidget` cards:
|
||
|
||
| Stat | Source | Alert |
|
||
|---|---|---|
|
||
| Total users | `users` count | — |
|
||
| Stations in DB | `stations` count + `max(last_seen_at)` | — |
|
||
| Latest oil prediction | Most recent `price_predictions` row — direction, confidence, source | Yellow if > 24h old |
|
||
| API errors (24h) | `api_logs` where `status_code >= 400` or `error IS NOT NULL`, last 24h | Red if > 0 |
|
||
|
||
No charts on the dashboard — keep it scannable. Charts live inside individual resources.
|
||
|
||
---
|
||
|
||
## 3. Resources
|
||
|
||
### 3.1 Users (`UserResource`)
|
||
|
||
**Purpose:** View all registered users, manage admin flag, correct postcodes.
|
||
|
||
**Table columns:** name, email, postcode, is_admin (badge), created_at
|
||
**Filters:** is_admin toggle
|
||
**Actions:**
|
||
- Edit: `is_admin` toggle, `postcode` text field (no other fields editable from admin)
|
||
- Delete: allowed (hard delete, with confirmation modal)
|
||
|
||
**Notes:**
|
||
- No subscription tier column yet — add when Cashier is integrated
|
||
- No impersonation in v1 — add later when user dashboard exists
|
||
|
||
---
|
||
|
||
### 3.2 API Logs (`ApiLogResource`)
|
||
|
||
**Purpose:** Primary debugging tool — see every outbound HTTP call made by the scheduler.
|
||
|
||
**Table columns:** service (badge), method, url (truncated), status_code (colour-coded), duration_ms, error (truncated), created_at
|
||
**Filters:** service (select: `fuel_finder`, `fred`, `anthropic`), errors only (toggle: where error IS NOT NULL or status >= 400), date range
|
||
**Default sort:** created_at DESC
|
||
**Actions:** View (modal showing full url, full error, request/response if available) — no edit, no delete
|
||
|
||
**Colour coding for status_code:**
|
||
- 2xx → success (green)
|
||
- 4xx → warning (yellow)
|
||
- 5xx / null → danger (red)
|
||
|
||
---
|
||
|
||
### 3.3 Oil Predictions (`OilPredictionResource`)
|
||
|
||
**Purpose:** Verify the daily `oil:predict` job is running and producing sensible output.
|
||
|
||
**Table columns:** predicted_for (date), source (badge: LLM / EWMA), direction (badge: rising/falling/flat with colour), confidence (progress bar 0–100), reasoning (truncated), generated_at
|
||
**Filters:** source, direction, date range
|
||
**Default sort:** predicted_for DESC
|
||
**Actions:**
|
||
- View (modal showing full reasoning text)
|
||
- **Run prediction now** (page-level action): executes `php artisan oil:predict` via `Artisan::call()`, shows success/failure notification
|
||
|
||
**No edit/delete** — predictions are immutable audit records.
|
||
|
||
---
|
||
|
||
### 3.4 Brent Prices (`BrentPriceResource`)
|
||
|
||
**Purpose:** Verify FRED fetch is populating data correctly.
|
||
|
||
**Table columns:** date, price_usd
|
||
**Default sort:** date DESC
|
||
**Actions:** none
|
||
|
||
Simple read-only table. No filters needed — data is always chronological. Include a line chart widget (`BrentPriceChartWidget`) showing the last 30 days using Filament's built-in chart widget.
|
||
|
||
---
|
||
|
||
### 3.5 Stations (`StationResource`)
|
||
|
||
**Purpose:** Browse the ~14,500 UK stations; verify supermarket tagging and closure flags.
|
||
|
||
**Table columns:** trading_name, brand_name, postcode, city, is_supermarket (badge), is_motorway_service_station (badge), temporary_closure (badge), last_seen_at
|
||
**Filters:** is_supermarket, is_motorway_service_station, temporary_closure, permanent_closure, postcode prefix (text search)
|
||
**Search:** trading_name, brand_name, postcode
|
||
**Default sort:** last_seen_at DESC
|
||
**Actions:**
|
||
- View (modal with full address, amenities, opening_times, fuel_types JSON)
|
||
- **Trigger full poll** (page-level action): dispatches a queued `PollFuelPricesJob` (wraps `fuel:poll --full`) rather than calling Artisan synchronously — full station refresh on 14,500 records would exceed HTTP timeout. Shows "Poll dispatched to queue" notification immediately; result visible in API Logs once complete.
|
||
|
||
**No edit** — station data is owned by Fuel Finder API, overwritten on each poll.
|
||
|
||
---
|
||
|
||
## 4. Resources Planned But Not Built Yet
|
||
|
||
These will be added once the underlying tables/services exist:
|
||
|
||
| Resource | Depends on |
|
||
|---|---|
|
||
| Alerts Log | `alerts` table + `NotificationDispatchService` |
|
||
| Scoring Results | `scoring_results` table + `AlertScoringService` |
|
||
| Subscriptions | Cashier integration + `subscriptions` table |
|
||
|
||
---
|
||
|
||
## 5. Navigation Groups
|
||
|
||
```
|
||
Dashboard (no group)
|
||
├── Users
|
||
Data
|
||
├── Stations
|
||
├── Brent Prices
|
||
├── Oil Predictions
|
||
System
|
||
├── API Logs
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Build Order
|
||
|
||
1. Migration — add `is_admin` to `users`
|
||
2. `AdminSeeder` — seed `uovidiu@sent.com` as admin
|
||
3. `AdminPanelProvider` — mount panel, configure auth
|
||
4. `ApiLogResource` — highest immediate value
|
||
5. `UserResource` — manage admin flag
|
||
6. `OilPredictionResource` + run-prediction action
|
||
7. `BrentPriceResource` + chart widget
|
||
8. `StationResource` + full-poll action
|
||
9. Dashboard widgets (last — depends on all resources being stable)
|
||
|
||
---
|
||
|
||
## 7. Out of Scope (v1)
|
||
|
||
- Role-based permissions beyond `is_admin` — single admin user is sufficient
|
||
- Activity log / audit trail of admin actions
|
||
- Dark mode customisation
|
||
- Custom Filament theme — use default
|
||
- Two-factor auth on admin panel — covered by app-level 2FA (Fortify)
|