Filament Admin Panel
Mounted at /systemadmin and implemented entirely in backend/app/Filament/.
Panel provider
app/Providers/Filament/SystemadminPanelProvider.php wires the panel:
$panel
->id('systemadmin')
->path('systemadmin')
->authGuard('systemadmin')
->spa()
->colors(['primary' => Color::Amber])
->discoverResources(in: app_path('Filament/Resources'),
for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'),
for: 'App\\Filament\\Pages')
->discoverWidgets(in: app_path('Filament/Widgets'),
for: 'App\\Filament\\Widgets')
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([Authenticate::class]);
Resources
Each resource is a CRUD unit. The convention is:
Filament/Resources/<Plural>/
├── <Singular>Resource.php # entry point (getModel(), pages())
├── Schemas/<Singular>Form.php # form definition
├── Tables/<Plural>Table.php # list-view columns + filters
└── Pages/
├── List<Plural>.php
├── Create<Singular>.php
└── Edit<Singular>.php
SystemAdmins
Manage platform operators.
- Form fields: name, email, phone, password (hashed on save).
- Table columns: name, email, phone, created_at.
Tenants
Manage clinics.
- Form fields: name, slug, email, phone, address, subscription_plan, status.
- Table columns: name, slug, email, plan badge, status badge.
- Overview widget:
TenantOverview— aggregates subscribed plans and active count.
Users
Clinic staff and owners (both live in the same table, filterable by account_type).
- Form fields: name, email, phone, account_type, current_tenant_id.
- Table columns: name, email, account_type, current tenant.
Clients
Pet owners as seen by clinics.
- Form fields: tenant, linked owner user (optional), full_name, email, phone, address, status.
- Table columns: full_name, tenant.name, email, phone, status.
Pets
- Form fields: tenant, client, name, species, breed, sex, date_of_birth, weight_kg, color_markings, allergies, medical_flags, status.
- Table columns: name, species, breed, client.full_name, status.
Appointments
- Form fields: tenant, pet, client, veterinarian (user), appointment_type, status, booking_source, scheduled_start, scheduled_end, reason, notes.
- Table columns: scheduled_start, pet.name, client.full_name, status, veterinarian.name.
- Filters: status, booking_source, date range.
Invoices
- Form fields: tenant, client, pet, invoice_number, invoice_type, status, totals (subtotal, tax_total, discount_total, grand_total, balance_due), currency, issued_at, due_at, notes.
- Table columns: invoice_number, client.full_name, grand_total (currency-formatted), status badge.
Payments
- Form fields: tenant, invoice, amount, payment_method, status, reference_number, paid_at.
- Table columns: invoice.invoice_number, amount, payment_method, status, paid_at.
Reminders
- Form fields: tenant, client, pet, title, reminder_type, channel, due_at, status, payload (JSON).
- Table columns: title, reminder_type, channel, due_at, status.
- Custom action: "Mark as sent" — bulk action to flip status.
Widgets
Filament/Widgets/OverviewDashboard.php renders the platform-level overview on the Filament dashboard:
- Total tenants, active tenants, suspended tenants.
- Users count split by
account_type. - Pets/appointments totals across all tenants.
Authentication
The Filament panel logs in through the systemadmin guard, which points at the SystemAdmin model and the system_admins provider defined in config/auth.php. It uses session auth — no bearer tokens — so every write request includes the standard Laravel CSRF token.
Adding a new Filament resource
php artisan make:filament-resource Foo --generate
This creates the FooResource.php, pages, schema and table stubs inside app/Filament/Resources/Foo/. Edit the form/table definitions, then visit /systemadmin/foo to use it.