Banyak dashboard yang dibuat developer justru tidak berguna: penuh angka besar yang terlihat mengesankan tetapi tidak membantu pengambilan keputusan. Ini disebut vanity metrics. Dashboard analitik yang baik menjawab pertanyaan nyata pemilik bisnis: "apakah penjualan bulan ini naik?", "produk mana yang laku?", "kapan jam ramai?". Tutorial ini menunjukkan cara membangun dashboard yang berguna di Laravel 11 — mulai dari memilih metrik yang tepat, agregasi data dengan Eloquent, mengumpan Chart.js, hingga men-cache query berat.
1. Pilih KPI, Bukan Vanity Metrics
Sebelum menulis kode, tentukan metrik yang bisa ditindaklanjuti. Bedakan keduanya:
- Vanity metric: total pengunjung sepanjang masa. Angkanya besar tapi tidak memandu tindakan apa pun.
- KPI yang berguna: pendapatan 30 hari terakhir dibanding periode sebelumnya, jumlah transaksi harian, produk terlaris, rata-rata nilai transaksi (AOV).
Aturan praktisnya: sebuah metrik layak dipasang jika ada keputusan yang berubah ketika angkanya berubah.
2. Agregasi Kartu Ringkasan
Kartu ringkasan (summary card) memakai count() dan sum() dengan filter rentang tanggal. Hindari mengambil seluruh baris lalu menghitung di PHP — biarkan database yang menghitung karena jauh lebih cepat.
use App\Models\Order;
use Carbon\Carbon;
$start = Carbon::now()->subDays(30);
$revenue = Order::where('created_at', '>=', $start)->sum('total');
$orderCount = Order::where('created_at', '>=', $start)->count();
$avgOrderValue = $orderCount > 0 ? $revenue / $orderCount : 0;
Untuk membandingkan dengan periode sebelumnya (agar muncul indikator naik/turun), hitung rentang yang sama panjang tepat sebelum periode ini:
$prevRevenue = Order::whereBetween('created_at', [
Carbon::now()->subDays(60),
Carbon::now()->subDays(30),
])->sum('total');
$growth = $prevRevenue > 0
? round(($revenue - $prevRevenue) / $prevRevenue * 100, 1)
: 0; // persentase pertumbuhan
3. Agregasi Deret Waktu untuk Grafik
Grafik tren memerlukan data dikelompokkan per hari. Gunakan selectRaw dengan DATE() lalu groupBy. Kembalikan hasil sebagai pasangan tanggal → total.
$daily = Order::query()
->where('created_at', '>=', Carbon::now()->subDays(30))
->selectRaw('DATE(created_at) as day, SUM(total) as revenue')
->groupBy('day')
->orderBy('day')
->pluck('revenue', 'day');
Masalah umum: hari tanpa transaksi tidak muncul, sehingga grafik "bolong". Isi tanggal kosong dengan nol supaya sumbu waktu rapi:
$labels = [];
$values = [];
for ($i = 29; $i >= 0; $i--) {
$date = Carbon::now()->subDays($i)->toDateString();
$labels[] = $date;
$values[] = (int) ($daily[$date] ?? 0);
}
4. Controller yang Mengembalikan Data Siap Pakai
Kumpulkan semua agregat di controller dan kirim ke view. Tambahkan juga produk terlaris memakai groupBy pada item transaksi:
public function index()
{
$topProducts = OrderItem::query()
->selectRaw('product_name, SUM(qty) as sold')
->groupBy('product_name')
->orderByDesc('sold')
->limit(5)
->get();
return view('dashboard', [
'revenue' => $this->revenue(),
'growth' => $this->growth(),
'chartLabels' => $this->chartLabels(),
'chartValues' => $this->chartValues(),
'topProducts' => $topProducts,
]);
}
5. Mengumpan Chart.js dengan JSON
Chart.js hanya butuh dua array: label dan data. Kirim dari Blade sebagai JSON dengan @json agar aman dari masalah kutip:
<canvas id="revenueChart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
new Chart(document.getElementById('revenueChart'), {
type: 'line',
data: {
labels: @json($chartLabels),
datasets: [{
label: 'Pendapatan Harian',
data: @json($chartValues),
borderColor: '#3b4b8b',
tension: 0.3,
}]
}
});
</script>
6. Cache Agregat Berat
Query agregasi bisa berat jika data jutaan baris dan halaman dashboard sering dibuka. Karena angka analitik tidak harus real-time, simpan hasilnya di cache selama beberapa menit. Ini mengurangi beban database secara drastis.
use Illuminate\Support\Facades\Cache;
$daily = Cache::remember('dashboard.daily_revenue', now()->addMinutes(10), function () {
return Order::query()
->where('created_at', '>=', Carbon::now()->subDays(30))
->selectRaw('DATE(created_at) as day, SUM(total) as revenue')
->groupBy('day')
->pluck('revenue', 'day');
});
Jika data harus lebih segar setelah ada transaksi baru, hapus cache-nya di event pembuatan order: Cache::forget('dashboard.daily_revenue').
Kesalahan Umum yang Perlu Dihindari
- Menghitung agregat di PHP: mengambil ribuan baris lalu
sum()collection sangat lambat. Gunakansum()/groupBymilik query builder. - Menampilkan vanity metrics: angka besar tanpa konteks perbandingan tidak membantu keputusan. Selalu sandingkan dengan periode sebelumnya.
- Lupa mengisi tanggal kosong: grafik jadi menyesatkan karena hari nol dilewati begitu saja.
Dashboard yang berguna bukan soal banyaknya grafik, melainkan seberapa cepat pemakainya bisa mengambil keputusan. Fokus pada beberapa KPI yang dapat ditindaklanjuti, hitung agregat di database, umpan grafik dengan JSON yang bersih, dan cache query berat — itulah resep dashboard yang benar-benar dipakai.
Kesalahan Umum Membangun Dashboard
Banyak dashboard gagal berguna karena menampilkan terlalu banyak metrik sekaligus sehingga pengguna kebingungan menentukan mana yang penting. Kesalahan lain adalah memakai grafik yang tidak sesuai jenis data, atau menyajikan angka tanpa konteks pembanding seperti periode sebelumnya maupun target. Dashboard yang baik fokus pada sedikit metrik kunci yang benar-benar mendorong keputusan, memakai visual yang tepat, dan memberi konteks agar angka mudah dimaknai. Hindari pula memuat seluruh data mentah ke satu halaman; sediakan ringkasan di atas dan detail yang bisa digali bila diperlukan. Terakhir, jaga performa: dashboard yang lambat karena kueri berat akan jarang dibuka. Dengan menghindari kesalahan ini, dashboard analitik Anda menjadi alat pengambilan keputusan yang benar-benar dipakai, bukan sekadar hiasan yang terlihat canggih namun membingungkan.