20 Agu 2025·7 menit membaca

Penyelesaian konflik formulir offline-first untuk Kotlin + SQLite

Pelajari penyelesaian konflik formulir offline-first: aturan merge yang jelas, alur sinkron sederhana dengan Kotlin + SQLite, dan pola UX praktis untuk konflik edit.

Penyelesaian konflik formulir offline-first untuk Kotlin + SQLite

Apa yang sebenarnya terjadi ketika dua orang mengedit saat offline

Formulir offline-first memungkinkan orang melihat dan mengedit data bahkan ketika jaringan lambat atau tidak tersedia. Alih-alih menunggu server, aplikasi menulis perubahan ke database SQLite lokal terlebih dahulu, lalu sinkron nanti.

Itu terasa instan, tetapi menciptakan kenyataan sederhana: dua perangkat bisa mengubah record yang sama tanpa mengetahui perubahan satu sama lain.

Contoh konflik tipikal: seorang teknisi lapangan membuka work order di tablet di ruang bawah tanah tanpa sinyal. Mereka menandai status sebagai "Done" dan menambahkan catatan. Pada saat yang sama, supervisor di ponsel lain memperbarui work order yang sama, mengalihkan penugasan, dan mengubah tanggal tenggat. Keduanya menekan Simpan. Keduanya sukses secara lokal. Tidak ada yang salah.

Saat sinkron akhirnya terjadi, server harus memutuskan apa yang menjadi record “nyata”. Jika Anda tidak menangani konflik secara eksplisit, biasanya hasilnya salah satu dari berikut:

  • Last write wins: sinkron yang lebih akhir menimpa perubahan sebelumnya dan seseorang kehilangan data.
  • Gagal keras: sinkron menolak salah satu pembaruan dan aplikasi menampilkan error yang tidak membantu.
  • Duplikat record: sistem membuat salinan kedua untuk menghindari penimpaan dan pelaporan menjadi berantakan.
  • Merge diam-diam: sistem menggabungkan perubahan, tapi mencampur field dengan cara yang tidak diharapkan pengguna.

Konflik bukan bug. Mereka adalah hasil yang dapat diprediksi dari membiarkan orang bekerja tanpa koneksi langsung, yang memang tujuan dari offline-first.

Tujuannya dua arah: melindungi data dan menjaga aplikasi mudah digunakan. Itu biasanya berarti aturan merge yang jelas (sering di tingkat field) dan pengalaman pengguna yang mengganggu hanya ketika benar-benar penting. Jika dua edit menyentuh field berbeda, Anda sering bisa menggabungkan secara diam-diam. Jika dua orang mengubah field yang sama dengan cara berbeda, aplikasi harus menampilkannya dan membantu seseorang memilih hasil yang benar.

Pilih strategi konflik yang sesuai dengan data Anda

Konflik bukan masalah teknis pertama-tama. Mereka adalah keputusan produk tentang apa yang dianggap “benar” ketika dua orang mengubah record yang sama sebelum sinkron.

Tiga strategi yang mencakup sebagian besar aplikasi offline:

  • Last write wins (LWW): terima edit terbaru dan timpa yang lama.
  • Tinjauan manual: berhenti dan minta manusia memilih apa yang disimpan.
  • Penggabungan per-field: gabungkan perubahan per field dan minta keputusan hanya ketika dua orang menyentuh field yang sama.

LWW bisa cocok ketika kecepatan lebih penting daripada akurasi sempurna dan biaya salah kecil. Pikirkan catatan internal, tag non-kritis, atau status draft yang bisa diedit lagi nanti.

Tinjauan manual adalah pilihan yang lebih aman untuk field berdampak tinggi di mana aplikasi tidak boleh menebak: teks legal, konfirmasi kepatuhan, jumlah payroll dan faktur, data perbankan, instruksi obat, dan apa pun yang bisa menimbulkan tanggung jawab.

Penggabungan per-field biasanya menjadi default terbaik untuk formulir di mana peran berbeda memperbarui bagian berbeda. Agen dukungan mengedit alamat sementara sales memperbarui tanggal perpanjangan. Merge per-field mempertahankan kedua perubahan tanpa mengganggu siapa pun. Tetapi jika kedua pengguna mengubah tanggal perpanjangan, field itu harus memicu keputusan.

Sebelum Anda mengimplementasikan apa pun, tuliskan apa arti “benar” untuk bisnis Anda. Checklist singkat membantu:

  • Field mana yang harus selalu mencerminkan nilai dunia nyata terbaru (seperti status saat ini)?
  • Field mana yang bersifat historis dan tidak boleh pernah ditimpa (seperti waktu pengiriman yang sudah dikirim)?
  • Siapa yang diizinkan mengubah setiap field (peran, kepemilikan, persetujuan)?
  • Apa sumber kebenaran saat nilai berbeda (perangkat, server, persetujuan manajer)?
  • Apa yang terjadi jika Anda memilih salah (ketidaknyamanan kecil vs dampak finansial atau hukum)?

Saat aturan-aturan ini jelas, kode sinkron punya satu tugas: menegakkannya.

Tetapkan aturan merge per field, bukan per layar

Saat konflik terjadi, jarang memengaruhi seluruh formulir secara merata. Satu pengguna mungkin memperbarui nomor telepon sementara yang lain menambahkan catatan. Jika Anda memperlakukan seluruh record sebagai semua-atau-tidak sama sekali, Anda memaksa orang mengulang pekerjaan yang baik.

Merge per-field lebih dapat diprediksi karena setiap field punya perilaku yang diketahui. UX tetap tenang dan cepat.

Cara sederhana untuk memulai adalah memisahkan field menjadi kategori “biasanya aman” dan “biasanya tidak aman”.

Biasanya aman untuk digabung otomatis: catatan dan komentar internal, tag, lampiran (sering kali union), dan timestamp seperti "last contacted" (sering ambil yang terbaru).

Biasanya tidak aman untuk digabung otomatis: status/state, assignee/owner, total/harga, flag persetujuan, dan jumlah inventaris.

Kemudian pilih aturan prioritas per field. Pilihan umum adalah server menang, client menang, peran menang (mis. manajer menimpa agen), atau tie-breaker deterministik seperti versi server terbaru.

Pertanyaan kuncinya adalah apa yang terjadi ketika kedua sisi mengubah field yang sama. Untuk setiap field, pilih satu perilaku:

  • Auto-merge dengan aturan jelas (mis. tag adalah union)
  • Simpan kedua nilai (mis. gabung catatan dengan penulis dan waktu)
  • Tandai untuk ditinjau (mis. status dan assignee memerlukan pilihan)

Contoh: dua staf dukungan mengedit tiket yang sama offline. Rep A mengubah status dari "Open" ke "Pending". Rep B mengubah notes dan menambahkan tag "refund". Saat sinkron, Anda bisa menggabungkan notes dan tags dengan aman, tetapi tidak boleh menggabungkan status dengan diam-diam. Prompt hanya untuk status, sementara yang lain sudah digabung.

Untuk mencegah perdebatan nanti, dokumentasikan setiap aturan dalam satu kalimat per field:

  • "notes: simpan kedua, tambahkan yang terbaru terakhir, sertakan penulis dan waktu.`
  • "tags: union, hapus hanya jika dihapus eksplisit di kedua sisi.`
  • "status: jika diubah di kedua sisi, minta pilihan pengguna.`
  • "assignee: manajer menang, jika tidak server menang.`

Aturan satu kalimat itu menjadi sumber kebenaran untuk kode Kotlin, query SQLite, dan UI konflik.

Dasar model data: versi dan field audit di SQLite

Jika Anda ingin konflik terasa dapat diprediksi, tambahkan satu set kolom metadata kecil ke setiap tabel yang disinkronkan. Tanpa mereka, Anda tidak bisa tahu apakah yang Anda lihat adalah edit baru, salinan lama, atau dua edit yang perlu digabung.

Minimum praktis untuk setiap record yang disinkronkan server:

  • id (primary key stabil): jangan pernah gunakan ulang
  • version (integer): bertambah pada setiap penulisan sukses di server
  • updated_at (timestamp): kapan record terakhir diubah
  • updated_by (text atau user id): siapa yang membuat perubahan terakhir

Di perangkat, tambahkan field hanya-lokal untuk melacak perubahan yang belum dikonfirmasi server:

  • dirty (0/1): ada perubahan lokal
  • pending_sync (0/1): antre untuk diunggah, tapi belum dikonfirmasi
  • last_synced_at (timestamp): terakhir kali baris ini cocok dengan server
  • sync_error (text, opsional): alasan kegagalan terakhir untuk ditampilkan di UI

Optimistic concurrency adalah aturan paling sederhana yang mencegah penimpaan diam-diam: setiap update menyertakan versi yang Anda kira sedang Anda edit (expected_version). Jika record server masih pada versi itu, update diterima dan server mengembalikan versi baru. Jika tidak, itu konflik.

Contoh: User A dan User B sama-sama mengunduh version = 7. A sinkron lebih dulu; server naik ke 8. Ketika B mencoba sinkron dengan expected_version = 7, server menolak dengan konflik sehingga aplikasi B menggabungkan alih-alih menimpa.

Untuk layar konflik yang bagus, simpan titik awal bersama: apa yang awalnya diedit pengguna. Dua pendekatan umum:

  • Simpan snapshot record terakhir yang disinkron (satu kolom JSON atau tabel paralel).
  • Simpan change log (baris per edit atau field per edit).

Snapshot lebih sederhana dan sering cukup untuk formulir. Change log lebih berat, tapi bisa menjelaskan persis apa yang berubah, field demi field.

Bagaimanapun, UI harus bisa menampilkan tiga nilai per field: edit pengguna, nilai server saat ini, dan titik awal bersama.

Snapshot record vs change log: pilih satu pendekatan

Dapatkan source code nyata
Ekspor kode sumber nyata ketika Anda butuh kontrol penuh atas Kotlin, SwiftUI, Go, dan Vue3.
Bangun sekarang

Saat Anda sinkronkan formulir offline-first, Anda bisa mengunggah full record (snapshot) atau mengunggah daftar operasi (change log). Keduanya bekerja dengan Kotlin dan SQLite, tapi berperilaku berbeda ketika dua orang mengedit record yang sama.

Opsi A: Snapshot seluruh record

Dengan snapshot, setiap Simpan menulis state penuh terbaru (semua field). Saat sinkron, Anda mengirim record plus nomor versi. Jika server melihat versi lama, Anda punya konflik.

Ini sederhana dibangun dan cepat dibaca, tapi sering menciptakan konflik lebih besar daripada yang perlu. Jika User A mengedit nomor telepon sementara User B mengedit alamat, pendekatan snapshot bisa memperlakukan itu sebagai satu bentrokan besar meskipun editnya tidak tumpang tindih.

Opsi B: Change log (operasi)

Dengan change log, Anda menyimpan apa yang berubah, bukan seluruh record. Setiap edit lokal menjadi operasi yang bisa diputar ulang di atas state server terbaru.

Operasi yang sering lebih mudah digabung:

  • Set nilai field (set email ke nilai baru)
  • Append catatan (menambah item catatan baru)
  • Tambah tag (menambah satu tag ke set)
  • Hapus tag (menghapus satu tag dari set)
  • Tandai checkbox selesai (set isDone true dengan timestamp)

Operation log dapat mengurangi konflik karena banyak aksi tidak saling tumpang tindih. Menambah catatan jarang konflik dengan orang lain yang menambah catatan berbeda. Tambah/hapus tag bisa digabung seperti matematika set. Untuk field bernilai tunggal, Anda masih perlu aturan per-field ketika dua edit berbeda bersaing.

Tradeoff-nya adalah kompleksitas: ID operasi yang stabil, pengurutan (urutan lokal dan waktu server), dan aturan untuk operasi yang tidak komutatif.

Pembersihan: kompak setelah sinkron sukses

Operation log bertambah besar, jadi rencanakan bagaimana mengecilkannya.

Pendekatan umum adalah kompak per-record: setelah semua operasi hingga versi server yang diketahui diakui, lipat mereka ke dalam snapshot baru, lalu hapus operasi yang lebih lama. Simpan ekor pendek hanya jika Anda butuh undo, auditing, atau debugging lebih mudah.

Alur sinkron langkah-demi-langkah untuk Kotlin + SQLite

Rancang model data siap sinkron
Modelkan data PostgreSQL dengan versi dan field audit menggunakan Data Designer visual AppMaster.
Mulai membangun

Strategi sinkron yang baik sebagian besar soal ketegasan pada apa yang Anda kirim dan apa yang Anda terima kembali. Tujuannya sederhana: jangan pernah menimpa data yang lebih baru dengan tidak sengaja, dan buat konflik jelas ketika Anda tidak bisa menggabungkan dengan aman.

Alur praktis:

  1. Tulis setiap edit ke SQLite terlebih dahulu. Simpan perubahan dalam transaksi lokal dan tandai record pending_sync = 1. Simpan local_updated_at dan versi server terakhir yang diketahui.

  2. Kirim patch, bukan seluruh record. Saat konektivitas kembali, kirim id record plus hanya field yang berubah, bersama expected_version.

  3. Biarkan server menolak versi yang tidak cocok. Jika versi server saat ini tidak cocok dengan expected_version, ia mengembalikan payload konflik (record server, perubahan yang diusulkan, dan field mana yang berbeda). Jika versi cocok, server menerapkan patch, menaikkan versi, dan mengembalikan record yang diperbarui.

  4. Terapkan auto-merge dulu, lalu minta pengguna. Jalankan aturan merge per-field. Perlakukan field aman seperti catatan berbeda dari field sensitif seperti status, harga, atau assignee.

  5. Commit hasil akhir dan bersihkan flag pending. Baik itu auto-merged atau diselesaikan manual, tulis record final kembali ke SQLite, perbarui server_version, set pending_sync = 0, dan catat cukup data audit untuk menjelaskan apa yang terjadi nanti.

Contoh: dua sales rep mengedit pesanan yang sama offline. Rep A mengubah tanggal pengiriman. Rep B mengubah nomor telepon pelanggan. Dengan patch, server dapat menerima kedua perubahan dengan bersih. Jika keduanya mengubah tanggal pengiriman, Anda munculkan satu keputusan jelas alih-alih memaksa entry ulang penuh.

Jaga janji UI konsisten: "Tersimpan" harus berarti tersimpan secara lokal. "Tersinkron" harus jadi status terpisah dan eksplisit.

Pola UX untuk menyelesaikan konflik di formulir

Konflik harus menjadi pengecualian, bukan alur normal. Mulailah dengan menggabungkan otomatis yang aman, lalu minta pengguna hanya ketika keputusan benar-benar diperlukan.

Buat konflik jarang dengan default aman

Jika dua orang mengedit field yang berbeda, gabungkan tanpa menampilkan modal. Pertahankan kedua perubahan dan tampilkan pesan kecil "Diperbarui setelah sinkron".

Simpan prompt untuk tabrakan nyata: field yang sama diubah di kedua perangkat, atau perubahan bergantung pada field lain (seperti status plus alasan status).

Saat harus meminta, buat cepat diselesaikan

Layar konflik harus menjawab dua hal: apa yang berubah, dan apa yang akan disimpan. Bandingkan nilai berdampingan: "Edit Anda", "Edit mereka", dan "Hasil yang disimpan". Jika hanya dua field yang konflik, jangan tampilkan seluruh formulir. Langsung lompat ke field tersebut dan buat sisanya hanya-baca.

Batasi aksi pada apa yang benar-benar dibutuhkan orang:

  • Simpan milikku
  • Simpan milik mereka
  • Edit hasil akhir
  • Tinjau field-demi-field (hanya saat perlu)

Merge parsial adalah tempat UX menjadi rumit. Sorot hanya field yang konflik dan beri label sumbernya dengan jelas ("Milik Anda" dan "Milik Mereka"). Praseleksi opsi yang paling aman sehingga pengguna bisa mengonfirmasi dan melanjutkan.

Tetapkan ekspektasi agar pengguna tidak merasa terjebak. Beri tahu apa yang terjadi jika mereka meninggalkan: mis. "Kami akan menyimpan versi Anda secara lokal dan mencoba sinkron lagi nanti" atau "Record ini akan tetap di Needs review sampai Anda memilih." Tampilkan status itu di daftar sehingga konflik tidak hilang.

Jika Anda membangun alur ini di AppMaster, pendekatan UX yang sama berlaku: gabungkan otomatis field aman dulu, lalu tampilkan langkah review fokus hanya ketika field tertentu bertabrakan.

Kasus rumit: hapus, duplikat, dan record yang "hilang"

Jadikan aturan merge dapat dieksekusi
Ubah aturan penggabungan per-field menjadi logika backend dengan Business Process seret-dan-lepas.
Buat proyek

Sebagian besar masalah sinkron yang terasa acak datang dari tiga situasi: seseorang menghapus sementara orang lain mengedit, dua perangkat membuat hal "yang sama" offline, atau sebuah record menghilang lalu muncul kembali. Ini butuh aturan eksplisit karena LWW sering mengejutkan pengguna.

Hapus vs edit: siapa yang menang?

Tentukan apakah delete lebih kuat daripada edit. Di banyak aplikasi bisnis, delete menang karena pengguna mengharapkan record yang dihapus tetap terhapus.

Set aturan praktis:

  • Jika sebuah record dihapus di perangkat mana pun, perlakukan sebagai dihapus di semua tempat, bahkan jika ada edit kemudian.
  • Jika delete perlu dapat dibalik, ubah delete menjadi state diarsipkan alih-alih hapus keras.
  • Jika edit datang untuk record yang terhapus, simpan edit dalam history untuk audit, tapi jangan kembalikan record.

Tabrakan pembuatan offline dan draft duplikat

Formulir offline-first sering membuat ID sementara (mis. UUID) sebelum server memberikan ID final. Duplikat terjadi ketika pengguna membuat dua draft untuk hal dunia nyata yang sama (nota yang sama, tiket yang sama, item yang sama).

Jika Anda punya natural key stabil (nomor nota, barcode, email + tanggal), gunakan untuk mendeteksi tabrakan. Jika tidak, terima bahwa duplikat akan terjadi dan sediakan opsi merge sederhana nanti.

Tip implementasi: simpan local_id dan server_id di SQLite. Ketika server merespons, tulis mapping dan pertahankan setidaknya sampai Anda yakin tidak ada perubahan antrean yang masih merujuk ke local ID.

Mencegah "resurrect" setelah sinkron

Resurrect terjadi ketika Device A menghapus record, tapi Device B offline lalu mengunggah salinan lama sebagai upsert, sehingga record muncul kembali.

Solusinya adalah tombstone. Alih-alih menghapus baris segera, tandai terhapus dengan deleted_at (sering juga deleted_by dan delete_version). Saat sinkron, perlakukan tombstone sebagai perubahan nyata yang bisa menimpa state non-deleted yang lebih lama.

Tentukan berapa lama menyimpan tombstone. Jika pengguna bisa offline selama berminggu-minggu, simpan lebih lama dari itu. Hapus hanya setelah Anda yakin perangkat aktif telah sinkron melewati delete.

Jika Anda mendukung undo, perlakukan undo sebagai perubahan lain: hapus deleted_at dan naikkan versi.

Kesalahan umum yang menyebabkan kehilangan data atau frustrasi pengguna

Jaga review konflik tetap kecil
Buat layar review fokus yang hanya menampilkan field yang benar-benar konflik.
Coba AppMaster

Banyak kegagalan sinkron datang dari asumsi kecil yang diam-diam menimpa data yang baik.

Kesalahan 1: Mengandalkan waktu perangkat untuk mengurutkan edit

Ponsel bisa punya jam yang salah, zona waktu berubah, dan pengguna bisa mengatur waktu secara manual. Jika Anda mengurutkan perubahan berdasarkan timestamp perangkat, Anda akhirnya menerapkan edit dengan urutan yang salah.

Lebih baik gunakan versi yang dikeluarkan server (serverVersion) dan perlakukan timestamp klien hanya untuk tampilan. Jika harus memakai waktu, tambahkan pengaman dan rekonsiliasi di server.

Kesalahan 2: LWW tidak sengaja pada field sensitif

LWW terlihat sederhana sampai mengenai field yang tidak boleh "menang" oleh siapa pun yang sinkron terakhir. Status, total, persetujuan, dan penugasan biasanya membutuhkan aturan eksplisit.

Checklist keselamatan untuk field berisiko tinggi:

  • Perlakukan transisi status sebagai state machine, bukan edit bebas.
  • Hitung ulang total dari line item. Jangan gabungkan total sebagai angka mentah.
  • Untuk counter, gabungkan dengan menerapkan delta, bukan memilih pemenang.
  • Untuk kepemilikan atau assignee, minta konfirmasi eksplisit pada konflik.

Kesalahan 3: Menimpa nilai server yang lebih baru dengan data cache lama

Ini terjadi ketika klien mengedit snapshot lama, lalu mengunggah full record. Server menerimanya dan perubahan server yang lebih baru hilang.

Perbaiki bentuk data yang Anda kirim: kirim hanya field berubah (atau change log), plus versi dasar yang Anda edit. Jika versi dasar tertinggal, server menolak atau memaksa merge.

Kesalahan 4: Tidak ada riwayat "siapa mengubah apa"

Ketika konflik terjadi, pengguna ingin satu jawaban: apa yang saya ubah, dan apa yang diubah orang lain? Tanpa identitas editor dan jejak perubahan per-field, layar konflik menjadi tebakan.

Simpan updatedBy, waktu update server jika ada, dan setidaknya jejak audit ringan per-field.

Kesalahan 5: UI konflik yang memaksa perbandingan seluruh record

Memaksa orang membandingkan seluruh record melelahkan. Sebagian besar konflik hanya satu sampai tiga field. Tampilkan hanya field yang konflik, pra-pilih opsi paling aman, dan biarkan pengguna menerima sisanya otomatis.

Jika Anda membangun formulir di tool no-code seperti AppMaster, tujuannya sama: selesaikan konflik di tingkat field sehingga pengguna membuat satu pilihan jelas daripada menggulir seluruh formulir.

Checklist cepat dan langkah selanjutnya

Jika Anda ingin edit offline terasa aman, perlakukan konflik sebagai kondisi normal, bukan error. Hasil terbaik datang dari aturan yang jelas, tes yang dapat diulang, dan UX yang menjelaskan apa yang terjadi dengan bahasa sederhana.

Sebelum menambahkan fitur, pastikan dasar-dasarnya terkunci:

  • Untuk setiap tipe record, tetapkan aturan merge per field (LWW, ambil max/min, append, union, atau selalu minta).
  • Simpan versi yang dikontrol server plus updated_at yang Anda kontrol, dan validasi saat sinkron.
  • Jalankan tes dua-perangkat di mana keduanya mengedit record yang sama offline, lalu sinkron dalam kedua urutan (A lalu B, B lalu A). Hasil harus dapat diprediksi.
  • Uji konflik keras: delete vs edit, dan edit vs edit pada field berbeda.
  • Buat status terlihat: Tersinkron, Menunggu unggah, dan Needs review.

Prototype alur penuh end-to-end dengan satu formulir nyata, bukan layar demo. Gunakan skenario realistis: teknisi lapangan memperbarui catatan pekerjaan di ponsel sementara dispatcher mengedit judul pekerjaan di tablet. Jika mereka menyentuh field berbeda, auto-merge dan tampilkan petunjuk kecil "Diperbarui dari perangkat lain". Jika mereka menyentuh field yang sama, arahkan ke layar review sederhana dengan dua pilihan dan preview yang jelas.

Saat Anda siap membangun aplikasi mobile penuh dan API backend bersama, AppMaster (appmaster.io) dapat membantu. Anda bisa memodelkan data, mendefinisikan logika bisnis, dan membangun UI web serta native mobile di satu tempat, lalu deploy atau ekspor source code ketika aturan sinkron Anda sudah matang.

FAQ

Apa itu konflik sinkron offline, dijelaskan secara sederhana?

Konflik terjadi ketika dua perangkat mengubah record yang sama yang didukung server saat mereka sedang offline (atau sebelum salah satu sempat sinkron), dan server kemudian melihat bahwa kedua pembaruan tersebut didasarkan pada versi lama. Sistem kemudian harus memutuskan nilai akhir untuk setiap field yang berbeda.

Strategi konflik mana yang harus saya pilih: last write wins, tinjauan manual, atau penggabungan per-field?

Mulailah dengan penggabungan per-field sebagai default untuk sebagian besar formulir bisnis, karena peran yang berbeda sering mengedit field yang berbeda sehingga Anda dapat mempertahankan kedua perubahan tanpa mengganggu siapa pun. Gunakan tinjauan manual hanya untuk field yang bisa menyebabkan kerugian nyata jika sistem menebak (uang, persetujuan, kepatuhan). Gunakan last write wins hanya untuk field berisiko rendah dimana kehilangan edit lama dapat diterima.

Kapan aplikasi harus meminta pengguna menyelesaikan konflik?

Jika dua edit menyentuh field yang berbeda, Anda biasanya dapat menggabungkan otomatis tanpa menampilkan modal. Jika dua edit mengubah field yang sama ke nilai berbeda, field itu harus memicu keputusan, karena pilihan otomatis bisa mengejutkan seseorang. Batasi ruang keputusan dengan hanya menampilkan field yang konflik, bukan seluruh formulir.

Bagaimana versi record mencegah penindihan tanpa disadari?

Perlakukan version sebagai penghitung monoton server untuk record, dan minta klien mengirim expected_version dengan setiap pembaruan. Jika versi server tidak cocok, tolak dengan respon konflik alih-alih menimpa. Aturan tunggal ini mencegah “kehilangan data diam-diam” bahkan ketika dua perangkat sinkron dalam urutan berbeda.

Metadata apa yang harus dimiliki setiap tabel SQLite yang disinkronkan?

Minimum praktis adalah id stabil, version yang dikontrol server, dan updated_at/updated_by yang dikontrol server agar Anda bisa menjelaskan apa yang berubah. Di perangkat, lacak apakah baris diubah dan menunggu unggah (mis. pending_sync) dan simpan versi server terakhir yang disinkronkan. Tanpa ini, Anda tidak bisa andal mendeteksi konflik atau menampilkan layar penyelesaian yang membantu.

Haruskah saya menyinkronkan seluruh record atau hanya field yang berubah?

Kirim hanya field yang berubah (patch) plus expected_version dasar. Unggahan seluruh record membuat edit kecil yang tidak tumpang tindih menjadi konflik yang tidak perlu dan meningkatkan kemungkinan menimpa nilai server yang lebih baru dengan cache lama. Patch juga membuat jelas field mana yang butuh aturan merge.

Lebih baik menyimpan snapshot atau change log untuk edit offline?

Snapshot lebih sederhana: Anda menyimpan record penuh terbaru dan membandingkannya dengan server nanti. Change log lebih fleksibel: Anda menyimpan operasi seperti “set field” atau “append note” dan memutarnya ulang di atas state server terbaru, yang seringkali bergabung lebih baik untuk catatan, tag, dan pembaruan aditif lain. Pilih snapshot untuk kecepatan implementasi; pilih change log jika penggabungan sering terjadi dan Anda butuh detail “siapa mengubah apa”.

Bagaimana saya harus menangani konflik delete vs edit?

Tentukan sejak awal apakah delete lebih kuat daripada edit, karena pengguna mengharapkan perilaku yang konsisten. Untuk banyak aplikasi bisnis, default aman adalah memperlakukan delete sebagai "tombstone" (tandai sebagai terhapus dengan deleted_at dan versi) sehingga upsert lama yang offline tidak secara tidak sengaja menghidupkan kembali record. Jika perlu dapat dibatalkan, gunakan status “archived” alih-alih hard delete.

Apa kesalahan paling umum yang menyebabkan kehilangan data sinkron offline?

Jangan urutkan penulisan kritis berdasarkan waktu perangkat, karena jam bisa meleset dan zona waktu berubah; gunakan versi server untuk pengurutan dan pemeriksaan konflik. Hindari LWW pada field sensitif seperti status, assignee, dan total; berikan aturan eksplisit atau tinjauan manual. Juga, jangan tampilkan layar perbandingan seluruh record ketika hanya satu atau dua field yang bertabrakan, karena itu meningkatkan kesalahan dan frustrasi.

Bagaimana saya bisa mengimplementasikan UX yang ramah konflik saat membangun dengan AppMaster?

Pertahankan janji bahwa “Tersimpan” berarti tersimpan secara lokal dan tampilkan status terpisah untuk “Tersinkronisasi” agar pengguna paham apa yang terjadi. Jika Anda membangun ini di AppMaster, terapkan struktur yang sama: definisikan aturan merge per-field sebagai bagian logika produk, gabungkan otomatis field aman, dan arahkan hanya tabrakan field nyata ke langkah review kecil. Uji dengan dua perangkat yang mengedit record yang sama offline dan sinkron dalam kedua urutan untuk memastikan hasil dapat diprediksi.

Mudah untuk memulai
Ciptakan sesuatu yang menakjubkan

Eksperimen dengan AppMaster dengan paket gratis.
Saat Anda siap, Anda dapat memilih langganan yang tepat.

Memulai