Aplicativo mobile desenvolvido em React Native com Expo com foco em offline-first, permitindo criar/editar/excluir Ordens de Serviço mesmo sem internet e sincronizar automaticamente quando a conexão voltar.
- Node.js (LTS recomendado)
- pnpm
- Expo CLI
- Android Studio (Android) e/ou Xcode (iOS)
- Java/JDK (Android)
pnpm installCrie um arquivo .env na raiz do projeto:
EXPO_PUBLIC_API_URL=https://fieldsync.onrender.comEste projeto utiliza módulos nativos (ex.: Realm), então é necessário gerar os diretórios nativos.
pnpm prebuild --cleanIsso criará as pastas android/ e ios/ com os arquivos nativos baseados no app.json.
Configuração extra (Android)
Caso ocorra algum erro no build relacionado ao SDK, crie um arquivo local.properties dentro da pasta android com o local do se SDK.
sdk.dir=/Users/{user}/Library/Android/sdk
Obs: Troque {user} pelo usuário da sua máquina
Android:
pnpm androidiOS:
pnpm ios-
Expo + Expo Dev Client (
expo,expo-dev-client) Permite desenvolvimento rápido com um fluxo produtivo, mantendo compatibilidade com módulos nativos necessários (Realm). -
expo-router Roteamento baseado em arquivos, simplificando navegação e organização das telas.
-
Realm + @realm/react (
realm,@realm/react) Banco local performático, ideal para offline-first com consultas reativas e persistência confiável. -
@react-native-community/netinfo Monitoramento de conectividade para disparar sincronização automática quando a internet volta.
-
Zustand + AsyncStorage (
zustand,@react-native-async-storage/async-storage) Estado global simples e objetivo, com persistência para dados que precisam sobreviver a reinícios (ex.: cursor de sync). -
React Hook Form + Zod (
react-hook-form,zod,@hookform/resolvers) Formulários performáticos com validação tipada e regras declarativas. -
TanStack React Query (
@tanstack/react-query) Organização das chamadas HTTP, cache e controle de estado de request onde faz sentido (especialmente para consumo remoto). -
NativeWind + TailwindCSS (
nativewind,tailwindcss,tailwind-merge) Estilização consistente e rápida, com reutilização de padrões e composição de classes. -
date-fns Formatação de datas de forma leve e consistente.
-
Biome (
@biomejs/biome) Padronização do código com lint/format (evita ruído no PR e melhora consistência do projeto).
Estrutura sugerida (pode variar conforme evolução):
src/servicesComunicação com API, regras de sync e serviços de domínio.src/realmSchemas do Realm e setup do banco local.src/storesZustand stores (ex.: estado de sincronização).src/common/hooksHooks reutilizáveis (ex.: conectividade e auto-sync).src/componentsComponentes de UI reaproveitáveis.app/(expo-router) Rotas/telas.
As Ordens de Serviço são salvas localmente em Realm e possuem campos de controle de sync, por exemplo:
__dirty: indica que existe alteração local pendente__opType: define o tipo da operação pendente (create,update,delete)__clientUpdatedAt: timestamp local da última modificação__remoteUpdatedAt: últimoupdatedAtconhecido do servidor__conflict: marca conflitos detectados durante o pull
Isso permite que o app funcione normalmente offline, armazenando mudanças localmente e sincronizando depois.
A conectividade é monitorada com @react-native-community/netinfo. Quando o dispositivo volta a ficar online, o app pode disparar automaticamente o fluxo de sincronização.
A sincronização segue a lógica:
- Pull remoto: busca alterações do servidor desde um timestamp (
/work-orders/sync?since=...) - Aplicação local: atualiza o Realm com os dados remotos (sem sobrescrever conflitos)
- Push local: envia alterações locais pendentes (
__dirty) para o servidor
Esse fluxo reduz inconsistências e evita sobrescritas indevidas.
Um conflito ocorre quando:
- o registro foi alterado localmente (
__dirty === true) - e existe uma atualização mais recente no servidor (
remote.updatedAt > __remoteUpdatedAt)
Nesses casos:
-
o registro é marcado com
__conflict = true -
a sincronização automática ignora itens em conflito
-
o usuário pode resolver manualmente escolhendo entre:
- Local vence: atualiza o servidor com os dados locais e limpa o conflito
- Remoto vence: aplica as informações remotas localmente e limpa o conflito
pnpm start— inicia o Expo dev serverpnpm prebuild— geraandroid/eios/pnpm android— roda no Android (build nativo)pnpm ios— roda no iOS (build nativo)pnpm web— roda no navegadorpnpm lint— lintpnpm lint:fix— lint/check corrigindopnpm format— formatação