Mengapa kami membangun opex-aio sebagai monorepo bun-workspaces

Satu platform, lima produk, satu database. Kalimat itu adalah alasan utama opex-aio ada — dan memaksa struktur tertentu pada cara kami membangun.

Satu deployable, banyak paket

Seluruh permukaan produk berangkat dari satu Cloudflare Worker (apps/aio). Paket produk (@opex/helpdesk, @opex/pmo, @opex/timesheets, @opex/crm, @opex/expenses) memiliki skema, sub-router Hono, dan modul klien beratnya masing-masing. Aplikasi merangkainya.

Aturan komposisi itu ditegakkan, bukan sekadar diharapkan:

  • Tanpa import relatif di mana pun — aturan oxlint kustom melarang ./ dan ../ sehingga setiap import adalah @/... (intra-paket) atau @opex/... (lintas-paket).
  • dependency-cruiser menolak import lintas-produk saat PR.
  • Produk hanya mengimpor @opex/core dan @opex/ui.

Mengapa bun workspaces dan bukan turbo

Bun menjalankan skrip workspace dalam urutan dependensi secara native — build suatu paket menunggu build dependensi workspace-nya. Itulah yang dinyatakan turbo melalui dependsOn: ["^build"], tanpa cache dan tanpa pemilih paket yang berubah. Build cukup cepat sehingga kami rela melepas cache; CI menjaga node_modules tetap hangat dengan cache berkunci bun.lock.

Hasilnya

Produk baru bersifat aditif: paket baru, skema, sub-router, satu gate requireProduct — dan shell, auth, serta tulang punggung tenant datang gratis. Monorepo adalah cara kami menjaga lima tim produk tetap mengirim ke satu deployable tanpa saling menginjak.