@extends('layouts.app') @section('title', 'Dashboard') @section('content')

Operations dashboard

{{ auth()->user()->organization?->name }} · {{ now()->format('l, j F Y H:i') }} {{ config('app.timezone') }}

+ New customer + New service Take payment
{{-- ============ Financial + subscriber KPIs ============ --}}
@include('components.kpi', ['label' => 'Monthly recurring revenue', 'value' => money($kpi['mrr']), 'variant' => 'good', 'href' => route('reports.financial'), 'delta' => 'ARR '.money($kpi['arr'])]) @include('components.kpi', ['label' => 'ARPU', 'value' => money($kpi['arpu']), 'variant' => 'info', 'href' => route('reports.subscribers'), 'delta' => $kpi['active_customers'].' active accounts']) @include('components.kpi', ['label' => 'Active services', 'value' => number_format($kpi['active_services']), 'href' => route('services.index', ['status' => 'active']), 'delta' => $kpi['suspended_services'].' suspended']) @include('components.kpi', ['label' => 'Online now', 'value' => number_format($kpi['online_now']), 'variant' => 'good', 'href' => route('radius.sessions', ['online' => 1]), 'delta' => 'live RADIUS sessions']) @include('components.kpi', ['label' => 'Outstanding', 'value' => money($finance['outstanding']), 'variant' => $finance['outstanding'] > 0 ? 'warn' : 'good', 'href' => route('reports.collections'), 'delta' => $collections['overdue_invoices'].' overdue invoices']) @include('components.kpi', ['label' => 'Collected today', 'value' => money($finance['collected_today']), 'variant' => 'good', 'href' => route('payments.index'), 'delta' => money($finance['collected_month']).' this month'])
{{-- Revenue trend --}}

Revenue collected — last 30 days

Successful payments by day
Report →
@include('components.chart', [ 'series' => collect($charts['revenue_30d'])->map(fn ($p) => [ 'label' => \Carbon\Carbon::parse($p['date'])->format('d M'), 'value' => $p['total'], ])->all(), 'type' => 'line', 'format' => 'money', 'height' => 200, ])
{{-- MRR trend --}}

MRR & subscriber trend

Nightly KPI snapshot, 12 months
Report →
@if (count($charts['mrr_trend']) > 1) @include('components.chart', [ 'series' => collect($charts['mrr_trend'])->map(fn ($p) => [ 'label' => \Carbon\Carbon::parse($p['date'])->format('M'), 'value' => $p['mrr'], ])->all(), 'type' => 'line', 'format' => 'money', 'height' => 200, ]) @else
📈 No KPI snapshots yet

Run php artisan nowills:snapshot to build the first data point.

@endif
{{-- Network health --}}

Network health

NOC →
Devices up
{{ $noc['devices']['up'] }}/{{ $noc['devices']['total'] }}
Availability 30d
{{ number_format($noc['availability'], 2) }}%
Active alerts {{ $noc['alerts']['active'] }} ({{ $noc['alerts']['critical'] }} critical)
Raised today{{ $noc['alerts']['today'] }}
Maintenance windows{{ count($noc['maintenance']) }}
@if ($criticalAlerts->isNotEmpty())
Critical now
@foreach ($criticalAlerts as $alert)
{{ $alert->severity }} {{ $alert->title }}
@endforeach @endif
{{-- Service delivery --}}

Service delivery

Tickets →
SLA breached {{ $operations['tickets_breached'] }}
Devices down {{ $operations['devices_down'] }}

Plan mix
@forelse (collect($charts['plan_mix'])->take(6) as $plan) @php $maxSubs = collect($charts['plan_mix'])->max('subscribers') ?: 1; @endphp
{{ $plan['plan'] }} {{ $plan['subscribers'] }}
@empty

No active subscriptions yet.

@endforelse
{{-- Collections --}}

Receivables

Detail →
Collection rate {{ number_format($finance['collection_rate'] ?? 0, 1) }}%
Overdue amount {{ money($collections['overdue_amount']) }}
New this month{{ $kpi['new_this_month'] }}
Churned this month {{ $kpi['churned_this_month'] }}
Aging
@php $agingMax = max(1, collect($collections['aging'])->max('amount')); @endphp @foreach ($collections['aging'] as $bucket)
{{ $bucket['label'] }} {{ money($bucket['amount']) }}
@endforeach
{{-- Overdue invoices --}}

Overdue invoices

All →
@forelse ($overdueInvoices as $invoice) @empty @endforelse
InvoiceCustomerBalanceDays
{{ $invoice->invoice_number }} {{ $invoice->customer->display_name }} {{ money($invoice->balance, $invoice->currency) }} {{ (int) $invoice->due_date->diffInDays(now()) }} Collect
@include('components.empty-state', ['icon' => '✓', 'title' => 'No overdue invoices', 'message' => 'Every account is current.'])
{{-- Live sessions --}}

Live sessions

All →
@forelse ($liveSessions as $session) @empty @endforelse
SubscriberIPNASUptimeTraffic
@if ($session->service) {{ $session->username }} @else {{ $session->username }} @endif {{ $session->framed_ip ?: '—' }} {{ $session->nas_ip }} {{ $session->duration_label }} {{ $session->traffic_label }}
@include('components.empty-state', ['icon' => '🔌', 'title' => 'No live sessions', 'message' => 'Sessions appear here once the NAS starts sending RADIUS accounting.'])
{{-- Open tickets --}}

Latest tickets

+ New
@forelse ($openTickets as $ticket) @empty @endforelse
TicketCustomerPriorityOwnerAge
{{ $ticket->ticket_number }}
{{ $ticket->subject }}
{{ $ticket->customer->display_name }} {{ $ticket->priority }} {{ $ticket->assignee?->name ?: 'Unassigned' }}
@include('components.empty-state', ['icon' => '✉', 'title' => 'No open tickets'])
{{-- Pending work orders --}}

Field jobs

Board →
@forelse ($pendingWorkOrders as $wo) @empty @endforelse
JobCustomerTypeTechnicianScheduled
{{ $wo->work_order_number }} {{ $wo->customer?->display_name ?: '—' }} {{ title_case_words($wo->type) }} {{ $wo->technician?->name ?: 'Unassigned' }} {{ $wo->scheduled_start?->format('d M H:i') ?: '—' }}
@include('components.empty-state', ['icon' => '🔧', 'title' => 'No pending jobs'])
{{-- Recent services --}}

Recently provisioned services

All services →
@forelse ($recentServices as $service) @empty @endforelse
ServiceCustomerPlanRADIUS user PriceStatusNext bill
{{ $service->service_number }} {{ $service->customer->display_name }} {{ $service->plan?->name }} {{ $service->username }} {{ money($service->effective_price, $service->customer->currency) }} {{ $service->status }} {{ $service->next_billing_date?->format('d M Y') ?: '—' }}
@include('components.empty-state', ['icon' => '⇄', 'title' => 'No services yet', 'message' => 'Provision your first subscriber to get started.', 'action' => '+ New service'])
@endsection