Membangun Platform Exchange Crypto Enterprise: Business Logic, Fitur, dan Domain Knowledge

Satu engineer. Satu bulan. Sekarang jadi backbone 4.1 juta nasabah. Cerita lengkap bagaimana saya membangun offline-first architecture untuk 5.000 petugas lapangan di pelosok Indonesia — dan pelajaran pahit jadi single point of failure.
"Technology is best when it brings people together." — Matt Mullenweg
Seluruh backend system project ini saya bangun sendiri (single-fighter) dari nol — arsitektur, API, message brokers, database, sync engine, hingga deployment — dengan target MVP 1 bulan. Tidak ada backend engineer lain. Sementara sisi frontend (React Native) ditangani oleh tim terpisah.
Project Tepati adalah sistem digitalisasi proses pembiayaan mikro syariah untuk salah satu bank syariah terbesar di Indonesia. Sistem ini menggantikan proses manual berbasis kertas menjadi aplikasi digital end-to-end yang digunakan 5,000+ Community Officer di seluruh Indonesia.
Artikel ini membedah fitur-fitur paling menantang dari sisi engineering dan bisnis.
Petugas lapangan (Community Officer) bekerja di remote area — dari pelosok Sumatera hingga desa-desa di Nusa Tenggara. Koneksi internet adalah kemewahan, bukan kepastian.
Sebelum Tepati dibangun, seluruh proses akuisisi nasabah dilakukan menggunakan Microsoft Power Apps. Petugas lapangan mengisi data melalui form Power Apps, mengirim via Teams, dan menunggu approval secara manual. Proses ini sangat lambat karena:
Sebelum Tepati, 23% pengajuan gagal karena data hilang atau tidak lengkap. Setiap kegagalan berarti petugas harus kembali ke nasabah — rata-rata membutuhkan 2-3 hari tambahan dan berdampak pada kepercayaan nasabah.
Banyak yang bertanya: bagaimana bisa satu orang membangun seluruh backend system sebesar ini dalam sebulan?
Jawabannya: ruthless prioritization + technology leverage.
Kuncinya adalah saya sudah sangat familiar dengan Golang dan message broker ecosystem (Kafka + AMQ + MQTT) sehingga tidak ada learning curve yang memperlambat. Setiap keputusan arsitektur backend saya buat untuk maximize velocity tanpa mengorbankan reliability. Tim frontend tinggal consume API yang sudah saya sediakan.
Problem: Petugas sering berada di area tanpa sinyal selama 4-6 jam.
Solution: Saya membangun arsitektur yang selalu offline dan hanya melakukan sinkronisasi saat ada sinyal.
graph TD
A[Community Officer] -->|Input Data| B[React Native App]
A --> I[(SQL Server - Schedule DB)]
B -->|Write| C[(SQLite Local DB)]
C -->|Queue| D[Sync Manager]
D -->|Delta Sync via MQTT| E[API Gateway - Golang]
E -->|Publish| F[Apache Kafka]
F -->|Consumer| G[(MongoDB)]
F -->|Fan-out| H[Notification Service]
H -->|Push| I[Approval Dashboard]Key Engineering Decisions:
// Simplified Sync Consumer (Golang)
func (s *SyncService) ProcessSyncBatch(ctx context.Context, batch []SyncEvent) error {
for _, event := range batch {
existing, err := s.repo.FindByDeviceID(ctx, event.DeviceID, event.RecordID)
if err != nil {
return fmt.Errorf("failed to find record: %w", err)
}
if existing != nil && existing.UpdatedAt.After(event.Timestamp) {
// Server version is newer — skip, notify client
s.notifier.SendConflict(ctx, event.DeviceID, existing)
continue
}
if err := s.repo.Upsert(ctx, event.ToRecord()); err != nil {
return fmt.Errorf("failed to upsert: %w", err)
}
s.kafka.Publish("sync.completed", event)
}
return nil
}Results:
| Metric | Sebelum | Sesudah | Improvement |
|---|---|---|---|
| Data loss rate | 23% | 0% | ↓ 100% |
| Avg sync time | 45 detik | 3.2 detik | ↓ 93% |
| Bandwidth usage per sync | 2.4 MB | 520 KB | ↓ 78% |
| App crash rate (offline) | 12% | 0.3% | ↓ 97.5% |
Problem: Form pengajuan pembiayaan memiliki 200+ fields yang berubah berdasarkan jenis usaha nasabah, lokasi, dan kebijakan branch. Setiap perubahan form memerlukan app update (re-deploy ke 5,000 devices).
Solution: Server-Driven Form Engine — form definition di-download sebagai JSON schema dari server dan dirender secara dinamis di client.
// Form Schema (simplified)
interface FormField {
id: string;
type: "text" | "number" | "select" | "photo" | "signature";
label: string;
rules: ValidationRule[];
dependencies?: {
field: string;
condition: "equals" | "gt" | "lt";
value: any;
action: "show" | "hide" | "require";
}[];
}Cross-Field Validation Examples:
jenis_usaha === "pertanian" → field lama_usaha minimum 2 tahun.income_busy_day < angsuran * 3 → tolak otomatis, tampilkan warning IIR.status_perkawinan === "menikah" → wajib upload img_surat_nikah_url dan img_ktp_pasangan_url.Results:
| Metric | Sebelum | Sesudah | Improvement |
|---|---|---|---|
| Form update cycle | 2-3 minggu (app release) | Real-time | ↓ 100% |
| Incomplete submission | 34% | 4.2% | ↓ 88% |
| Avg form completion time | 45 menit | 18 menit | ↓ 60% |
Problem: Pengajuan pembiayaan harus melewati 6 level approval (CO → BM → SBM → BC → DH1 → DH2). Sebelumnya, approval dilakukan via WhatsApp group — rawan human error dan tidak auditable.
Solution: Event-driven approval pipeline menggunakan Kafka + AMQ yang saya rancang sendiri.
graph LR
CO[CO Submit] -->|Kafka Event| BM[Branch Manager]
BM -->|Approve/Reject| SBM[Sub-Branch Manager]
SBM -->|Approve/Reject| BC[Business Controller]
BC -->|Approve/Reject| DH1[Division Head 1]
DH1 -->|Approve/Reject via AMQ| DH2[Division Head 2 - Final]
DH2 -->|Final Decision| CORE[Core Banking System]Key Engineering:
Results:
| Metric | Sebelum | Sesudah | Improvement |
|---|---|---|---|
| Approval cycle time | 5-7 hari | < 24 jam | ↓ 85% |
| Bottleneck detection | Manual | Real-time dashboard | — |
| Approval fraud rate | ~2.1% | 0.08% | ↓ 96% |
Problem: Petugas harus menghitung Installment to Income Ratio (IIR) secara manual. Kesalahan hitung menyebabkan pengajuan ditolak di level atas, membuang waktu semua pihak.
Solution: Real-time IIR calculator yang berjalan di device (offline-capable), dengan tabel tenor dan margin yang di-sync dari server.
// IIR Calculation Engine (Golang - mirrored in React Native)
type IIRSimulation struct {
Tenor int `json:"tenor"`
Angsuran int64 `json:"angsuran"`
TotalIIR float64 `json:"total_iir"`
Margin float64 `json:"margin"`
IsEligible bool `json:"is_eligible"`
}
func SimulateIIR(totalIncome, existingInstallment, requestedAmount int64, tenors []int) []IIRSimulation {
var results []IIRSimulation
for _, tenor := range tenors {
angsuran := calculateAngsuran(requestedAmount, tenor, getMarginRate(tenor))
totalIIR := float64(angsuran+existingInstallment) / float64(totalIncome) * 100
results = append(results, IIRSimulation{
Tenor: tenor,
Angsuran: angsuran,
TotalIIR: totalIIR,
Margin: getMarginRate(tenor),
IsEligible: totalIIR <= 30.0, // OJK threshold
})
}
return results
}Results:
| Metric | Sebelum | Sesudah | Improvement |
|---|---|---|---|
| IIR calculation error | 18% | 0.1% (rounding only) | ↓ 99.4% |
| Rejection at upper level (due to IIR) | 22% | 3% | ↓ 86% |
| Time to simulate | 5-10 menit (manual) | < 1 detik | ↓ 99% |
Problem: Petugas mengambil foto KTP, KK, Surat Nikah menggunakan kamera personal dan mengirim via WhatsApp. Masalah: kualitas tidak konsisten, tidak terenkripsi, tidak auditable.
Solution: In-app camera module dengan:
Results:
| Metric | Sebelum | Sesudah | Improvement |
|---|---|---|---|
| Document re-capture rate | 31% | 5% | ↓ 84% |
| Avg upload success rate | 67% | 99.2% | ↑ 48% |
| Security incidents (data leak) | 3 per tahun | 0 | ↓ 100% |
Problem: Tantangan terbesar muncul saat Partial Rollout peran baru: Community Officer (CO).
Sebelumnya, role terendah di sistem adalah Business Manager (BM). Ketika CO diperkenalkan di versi v1.14.1, para atasan (BM/SBM) masih menggunakan versi lama (v1.14.0 dan v1.13.0) yang belum mengenal entitas "CO".
Masalahnya: Saat CO (v1.14.1) mengirim pengajuan, aplikasi atasan (v1.14.0) crash saat mencoba me-render data approval karena tidak memiliki UI component untuk role baru tersebut. Update serentak mustahil dilakukan karena BM tersebar di area dengan sinyal sangat terbatas.
Solution: Saya menerapkan "Role-Based Downstream Adapter" di Backend.
"Backward compatibility bukan sekadar menjaga data lama tetap bisa dibaca. Tantangannya adalah: Bagaimana aplikasi masa lalu (Managers) bisa tetap bekerja saat menerima data dari masa depan (New Officers)?"
Implementasi keseluruhan Tepati mengubah fundamental cara kerja pembiayaan mikro:
Setelah MVP berhasil di-deliver, ada beberapa tantangan non-teknis yang cukup berdampak terhadap velocity pengembangan selanjutnya. Saya dokumentasikan ini sebagai pembelajaran:
Arsitektur awal menggunakan AMQ dan MQTT untuk handling koneksi offline-first. Namun, kendala infrastruktur server menyebabkan koneksi ke broker sering terputus di tengah jalan (intermittent). Pasca-launch, protokol diubah ke HTTP-based untuk mengatasi instabilitas tersebut sekaligus menyelaraskan dengan enterprise backend ecosystem yang sudah mature.
Meskipun MQTT lebih efisien secara bandwidth, memelihara stateful connection broker di skala enterprise membutuhkan overhead operasional yang tinggi. Transisi ke HTTP dipilih untuk menjamin maintainability jangka panjang oleh tim operasional yang sudah sangat ahli di REST/HTTP environment, meskipun harus mengorbankan sedikit efisiensi bandwidth.
Ini adalah pelajaran tentang "Organizational-Fit". Arsitektur terbaik bukan hanya yang paling canggih secara teknis, tapi yang bisa di-support dengan baik oleh kapabilitas operasional organisasi saat ini.
Salah satu hambatan signifikan dalam iterasi pengembangan adalah kecepatan deployment pipeline. Pada kondisi saat itu:
| Stage | Durasi | Catatan |
|---|---|---|
| Build → Beta | ~15 menit | Cukup lama untuk rapid iteration |
| Build → Production | ~30 menit | Belum termasuk rollback jika error |
| Hotfix cycle | 45-60 menit | Termasuk re-test dan re-deploy |
Sebagai perbandingan, standar industri untuk pipeline modern adalah < 5 menit untuk build-to-deploy. Pipeline yang lambat ini menghambat feedback loop dan memperlambat siklus perbaikan bug di lapangan.
Seiring matangnya project, standar keamanan perusahaan (Enterprise Security) mulai diterapkan sepenuhnya, termasuk penggunaan perangkat terstandarisasi dengan EDR (Endpoint Detection & Response) dan VPN corporate.
Tantangan yang muncul adalah menyeimbangkan Compliance dengan Velocity:
Ini adalah trade-off yang wajar di industri perbankan: Security is non-negotiable, namun tantangannya adalah bagaimana tetap menjaga feedback loop pengembangan tetap cepat di dalam batasan tersebut.
Refleksi penting lainnya adalah mengenai alokasi resource engineer dalam fase maintenance.
1. Multitasking vs Deep Work Di fase awal (zero-to-one), peran hybrid (Backend + Infra + Support) sangat efektif untuk kecepatan. Namun di fase steady state, peran ini perlu dispesialisasi. Mengharapkan satu engineer menangani logic bisnis sekaligus isue infrastruktur dapat memecah fokus (context switching) yang berisiko pada kualitas jangka panjang.
Efisiensi tim tidak hanya diukur dari "seberapa banyak role yang dipegang satu orang", tapi dari seberapa fokus tim tersebut dapat menyelesaikan masalah spesifik tanpa distraksi operasional yang berlebihan.
2. Optimizing Processes Proses deployment dan policy keamanan adalah bagian vital dari governance. Tantangan engineering leadership adalah memastikan proses ini efisien (misalnya melalui otomatisasi CI/CD yang lebih baik atau whitelisting policy) sehingga engineer tidak menghabiskan waktu menunggu proses (wait time), melainkan mencipta solusi (build time).
3. Conclusion True efficiency adalah ketika sistem pendukung (people, process, tools) memungkinkan tim engineering bekerja dengan friksi minimal, menyeimbangkan kecepatan inovasi dengan kepatuhan regulasi.
Kecepatan ekstrem di awal seringkali menjadi candu. Namun, membiarkan satu orang memegang kunci seluruh sistem tanpa pendamping adalah kesalahan manajerial yang fatal.
The Illusion of Speed Saat Anda memiliki "Hero Developer", Anda merasa aman karena fitur ter-deliver cepat. Realitanya, Anda sedang menumpuk bunga berbunga dari utang organisasi. Ketergantungan ini adalah bom waktu.
Ketergantungan pada satu individu adalah Single Point of Failure (SPOF) terbesar.
Jika Anda tidak mendistribusikan pengetahuan sekarang, bersiaplah menghadapi realita pahit saat transisi terjadi:
Stop berharap pada satu orang. Pecah silo pengetahuan hari ini, atau Anda akan dipaksa me-reboot ulang produk Anda di masa depan.
Personal branding sering menggambarkan "Single Fighter" sebagai sosok heroik. Realitanya jauh lebih brutal.
Saya ingat betul momen Malam Takbiran (Idul Fitri) tahun lalu. Traffic melonjak drastis karena semua petugas mengejar target sebelum libur panjang. Pukul 09:00 pagi, MQTT Broker Overload & Intermittent karena jutaan pesan antrian menumpuk dan koneksi yang flaky.
Saat orang lain berkumpul dengan keluarga, saya mojok di kamar tamu dengan laptop, melakukan restart broker dan clearing retained messages secara manual via terminal.
Di luar batasan teknis, gesekan terbesar justru datang dari sisi organisasi.
1. Fenomena "Service Center" Squad saya seringkali diposisikan sebagai tempat eskalasi untuk fitur-fitur kompleks yang belum matang dari tim lain.
2. Tembok Silo: Integrasi Enterprise Security Contoh nyata gesekan organisasi adalah saat proses integrasi Enterprise Security Gateway di environment On-Premise Infrastructure.
3. Jarak Hierarki (Hierarchical Gap) Jarak antara "manajemen" dan "engineering" bagaikan jurang pemisah. Keputusan sering dibuat di ruang rapat tanpa memahami technical debt yang ditimbulkannya, sementara engineer berada terlalu jauh dari strategi untuk bisa memberikan masukan teknis yang berarti.
Project ini membuktikan bahwa seorang backend engineer yang menguasai arsitektur distributed systems — dari API design, message brokers, hingga sync engine — bisa men-deliver seluruh backend infrastructure sendirian dalam waktu yang sangat terbatas.
Fitur tersulit bukan selalu tentang algoritma AI yang canggih. Terkadang, engineering excellence adalah tentang empati — memahami bahwa user kita berdiri di tengah sawah dengan sinyal 1 bar, dan memastikan teknologi tetap melayani mereka dengan tangguh.
Yang membuat saya bangga: teknologi yang baik adalah teknologi yang invisible. Petugas tidak perlu tahu tentang Kafka, MQTT, atau delta sync. Yang mereka tahu: aplikasi ini just works, bahkan di tengah hutan — dan seluruh backend yang menopang itu saya bangun sendiri dalam 30 hari.



