feat: add Filament admin panel with migrations and design spec
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

- 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)
This commit is contained in:
Ovidiu U
2026-04-04 13:40:56 +01:00
parent e532cc1208
commit d5fb7f85bd
59 changed files with 3422 additions and 28 deletions

View File

@@ -0,0 +1,160 @@
# 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 0100), 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)