20 de ago. de 2025·8 min de leitura

Resolução de conflitos em formulários offline-first para Kotlin + SQLite

Aprenda resolução de conflitos em formulários offline-first: regras de mesclagem claras, workflow simples de sync em Kotlin + SQLite e padrões de UX práticos para conflitos de edição.

Resolução de conflitos em formulários offline-first para Kotlin + SQLite

O que realmente acontece quando duas pessoas editam offline

Formulários offline-first deixam as pessoas verem e editarem dados mesmo quando a rede está lenta ou indisponível. Em vez de esperar pelo servidor, o app grava mudanças primeiro em um banco local SQLite e sincroniza depois.

Isso parece instantâneo, mas cria uma realidade simples: dois dispositivos podem alterar o mesmo registro sem saber um do outro.

Um conflito típico é assim: um técnico abre uma ordem de serviço em um tablet no subsolo sem sinal. Ele marca o status como "Done" e adiciona uma nota. Ao mesmo tempo, um supervisor em outro telefone atualiza a mesma ordem, reatribui e altera a data de vencimento. Ambos tocam em Salvar. Ambos os salvamentos funcionam localmente. Ninguém fez nada de errado.

Quando a sincronização finalmente acontece, o servidor precisa decidir qual é o registro "real". Se você não tratar conflitos explicitamente, normalmente acaba com um destes resultados:

  • Último a gravar vence: o sincronizador mais recente sobrescreve mudanças anteriores e alguém perde dados.
  • Falha dura: a sincronização rejeita uma atualização e o app mostra um erro pouco útil.
  • Registros duplicados: o sistema cria uma segunda cópia para evitar sobrescrever e os relatórios ficam bagunçados.
  • Mesclagem silenciosa: o sistema combina mudanças, mas mistura campos de maneiras que os usuários não esperavam.

Conflitos não são um bug. Eles são o resultado previsível de permitir que as pessoas trabalhem sem conexão ao vivo, que é justamente o objetivo do offline-first.

O objetivo é duplo: proteger os dados e manter o app fácil de usar. Isso geralmente significa regras de mesclagem claras (frequentemente no nível de campo) e uma experiência que interrompe o usuário somente quando realmente importa. Se duas edições alteram campos diferentes, você costuma mesclar silenciosamente. Se duas pessoas mudaram o mesmo campo de formas diferentes, o app deve tornar isso visível e ajudar alguém a escolher o resultado correto.

Escolha uma estratégia de conflito que combine com seus dados

Conflitos não são um problema técnico primeiro. São uma decisão de produto sobre o que significa "correto" quando duas pessoas alteraram o mesmo registro antes da sincronização.

Três estratégias cobrem a maioria dos apps offline:

  • Último a gravar vence (LWW): aceita a edição mais nova e sobrescreve a anterior.
  • Revisão manual: interrompe e pede a um humano para escolher o que manter.
  • Mesclagem por campo: combina mudanças por campo e só pede intervenção quando duas pessoas tocaram o mesmo campo.

LWW pode ser aceitável quando velocidade importa mais que precisão perfeita e o custo do erro é baixo. Pense em notas internas, tags não críticas ou um rascunho que pode ser editado novamente depois.

Revisão manual é a escolha mais segura para campos de alto impacto onde o app não deve adivinhar: texto legal, confirmações de conformidade, valores de folha de pagamento e faturas, dados bancários, instruções de medicação e qualquer coisa que gere responsabilidade.

Mesclagem por campo costuma ser o melhor padrão para formulários em que papéis diferentes atualizam partes distintas. Um agente de suporte edita o endereço enquanto vendas atualiza a data de renovação. Uma mesclagem por campo preserva ambas as mudanças sem incomodar ninguém. Mas se ambos editaram a data de renovação, esse campo deve acionar uma decisão.

Antes de implementar qualquer coisa, escreva o que "correto" significa para o seu negócio. Um checklist rápido ajuda:

  • Quais campos devem sempre refletir o valor real mais recente (como status atual)?
  • Quais campos são históricos e nunca devem ser sobrescritos (como um timestamp de envio)?
  • Quem pode mudar cada campo (papel, propriedade, aprovações)?
  • Qual é a fonte da verdade quando os valores discordam (dispositivo, servidor, aprovação do gerente)?
  • O que acontece se você escolher errado (incômodo menor vs impacto financeiro ou legal)?

Quando essas regras estão claras, o código de sincronização tem um único trabalho: aplicá-las.

Defina regras de mesclagem por campo, não por tela

Quando um conflito acontece, raramente ele afeta o formulário inteiro de maneira uniforme. Um usuário pode atualizar um telefone enquanto outro adiciona uma nota. Se você tratar o registro todo como tudo ou nada, força as pessoas a refazerem trabalho bom.

Mesclagem por campo é mais previsível porque cada campo tem um comportamento conhecido. A UX permanece calma e rápida.

Uma forma simples de começar é separar campos em categorias “geralmente seguros” e “geralmente inseguros”.

Geralmente seguro mesclar automaticamente: notas e comentários internos, tags, anexos (frequentemente união) e timestamps como "last contacted" (frequentemente manter o mais recente).

Geralmente inseguro mesclar automaticamente: status/estado, assignee/owner, totais/preços, flags de aprovação e contagens de inventário.

Depois escolha uma regra de prioridade por campo. Escolhas comuns são servidor vence, cliente vence, papel vence (por exemplo, gerente sobrescreve agente) ou um tie-breaker determinístico como a versão do servidor mais nova.

A pergunta chave é o que acontece quando os dois lados mudaram o mesmo campo. Para cada campo, escolha um dos comportamentos:

  • Auto-mesclar com regra clara (por exemplo, tags são união)
  • Manter ambos os valores (por exemplo, anexar notas com autor e hora)
  • Marcar para revisão (por exemplo, status e assignee exigem escolha)

Exemplo: dois atendentes editam o mesmo ticket offline. O Rep A muda o status de "Open" para "Pending". O Rep B altera notes e adiciona a tag "refund". Na sincronização, você pode mesclar notes e tags com segurança, mas não deve mesclar status silenciosamente. Peça escolha apenas para status, com todo o resto já mesclado.

Para evitar debates depois, documente cada regra em uma frase por campo:

  • "notes: manter ambos, anexar o mais novo por último, incluir autor e hora."
  • "tags: união, remover apenas se removido explicitamente em ambos os lados."
  • "status: se alterado em ambos, exigir escolha do usuário."
  • "assignee: gerente vence, caso contrário servidor vence."

Essa frase torna-se a fonte da verdade para o código Kotlin, queries SQLite e a UI de conflito.

Noções básicas do modelo de dados: versões e campos de auditoria no SQLite

Se você quer que conflitos pareçam previsíveis, adicione um pequeno conjunto de colunas de metadados em cada tabela sincronizada. Sem elas, você não consegue dizer se está olhando para uma edição recente, uma cópia antiga ou duas edições que precisam de mesclagem.

Um mínimo prático para cada registro sincronizado pelo servidor:

  • id (chave primária estável): nunca reaproveite
  • version (inteiro): incrementa a cada gravação bem-sucedida no servidor
  • updated_at (timestamp): quando o registro foi alterado por último
  • updated_by (texto ou id de usuário): quem fez a última alteração

No dispositivo, adicione campos locais para rastrear mudanças que não foram confirmadas pelo servidor:

  • dirty (0/1): existem mudanças locais
  • pending_sync (0/1): enfileirado para upload, mas não confirmado
  • last_synced_at (timestamp): última vez que essa linha bateu com o servidor
  • sync_error (texto, opcional): última razão de falha para mostrar na UI

Concorrência otimista é a regra mais simples que evita sobrescritas silenciosas: toda atualização inclui a versão que você acredita estar editando (um expected_version). Se o registro do servidor ainda estiver naquela versão, a atualização é aceita e o servidor retorna a nova versão. Se não, é um conflito.

Exemplo: Usuário A e Usuário B baixaram version = 7. A sincroniza primeiro; o servidor sobe para 8. Quando B tenta sincronizar com expected_version = 7, o servidor rejeita com conflito para que o app de B mescle em vez de sobrescrever.

Para uma boa tela de conflito, armazene o ponto de partida compartilhado: de onde o usuário originalmente editou. Duas abordagens comuns:

  • Armazenar um snapshot do último registro sincronizado (uma coluna JSON ou uma tabela paralela).
  • Armazenar um change log (linha-por-edição ou campo-por-edição).

Snapshots são mais simples e frequentemente suficientes para formulários. Change logs são mais pesados, mas podem explicar exatamente o que mudou, campo a campo.

De qualquer forma, a UI deve ser capaz de mostrar três valores por campo: a edição do usuário, o valor atual do servidor e o ponto de partida compartilhado.

Snapshots de registro vs change logs: escolha uma abordagem

Construa full stack em um só lugar
Gere backend, web e apps móveis prontos para produção a partir de um workspace no-code.
Experimentar agora

Ao sincronizar formulários offline-first, você pode enviar o registro completo (um snapshot) ou enviar uma lista de operações (um change log). Ambos funcionam com Kotlin e SQLite, mas se comportam de forma diferente quando duas pessoas editam o mesmo registro.

Opção A: Snapshots do registro inteiro

Com snapshots, cada salvamento grava o estado completo mais recente (todos os campos). Na sincronização, você envia o registro mais um número de versão. Se o servidor ver que a versão é antiga, você tem um conflito.

Isso é simples de construir e rápido para ler, mas tende a criar conflitos maiores do que o necessário. Se o Usuário A edita o telefone enquanto o Usuário B edita o endereço, uma abordagem por snapshot pode tratar como um grande choque mesmo que as edições não se sobreponham.

Opção B: Change logs (operações)

Com change logs, você armazena o que mudou, não todo o registro. Cada edição local vira uma operação que você pode reaplicar sobre o estado mais recente do servidor.

Operações que costumam ser mais fáceis de mesclar:

  • Definir um valor de campo (setar email para um novo valor)
  • Anexar uma nota (adiciona um item de nota)
  • Adicionar uma tag (adiciona uma tag ao conjunto)
  • Remover uma tag (remove uma tag do conjunto)
  • Marcar uma checkbox como concluída (setar isDone true com timestamp)

Change logs podem reduzir conflitos porque muitas ações não se sobrepõem. Anexar notas raramente conflita com outra pessoa anexando nota diferente. Adições e remoções de tags podem mesclar como matemática de conjuntos. Para campos de valor único, você ainda precisa de regras por campo quando duas edições diferentes competirem.

A troca é complexidade: ids estáveis para operações, ordenação (sequência local e tempo do servidor) e regras para operações que não comutam.

Limpeza: compactação após sincronização bem-sucedida

Change logs crescem, então planeje como encolhê-los.

Uma abordagem comum é compactação por registro: uma vez que todas as operações até uma versão conhecida do servidor sejam reconhecidas, consolide-as em um novo snapshot e então apague aquelas operações antigas. Mantenha apenas um rabo curto se você precisar de undo, auditoria ou depuração mais fácil.

Fluxo de sync passo a passo para Kotlin + SQLite

Previna sobrescritas silenciosas
Configure atualizações estilo patch e checagens de versão para que dados mais recentes não sejam sobrescritos silenciosamente.
Começar a construir

Uma boa estratégia de sync é principalmente ser estrita com o que você envia e o que aceita de volta. O objetivo é simples: nunca sobrescrever dados mais novos por acidente e deixar conflitos óbvios quando você não pode mesclar com segurança.

Um fluxo prático:

  1. Grave toda edição primeiro no SQLite. Salve mudanças em uma transação local e marque o registro como pending_sync = 1. Armazene local_updated_at e a última server_version conhecida.

  2. Envie um patch, não o registro inteiro. Quando a conectividade voltar, envie o id do registro mais apenas os campos que mudaram, junto com expected_version.

  3. Deixe o servidor rejeitar versões incompatíveis. Se a versão atual do servidor não coincidir com expected_version, ele retorna um payload de conflito (registro do servidor, mudanças propostas e quais campos diferem). Se as versões coincidirem, aplica o patch, incrementa a versão e retorna o registro atualizado.

  4. Aplique auto-mesclagem primeiro, depois peça ao usuário. Execute regras de mesclagem por campo. Trate campos seguros como notas de maneira diferente de campos sensíveis como status, preço ou responsável.

  5. Comite o resultado final e limpe flags pendentes. Seja auto-mesclado ou resolvido manualmente, escreva o registro final de volta no SQLite, atualize server_version, defina pending_sync = 0 e registre dados de auditoria suficientes para explicar o que aconteceu depois.

Exemplo: dois representantes de vendas editam o mesmo pedido offline. O Rep A muda a data de entrega. O Rep B muda o telefone do cliente. Com patches, o servidor pode aceitar ambas as mudanças limpas. Se ambos mudaram a data de entrega, você apresenta uma única decisão clara em vez de forçar reentrada total.

Mantenha a promessa da UI consistente: "Salvo" deve significar salvo localmente. "Sincronizado" deve ser um estado separado e explícito.

Padrões de UX para resolver conflitos em formulários

Conflitos devem ser exceção, não fluxo normal. Comece auto-mesclando o que é seguro e só peça ao usuário quando uma decisão for realmente necessária.

Torne conflitos raros com padrões seguros

Se duas pessoas editam campos diferentes, mescle sem mostrar um modal. Mantenha ambas as mudanças e mostre uma pequena mensagem "Atualizado após sincronização".

Reserve prompts para colisões verdadeiras: o mesmo campo foi alterado em ambos os dispositivos, ou uma mudança depende de outro campo (como status mais motivo do status).

Quando for preciso perguntar, torne rápido terminar

Uma tela de conflito deve responder duas coisas: o que mudou e o que será salvo. Compare valores lado a lado: "Sua edição", "Edição deles" e "Resultado salvo". Se só dois campos conflitam, não mostre o formulário inteiro. Pule direto para esses campos e mantenha o resto somente-leitura.

Mantenha as ações limitadas ao que as pessoas realmente precisam:

  • Manter minha versão
  • Manter a deles
  • Editar o resultado final
  • Revisar campo-a-campo (só quando necessário)

Mesclagens parciais são onde a UX fica complicada. Destaque apenas os campos conflitantes e rotule claramente a origem ("Seu" e "Deles"). Preselecione a opção mais segura para que o usuário confirme e siga em frente.

Defina expectativas para que os usuários não se sintam presos. Diga o que acontece se saírem: por exemplo, "Vamos manter sua versão localmente e tentar sincronizar novamente depois" ou "Este registro ficará em Necessita revisão até você escolher." Torne esse estado visível na lista para que conflitos não se percam.

Se estiver construindo esse fluxo no AppMaster, a mesma abordagem UX vale: auto-mescleie campos seguros primeiro, depois mostre um passo de revisão focado apenas quando campos específicos colidirem.

Casos complicados: deletes, duplicados e registros “ausentes"

Obtenha código-fonte real
Exporte código-fonte real quando precisar de controle total sobre Kotlin, SwiftUI, Go e Vue3.
Construir agora

A maioria dos problemas de sync que parecem aleatórios vem de três situações: alguém deleta enquanto outro edita, dois dispositivos criam a "mesma" coisa offline, ou um registro desaparece e depois reaparece. Essas situações precisam de regras explícitas porque LWW frequentemente surpreende usuários.

Delete vs edit: quem vence?

Decida se um delete é mais forte que uma edição. Em muitos apps de negócio, delete vence porque os usuários esperam que um registro removido permaneça removido.

Um conjunto prático de regras:

  • Se um registro foi deletado em qualquer dispositivo, trate-o como deletado em todo lugar, mesmo que haja edições posteriores.
  • Se deletes precisarem ser reversíveis, converta "delete" em um estado arquivado em vez de um delete hard.
  • Se uma edição chegar para um registro deletado, mantenha a edição no histórico para auditoria, mas não restaure o registro.

Colisões de criação offline e rascunhos duplicados

Formulários offline-first frequentemente criam IDs temporários (como UUID) antes do servidor atribuir um ID final. Duplicados acontecem quando usuários criam dois rascunhos para a mesma coisa do mundo real (o mesmo recibo, o mesmo ticket, o mesmo item).

Se você tem uma chave natural estável (número de recibo, código de barras, email + data), use-a para detectar colisões. Se não, aceite que duplicados vão acontecer e forneça uma opção simples de mesclagem mais tarde.

Dica de implementação: armazene tanto local_id quanto server_id no SQLite. Quando o servidor responder, escreva um mapeamento e mantenha-o pelo menos até ter certeza que nenhuma mudança enfileirada ainda referencia o local ID.

Evitando a “ressurreição" após sync

Ressurreição acontece quando o Dispositivo A deleta um registro, mas o Dispositivo B está offline e depois envia uma cópia antiga como upsert, recriando-o.

A correção é um tombstone. Em vez de remover a linha imediatamente, marque-a deletada com deleted_at (frequentemente também deleted_by e delete_version). Durante a sincronização, trate tombstones como mudanças reais que podem sobrescrever estados não-deletados mais antigos.

Decida por quanto tempo manter tombstones. Se usuários podem ficar offline por semanas, mantenha por mais tempo que isso. Purge apenas quando tiver certeza de que dispositivos ativos sincronizaram além do delete.

Se você suporta undo, trate o undo como outra mudança: limpe deleted_at e aumente a versão.

Erros comuns que causam perda de dados ou frustração do usuário

Entregue uma UI amigável a conflitos
Crie UIs web e móveis nativas que mantenham “Salvo localmente” e “Sincronizado” como estados separados.
Construir app

Muitas falhas de sync vêm de pequenas suposições que silenciosamente sobrescrevem dados válidos.

Erro 1: Confiar no tempo do dispositivo para ordenar edições

Telefones podem ter relógios errados, fusos mudam e usuários podem alterar o horário manualmente. Se você ordenar mudanças por timestamps do dispositivo, eventualmente aplicará edições na ordem errada.

Prefira versões emitidas pelo servidor (um serverVersion monotônico) e trate timestamps do cliente como só para exibição. Se precisar usar tempo, adicione salvaguardas e reconcilie no servidor.

Erro 2: LWW acidental em campos sensíveis

LWW parece simples até atingir campos que não deveriam ser "vencidos" por quem sincroniza por último. Status, totais, aprovações e atribuições normalmente precisam de regras explícitas.

Um checklist de segurança para campos de alto risco:

  • Trate transições de status como uma máquina de estados, não como edição livre.
  • Recalcule totais a partir de itens de linha. Não mescle totais como números crus.
  • Para contadores, mescle aplicando deltas, não escolhendo um vencedor.
  • Para propriedade ou assignee, exija confirmação explícita em conflitos.

Erro 3: Sobrescrever valores do servidor mais novos com dados em cache antigos

Isso acontece quando o cliente edita um snapshot antigo e depois faz upload do registro inteiro. O servidor aceita e mudanças mais novas no servidor desaparecem.

Ajuste o formato do que você envia: envie apenas campos alterados (ou um change log), mais a versão base que você editou. Se a versão base estiver atrasada, o servidor rejeita ou força uma mesclagem.

Erro 4: Sem histórico “quem mudou o quê"

Quando conflitos acontecem, os usuários querem uma resposta: o que eu mudei e o que a outra pessoa mudou? Sem identidade do editor e histórico por campo, sua tela de conflito vira chute.

Armazene updatedBy, tempo de atualização server-side se disponível, e ao menos um rastro leve por campo.

Erro 5: UI de conflito que força comparação do registro inteiro

Fazer as pessoas compararem registros inteiros é exaustivo. A maioria dos conflitos envolve um a três campos. Mostre apenas os campos conflitantes, preselecione a opção mais segura e deixe o usuário aceitar o resto automaticamente.

Se estiver construindo formulários em uma ferramenta no-code como AppMaster, vise o mesmo resultado: resolva conflitos no nível de campo para que os usuários façam uma escolha clara em vez de rolarem por todo o formulário.

Checklist rápido e próximos passos

Se quiser que edições offline pareçam seguras, trate conflitos como um estado normal, não um erro. Os melhores resultados vêm de regras claras, testes repetíveis e UX que explica o que aconteceu em linguagem simples.

Antes de adicionar mais recursos, garanta que esses básicos estejam travados:

  • Para cada tipo de registro, atribua uma regra de mesclagem por campo (LWW, manter max/min, anexar, união ou sempre perguntar).
  • Armazene uma versão controlada pelo servidor mais um updated_at que você controle e valide-os durante a sincronização.
  • Rode um teste com dois dispositivos onde ambos editam o mesmo registro offline e depois sincronizam em ambas ordens (A então B, B então A). O resultado deve ser previsível.
  • Teste conflitos duros: delete vs edit e edit vs edit em campos diferentes.
  • Torne o estado óbvio: mostre Sincronizado, Pendente de upload e Necessita revisão.

Prototipe o fluxo completo de ponta a ponta com um formulário real, não uma tela de demo. Use um cenário realista: um técnico de campo atualiza uma nota de trabalho no celular enquanto um despachante edita o mesmo título do trabalho em um tablet. Se tocarem campos diferentes, auto-mescleie e mostre um pequeno aviso "Atualizado de outro dispositivo". Se tocarem o mesmo campo, direcione para uma tela de revisão simples com duas escolhas e uma pré-visualização clara.

Quando estiver pronto para construir o app móvel completo e as APIs de backend juntos, AppMaster (appmaster.io) pode ajudar. Você pode modelar dados, definir lógica de negócio e criar UIs web e nativas em um só lugar, então fazer deploy ou exportar código-fonte quando suas regras de sync estiverem sólidas.

FAQ

O que é um conflito de sincronização offline, em termos simples?

Um conflito acontece quando dois dispositivos alteram o mesmo registro com suporte do servidor enquanto estão offline (ou antes de qualquer um sincronizar) e o servidor vê depois que ambas as atualizações se basearam em uma versão antiga. O sistema então precisa decidir qual será o valor final para cada campo que difere.

Qual estratégia de conflito eu devo escolher: último a gravar vence, revisão manual ou mesclagem por campo?

Comece com mesclagem por campo como padrão para a maioria dos formulários de negócios, porque diferentes cargos costumam editar partes diferentes e você consegue manter ambas as alterações sem incomodar ninguém. Use revisão manual apenas para campos que podem causar danos reais se você chutar errado (dinheiro, aprovações, conformidade). Use último a gravar vence apenas para campos de baixo risco onde perder um edit antigo é aceitável.

Quando o app deve pedir ao usuário para resolver um conflito?

Se duas edições tocam campos diferentes, normalmente você pode mesclar automaticamente e manter a UI discreta. Se duas edições mudam o mesmo campo para valores diferentes, esse campo deve disparar uma decisão, porque qualquer escolha automática pode surpreender alguém. Mantenha o escopo da decisão pequeno mostrando apenas os campos conflitantes, não o formulário inteiro.

Como as versões de registro evitam sobrescritas silenciosas?

Trate version como o contador monotônico do servidor para o registro e exija que o cliente envie um expected_version com cada atualização. Se a versão atual do servidor não corresponder, rejeite com uma resposta de conflito em vez de sobrescrever. Essa regra única previne “perda silenciosa de dados” mesmo quando dois dispositivos sincronizam em ordens diferentes.

Quais metadados todas as tabelas sincronizadas em SQLite devem incluir?

Um mínimo prático é um id estável, um version controlado pelo servidor e updated_at/updated_by controlados pelo servidor para que você possa explicar o que mudou. No dispositivo, registre se a linha foi alterada e está aguardando upload (por exemplo pending_sync) e mantenha a última versão do servidor sincronizada. Sem isso, você não consegue detectar conflitos de forma confiável nem mostrar uma tela de resolução útil.

Devo sincronizar o registro inteiro ou apenas os campos alterados?

Envie apenas os campos que mudaram (um patch) mais o expected_version base. Uploads de registro completo transformam edições pequenas e não sobrepostas em conflitos desnecessários e aumentam a chance de sobrescrever um valor de servidor mais novo com dados em cache desatualizados. Patches também deixam mais claro quais campos precisam de regras de mesclagem.

É melhor armazenar snapshots ou um change log para edições offline?

Um snapshot é mais simples: você armazena o registro completo mais recente e o compara com o servidor depois. Um change log é mais flexível: você guarda operações como “definir campo” ou “acrescentar nota” e as reaplica sobre o estado de servidor mais novo, o que geralmente mescla melhor notas, tags e outras atualizações aditivas. Escolha snapshots para velocidade de implementação; escolha change logs se as mesclagens forem frequentes e você precisar de um histórico claro de “quem mudou o quê”.

Como devo tratar conflitos delete vs edit?

Decida antecipadamente se um delete é mais forte que uma edição, porque as pessoas esperam comportamento consistente. Para muitos apps de negócio, um padrão seguro é tratar deletes como “tombstones” (marcar como deletado com deleted_at e uma versão) para que um upsert offline antigo não traga o registro de volta acidentalmente. Se precisar de reversibilidade, use um estado “arquivado” em vez de um delete hard.

Quais são os erros mais comuns que causam perda de dados na sincronização offline?

Não ordene gravações críticas por tempo do dispositivo, porque relógios variam e fusos mudam; use versões do servidor para ordenação e checagens de conflito. Evite LWW em campos sensíveis como status, responsável e totais; dê a esses campos regras explícitas ou revisão manual. Além disso, não mostre uma tela de conflito do registro inteiro quando somente um ou dois campos colidem, pois isso aumenta erros e frustração.

Como posso implementar uma UX amigável a conflitos ao construir com AppMaster?

Mantenha a promessa de que “Salvo” significa salvo localmente e mostre um estado separado para “Sincronizado” para que os usuários entendam o que está acontecendo. Se construir isso no AppMaster, siga a mesma estrutura: defina regras de mesclagem por campo como parte da lógica do produto, auto-mescleie campos seguros e encaminhe apenas colisões reais de campo para um pequeno passo de revisão. Teste com dois dispositivos editando o mesmo registro offline e sincronizando em ambas ordens para confirmar que os resultados são previsíveis.

Fácil de começar
Criar algo espantoso

Experimente o AppMaster com plano gratuito.
Quando estiver pronto, você poderá escolher a assinatura adequada.

Comece