Kategori: Software Development

  • Pengalaman Membangun Backend Manajemen Gudang Menggunakan Laravel


    Pendahuluan

    Banyak pengelolaan gudang yang masih sering kali menggunakan metode pencatatan manual dalam mengelola gudang, seperti melalui buku catatan atau spreadsheet sederhana. Metode ini memiliki banyak keterbatasan, di antaranya rentan terhadap kesalahan pencatatan, sulit dalam pelacakan barang, serta lambat dalam proses pembaruan data. Akibatnya, sering terjadi ketidaksesuaian antara stok fisik dengan catatan administrasi, yang dapat menyebabkan pemborosan, keterlambatan distribusi, hingga potensi kerugian akibat kehilangan barang atau kelebihan persediaan.

    Sebagai solusi kami mengembangkan sistem backend yang memungkinkan pemantauan stok secara real-time, otomatisasi pencatatan barang masuk dan keluar, integrasi dengan sistem lain, serta analisis data untuk mendukung pengambilan keputusan yang lebih akurat. Implementasi sistem ini tidak hanya meningkatkan efisiensi dan efektivitas dalam pengelolaan gudang, tetapi juga mengurangi risiko kesalahan serta meningkatkan transparansi dalam manajemen persediaan.


    Mengapa Laravel untuk Backend Aplikasi?

    Laravel dipilih karena kami sebagai mahasiswa TI memilih tools yang sudah sangat populer dan ekosistem yang lengkap sehingga waktu atau cost saat development menjadi lebih efisien karena kami tidak perlu banyak belajar lagi untuk mempelajari teknologi baru.

    Dari segi teknis, untuk membuat routing REST API itu sangat mudah, simpel, dan juga kodenya konsisten, kemudian setup Authentication dan Authorization yang mudah, beserta mempercepat pengembangan backend dengan adanya Eloquent ORM, mudah menambah middleware untuk melakukan validasi otomatis untuk menjaga keamanan atau sanitasi pada input, serta dokumentasi laravel yang jelas dan komunitas yang sudah besar.


    Gambaran Arsitektur Backend

    • Controller: Menerima request
    • Service: Mengolah logika
    • Model: Mengelola data dan relasi antar model
    • Middleware: Otorisasi role super admin dan admin gudang
    • Resources/Response JSON: Output JSON yang standar dan rapi

    Fitur Utama dalam Sistem Manajemen Gudang

    FiturKonsep Laravel yang DigunakanManfaat
    Login Multi-RoleAuth, Middleware, PolicyPembatasan akses per jabatan
    CRUD Data Barang & KategoriEloquent ORM, Form Request ValidationManajemen stok lebih akurat
    Riwayat Pengiriman & PenerimaanRelasi Many-to-Many / One-to-ManyTracking distribusi barang
    Dashboard Ringkasan StokAggregation QueryKeputusan cepat berdasarkan data

    Pengelolaan relasi antar-entitas merupakan bagian paling penting dalam memastikan setiap transaksi terekam dengan benar.


    Contoh Implementasi API

    Route API (api.php):

    Route::middleware(['role:SuperAdmin'])->group(function () {
            Route::resource('gudangs', GudangController::class);
            Route::patch('gudangs/{id}/activate', [GudangController::class, 'activate'])->name('gudangs.activate');
            Route::patch('gudangs/{id}/deactivate', [GudangController::class, 'deactivate'])->name('gudangs.deactivate');
        });
    PHP

    Controller method untuk CRUD:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Http\Resources\GudangIndexResource;
    use Illuminate\Http\Request;
    use App\Models\GudangDanToko;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Validation\ValidationException;
    use Illuminate\Database\Eloquent\ModelNotFoundException;
    
    class GudangController extends Controller
    {
        public function index()
        {
            try {
                $GudangDanToko = GudangDanToko::where('kategori_bangunan', 0)
                    ->orderBy('id')
                    ->get([
                        'id',
                        'nama_gudang_toko',
                        'alamat',
                        'no_telepon',
                        'flag',
                    ]);
    
                $headings = [
                    "NO",
                    "Nama Gudang",
                    "Alamat",
                    "No telepon",
                    "Status"
                ];
    
                return response()->json([
                    'status' => true,
                    'message' => 'Data Gudang',
                    'data' => [
                        'gudangs' => GudangIndexResource::collection($GudangDanToko),
                        /** @var array<int, string> */
                        'headings' => $headings,
                    ],
                ]);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => 'Terjadi kesalahan saat mengambil data gudang.',
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function create()
        {
            try {
                return response()->json([
                    'status' => true,
                    'message' => 'Form Tambah Gudang',
                ]);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => 'Terjadi kesalahan saat menyiapkan form tambah gudang.',
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function store(Request $request)
        {
            $gudang = GudangDanToko::all();
            try {
                $validated = $request->validate([
                    'nama_gudang_toko' => 'required|string|max:255',
                    'alamat' => 'nullable|string',
                    'no_telepon' => 'nullable|string|max:20',
                ]);
    
                $gudang = array_merge($validated, ['kategori_bangunan' => 0]);
    
                DB::transaction(function () use ($gudang) {
                    GudangDanToko::create($gudang);
                }, 3);
    
                return response()->json([
                    'status' => true,
                    'message' => "Berhasil menambahkan data gudang.",
                ], 201);
            } catch (ValidationException $e) {
                return response()->json([
                    'status' => false,
                    'message' => 'Data yang diberikan tidak valid.',
                    'errors' => $e->errors()
                ], 422);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => 'Terjadi kesalahan saat menyimpan gudang.',
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function show(string $id)
        {
            try {
                $gudang = GudangDanToko::findOrFail($id, [
                    'id',
                    'nama_gudang_toko',
                    'alamat',
                    'no_telepon',
                    'flag'
                ]);
    
                return response()->json([
                    'status' => true,
                    'message' => "Detail Data {$gudang->nama_gudang_toko}",
                    'data' => new GudangIndexResource($gudang),
                ]);
            } catch (ModelNotFoundException $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Data gudang tidak ditemukan.",
                    'error' => $e->getMessage(), 
                ], 404);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Terjadi kesalahan saat mengambil detail data gudang.",
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function edit(string $id)
        {
            try {
                $gudang = GudangDanToko::findOrFail($id, [
                    'id',
                    'nama_gudang_toko',
                    'alamat',
                    'no_telepon'
                ]);
    
                return response()->json([
                    'status' => true,
                    'message' => "Data untuk Form Edit Gudang",
                    'data' => new GudangIndexResource($gudang),
                ]);
            } catch (ModelNotFoundException $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Data gudang tidak ditemukan.",
                    'error' => $e->getMessage(),
                ], 404);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Terjadi kesalahan saat mengambil data untuk form edit Gudang.",
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function update(Request $request, string $id)
        {
            try {
    
                $validated = $request->validate([
                    'nama_gudang_toko' => 'required|string|max:255',
                    'alamat' => 'nullable|string',
                    'no_telepon' => 'nullable|string|max:20',
                ]);
    
                $gudang = GudangDanToko::findOrFail($id);
    
                DB::transaction(function () use ($gudang, $validated) {
                    $gudang->update($validated);
                }, 3);
    
                return response()->json([
                    'status' => true,
                    'message' => "{$gudang->nama_gudang_toko} berhasil diperbarui.",
                    'data' => new GudangIndexResource($gudang)
                ]);
            } catch (ValidationException $e) {
                return response()->json([
                    'status' => false,
                    'message' => 'Data yang diberikan tidak valid.',
                    'errors' => $e->errors(),
                ], 422);
            } catch (ModelNotFoundException $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Data gudang tidak ditemukan.",
                    'error' => $e->getMessage(),
                ], 404);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Terjadi kesalahan saat memperbarui data gudang.",
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function deactivate(string $id)
        {
            try {
                $gudang = GudangDanToko::findOrFail($id);
    
                if ($gudang->flag == 0) {
                    return response()->json([
                        'status' => false,
                        'message' => "{$gudang->nama_gudang_toko} sudah dinonaktifkan.",
                    ], 409);
                }
    
                DB::transaction(function () use ($gudang) {
                    $gudang->update(['flag' => 0]);
                }, 3);
    
                return response()->json([
                    'status' => true,
                    'message' => "{$gudang->nama_gudang_toko} berhasil dinonaktifkan.",
                    'data' => new GudangIndexResource($gudang),
                ]);
            } catch (ModelNotFoundException $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Data gudang tidak ditemukan.",
                    'error' => $e->getMessage(),
                ], 404);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Terjadi kesalahan saat menonaktifkan data gudang.",
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    
        public function activate(string $id)
        {
            try {
                $gudang = GudangDanToko::findOrFail($id);
    
                if ($gudang->flag == 1) {
                    return response()->json([
                        'status' => false,
                        'message' => " {$gudang->nama_gudang_toko} sudah diaktifkan.",
                    ], 400);
                }
    
                DB::transaction(function () use ($gudang) {
                    $gudang->update(['flag' => 1]);
                }, 3);
    
                return response()->json([
                    'status' => true,
                    'message' => "{$gudang->nama_gudang_toko} berhasil diaktifkan.",
                    'data' => new GudangIndexResource($gudang),
                ], 201);
            } catch (ModelNotFoundException $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Data gudang tidak ditemukan.",
                    'error' => $e->getMessage(),
                ], 404);
            } catch (\Exception $e) {
                return response()->json([
                    'status' => false,
                    'message' => "Terjadi kesalahan saat mengaktifkan data gudang.",
                    'error' => $e->getMessage(),
                ], 500);
            }
        }
    }
    PHP

    Response JSON terstruktur:

    <?php
    
    namespace App\Http\Resources;
    
    use Carbon\Carbon;
    use App\Helpers\TimeHelpers;
    use Illuminate\Http\Request;
    use Illuminate\Http\Resources\Json\JsonResource;
    
    class GudangIndexResource extends JsonResource
    {
        /**
         * Transform the resource into an array.
         *
         * @return array<string, mixed>
         */
        public function toArray(Request $request): array
        {
            return [
                'id' => (int) $this->id,
                'nama_gudang' => $this->nama_gudang_toko,
                'alamat' => $this->alamat,
                'no_telepon' => $this->no_telepon,
                'status' => $this->flag ? 'Aktif' : 'Nonaktif',
            ];
        }
    }
    PHP

      Hasil yang Didapat

      Dengan ini backend untuk manajemen gudang sudah siap digunakan dengan client manapun (website, mobile) dan mudah untuk diintegrasikan dengan menambahkan dokumentasi API yang rapi dan mudah untuk dibaca dan dimengerti bagi developer frontend web maupun mobile. Dokumentasi API bisa melalui Swagger OpenAPI atau bisa membuat dokumentasi manual melalui fitur yang dihadirkan di Postman.


      Kesimpulan

      Laravel sangat cocok untuk backend REST API maupun dibuat fullstack dan untuk pemula yang ingin belajar menyelami dunia backend, disini teman-teman bisa banyak belajar mengenai arsitektur server-side dan keamanan akses sehingga teman-teman bisa menghasilkan backend yang cepat untuk deliver sehingga bisa dipakai segera oleh aplikasi client. Jadi jika teman-teman baru mulai belajar backend, Laravel adalah framework yang tepat untuk memulai sekaligus membangun proyek nyata yang bermanfaat bagi masyarakat luas.

    • Membangun Aplikasi Wicara: Perjalanan Membuat Aplikasi Pengaduan Kampus Menggunakan Flutter


      Pendahuluan

      Di kampus Politeknik Negeri Semarang (atau yang biasa disebut POLINES), sering sekali disini menemukan masalah mengenai fasilitas rusak, pelayanan yang kurang oke, sampai barang hilang yang informasinya hanya sekedar lewat di grup chat saja. Proses pengaduan dan laporan seperti ini masih manual dan tidak terorganisir sehingga penanganannya lambat dan membuat mahasiswa kurang puas.

      Nah, dari situ muncul ide: “gimana kalau semua hal ini bisa dilakukan lewat satu aplikasi aja? Biar lebih cepat, lebih jelas, dan tentu lebih efisien.”

      Di sinilah WICARA hadir sebagai solusi digital untuk membantu mahasiswa menyampaikan keluhan, melaporkan kehilangan, dan memberikan rating pada unit-unit pelayanan kampus. Semua jadi lebih rapi dan gampang!

      WICARA merupakan singkatan dari Wadah Informasi Catatan Aspirasi dan Rating Akademik.


      Cerita Awal Pengembangan

      Awalnya, kami melihat banyak laporan barang hilang yang ujung-ujungnya nggak jelas kabarnya. Belum lagi soal ruangan yang rusak atau pelayanan yang kurang memuaskan. Dari situ kami berpikir: “Kita kan anak TI, masa nggak bisa bikin solusi?”

      Akhirnya kami memutuskan untuk membuat aplikasi mobile menggunakan Flutter karena enak dipakai, tampilannya modern, dan bisa jalan di banyak perangkat. Fitur awal yang kami bangun fokus ke tiga hal utama:

      1. Lapor fasilitas rusak
      2. Laporan barang hilang
      3. Rating pelayanan kampus (misalnya poliklinik di kampus)

      Mengenal Flutter Secara Ringan

      Alasan kenapa kami memilih Flutter sebagai tools yang kami pakai untuk membangun sistem WICARA adalah cross-platform sehingga aplikasi bisa di deploy ke android and ios. Kemudian banyak sekali library yang sudah menyiapkan widget atau UI yang sudah siap pakai. Terakhir, karena komunitas Flutter merupakan komunitas yang besar sehingga ketika kami menghadapi masalah atau perlu melakukan debugging kami mudah untuk mencari referensi atau jawaban atas masalah yang sedang dihadapi saat pengembangan.


      Tantangan dalam Pengembangan

      Kesulitan dan tantangan yang kami hadapi sepanjang pengembangan adalah pengimplementasian desain antarmuka yang dibuat figma dikonversi ke widget UI di Flutter itu memakan banyak waktu karena dari kami belum ada pengalaman sama sekali menggunakan Flutter jadi kami masih sering kesulitan untuk slicing UI nya.

      Pemanggilan API dan pengiriman data ke server juga sedikit memakan waktu karena perlu adaptasi dengan best practice yang biasanya orang-orang terapkan ketika melakukan pemanggilan API dan pengiriman data ke server.

      Alur atau flow aplikasi atau sistem yang masih berubah-ubah karena perubahan requirement yang masih labil mengakibatkan fase pengembangan menjadi lebih lama karena kami menggunakan Agile.

      Selain itu, kami juga masih belum terbiasa dengan kolaboratif tim jadi masih harus membiasakan dan ini merupakan salah satu faktor yang menjadi penghambat atau tantangan kami saat mengembangkan aplikasi ini.


      Fitur-Fitur Unggulan Wicara

      Fitur-fitur yang kami hadirkan ada 3 yaitu:

      1. Lapor fasilitas yang kurang dengan melapor dengan informasi detail lokasi fasilitas
      2. Lapor barang hilang sehingga kampus bisa menemukan barangnya dan mengembalikan barang ke pemilik
      3. Rating unit kampus seperti poliklinik

      Fitur-fitur ini cukup untuk MVP aplikasi kami sehingga bisa menyelesaikan permasalahan utama dan yang umum terjadi di lingkungan kampus kami.


      Harapan & Pengembangan ke Depan

      Keinginan dan harapan kami dari aplikasi atau sistem yang kami buat ini agar bisa benar-benar membantu kampus bisa semakin lebih baik dan juga berkembang sehingga bisa membuat orang-orang di kampus menjadi lebih nyaman dengan hadirnya aplikasi yang kami buat.


      Penutup

      Kiranya melalui pengalaman saya mengenai membangun sistem menggunakan platform Flutter yang saya bagikan disini bisa menginspirasi teman-teman untuk bisa mengembangkan aplikasi atau sistem dengan dasar adanya kebutuhan dari masyarakat kampus. Mewujudkan aplikasi bisa melalui tools Flutter yang ramah sekali untuk pemula karena aplikasinya ketika jadi bisa didistribusikan ke android maupun ios sehingga bisa mengurangi biaya dan mempercepat proses pengembangan aplikasi yang teman-teman bikin biar bisa memberikan dampak dan kontribusi nyata ke masyarakat kampus maupun masyarakat luas di sekitar teman-teman.

    • Membangun Aplikasi “Leader Election App” Menggunakan Laravel sebagai Full Stack Framework


      Pendahuluan

      Sebagai mahasiswa Teknik Informatika, saya sering mendengar bahwa Laravel adalah salah satu framework PHP terbaik untuk membangun aplikasi web. Namun awalnya, saya masih ragu apakah Laravel cukup kuat untuk menangani full stack development dalam satu framework saja, tanpa harus menambahkan framework frontend lain seperti React atau Vue.

      Di sinilah saya mulai membuat sebuah aplikasi sederhana yang saya beri nama Leader Election App, dengan tujuan membuktikan bahwa Laravel tetap bisa menjadi pilihan tepat untuk membangun aplikasi fullstack yang dinamis sekaligus powerful.


      Apa itu Leader Election App?

      Secara sederhana, aplikasi ini digunakan untuk melakukan pemilihan ketua dalam suatu organisasi. Pengguna bisa login, melihat kandidat, dan memberikan suara. Sistem kemudian akan menyimpan hasil suara dan menampilkan ringkasan hasil pemilihan jika waktu pemilihan sudah habis.

      Walaupun terdengar sederhana, di dalamnya ada fitur-fitur penting seperti manajemen user, otorisasi, CRUD data, dan pengolahan data di dashboard.


      Kenapa Saya Memilih Laravel sebagai Fullstack?

      Saat mulai merancang aplikasi ini, saya mempertimbangkan beberapa poin seperti:

      • Laravel itu sudah menyediakan Blade templating yang berarti kita bisa bikin frontend yang dinamis dengan mudah
      • Authentication sangat mudah disetup (menggunakan Laravel Breeze/Jetstream atau manual)
      • Arsitekturnya rapi dan mudah dipahami (MVC -> Model View Controller)
      • Dokumentasi Laravel yang sangat lengkap sehingga cocok untuk pemula
      • Banyak fitur bawaan dan library yang menghemat waktu development

      Jadi, dengan satu framework saja saya bisa mengatur routing, logic bisnis, database, dan tampilan. Itu sangat membantu saya memahami alur aplikasi dari ujung ke ujung.


      Proses Pengembangan

      Di awal pengembangan, saya langsung setup projek Laravel dan mulai dari menambahkan autentikasi pada user. Tantangan pertama saya disini adalah memahami alur request dari View -> Controller -> Model -> Database, begitu juga ketika memahami alur response yang mulai dari Database -> Model -> Controller -> View.

      Di tahap in saya banyak melakukan trial and error terutama dalam:

      • Mendesain migrasi database
      • Setup rute dan controller
      • Membuat view dengan menggunakan Blade template engine

      Terkadang saya membuat beberapa kesalahan yang sempat terulang beberapa kali yaitu lupa untuk cache seperti caching route, view, dll sehingga membuat aplikasi terasa lambat.


      Fitur-Fitur Utama yang Dibangun

      • Autentikasi pengguna: login & register
      • Role user sederhana: admin dan user biasa
      • CRUD kandidat: admin bisa menambah/mengedit kandidat
      • CRUD voter: admin bisa menambah dan menghapus voter
      • Voting: user memberikan pilihan secara langsung
      • Dashboard hasil pemilihan: menampilkan total suara dan ringkasan kandidat

      Fitur ini saja sudah memberikan gambaran lengkap tentang bagaimana backend dan frontend saling terhubung di Laravel.


      Arsitektur & Flow Sederhana

      Secara garis besar, alurnya seperti ini:

      • User mengakses halaman Blade
      • View mengirim request ke Route
      • Route memanggil Controller
      • Controller mengolah data via Model ke Database
      • Controller mengembalikan data ke View
      • Tampilan diperbarui secara dinamis

      Dengan alur MVC ini, saya belajar pentingnya pemisahan logika aplikasi dan antarmuka.


      Tools & Teknologi yang Digunakan

      • Laravel (Framework utama)
      • Blade Template Engine
      • Tailwind untuk tampilan UI yang cepat dan responsif
      • MySQL sebagai database
      • Git & GitHub untuk version control

      Hasil Akhir

      Saya berhasil membangun aplikasi e-voting yang berfungsi dari awal hingga akhir. Pengguna bisa login dan voting, kemudian dari sisi Admin bisa menampilkan hasil ringkasan jumlah suara yang terkumpul untuk masing-masing kandidat. Projek ini menjadi pengalaman berharga dalam memahami konsep fullstack web development.


      Penutup

      Melalui projek ini, saya belajar bahwa kita tidak harus ahli dulu untuk mulai membangun aplikasi atau sistem, kita justru menjadi ahli ketika kita berani untuk memulai.

      Saya berharap cerita ini bisa menginspirasi teman-teman yang masih ragu memulai projek menggunakan Laravel. Framework ini sangat ramah pemula, tapi tetap kuat untuk membuat aplikasi yang siap dipakai secara produksi.

    • Alasan Masuk ke Teknik Informatika


      Sebenarnya alasan saya masuk ke teknik informatika dan masuk ke dunia IT itu pada dasarnya awalnya tidak jauh-jauh dari karena adanya keinginan untuk menjadi programmer yang handal yang bisa membuat kode dan algoritma yang bagus haha, tapi di sisi lain saya melihat di dunia IT itu kesempatan mencari pundi-pundi uang itu sangat tidak terbatas hanya pada kerja di kantor, tapi bisa juga mencari uang dari freelancer atau kerja remote dengan perusahaan atau client yang berada jauh dari tempat kita tinggal di Indonesia maupun di mancanegara.

      Selain karena alasan yang saya sebutkan sebelumnya saya juga tertarik dengan banyaknya bidang di dunia IT yang sangat luas ini mulai dari bidang software yang membuat aplikasi dengan basis web yang sudah sangat populer saat ini kemudian ada aplikasi berbasis desktop yang biasanya digunakan di kantor maupun di sekolah-sekolah dan aplikasi berbasis perangkat bergerak atau mobile yang belakangan ini marak-maraknya bermunculan, kemudian ada bidang network yang membahas mengenai jaringan komputer, bagaimana komputer bisa berkomunikasi dengan komputer lainnya hingga ke bagaimana kita mengakses web seseorang yang disetup oleh web server seperti Apache dan Nginx.

      Sebenarnya masih banyak lagi bidang yang ingin saya sebutkan disini yang masuk ke dunia IT tapi dari beberapa alasan sebelumnya yang sudah saya sebutkan itu sudah meyakinkan saya untuk masuk ke teknik informatika, disitu saya bisa belajar banyak hal mulai dari membuat dan mendesain software dan database yang efisien, arsitektur komputer, setup jaringan komputer hingga setup layanan komputasi awan, AI/ML (Artificial Intelligence/Machine Learning) yang sekarang sedang populer-populernya sehingga hal-hal yang saya pelajari ini harapannya bisa menjadi bekal saya untuk menjadi seseorang yang bisa beradaptasi hingga jangka panjang di dunia IT dan juga bisa membawa perubahan yang bermakna bagi orang-orang atau masyarakat sekitar, karena ilmu yang kita punya tidak akan berguna jika kita ujung-ujungnya tidak bisa membawa perubahan atau manfaat positif bagi masyarakat sekitar kita.