Skip to content

Ilannildo/inmeta

Repository files navigation

Inmeta — Gerenciador de Ordens de Serviço

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.


Sumário


Requisitos

  • Node.js (LTS recomendado)
  • pnpm
  • Expo CLI
  • Android Studio (Android) e/ou Xcode (iOS)
  • Java/JDK (Android)

Setup do projeto

1) Instalação

pnpm install

2) Variáveis de ambiente

Crie um arquivo .env na raiz do projeto:

EXPO_PUBLIC_API_URL=https://fieldsync.onrender.com

3) Expo prebuild

Este projeto utiliza módulos nativos (ex.: Realm), então é necessário gerar os diretórios nativos.

pnpm prebuild --clean

Isso criará as pastas android/ e ios/ com os arquivos nativos baseados no app.json.

4) Rodar no Android/iOS

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 android

iOS:

pnpm ios

Tecnologias e por quê

  • 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).


Arquitetura e organização

Estrutura sugerida (pode variar conforme evolução):

  • src/services Comunicação com API, regras de sync e serviços de domínio.
  • src/realm Schemas do Realm e setup do banco local.
  • src/stores Zustand stores (ex.: estado de sincronização).
  • src/common/hooks Hooks reutilizáveis (ex.: conectividade e auto-sync).
  • src/components Componentes de UI reaproveitáveis.
  • app/ (expo-router) Rotas/telas.

Offline-first

Persistência local (Realm)

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: último updatedAt conhecido do servidor
  • __conflict: marca conflitos detectados durante o pull

Isso permite que o app funcione normalmente offline, armazenando mudanças localmente e sincronizando depois.

Detecção de conectividade

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.

Sincronização

A sincronização segue a lógica:

  1. Pull remoto: busca alterações do servidor desde um timestamp (/work-orders/sync?since=...)
  2. Aplicação local: atualiza o Realm com os dados remotos (sem sobrescrever conflitos)
  3. Push local: envia alterações locais pendentes (__dirty) para o servidor

Esse fluxo reduz inconsistências e evita sobrescritas indevidas.

Conflitos e resolução

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

Scripts

  • pnpm start — inicia o Expo dev server
  • pnpm prebuild — gera android/ e ios/
  • pnpm android — roda no Android (build nativo)
  • pnpm ios — roda no iOS (build nativo)
  • pnpm web — roda no navegador
  • pnpm lint — lint
  • pnpm lint:fix — lint/check corrigindo
  • pnpm format — formatação

About

INMETA é um app mobile em React Native + Expo com arquitetura offline-first, usando Realm para persistência local e sincronização inteligente de ordens de serviço.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages