Skip to content

Repository files navigation

Offline Data Sync App

A React Native / Expo Android app that demonstrates offline-first note syncing with Firebase Realtime Database. The app keeps notes available while offline, then syncs changes when connectivity returns.

What is already implemented

  • Separate email/password login and registration flows.
  • Notes CRUD: create, edit, delete, and browse notes.
  • Offline-aware sync through Firebase Realtime Database.
  • Network status tracking with @react-native-community/netinfo.
  • Local UI/session persistence with Zustand + AsyncStorage.
  • Theme and session state persisted across app restarts.
  • Native Firebase configuration for Android through google-services.json.
  • Release-safe logging with secret redaction in development.
  • Registration password policy enforced (min 8 chars with letter, number, and special character).

Architecture

The app follows a layered flow:

DataSource -> Repository -> UseCase -> Zustand -> UI

That means:

  • Firebase access lives in datasource files.
  • Repositories wrap datasource calls.
  • Use cases expose domain actions.
  • Zustand stores app state and orchestrates use cases.
  • Screens and components only talk to the store.

Tech Stack

  • Expo / React Native
  • React Navigation
  • Firebase Realtime Database
  • Firebase JS SDK (firebase package)
  • Zustand
  • AsyncStorage
  • NetInfo
  • React Native Paper
  • Jest + React Test Renderer

Project Structure

src/
  App.js
  features/
    auth/
      data/
        datasources/
        repositories/
      domain/
        usecases/
      screens/
    notes/
      components/
      data/
        datasources/
        repositories/
      domain/
        usecases/
      screens/
      store/
    settings/
      screens/
  navigation/
  shared/
    components/
    utils/
  test/

Firebase Setup

This project currently initializes Firebase through the JavaScript SDK in src/shared/firebase/firebaseClient.js.

  • app.json points Android to google-services.json for native Android build metadata.
  • The app also parses google-services.json in JS to populate initializeApp(...) config values (apiKey, appId, projectId, databaseURL, and related fields).
  • This keeps one Firebase source of truth for Android and avoids duplicating those values in code.

If you want separate environments, keep per-environment Firebase config files and switch them via Expo config/EAS build profiles.

Platform caveats

  • Android: the current flow works as-is because google-services.json is available and mapped in app.json.
  • iOS: this repo does not include a GoogleService-Info.plist path/config; add iOS Firebase config and update Expo settings before shipping iOS.
  • Web: google-services.json is Android-specific. For web builds, provide Firebase JS config through environment variables or a web-specific config module.
  • Dependency note: @react-native-firebase/* packages are installed, but app runtime in this repository uses the Firebase JS SDK path in src/shared/firebase/firebaseClient.js.

Getting Started

1. Install dependencies

npm install

If you are setting up Firebase manually for this code path, make sure the JS SDK is installed:

npm install firebase

Optional: if you later migrate runtime calls to native Firebase modules, then install @react-native-firebase/app and @react-native-firebase/database as part of that migration.

2. Configure Firebase

  • Create a Firebase project.
  • Enable Realtime Database.
  • Download the Android google-services.json file.
  • Place it at the project root.
  • Keep app.json configured with android.googleServicesFile.

3. Start the app

npx expo start -c

Because runtime data/auth calls use the Firebase JS SDK, you can run the app in Expo Go for Android flows. If you later switch runtime calls to @react-native-firebase/*, use a development build.

4. Build Android

The existing EAS profiles in eas.json include:

  • preview3 for a development client build
  • preview / preview4 for internal builds
  • production for release builds

Example:

eas build --profile preview3 --platform android

Testing

Run tests

Project script (watch mode):

npm test

One-time run (recommended for CI/local verification):

npx jest --watchAll=false

Targeted test suites

The project includes unit tests for key layers:

  • Repository layer
    • src/features/auth/data/repositories/__tests__/authRepository.test.js
    • src/features/notes/data/repositories/__tests__/notesRepository.test.js
  • Datasource layer
    • src/features/auth/data/datasources/__tests__/authRemoteDataSource.test.js
    • src/features/notes/data/datasources/__tests__/notesRemoteDataSource.test.js
  • Use case layer
    • src/features/auth/domain/usecases/__tests__/authUseCases.test.js
    • src/features/notes/domain/usecases/__tests__/notesUseCases.test.js
  • Zustand business logic
    • src/features/notes/store/__tests__/useNotesStore.test.js
  • Shared widgets/components
    • src/shared/components/__tests__/Loader.test.js
    • src/shared/components/__tests__/PasswordInput.test.js

Run only these suites:

npx jest --runInBand \
  src/features/auth/data/datasources/__tests__/authRemoteDataSource.test.js \
  src/features/notes/data/datasources/__tests__/notesRemoteDataSource.test.js \
  src/features/auth/domain/usecases/__tests__/authUseCases.test.js \
  src/features/notes/domain/usecases/__tests__/notesUseCases.test.js \
  src/features/auth/data/repositories/__tests__/authRepository.test.js \
  src/features/notes/data/repositories/__tests__/notesRepository.test.js \
  src/features/notes/store/__tests__/useNotesStore.test.js \
  src/shared/components/__tests__/Loader.test.js \
  src/shared/components/__tests__/PasswordInput.test.js

CI/CD (GitHub Actions)

APK release automation is configured with the workflow at .github/workflows/build-apk.yml.

What the workflow does

  • Installs dependencies
  • Runs tests
  • Builds Android APK with EAS
  • Downloads the APK artifact
  • Publishes the APK to GitHub Releases

Triggers

  • Push to main (creates a release with auto tag format v0.0.0-main-<run_number>)
  • Tag push matching v* (for example: v1.0.1)
  • Manual run from Actions (workflow_dispatch) with selectable EAS profile

Required GitHub Secret

Add this repository secret before running the workflow:

  • EXPO_TOKEN: Expo access token used by EAS CLI in CI

Publish an APK release

git tag v1.0.1
git push origin v1.0.1

After the workflow finishes, the APK is attached to the matching GitHub Release tag.

Screens in the App

  • Login / registration screen
  • Notes list screen
  • Note editor screen
  • Settings screen

Notes

  • Firebase console keys should not be hardcoded in UI files.
  • Console logging is disabled in release builds and redacted in development.
  • The main app entry is src/App.js.

Learn More

Screenshots

Splash & Auth Screen

offline-sync-figma-preview

studio64_CuuGwCYE0t studio64_MddeKBOdCM

Home Screens

studio64_X04qLq6rL3 studio64_oLfS7GQ0Wz studio64_NffQClFk1b studio64_60sHmSZ7cn studio64_xOKTO8tb6q studio64_LzwtyRNs01

Online vs Offline Mode

studio64_oLfS7GQ0Wz studio64_60sHmSZ7cn

Others

studio64_dXVoQYmPF9

About

This project demonstrates how to build an Android cloud application with offline data persistence capabilities, similar to Google Keep and WhatsApp. The application utilizes a real-time database that ensures data is persistently stored locally even when the app is offline or restarted

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages