Aplikasi ERP Laravel: Cara Membangun Sistem yang Cepat dan Ringan
Aplikasi ERP Laravel membutuhkan perencanaan yang matang sejak awal, terutama jika sistem akan digunakan untuk mengelola transaksi, stok, pembelian, penjualan, keuangan, pelanggan, hingga laporan bisnis dalam jumlah besar.
ERP atau Enterprise Resource Planning bukan sekadar aplikasi dengan banyak menu. Di dalamnya terdapat berbagai proses yang saling berhubungan dan hampir semuanya bergantung pada database. Ketika jumlah transaksi semakin besar, masalah performa biasanya mulai muncul dari query yang tidak efisien, struktur tabel yang kurang tepat, terlalu banyak data yang diproses dalam satu request, atau proses berat yang seharusnya dijalankan secara asynchronous.
Karena itu, membangun ERP menggunakan Laravel tidak cukup hanya dengan membuat fitur berjalan. Arsitektur aplikasi harus dirancang agar tetap responsif ketika jumlah data dan pengguna bertambah.
Laravel menyediakan Query Builder, Eloquent ORM, database transaction, cache, queue, scheduler, serta berbagai komponen lain yang dapat digunakan untuk membangun aplikasi berskala besar. Dokumentasi resminya juga menyediakan pembahasan mengenai database, monitoring query, koneksi read/write, dan berbagai fitur pendukung lainnya.
Mengapa Performa Database Sangat Penting dalam Sistem ERP?
Database merupakan salah satu komponen paling sibuk dalam aplikasi ERP.
Bayangkan sebuah perusahaan memiliki:
- 100.000 data pelanggan.
- 500.000 transaksi penjualan.
- 300.000 detail transaksi.
- 200.000 data pembelian.
- Ribuan perubahan stok setiap hari.
- Banyak pengguna yang mengakses sistem secara bersamaan.
Jika setiap halaman melakukan query tanpa optimasi, beban database dapat meningkat dengan cepat.
Masalah tersebut biasanya terlihat dalam bentuk:
- Halaman dashboard semakin lambat.
- Laporan membutuhkan waktu lama.
- Proses pencarian terasa berat.
- Server menggunakan CPU dan RAM tinggi.
- Timeout ketika banyak pengguna mengakses sistem.
- Transaksi menjadi lambat ketika database semakin besar.
Oleh karena itu, performa sebaiknya dipikirkan sejak tahap desain, bukan setelah aplikasi sudah mengalami masalah.
Prinsip Dasar Membangun Aplikasi ERP Laravel
Ada beberapa prinsip yang sebaiknya diterapkan sejak awal.
1. Jangan Membebankan Semua Proses ke Database
Database sebaiknya digunakan untuk pekerjaan yang memang menjadi tanggung jawabnya, seperti menyimpan dan mengambil data.
Proses yang berat seperti:
- membuat laporan PDF,
- mengirim email dalam jumlah besar,
- sinkronisasi marketplace,
- sinkronisasi stok,
- import ribuan data,
- generate dokumen,
- mengirim notifikasi,
lebih baik dipisahkan dari request utama.
Untuk pekerjaan seperti ini, sistem queue dapat digunakan agar pengguna tidak perlu menunggu seluruh proses selesai.
Laravel menyediakan mekanisme queue untuk memindahkan pekerjaan yang membutuhkan waktu lama ke proses background.

Desain Database Harus Dipikirkan Sejak Awal
Performa aplikasi sangat dipengaruhi oleh bagaimana database dirancang.
Contohnya, sistem penjualan sebaiknya tidak menyimpan seluruh informasi transaksi dalam satu tabel besar.
Struktur yang lebih terorganisir dapat berupa:
sales
├── id
├── customer_id
├── invoice_number
├── transaction_date
├── subtotal
├── discount
├── tax
└── grand_total
sales_items
├── id
├── sale_id
├── product_id
├── quantity
├── price
└── subtotal
Dengan struktur seperti ini, data transaksi dan detail barang dapat dikelola secara terpisah tetapi tetap memiliki hubungan yang jelas.
Gunakan foreign key untuk menjaga integritas data dan index pada kolom yang sering digunakan dalam pencarian maupun relasi.
Dokumentasi MySQL menjelaskan bahwa index dapat mempercepat pencarian baris berdasarkan kondisi tertentu, tetapi index yang terlalu banyak juga menambah biaya pada operasi INSERT, UPDATE, dan DELETE. Karena itu, index harus dibuat berdasarkan pola query yang benar-benar digunakan.
Optimasi Query Laravel
Salah satu sumber masalah performa yang paling sering ditemukan adalah query yang tidak efisien.
Contoh sederhana:
$products = Product::all();
Jika tabel memiliki ratusan ribu data, mengambil seluruh record tentu bukan pendekatan yang ideal.
Lebih baik gunakan pagination:
$products = Product::query()
->latest()
->paginate(20);
Dengan cara tersebut, aplikasi hanya mengambil data yang diperlukan untuk halaman saat ini.
Laravel juga menyediakan Query Builder dan Eloquent untuk berinteraksi dengan database. Parameter binding pada query membantu mencegah SQL injection ketika nilai pengguna digunakan dalam query.
Hindari Masalah N+1 Query
Masalah N+1 sering muncul ketika aplikasi mengambil data relasi satu per satu.
Contoh yang kurang efisien:
$orders = Order::all();
foreach ($orders as $order) {
echo $order->customer->name;
}
Jika terdapat banyak transaksi, aplikasi dapat menghasilkan query tambahan untuk setiap customer.
Gunakan eager loading:
$orders = Order::with('customer')->get();
foreach ($orders as $order) {
echo $order->customer->name;
}
Pendekatan tersebut membantu mengurangi jumlah query yang dikirim ke database.
Laravel mendukung eager loading melalui relasi Eloquent sehingga data relasi dapat diambil secara lebih efisien.
Baca juga: Panduan Optimasi Database MySQL untuk Meningkatkan Performa Website dan Aplikasi
Gunakan Index Berdasarkan Kebutuhan
Tidak semua kolom perlu diberikan index.
Prioritaskan kolom yang sering digunakan untuk:
WHEREJOINORDER BY- pencarian berdasarkan kode
- pencarian berdasarkan nomor invoice
- relasi foreign key
Contoh migration:
Schema::table('sales', function (Blueprint $table) {
$table->index('customer_id');
$table->index('transaction_date');
});
Untuk nomor invoice yang harus unik:
Schema::table('sales', function (Blueprint $table) {
$table->unique('invoice_number');
});
Jangan membuat index pada setiap kolom hanya karena ingin mempercepat query. Index juga membutuhkan ruang penyimpanan dan harus diperbarui ketika data berubah.
Gunakan EXPLAIN untuk Menganalisis Query
Jangan menebak penyebab query lambat.
Gunakan EXPLAIN untuk melihat bagaimana MySQL menjalankan sebuah query.
Contohnya:
EXPLAIN
SELECT *
FROM sales
WHERE customer_id = 100;
Hasil analisis dapat membantu mengetahui apakah database menggunakan index atau justru melakukan full table scan.
Dokumentasi MySQL menjelaskan bahwa EXPLAIN dapat digunakan untuk melihat execution plan, termasuk bagaimana tabel digabungkan dan index apa yang digunakan oleh optimizer.
Dengan demikian, proses optimasi dapat dilakukan berdasarkan data, bukan asumsi.
Batasi Data yang Diambil
Kesalahan umum lainnya adalah mengambil terlalu banyak kolom.
Contoh:
$customers = Customer::all();
Jika halaman hanya membutuhkan nama dan email, lebih baik:
$customers = Customer::query()
->select(['id', 'name', 'email'])
->paginate(20);
Cara ini membantu mengurangi jumlah data yang dikirim dari database ke aplikasi.
Prinsipnya sederhana: ambil hanya data yang benar-benar dibutuhkan.
Gunakan Pagination pada Data Besar
Halaman seperti:
- daftar pelanggan,
- daftar produk,
- transaksi penjualan,
- pembelian,
- stok,
- laporan,
sebaiknya tidak menampilkan seluruh data sekaligus.
Gunakan pagination:
$customers = Customer::paginate(25);
Untuk dataset yang sangat besar atau proses background, chunk() maupun cursor() dapat dipertimbangkan sesuai kebutuhan.
Dengan pagination, aplikasi tidak perlu memuat ribuan bahkan jutaan record hanya untuk menampilkan sebagian kecil data kepada pengguna.
Manfaatkan Cache
Tidak semua data harus selalu dibaca langsung dari database.
Data yang relatif jarang berubah dapat disimpan dalam cache.
Contohnya:
- daftar kategori,
- konfigurasi perusahaan,
- daftar satuan produk,
- hak akses,
- pengaturan aplikasi,
- dashboard summary tertentu.
Contoh sederhana:
$categories = Cache::remember(
'categories',
3600,
function () {
return Category::orderBy('name')->get();
}
);
Dengan pendekatan ini, query yang sama tidak perlu selalu dijalankan pada setiap request.
Laravel menyediakan sistem cache yang dapat digunakan untuk menyimpan data sementara dan mendukung beberapa backend penyimpanan.
Jangan Membuat Dashboard dengan Query Berlebihan
Dashboard ERP sering menjadi halaman yang berat karena menampilkan banyak informasi sekaligus.
Misalnya:
- total penjualan hari ini,
- penjualan bulan berjalan,
- jumlah pelanggan,
- stok menipis,
- piutang,
- hutang,
- grafik penjualan,
- produk terlaris.
Jika setiap widget menjalankan banyak query secara terpisah, halaman akan semakin lambat.
Salah satu pendekatan adalah menggabungkan query yang memungkinkan, menggunakan cache untuk statistik yang tidak harus real-time, serta memindahkan proses perhitungan berat ke background job.
Untuk laporan yang kompleks, pertimbangkan membuat tabel agregasi atau summary agar sistem tidak harus menghitung ulang jutaan transaksi setiap kali halaman dibuka.
Pisahkan Proses Berat dengan Queue
Bayangkan pengguna melakukan proses:
Klik “Generate Laporan Bulanan”
Kemudian sistem harus:
- Mengambil jutaan transaksi.
- Menghitung total.
- Membuat file Excel.
- Membuat PDF.
- Mengirim email.
- Menyimpan file.
Jika seluruh proses dilakukan dalam satu HTTP request, pengguna harus menunggu sangat lama.
Solusi yang lebih baik adalah:
User
↓
Request
↓
Create Job
↓
Queue
↓
Background Worker
↓
Generate Report
↓
Save File
↓
Send Notification
Dengan arsitektur tersebut, request utama dapat segera memberikan respons kepada pengguna sementara pekerjaan berat diproses di belakang layar.
Gunakan Transaction untuk Proses Bisnis Penting
ERP memiliki banyak transaksi yang harus menjaga konsistensi data.
Contohnya ketika melakukan penjualan:
Simpan invoice
↓
Simpan detail invoice
↓
Kurangi stok
↓
Catat jurnal
↓
Simpan pembayaran
Jika salah satu proses gagal, aplikasi tidak boleh meninggalkan data setengah jadi.
Gunakan database transaction:
DB::transaction(function () use ($data) {
$sale = Sale::create($data);
foreach ($data['items'] as $item) {
SaleItem::create([
'sale_id' => $sale->id,
'product_id' => $item['product_id'],
'quantity' => $item['quantity'],
'price' => $item['price'],
]);
}
});
Jika terjadi exception di dalam transaction, perubahan dapat dibatalkan sehingga konsistensi data lebih terjaga.
Terapkan Read dan Write Database Secara Terpisah
Ketika jumlah pengguna semakin besar, beban database dapat dipisahkan antara operasi baca dan tulis.
Konsep sederhananya:
Application
|
+---- READ ----> Database Replica
|
+---- WRITE ---> Primary Database
Laravel mendukung konfigurasi koneksi read/write sehingga query pembacaan dapat diarahkan ke server tertentu dan operasi penulisan tetap menuju server utama.
Namun, pendekatan ini tidak selalu diperlukan untuk semua proyek. Gunakan ketika beban sistem memang sudah membutuhkan arsitektur tersebut.
Monitoring Query dan Performa
Optimasi tidak berhenti setelah aplikasi selesai dibuat.
Performa harus dipantau secara berkala.
Beberapa metrik yang dapat diperhatikan:
- Waktu eksekusi query.
- Jumlah query per request.
- Penggunaan CPU.
- Penggunaan RAM.
- Database connection.
- Queue backlog.
- Response time.
- Error rate.
- Slow query.
Laravel juga menyediakan mekanisme untuk memantau query yang berjalan serta menetapkan threshold waktu query tertentu sehingga pengembang dapat menemukan request yang menghabiskan terlalu banyak waktu di database.
Struktur Kode Harus Mudah Dikembangkan
ERP biasanya terus berkembang.
Hari ini mungkin hanya memiliki:
Master Data
Penjualan
Pembelian
Stok
Beberapa tahun kemudian bisa bertambah menjadi:
Accounting
HR
Payroll
CRM
Warehouse
Manufacturing
Purchase
Sales
Asset Management
Reporting
Karena itu, struktur kode harus dipisahkan berdasarkan tanggung jawab.
Contohnya:
app/
├── Models/
├── Services/
├── Repositories/
├── Actions/
├── Jobs/
├── Events/
├── Listeners/
├── Policies/
└── Http/
├── Controllers/
└── Requests/
Tidak semua proyek harus menggunakan struktur yang sama. Yang paling penting adalah setiap komponen memiliki tanggung jawab yang jelas dan tidak mencampurkan terlalu banyak proses dalam satu controller.
Gunakan Service untuk Proses Bisnis Kompleks
Hindari controller yang berisi ratusan baris kode.
Misalnya proses pembuatan invoice dapat dipindahkan ke service:
class CreateSaleService
{
public function execute(array $data)
{
return DB::transaction(function () use ($data) {
// Validasi bisnis
// Simpan transaksi
// Simpan detail
// Update stok
// Catat pembayaran
});
}
}
Controller kemudian cukup memanggil service:
public function store(
StoreSaleRequest $request,
CreateSaleService $service
) {
$sale = $service->execute($request->validated());
return redirect()
->route('sales.show', $sale);
}
Struktur seperti ini membuat kode lebih mudah diuji, dipelihara, dan dikembangkan.
Jangan Mengejar Performa Secara Berlebihan
Sistem yang cepat bukan berarti semua hal harus dibuat kompleks.
Tidak semua aplikasi membutuhkan:
- database cluster,
- microservices,
- read replica,
- Redis cluster,
- Elasticsearch,
- Kubernetes,
- message broker.
Jika jumlah pengguna masih kecil, arsitektur sederhana yang dirancang dengan benar sering kali sudah cukup.
Prinsip yang lebih sehat adalah:
Ukur terlebih dahulu, temukan bottleneck, kemudian optimalkan bagian yang memang bermasalah.
Dengan pendekatan tersebut, biaya infrastruktur dan kompleksitas sistem dapat tetap terkendali.
Internal Link yang Disarankan
Untuk memperkuat struktur internal website, artikel ini dapat dihubungkan dengan konten lain yang masih berkaitan, misalnya:
- Optimasi Database MySQL untuk Performa Website →
/optimasi-database-mysql - Belajar Laravel untuk Pemula →
/belajar-laravel - Integrasi API dengan Laravel →
/integrasi-api-laravel - Panduan Membuat REST API Laravel →
/rest-api-laravel - Jasa Pembuatan Aplikasi ERP →
/jasa-pembuatan-erp
Letakkan tautan tersebut pada paragraf yang memang membahas topik terkait, bukan sekadar menumpuk link di bagian akhir.
Outbound Link yang Relevan
Untuk memperkuat kredibilitas artikel, gunakan sumber resmi dan relevan.
Dokumentasi Laravel – Database
Laravel Database Documentation
Dokumentasi Laravel – Eloquent Relationships
Laravel Eloquent Relationships
Dokumentasi Laravel – Queues
Laravel Queues
Dokumentasi Laravel – Cache
Laravel Cache
Dokumentasi MySQL – Optimization
MySQL Optimization
Sumber-sumber tersebut relevan karena membahas langsung database, indexing, query optimization, cache, queue, serta pengelolaan performa aplikasi. Dokumentasi MySQL secara khusus membahas optimasi SQL, struktur database, index, execution plan, caching, dan pengukuran performa.
Checklist Sebelum ERP Masuk Production
Sebelum sistem digunakan secara penuh, lakukan pemeriksaan berikut:
Database
- Primary key sudah tersedia.
- Foreign key digunakan dengan tepat.
- Index berdasarkan pola query.
- Tidak ada query yang tidak diperlukan.
- Query besar sudah dianalisis menggunakan
EXPLAIN. - Backup berjalan otomatis.
- Monitoring database tersedia.
Laravel
- Eager loading diterapkan pada relasi yang diperlukan.
- Pagination digunakan untuk data besar.
- Cache diterapkan pada data yang sesuai.
- Proses berat menggunakan queue.
- Transaction digunakan untuk proses bisnis penting.
- Validasi request diterapkan.
- Error handling tersedia.
- Logging tidak menyimpan informasi sensitif.
Infrastruktur
- HTTPS aktif.
- Database tidak terbuka langsung ke publik.
- Backup disimpan pada lokasi terpisah.
- Monitoring server tersedia.
- Queue worker dipantau.
- Resource server dievaluasi berdasarkan penggunaan nyata.
Kesimpulan
Membangun Aplikasi ERP Laravel yang cepat dan ringan bukan hanya masalah memilih framework yang tepat. Performa sangat ditentukan oleh desain database, kualitas query, penggunaan index, pengelolaan relasi, caching, queue, transaction, serta kemampuan sistem dalam memproses data secara efisien.
Mulailah dari arsitektur yang sederhana tetapi terstruktur. Gunakan pagination untuk dataset besar, eager loading untuk menghindari N+1 query, EXPLAIN untuk menganalisis SQL, cache untuk data yang sesuai, serta queue untuk pekerjaan yang membutuhkan waktu lama.
Ketika jumlah pengguna dan transaksi meningkat, barulah pertimbangkan strategi lanjutan seperti pemisahan read/write database, replica, worker tambahan, dan optimasi infrastruktur.
Yang paling penting, jangan melakukan optimasi berdasarkan perkiraan semata. Ukur performa, temukan bottleneck, lakukan perubahan, kemudian ukur kembali. Dengan pendekatan tersebut, sistem ERP dapat tetap responsif, mudah dikembangkan, dan mampu mengikuti pertumbuhan kebutuhan bisnis.