Case Study: Offline-First Architecture di Enterprise Isla...
Engineering Case Study: Project Tepati
"Technology is best when it brings people together." — Matt Mullenweg
Context
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.
🏔️ 1. The Challenge
Petugas lapangan (Community Officer) bekerja di remote area — dari pelosok Sumatera hingga desa-desa di Nusa Tenggara. Koneksi internet adalah kemewahan, bukan kepastian.
Kondisi Sebelum Tepati
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:
- ❌ Tidak ada offline capability yang reliable — Power Apps membutuhkan koneksi internet stabil untuk sinkronisasi data.
- 🗃️ Data tersebar di berbagai file dan chat thread — sulit di-track dan rawan kehilangan.
- ⏳ Approval bottleneck — atasan harus membuka attachment satu per satu di Teams.
- 🙈 Tidak ada real-time visibility — manajemen tidak bisa memonitor progress akuisisi secara live.
Tantangan Engineering
- 🛡️ Data Integrity: Data finansial nasabah (income, expense, cashflow) tidak boleh hilang saat sinyal putus-nyambung.
- 🧩 Complex State: Form aplikasi pembiayaan memiliki 200+ fields dengan logika validasi silang (cross-field validation) yang kompleks.
- 🔄 Conflict Resolution: Data yang diubah di device A (saat offline) dan device B (saat online) secara bersamaan harus resolved tanpa data loss.
- 🏢 Multi-Level Approval: Setiap pengajuan harus melewati 6 level approval (CO → BM → SBM → BC → DH1 → DH2) yang tersebar di geografis berbeda.
- ⚖️ Regulatory Compliance: Semua transaksi harus sesuai dengan regulasi OJK dan prinsip syariah.
- ⏱️ Solo Backend Engineer, Deadline Ketat: Seluruh backend harus saya deliver sendiri dalam 1 bulan untuk MVP — tanpa backend engineer lain.
Business Impact
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.
⚔️ 2. Single-Fighter Backend
Banyak yang bertanya: bagaimana bisa satu orang membangun seluruh backend system sebesar ini dalam sebulan?
Jawabannya: ruthless prioritization + technology leverage.
- 🏗️ Minggu 1: Setup infrastruktur (Golang services, Kafka, AMQ, database schema, CI/CD pipeline).
- ⚙️ Minggu 2: Core sync engine backend + API endpoints untuk dynamic form engine. Ini 80% dari backend complexity.
- 🚀 Minggu 3: Approval pipeline (Kafka consumers + AMQ), IIR simulation API, document upload service.
- 🧪 Minggu 4: Integration testing dengan tim frontend, bug fixing, deployment ke staging & production.
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.
🛠️ 3. Technology Stack
Backend
- 🐹 Golang: High-concurrency microservices, mampu handle 15,000 concurrent connections dengan memory footprint minimal.
- 📨 Apache Kafka: Event streaming untuk data ingestion dari lapangan — throughput 50,000 events/second pada peak hours.
- 📬 AMQ (ActiveMQ): Message broker untuk orchestrasi approval workflow antar-level.
- MongoDB: Primary database untuk menyimpan data formulir dinamis (JSON) dari lapangan.
- Microsoft SQL Server: Database relasional untuk menyimpan data struktur organisasi dan hierarki approval.
- ⚡ Redis: Distributed caching dan session management.
Frontend (Mobile)
- ⚛️ React Native: Cross-platform mobile app yang di-deploy ke 5,000+ Android devices.
- 🗄️ SQLite: Local database — menyimpan hingga 10,000 records per device tanpa degradasi performa.
- 📡 MQTT (Mosquitto): Protokol ringan untuk real-time notification di kondisi bandwidth < 50kbps (intermittent).
🔍 4. Feature Deep Dives
Feature #1: Offline-First Sync Engine
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.
Key Engineering Decisions:
- 📦 Delta Sync Protocol: Hanya mengirim perubahan, bukan seluruh payload. Menghemat bandwidth rata-rata 78%.
- ⚔️ Conflict Resolution: Last-Write-Wins (LWW) untuk data non-finansial, server-authoritative merge untuk data finansial kritikal.
- 🔄 Retry with Exponential Backoff: Max 5 retries dengan jitter untuk menghindari thundering herd.
// 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% |
Feature #2: Dynamic Form Engine
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:
- 🌾 Jika
jenis_usaha === "pertanian"→ fieldlama_usahaminimum 2 tahun. - 💰 Jika
income_busy_day < angsuran * 3→ tolak otomatis, tampilkan warning IIR. - 💍 Jika
status_perkawinan === "menikah"→ wajib uploadimg_surat_nikah_urldanimg_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% |
Feature #3: Real-Time Multi-Level Approval Pipeline
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.
Key Engineering:
- 🏎️ Setiap level approval adalah independent Kafka consumer — jika satu level down, yang lain tetap jalan.
- 🔒 AMQ digunakan untuk DH-level approval karena memerlukan guaranteed delivery dengan transaction support.
- 🔔 MQTT push notification ke device approver — response time turun dari jam ke menit.
- 📝 Audit trail lengkap: siapa approve, kapan, dari device mana, di koordinat GPS berapa.
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% |
Feature #4: IIR Simulation Engine
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% |
Feature #5: Secure Document Capture & Upload
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:
- 📸 Auto-detect document boundaries (OpenCV-based edge detection).
- 👁️ Image quality validator — reject jika blur score > threshold.
- 🔐 AES-256 encryption at rest di SQLite, decrypted hanya saat upload.
- 📤 Progressive upload — gambar dikirim dalam chunks saat sinyal tersedia.
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% |
🚀 5. Overall Business Impact
Implementasi keseluruhan Tepati mengubah fundamental cara kerja pembiayaan mikro:
Key Numbers
- 📈 Nasabah ter-serve: dari 2.8 juta → 4.1 juta (+46%) dalam 18 bulan
- 💰 Cost per acquisition: turun 62% secara year-on-year
- ⚡ Turnaround time: dari 7 hari → < 24 jam (↓85%)
- 📉 NPL (Non-Performing Loan): turun dari 1.8% → 1.2% karena data underwriting lebih akurat
- 👩💼 CO productivity: naik 2.3x (dari 8 nasabah/hari → 18 nasabah/hari)
🏢 6. Post-Launch: Tantangan Organisasi
Setelah MVP berhasil di-deliver, ada beberapa tantangan non-teknis yang cukup berdampak terhadap velocity pengembangan selanjutnya. Saya dokumentasikan ini sebagai pembelajaran:
6.1 Migrasi Protokol: AMQ/MQTT (Intermittent) → HTTP
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.
Engineering Insight
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.
6.2 CI/CD Pipeline yang Belum Optimal
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.
6.3 Security Compliance & Developer Experience
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:
- Resource Constraints: Tooling keamanan enterprise seringkali memakan resource CPU/IO yang signifikan, yang berdampak pada waktu kompilasi (terutama Golang/React Native) dibandingkan environment development non-standard.
- Workflow Adaptation: Developer perlu beradaptasi dengan environment yang lebih terbatas demi menjaga keamanan data nasabah.
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.
6.4 The Efficiency Dilemma: Balancing Scope & Focus
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.
Sustainability Note
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.
☠️ 6.5 The Silent Killer: Technical & Intellectual Bankruptcy
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.
Critical Risk Assessment
Ketergantungan pada satu individu adalah Single Point of Failure (SPOF) terbesar.
Jika Anda tidak mendistribusikan pengetahuan sekarang, bersiaplah menghadapi realita pahit saat transisi terjadi:
- Lumpuh Total: Engineer baru butuh waktu 3-4 sprint (1-2 bulan) hanya untuk sekadar membaca dan memahami mental model kode "jenius" tersebut tanpa berani menyentuhnya.
- The Inevitable Rewrite: Seringkali, kompleksitas kode "single-fighter" begitu tinggi dan spesifik sehingga engineer pengganti akan memvonis: "Ini harus di-rewrite ulang dari nol."
- Biaya Ganda: Anda tidak hanya membayar gaji engineer baru, tapi juga membayar biaya hilangnya momentum bisnis karena stagnasi pengembangan selama berbulan-bulan.
Stop berharap pada satu orang. Pecah silo pengetahuan hari ini, atau Anda akan dipaksa me-reboot ulang produk Anda di masa depan.
🎓 7. Lessons Learned
What Went Well
- 🧠 Offline-first mindset dari hari pertama — bukan afterthought.
- 🐹 Golang terbukti ideal untuk high-concurrency sync workloads.
- 📡 MQTT (sebelum migrasi) jauh lebih efisien dibanding HTTP polling untuk kondisi low-bandwidth.
- 🦸♂️ Single-fighter backend memungkinkan keputusan arsitektur yang cepat tanpa bottleneck meeting dan approval. Tim frontend cukup consume API contract yang sudah saya definisikan di awal.
- 💬 Menggantikan Microsoft Teams workflow dengan sistem dedicated meningkatkan efisiensi secara drastis.
What I'd Do Differently
- 📝 Mulai dengan CRDT (Conflict-free Replicated Data Types) sejak awal, bukan LWW yang kemudian harus di-migrate.
- 🤖 Invest lebih awal di automated E2E testing untuk offline scenarios — sulit dikoordinasikan antara backend (saya) dan frontend (tim lain) saat deadline ketat.
- 📦 Gunakan Protocol Buffers sejak awal — JSON parsing overhead terasa pada device low-end.
- 📢 Advokasi lebih kuat untuk mempertahankan message broker architecture dengan menyediakan runbook dan monitoring yang lebih baik untuk tim operations.
- ⏩ Push for better CI/CD infrastructure sejak awal — pipeline yang lambat menghambat seluruh tim, bukan hanya saya.
Technical Debt yang Masih Ada
- 🔄 Migration dari SQLite ke WatermelonDB untuk lazy loading yang lebih baik.
- ⚠️ Standardisasi error codes antara Kafka events dan REST API responses.
- 🔌 Implementasi circuit breaker pattern di Sync Manager.
- ⏩ Optimisasi CI/CD pipeline — target di bawah 5 menit per deployment stage.
🎉 Conclusion
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.
Personal Note
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.