Ketika dipercaya mengelola sistem IT untuk sebuah agensi travel umroh skala menengah (Enterprise Travel Agency) secara mandiri (solo developer), tantangan terbesar bukan hanya menulis kode baru, melainkan bagaimana memelihara seluruh ekosistem aplikasi agar tetap sinkron. Agensi travel umroh biasanya tidak hanya membutuhkan satu website publik, tapi juga berbagai sistem internal:
- Dashboard Admin & Finance: Untuk mengelola keuangan, manifest pesawat, hotel, dan pembayaran jamaah.
- Portal Agen (Mitra): Untuk memudahkan agen pemasaran mendaftarkan jamaah di daerah secara mandiri.
- Dashboard Operasional & Airport Handling: Khusus untuk petugas lapangan di bandara saat melepas keberangkatan (turing) atau menyambut kepulangan jamaah.
Jika kita memisahkan ketiga dashboard ini ke dalam repositori mandiri (multi-repo), kita akan menghadapi mimpi buruk kolaborasi data. Perubahan kecil pada skema database atau struktur tipe data (misalnya, penambahan kolom status paspor jamaah) mengharuskan kita memperbarui tipe data di tiga repositori berbeda satu per satu. Sangat rawan bug dan tidak efisien.
Solusi terbaik untuk masalah ini adalah dengan menggunakan arsitektur **Monorepo** dengan memanfaatkan fitur **pnpm workspaces**.
Struktur Folder Monorepo yang Ideal
Mari kita lihat bagaimana menyusun struktur direktori proyek monorepo yang bersih:
my-travel-monorepo/
├── apps/
│ ├── admin-dashboard/ # Next.js/Astro App
│ ├── agent-portal/ # Next.js/Astro App
│ └── airport-handling/ # Next.js/Astro App
├── packages/
│ ├── types/ # Shared TypeScript Interfaces
│ ├── api-client/ # Shared SDK Fetcher (Axios/Ky wrapper)
│ ├── ui/ # Shared UI Components (Button, Modal, etc.)
│ └── config/ # Shared ESLint, Tailwind, TSConfig
├── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
Langkah Setup pnpm Workspaces
pnpm dipilih karena kecepatannya yang luar biasa dalam resolusi dependency dan efisiensi penyimpanan lokal (menggunakan hard link global). Pertama, buat file pnpm-workspace.yaml di root direktori proyek Anda:
packages:
- 'apps/*'
- 'packages/*'
Membangun Shared Packages
Mari kita buat package shared types di packages/types. Tipe data ini akan diimpor oleh ketiga aplikasi di folder apps.
Di packages/types/package.json:
{
"name": "@travel/types",
"version": "1.0.0",
"main": "./src/index.ts",
"types": "./src/index.ts",
"devDependencies": {
"typescript": "^5.0.0"
}
}
Di packages/types/src/index.ts, buat tipe data pemesanan umroh:
export type VisaStatus = 'PENDING' | 'SUBMITTED' | 'APPROVED' | 'REJECTED';
export interface Jamaah {
id: string;
fullName: string;
passportNumber: string;
birthDate: string;
phoneNumber: string;
visaStatus: VisaStatus;
airportStatus: 'NOT_ARRIVED' | 'CHECKED_IN' | 'BOARDED';
}
export interface PackageUmroh {
id: string;
name: string;
departureDate: string;
quota: number;
price: number;
}
Mengkonsumsi Shared Packages di Dashboard
Sekarang, bagaimana cara dashboard admin atau portal agen mengimpor tipe data tersebut? Kita cukup mendaftarkannya di package.json masing-masing aplikasi dengan prefix workspace:*.
Di apps/admin-dashboard/package.json:
{
"name": "admin-dashboard",
"dependencies": {
"@travel/types": "workspace:*",
"react": "^18.0.0"
}
}
Setelah mendaftarkannya, jalankan perintah pnpm install di root monorepo. pnpm secara otomatis akan membuat link lokal (symlink) dari packages/types ke dalam node_modules milik admin-dashboard. Sekarang Anda bisa mengimpor tipe data tersebut dengan sangat bersih:
import type { Jamaah, VisaStatus } from "@travel/types";
const verifyPassport = (jamaah: Jamaah) => {
if (jamaah.passportNumber.length < 5) {
throw new Error("Nomor paspor tidak valid");
}
};
Keuntungan Nyata dalam Operasional Travel
- Konsistensi Data Mutlak: Jika status visa ditambahkan opsi baru (misal: 'ISSUED'), kita hanya perlu mengubah satu file di
packages/types. Secara otomatis, IDE (VS Code) akan mendeteksi perubahan tersebut di semua folder dashboard dan memperingatkan jika ada kode yang belum disesuaikan. - Kecepatan Setup Proyek Baru: Jika perusahaan ingin meluncurkan dashboard baru (misalnya dashboard logistik perlengkapan umroh), kita tidak perlu mengatur konfigurasi build, Tailwind, ESLint, API client, atau UI library dari awal. Cukup buat folder baru di
apps/dan impor seluruh konfigurasi daripackages/. - CI/CD yang Efisien: Menggunakan build pipeline modern seperti Turborepo bersama monorepo pnpm memungkinkan kita mendeteksi aplikasi mana saja yang terdampak perubahan kode. Jika hanya folder
apps/agent-portalyang berubah, pipeline build hanya akan merefresh aplikasi tersebut tanpa mengganggu server admin atau airport-handling.
Kesimpulan
Arsitektur monorepo bukanlah hal eksklusif untuk tim besar dengan ratusan insinyur. Bagi solo developer, monorepo justru menjadi penyelamat produktivitas. Monorepo menghemat waktu maintenance, memastikan konsistensi tipe data di seluruh sistem manajemen umroh, dan memungkinkan kode digunakan kembali (code reuse) semaksimal mungkin.
Commit. Push. Repeat.