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.
- 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).
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.
- Expo / React Native
- React Navigation
- Firebase Realtime Database
- Firebase JS SDK (
firebasepackage) - Zustand
- AsyncStorage
- NetInfo
- React Native Paper
- Jest + React Test Renderer
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/
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.
- 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.plistpath/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.
npm installIf you are setting up Firebase manually for this code path, make sure the JS SDK is installed:
npm install firebaseOptional: 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.
- Create a Firebase project.
- Enable Realtime Database.
- Download the Android
google-services.jsonfile. - Place it at the project root.
- Keep app.json configured with
android.googleServicesFile.
npx expo start -cBecause 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.
The existing EAS profiles in eas.json include:
preview3for a development client buildpreview/preview4for internal buildsproductionfor release builds
Example:
eas build --profile preview3 --platform androidProject script (watch mode):
npm testOne-time run (recommended for CI/local verification):
npx jest --watchAll=falseThe project includes unit tests for key layers:
- Repository layer
src/features/auth/data/repositories/__tests__/authRepository.test.jssrc/features/notes/data/repositories/__tests__/notesRepository.test.js
- Datasource layer
src/features/auth/data/datasources/__tests__/authRemoteDataSource.test.jssrc/features/notes/data/datasources/__tests__/notesRemoteDataSource.test.js
- Use case layer
src/features/auth/domain/usecases/__tests__/authUseCases.test.jssrc/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.jssrc/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.jsAPK release automation is configured with the workflow at .github/workflows/build-apk.yml.
- Installs dependencies
- Runs tests
- Builds Android APK with EAS
- Downloads the APK artifact
- Publishes the APK to GitHub Releases
- Push to
main(creates a release with auto tag formatv0.0.0-main-<run_number>) - Tag push matching
v*(for example:v1.0.1) - Manual run from Actions (
workflow_dispatch) with selectable EAS profile
Add this repository secret before running the workflow:
EXPO_TOKEN: Expo access token used by EAS CLI in CI
git tag v1.0.1
git push origin v1.0.1After the workflow finishes, the APK is attached to the matching GitHub Release tag.
- Login / registration screen
- Notes list screen
- Note editor screen
- Settings screen
- 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.
- Expo docs
- Expo development builds
- Firebase Realtime Database
- React Native Firebase
- Zustand
- React Native Paper
