Tutorial

Panduan Lengkap Membangun Aplikasi Kas Kecil: Monorepo, Backend, Frontend, dan Mobile

D
Donar Azhar
10 Feb 2026 215 views
Panduan Lengkap Membangun Aplikasi Kas Kecil: Monorepo, Backend, Frontend, dan Mobile

Membangun aplikasi multi-platform (web dan mobile) dari nol adalah proses yang kompleks. Dalam artikel ini, saya akan membagikan secara detail bagaimana proses pembuatan Aplikasi Kas Kecil (Petty Cash) — sebuah sistem pengelolaan keuangan berbasis metode Imprest yang berjalan di web dan mobile. Artikel ini bisa menjadi panduan referensi untuk membangun aplikasi serupa di masa depan.

📋 Gambaran Proyek

Kas Kecil adalah aplikasi untuk mengelola dana kas kecil (petty cash) di organisasi multi-level. Fitur utamanya meliputi:

  • Manajemen organisasi hierarkis: Instansi → Cabang → Unit
  • Input transaksi pengeluaran dan pengisian kas (metode Imprest/Dana Tetap)
  • Role-based access: Super Admin dan Admin Unit
  • Upload bukti transaksi (lampiran)
  • Dashboard dan laporan keuangan
  • Tersedia di Web (admin panel) dan Mobile (untuk petugas lapangan)

🏗️ Arsitektur Monorepo

Apa Itu Monorepo?

Monorepo adalah pendekatan di mana semua bagian aplikasi (backend, frontend, mobile) disimpan dalam satu repository GitHub yang sama. Ini berbeda dengan pendekatan multi-repo di mana setiap bagian memiliki repository terpisah.

Mengapa Monorepo?

  • Satu tempat — Semua kode ada di satu repo, mudah di-clone dan di-manage
  • Konsistensi — Perubahan di backend dan frontend bisa di-commit bersamaan
  • Shared code — Bisa berbagi logic, tipe data, dan validasi antara web dan mobile
  • Satu history — Git log menampilkan keseluruhan perjalanan proyek

Struktur Folder Monorepo Kas Kecil

kaskecil/                    # Root monorepo
├── api/                     # Backend - Laravel 12 (REST API)
│   ├── app/                 # Models, Controllers, Services
│   ├── database/            # Migrations, Seeders
│   ├── routes/              # API routes
│   ├── composer.json        # PHP dependencies
│   └── .env                 # Environment variables
│
├── web/                     # Frontend - React + Vite + Tailwind
│   ├── src/                 # Components, Pages, Hooks
│   ├── package.json         # Node dependencies (KHUSUS web)
│   ├── vite.config.ts       # Vite build configuration
│   └── tailwind.config.js   # Tailwind CSS configuration
│
├── mobile/                  # Mobile - React Native + Expo
│   ├── src/                 # Screens, Components, Navigation
│   ├── app.json             # Expo configuration
│   ├── eas.json             # EAS Build profiles
│   ├── package.json         # Node dependencies (KHUSUS mobile)
│   └── .easignore           # File exclusion untuk EAS Build
│
├── docs/                    # Dokumentasi
├── package.json             # Root package.json (scripts global)
├── .gitignore               # Git ignore rules
└── nginx_kaskecil.conf      # Konfigurasi Nginx untuk deployment

Root package.json — Script Lintas Proyek

File package.json di root monorepo berisi script shortcut untuk menjalankan berbagai bagian aplikasi tanpa perlu pindah-pindah folder:

{
  "name": "kas-kecil-monorepo",
  "scripts": {
    "api:dev": "cd api && php artisan serve",
    "web:dev": "cd web && npm run dev",
    "mobile:dev": "cd mobile && npm start",
    "api:migrate": "cd api && php artisan migrate",
    "api:seed": "cd api && php artisan db:seed",
    "install:all": "cd web && npm install && cd ../mobile && npm install"
  }
}

Dengan script ini, Anda cukup menjalankan npm run api:dev dari root folder untuk menjalankan backend, tanpa perlu cd api dulu secara manual.

⚙️ Backend — Laravel REST API

Pemilihan Teknologi

  • Laravel 12 — Framework PHP yang mature dan memiliki ekosistem lengkap
  • PHP 8.2+ — Versi PHP terbaru dengan fitur modern (typed properties, enums, dll)
  • PostgreSQL — Database relasional yang powerful, lebih cocok untuk data keuangan karena mendukung transaksi ACID dengan lebih baik
  • Laravel Sanctum — Autentikasi token-based yang ringan, cocok untuk SPA dan mobile app

Proses Pembuatan Backend

1. Inisialisasi Project Laravel:

# Buat project Laravel baru di folder api/
composer create-project laravel/laravel api

# Masuk ke folder
cd api

# Install Sanctum untuk autentikasi API
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

2. Desain Database (Migration):

Sistem Kas Kecil memiliki struktur hierarki organisasi yang kompleks. Migration dibuat berurutan sesuai dependency:

# Urutan migration (dependency-based)
php artisan make:migration create_instansi_table      # Level 1: Organisasi induk
php artisan make:migration create_cabang_table        # Level 2: Cabang (FK ke instansi)
php artisan make:migration create_unit_table          # Level 3: Unit kerja (FK ke cabang)
php artisan make:migration create_roles_table         # Roles (Super Admin, Admin Unit)
php artisan make:migration create_users_table         # Users (FK ke role, cabang, unit)
php artisan make:migration create_akun_aas_table      # Akun AAS (FK ke unit)
php artisan make:migration create_akun_ma_table       # Mata Anggaran (FK ke akun AAS)
php artisan make:migration create_transaksi_table     # Transaksi (FK ke unit, user)

3. Model dan Relationship:

Setiap model menggunakan Eloquent relationship untuk menghubungkan data:

// Contoh: Model Unit
class Unit extends Model {
    public function cabang() { return $this->belongsTo(Cabang::class); }
    public function users() { return $this->hasMany(User::class); }
    public function transaksi() { return $this->hasMany(Transaksi::class); }
    public function akunAas() { return $this->hasMany(AkunAas::class); }
}

4. API Routes dan Controller:

Semua endpoint dibuat sebagai REST API (tidak menggunakan Blade view), karena frontend terpisah:

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('instansi', InstansiController::class);
    Route::apiResource('cabang', CabangController::class);
    Route::apiResource('unit', UnitController::class);
    Route::apiResource('transaksi', TransaksiController::class);
    Route::get('/dashboard', [DashboardController::class, 'index']);
});

5. Autentikasi dengan Sanctum:

Sanctum menggunakan token-based auth. Setelah login, client menerima token yang harus disertakan di setiap request:

// Login endpoint mengembalikan token
$token = $user->createToken('auth-token')->plainTextToken;

// Client mengirim token di header:
// Authorization: Bearer {token}

🖥️ Frontend Web — React + Vite

Pemilihan Teknologi

  • React 18 — Library UI yang paling populer dengan ekosistem besar
  • Vite — Build tool yang sangat cepat dibanding Webpack
  • TypeScript — Type safety untuk mengurangi bug
  • Tailwind CSS — Utility-first CSS framework untuk styling cepat
  • Radix UI — Unstyled, accessible component library
  • TanStack React Query — Data fetching dan caching hook
  • Zustand — State management yang ringan dan simpel
  • React Hook Form + Zod — Form handling dengan validasi schema

Proses Pembuatan Frontend

1. Inisialisasi Project React:

# Buat project Vite + React + TypeScript
npm create vite@latest web -- --template react-ts

# Masuk ke folder web
cd web

# Install dependencies
npm install

# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# Install UI dan state libraries
npm install @radix-ui/react-select @radix-ui/react-dropdown-menu
npm install @tanstack/react-query axios zustand
npm install react-router-dom react-hook-form @hookform/resolvers zod

2. Struktur Folder Frontend:

web/src/
├── components/          # Reusable UI components (Button, Modal, Table, dll)
│   └── ui/              # Base components (Radix-based)
├── pages/               # Halaman-halaman (Dashboard, Transaksi, Users, dll)
├── hooks/               # Custom hooks (useAuth, useTransaksi, dll)
├── lib/                 # API client, utility functions
├── stores/              # Zustand stores (auth store, UI store)
├── types/               # TypeScript type definitions
├── App.tsx              # Root component + Router
└── main.tsx             # Entry point

3. API Client Pattern:

Semua komunikasi ke backend menggunakan Axios dengan interceptor untuk menyertakan token otomatis:

// lib/api-client.ts
const apiClient = axios.create({
  baseURL: import.meta.env.VITE_API_URL, // dari .env
  headers: { 'Content-Type': 'application/json' }
});

// Interceptor: otomatis tambah token di setiap request
apiClient.interceptors.request.use((config) => {
  const token = localStorage.getItem('auth_token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

📱 Mobile — React Native + Expo

Pemilihan Teknologi

  • React Native 0.81 — Framework mobile cross-platform berbasis React
  • Expo SDK 54 — Toolchain dan runtime yang mempermudah pengembangan React Native
  • NativeWind — Tailwind CSS untuk React Native (styling konsisten dengan web)
  • React Navigation — Navigasi screen (Stack, Tab, dll)
  • Expo Secure Store — Penyimpanan token yang aman (keychain/keystore)
  • EAS Build — Cloud build service untuk menghasilkan APK/AAB

Proses Pembuatan Mobile

1. Inisialisasi Project Expo:

# Buat project Expo baru di folder mobile/
npx create-expo-app mobile --template blank-typescript

# Masuk ke folder
cd mobile

# Install navigation
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
npm install react-native-screens react-native-safe-area-context

# Install NativeWind (Tailwind untuk RN)
npm install nativewind
npm install -D [email protected]

# Install data fetching dan form
npm install @tanstack/react-query axios react-hook-form zod

# Install secure storage untuk token
npx expo install expo-secure-store

2. Konfigurasi app.json:

File app.json adalah konfigurasi utama Expo yang mendefinisikan nama aplikasi, icon, splash screen, package name, dan plugin:

{
  "expo": {
    "name": "Kas Kecil",
    "slug": "kas-kecil-mobile",
    "version": "1.0.0",
    "android": {
      "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png" },
      "package": "com.donarazhar.kaskecilmobile"
    },
    "plugins": [
      "@react-native-community/datetimepicker",
      "expo-secure-store"
    ],
    "extra": {
      "eas": { "projectId": "your-project-id" }
    }
  }
}

⚠️ Pelajaran Penting: Install Node di Dalam Folder Aplikasi, Bukan di Parent!

Ini adalah salah satu pelajaran paling penting yang saya dapatkan. Dalam monorepo, jangan install node_modules di folder root saja — install di masing-masing subfolder yang membutuhkan.

❌ SALAH — Install di root saja:

kaskecil/              # Install npm di sini
├── node_modules/      # Semua package ada di sini
├── web/               # Tidak punya node_modules sendiri
└── mobile/            # Tidak punya node_modules sendiri ← AKAN BERMASALAH!

✅ BENAR — Install di masing-masing folder:

kaskecil/
├── package.json       # Root scripts (shortcut saja)
├── web/
│   ├── package.json   # Dependencies khusus web
│   └── node_modules/  # Node modules KHUSUS web
└── mobile/
    ├── package.json   # Dependencies khusus mobile
    └── node_modules/  # Node modules KHUSUS mobile

Mengapa ini penting?

  • EAS Build (Expo) membutuhkan node_modules di dalam folder mobile saat build APK di cloud. Jika tidak ada, build akan gagal.
  • Versi dependency berbeda — Web mungkin butuh React 18, tapi mobile butuh React 19. Kalau di-share, akan conflict.
  • Metro bundler (React Native) mencari modules dari folder project, bukan dari parent.
  • Vite (Web) juga resolve modules dari folder project-nya sendiri.

Cara install yang benar:

# Install untuk web
cd web
npm install

# Install untuk mobile (dari folder mobile)
cd ../mobile
npm install

# JANGAN: cd kaskecil/ && npm install (ini hanya untuk root scripts)

📦 Build Mobile APK dengan EAS Build

EAS (Expo Application Services) Build adalah layanan cloud dari Expo untuk mengkompilasi React Native menjadi APK (Android) atau IPA (iOS) tanpa perlu Android Studio atau Xcode di komputer lokal.

Setup EAS Build

# 1. Install EAS CLI secara global
npm install -g eas-cli

# 2. Login ke akun Expo
eas login

# 3. Konfigurasi project (dari dalam folder mobile!)
cd mobile
eas build:configure

Konfigurasi eas.json

File eas.json mendefinisikan profil build yang berbeda untuk kebutuhan berbeda:

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "android": {
        "buildType": "apk"        // ← Menghasilkan file .apk yang bisa di-share
      }
    },
    "production": {
      "android": {
        "buildType": "app-bundle"  // ← Menghasilkan .aab untuk Google Play
      }
    }
  }
}
  • development — Untuk development dengan dev client (hot reload di device fisik)
  • preview — Menghasilkan APK yang bisa langsung di-share via link download
  • production — Menghasilkan AAB (Android App Bundle) untuk upload ke Google Play Store

Build APK (Preview) yang Bisa Di-share

# PENTING: Jalankan dari dalam folder mobile!
cd mobile

# Build APK untuk preview (bisa langsung di-install)
eas build --platform android --profile preview

Setelah build selesai (biasanya 10-20 menit), EAS akan memberikan link download APK yang bisa langsung dibagikan ke siapa saja. Penerima tinggal klik link → download → install APK di Android mereka.

⚠️ File .easignore — Kunci Sukses Build di Monorepo

Ini adalah file yang sangat penting dalam monorepo. Ketika EAS Build mengupload source code ke cloud, ia akan mengupload seluruh repository termasuk folder api/ dan web/. Ini menyebabkan masalah karena:

  • Folder api/ Laravel mengandung symlink (storage/app/public) yang tidak didukung di cloud build
  • Upload menjadi sangat besar dan lambat
  • Build bisa gagal karena konflik dependency

Solusi: Buat file .easignore di root DAN di folder mobile:

File .easignore di root monorepo:

# Exclude backend API folder (contains symlinks)
api
api/**

# Exclude web folder
web
web/**

# Exclude docs
docs

# Exclude unnecessary files
*.tar.gz
*.zip
node_modules
.git
dist.zip

File .easignore di folder mobile:

# Exclude sibling folders yang menyebabkan masalah
../api
../web
../docs
../.git

# Exclude build artifacts
dist
.expo

# node_modules akan di-install ulang saat build
node_modules

# Exclude unnecessary files
*.tar.gz
*.zip

Dengan .easignore, EAS Build hanya mengupload file yang dibutuhkan untuk build mobile, sehingga proses lebih cepat dan tidak error.

🔄 Workflow GitHub untuk Monorepo

Daily Development Workflow

# 1. Pull perubahan terbaru
git pull origin main

# 2. Jalankan backend (terminal 1)
cd api
php artisan serve

# 3. Jalankan frontend web (terminal 2)
cd web
npm run dev

# 4. Jalankan mobile (terminal 3)
cd mobile
npm start

# 5. Setelah selesai, commit perubahan
git add .
git commit -m "feat: tambah fitur transaksi"
git push origin main

Tips Commit Message di Monorepo

Karena satu repository berisi beberapa aplikasi, sertakan scope agar jelas bagian mana yang berubah:

# Format: type(scope): description
git commit -m "feat(api): tambah endpoint transaksi"
git commit -m "fix(web): perbaiki bug form login"
git commit -m "feat(mobile): tambah halaman dashboard"
git commit -m "chore(root): update gitignore"

Deploy ke Server

# Di server (SSH):
cd /var/www/kaskecil

# Pull perubahan
git pull origin main

# Update backend
cd api
composer install --no-dev --optimize-autoloader
php artisan migrate
php artisan config:cache

# Update frontend
cd ../web
npm install
npm run build

# Restart services
sudo systemctl restart php8.2-fpm nginx

🌐 Konfigurasi Nginx untuk Monorepo

Karena web dan API berada dalam satu server, Nginx perlu dikonfigurasi untuk merutekan request dengan benar:

server {
    listen 80;
    server_name _;

    # 1. Web Application (React/Vite) — root path
    location / {
        root /var/www/kaskecil/web/dist;
        try_files $uri $uri/ /index.html;    # SPA fallback
    }

    # 2. Backend API (Laravel) — /api path
    location /api {
        alias /var/www/kaskecil/api/public;
        try_files $uri $uri/ @laravel;
    }

    location @laravel {
        root /var/www/kaskecil/api/public;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME /var/www/kaskecil/api/public/index.php;
        include fastcgi_params;
    }

    # 3. Storage — untuk akses file upload
    location /storage {
        alias /var/www/kaskecil/api/public/storage;
        try_files $uri $uri/ =404;
    }
}

Konfigurasi ini membuat satu domain bisa melayani web app (di /) dan API (di /api) sekaligus.

💡 Pelajaran Penting (Lessons Learned)

Berikut rangkuman tips paling penting yang saya pelajari selama membangun proyek ini:

1. Selalu Install node_modules di Folder Masing-masing

Jangan pernah hanya install di root monorepo. Setiap subfolder (web, mobile) harus punya node_modules sendiri karena dependency-nya berbeda.

2. Buat .easignore untuk EAS Build

Tanpa file ini, EAS Build akan mengupload seluruh monorepo termasuk folder yang tidak relevan, menyebabkan build gagal karena symlink atau dependency conflict.

3. Environment Variables Terpisah

Setiap subfolder punya file .env sendiri yang mengarah ke URL yang sesuai:

  • api/.env — Database credentials, app key
  • web/.env — VITE_API_URL=http://localhost:8000 (dev) atau URL production
  • mobile/.env — API_URL=http://192.168.x.x:8000 (IP komputer untuk device fisik)

4. Mobile Harus Menggunakan IP, Bukan localhost

Saat development mobile di device fisik atau emulator, gunakan IP address komputer (192.168.x.x), bukan localhost. Device fisik tidak mengenal localhost komputer Anda.

5. Jalankan EAS Build dari Folder Mobile

Perintah eas build harus dijalankan dari dalam folder mobile/, bukan dari root monorepo. EAS mencari app.json dan package.json di current directory.

6. Gunakan Sanctum Token, Simpan di Secure Store

Di mobile, jangan simpan auth token di AsyncStorage biasa. Gunakan expo-secure-store yang mengenkripsi data menggunakan native keychain (iOS) atau keystore (Android).

7. Test API di Lokal Sebelum Push

Selalu pastikan API berjalan dan endpoint berfungsi di lokal sebelum push ke server. Gunakan tools seperti Postman, Insomnia, atau cURL untuk testing.

8. Git Ignore yang Benar

Pastikan .gitignore mengecualikan semua folder yang tidak perlu di-track:

node_modules/           # Dependencies (install ulang via npm install)
**/node_modules/        # node_modules di semua subfolder
.env                    # Environment variables (rahasia!)
dist/                   # Build output (generate ulang via npm run build)
vendor/                 # PHP dependencies (install ulang via composer install)

📊 Tech Stack Ringkasan

  • Backend: Laravel 12, PHP 8.2+, PostgreSQL, Sanctum
  • Frontend Web: React 18, Vite, TypeScript, Tailwind CSS, Radix UI, TanStack Query, Zustand
  • Mobile: React Native 0.81, Expo SDK 54, NativeWind, React Navigation, EAS Build
  • Validasi: Zod (bisa di-share antara frontend dan backend)
  • Monorepo: Root package.json dengan scripts lintas-project
  • Deployment: Nginx (web + API), EAS Build (mobile APK/AAB)

Dengan mengikuti arsitektur dan workflow yang dijelaskan dalam artikel ini, Anda bisa membangun aplikasi multi-platform yang terstruktur, maintainable, dan scalable. Semoga panduan ini bermanfaat untuk proyek-proyek Anda di masa depan! 🚀

Share this article

Related Articles

Continue reading with these related posts