AquaX Mobile Architecture

Owner: Mobile & Architecture
Reviewers: Backend, Product Design, QA, Security, DevOps
Status: Draft - Current-Code Baseline
Version: 0.1
Last Updated: 2026-09-17
Review Cycle: Per mobile navigation, auth, API, storage, notification or release change

1. Purpose And Scope

This document describes the current AquaX mobile architecture as implemented in mobile/. It focuses on runtime composition, role-based navigation, state management, API integration, authentication/session storage, notifications, feature boundaries, design-system usage, build/release behavior and known mobile risks.

This document covers the Expo React Native mobile app only. Web frontend architecture is documented in docs/04-architecture/FE_Architecture.md.

Sources reviewed:

  • mobile/package.json
  • mobile/app.json
  • mobile/babel.config.js
  • mobile/tsconfig.json
  • mobile/src/main.tsx
  • mobile/src/App.tsx
  • mobile/src/core/components/**
  • mobile/src/core/config/**
  • mobile/src/core/navigation/**
  • mobile/src/core/store/**
  • mobile/src/core/hooks/**
  • mobile/src/core/services/**
  • mobile/src/core/types/**
  • mobile/src/features/**
  • mobile/scripts/deploy_android_playstore.sh
  • docs/current/architecture/mobile-architecture.md
  • docs/07_Design System.md

2. High-Level Mobile Context

AquaX mobile is an Expo React Native app for role-based farm operations. It supports public auth flows and authenticated role surfaces for ADMIN, MANAGER, TECHNICIAN and OWNER.

Current stack:

Area Current implementation
Runtime Expo SDK 56
React React 19
Native runtime React Native 0.85
Language TypeScript
Navigation React Navigation native stack + bottom tabs
Server state TanStack Query
Auth/client state Zustand
HTTP client Axios
Forms React Hook Form
Validation Zod
UI library Ant Design React Native
Icons lucide-react-native and Ant Design React Native icons
Storage Expo SecureStore and AsyncStorage
Notifications Expo Notifications, REST/SSE notification sync
Toast react-native-toast-message

Primary runtime flow:

AppProviders
  -> RootNavigator
    -> AuthNavigator or MainNavigator
      -> role navigator
        -> feature screen
          -> domain hook
            -> API service
              -> apiClient
                -> backend /api

3. Source Layout

Current source layout:

mobile/src/
  core/
    components/
    config/
    constants/
    hooks/
    libs/
    navigation/
    services/
    store/
    theme/
    types/
  features/
    admin/
    auth/
    manager/
    owner/
    shared/
    technician/
  App.tsx
  main.tsx

Boundaries:

Folder Responsibility
core/components/ App-wide reusable primitives and providers
core/config/ API client, env, i18n and query client
core/constants/ API URLs, query keys, app constants and ticket configs
core/hooks/ Domain hooks and cross-cutting hooks
core/navigation/ Auth, root, role and shared tab navigators
core/services/api/ Domain API service wrappers
core/services/storage/ SecureStore and AsyncStorage abstractions
core/services/toast/ Toast abstraction
core/store/ Zustand auth store
core/theme/ Theme provider, colors, spacing, layout and typography tokens
core/types/ API, auth, navigation and domain DTO types
features/ Role and feature screens/components

Important alignment note:

  • Older docs described a flatter navigation/ and screens/ root layout. Current code uses core/ plus features/.
  • Current code uses role OWNER, not VIEWER, for owner/viewer mobile flows.

4. App Bootstrap

mobile/src/main.tsx registers the Expo root component.

registerRootComponent(App)

mobile/src/App.tsx composes:

AppProviders
  -> RootNavigator

AppProviders composes:

GestureHandlerRootView
  -> QueryClientProvider
    -> SafeAreaProvider
      -> ThemeProvider
        -> Ant Design Provider
          -> app children
          -> AppToast

It also loads Ant Design icon fonts and shows a custom branded launch loading screen while fonts are loading.

5. Build And Runtime Configuration

5.1 Expo App Config

mobile/app.json confirms:

Item Current value
App name AquaX
Slug aquax-mobile
Version 1.0.0
Scheme aquax
Orientation portrait
iOS bundle id com.aquax.app
Android package com.aquax.app
UI style light
Expo updates disabled
Plugins expo-splash-screen, expo-notifications, expo-secure-store
React compiler experiment enabled

5.2 Environment

core/config/env.ts uses:

Variable Purpose Default
EXPO_PUBLIC_API_URL Backend API base URL http://localhost:3001/api
EXPO_PUBLIC_APP_ENV App environment label development

Android emulator behavior:

  • When running on Android, localhost is rewritten to 10.0.2.2.

5.3 Module Resolution

babel.config.js and tsconfig.json define:

@/* -> ./src/*

TypeScript is strict and uses bundler module resolution.

6. Navigation Architecture

6.1 Root Navigation

RootNavigator owns auth restoration and top-level routing.

Flow:

isRestoring
  -> show ActivityIndicator
else accessToken exists
  -> MainNavigator
else
  -> AuthNavigator

Session restoration:

  1. Calls authAPI.restoreSession().
  2. restoreSession() calls refresh flow using SecureStore refresh token.
  3. On success, Zustand setSession() stores access token/user and refresh token.
  4. On failure, Zustand clearSession() clears session.

Deep link reset password:

Prefix Route
mobile:// reset-password
https://app.aquax.app reset-password

6.2 Auth Navigator

Auth stack screens:

Screen Purpose
Login Login
Register Registration screen
ForgotPassword Password reset request
CheckEmail Reset request confirmation
ResetLinkExpired Expired reset link surface
ResetPassword Reset password with token

6.3 Main Navigator

MainNavigator selects a role navigator from the authenticated user's role:

Role Navigator
ADMIN AdminNavigator
MANAGER ManagerNavigator
TECHNICIAN TechnicianNavigator
OWNER OwnerNavigator
missing/unknown defaults to OwnerNavigator

MainNavigator also starts:

  • push notification token registration;
  • notification realtime stream.

6.4 Shared Role Tab Navigator

RoleTabNavigator provides:

  • bottom tab navigation;
  • shared app header;
  • role-specific tabs;
  • hidden screens for stack-like flows;
  • safe-area-aware tab bar sizing;
  • notification bell for OWNER and TECHNICIAN.

7. Role Navigation Map

7.1 ADMIN

Visible tabs:

Tab Screen
Users AdminUserScreen
Farms AdminFarmsNavigator
Ponds AdminPondScreen
Profile ProfileScreen

Hidden screens:

  • AdminAddUser
  • AdminDetailUser
  • AdminEditUser

7.2 MANAGER

Visible tabs:

Tab Screen
Home HomeScreen
Profile ProfileScreen

7.3 OWNER

Visible tabs:

Tab Screen
Home ViewerHomeScreen
Farms FarmsNavigator
AISupport AiSupportScreen
Ticket ActivityLogScreen
Profile ProfileScreen

Hidden screens:

  • FarmingLog
  • Notifications
  • PondDetail
  • CreateProblem
  • ProblemDetail
  • TodoForm

7.4 TECHNICIAN

Visible tabs:

Tab Screen
TechHome TechHomeScreen
TechIncidentList TechIncidentListScreen
Profile ProfileScreen

Hidden screens:

  • TechIncidentDetail
  • TechIncidentAccept
  • Notifications
  • PondDetail

8. State Management Architecture

8.1 Zustand Auth Store

core/store/auth.store.ts owns authenticated session state.

State:

Field Purpose
accessToken In-memory access token for API requests
expiresAt Access token expiry timestamp
isRestoring Root restoration/loading state
user Current authenticated user

Actions:

Action Behavior
setSession Stores refresh token in SecureStore if present and updates access token/user
clearSession Removes refresh token and clears auth state
finishRestoring Marks restore flow as complete

8.2 Token Storage

Refresh token storage:

expo-secure-store key: auth.refreshToken

General storage abstraction:

AsyncStorage JSON get/set/remove

Security rule:

  • Refresh token must stay in SecureStore.
  • Access token is kept in Zustand state and attached by the API client.

8.3 TanStack Query

queryClient defaults:

Setting Value
Query staleTime 60 seconds
Query gcTime 30 minutes
Query refetchOnReconnect true
Query refetchOnWindowFocus false
Query retry no retry for HTTP status < 500; otherwise up to 2 failures
Mutation retry false

Domain hooks use Query Client invalidation after mutations.

9. API Integration Architecture

9.1 API Client

core/config/api-client.ts creates the Axios client.

Current config:

Concern Current code
Base URL env.apiUrl
Timeout 15 seconds
Content type application/json
Mobile client header x-client-type: mobile
Credentials withCredentials: false
Request auth Adds Authorization: Bearer <accessToken> from Zustand
FormData Removes Content-Type to let native boundary be set

9.2 Refresh Flow

When a request receives 401:

  1. Login and refresh requests are excluded from retry.
  2. If refresh token is missing, session is cleared.
  3. If a refresh is already in progress, requests wait in a queue.
  4. Refresh uses SecureStore refresh token.
  5. Refresh request sends:
    • body { refreshToken };
    • x-client-type: mobile;
    • x-refresh-token: <refreshToken>.
  6. On success, setSession() updates auth store and refresh token.
  7. Queued requests replay with the new access token.
  8. On failure, queue rejects and session is cleared.

Mobile refresh flow is intentionally different from web because native clients do not rely on browser httpOnly cookie behavior.

9.3 API Services

Current domain API services:

Service Area
authAPI Login, restore/refresh, logout, profile, password flows
userAPI Admin user list/detail/create/update/status
farmAPI Admin farm list, owner farm/home/detail, technician home, create pond
pondAPI Pond detail, dashboard, tabs, timeseries, update/delete
cropAPI Crop lifecycle and crop catalog
deviceAPI IoT output control, output mode, auto-rules
feedingAPI Feed types and feeding records
farmingLogAPI Manual water, mineral, siphon, combined logs and attachments
ticketAPI Ticket list/detail/lifecycle/comment/attachments
notificationAPI Notifications, stats, read state and device token registration
activityLogAPI Activity log infinite list
todoAPI Owner todo home and task CRUD

10. Domain Hooks Architecture

Hooks live in core/hooks and are the preferred screen-facing API.

Current hook areas:

Hook Responsibility
useAuth Login, forgot/reset password, profile, change password
useUser Admin user queries and mutations
useFarm Admin farms, owner farms/home/detail, technician home, create pond
usePond Pond detail tabs, device control, crop, feeding, auto-rules
useFarmingLog Farming logs and attachment mutations
useTicket Ticket list/detail/lifecycle/comment/attachments
useTodoTask Todo home and task CRUD
useNotification Notification list/stats/read/delete/push/SSE
useActivityLog Infinite activity logs
useDebouncedValue Debounced UI inputs
useKeyboardHeight Keyboard-aware form layout

Architecture rule:

  • Screens should call hooks, not raw API services, when a hook exists.
  • Hooks should own cache keys, invalidation and toast side effects.

11. Feature Modules

Current feature grouping:

Feature root Current scope
features/auth Login, registration and password recovery
features/admin/users Admin user list/detail/add/edit
features/admin/farms Admin farm list and farm navigator
features/admin/ponds Admin pond screen
features/manager/home Manager home
features/owner/home Owner home and todo tasks
features/owner/farms Owner farm list/detail, pond detail, crop and feeding flows
features/owner/farming-logs Farming log navigator/list/form/type selector
features/owner/activity-log Owner activity log
features/owner/ai-support AI support screen
features/owner/problems Problem/ticket creation and detail
features/technician/home Technician home
features/technician/incidents Technician incident list/detail/accept
features/technician/notifications Technician notifications screen
features/technician/profile Technician profile screen
features/shared Alerts, notifications, profile, ticket and shared user surfaces

12. Notifications Architecture

Mobile notifications have three layers:

  1. REST list/stats/read/delete APIs.
  2. SSE realtime stream.
  3. Expo push token registration.

Realtime stream:

  • Starts when authenticated.
  • Uses fetch with Accept: text/event-stream.
  • Sends Authorization: Bearer <accessToken>.
  • Sends x-client-type: mobile.
  • Listens for event type notification.created.
  • Invalidates notification queries on matching event.
  • Reconnect delay is 5 seconds.
  • Stops when AppState is not active and reconnects when active.

Push registration:

  • Ensures Android notification channel.
  • Requests notification permission.
  • Uses Expo project ID from app config.
  • Registers Expo push token with backend.
  • Failures are swallowed because REST/SSE remains source of truth.

13. Theme And Design System Integration

Theme provider:

ThemeProvider -> useTheme()

Theme tokens:

Token group File
Colors core/theme/colors.ts
Spacing core/theme/spacing.ts
Typography core/theme/typography.ts
Layout core/theme/layout.ts

Current reusable components:

Component Purpose
Screen Safe-area-aware scroll/static screen wrapper
AppButton Themed Ant Design button wrapper
AppToast Custom toast renderer
BrandLogo Brand logo wrapper
AppProviders App provider composition and launch loading

Current design-system gap:

  • Core theme primary color is blue, while many production screens use AquaX teal hardcoded values such as #00796B, #006B5F, #005D4E.
  • Future cleanup should align core theme tokens with the AquaX teal palette before expanding token usage.

14. File Upload And Native Capabilities

Confirmed native capabilities:

Capability Usage
Image/file picking expo-image-picker dependency; ticket/farming-log attachment APIs accept file URI/mime/name
Secure token storage expo-secure-store
Push notifications expo-notifications
Safe areas react-native-safe-area-context
Gesture handling react-native-gesture-handler
Reanimated react-native-reanimated plugin configured

FormData behavior:

  • API client removes Content-Type when request body is FormData.
  • Ticket and farming-log attachment services append native file objects.

15. Build, CI And Release Considerations

Package scripts:

Script Purpose
npm start Start Expo dev server
npm run android Run Android native app
npm run ios Run iOS native app
npm run web Run Expo web
npm run lint Expo lint
npm run typecheck tsc --noEmit
npm run format Prettier write
npm run format:check Prettier check

Android release script:

mobile/scripts/deploy_android_playstore.sh

Confirmed release flow:

  1. Load mobile/secrets/build_config.env if present.
  2. Detect Android keystore from mobile/secrets.
  3. Require Google Play service account JSON.
  4. Run npm install.
  5. Run npx expo prebuild --platform android --clean.
  6. Set Android versionCode.
  7. Run Gradle bundleRelease.
  8. Upload AAB with Fastlane supply.

Supported tracks:

  • internal
  • alpha
  • beta
  • production

Release gaps:

  • iOS TestFlight/App Store release process is not documented in repo.
  • Mobile CI/CD is not wired into GitHub Actions.
  • Android release script mutates app.json versionCode during release; this should be handled carefully in release branches.

16. Performance And UX Considerations

Current confirmed patterns:

  • TanStack Query caches server state.
  • Infinite query is used for activity logs.
  • Pond detail loads multiple tab queries in parallel.
  • Device tab and water timeseries poll while viewing pond detail.
  • Notification stream suspends when app is not active.
  • Keyboard-aware helper exists for long forms.
  • Safe-area-aware layout is used in Screen and tab/header UI.

Current gaps:

  • No mobile performance budget is documented.
  • No crash/error monitoring provider is confirmed.
  • Large screens contain substantial local styles and may need decomposition as features grow.

17. Security And Privacy Considerations

Confirmed controls:

  • Refresh token stored in Expo SecureStore.
  • API client sends x-client-type: mobile.
  • Access token is attached only through Axios interceptor.
  • Refresh queue prevents parallel refresh storms.
  • Session restore clears local state when refresh fails.

Risks:

ID Risk Impact Required follow-up
MOB-SEC-01 Access token is held in memory and refreshed by native client Expected native behavior, but requires backend refresh hardening Keep refresh token rotation and revoke behavior tested
MOB-SEC-02 Push token registration swallows failures Push delivery issues may be silent Add observability or user-visible diagnostics if push becomes critical
MOB-SEC-03 Mobile release secrets live under mobile/secrets convention Risk if secrets are committed accidentally Ensure secrets remain gitignored and rotate exposed keys
MOB-SEC-04 AI support screen exists but production AI backend is not implemented User expectations may exceed actual backend Keep AI feature status aligned with PRD/SRS

18. Architecture Risks And Action Items

ID Risk Impact Required follow-up
MOB-ARCH-01 Older docs referenced VIEWER; current code uses OWNER Role docs can drift from app behavior Keep permission matrix and mobile docs on OWNER
MOB-ARCH-02 Mobile CI/CD is not configured in GitHub Actions Release quality depends on manual checks Add lint/typecheck/build workflow
MOB-ARCH-03 iOS release process is TBD App Store release cannot be repeated reliably Document TestFlight/App Store runbook
MOB-ARCH-04 Theme tokens are not fully aligned with production teal UI UI inconsistency and harder maintenance Align core/theme with AquaX design tokens
MOB-ARCH-05 Some API services normalize inconsistent backend response shapes Contract drift can leak into screens Align backend API responses and update 08_API Specification.md
MOB-ARCH-06 Role navigator defaults unknown role to OWNER Misconfigured user role could show owner UI Consider explicit unsupported-role screen
MOB-ARCH-07 No crash/error monitoring provider confirmed Production issues may be hard to diagnose Add crash reporting and API error monitoring

19. Change Rules

When changing mobile architecture:

  1. Add route types to core/types/navigation.types.ts.
  2. Register screens in the correct role navigator.
  3. Add endpoint constants in core/constants/apiURL.constants.ts.
  4. Add or update API service wrapper in core/services/api.
  5. Add or update domain hook in core/hooks.
  6. Keep refresh token handling inside SecureStore-backed auth store.
  7. Keep server-state cache/invalidation in hooks.
  8. Update docs/08_API Specification.md for contract changes.
  9. Update this file when navigation, auth, storage, notification or release architecture changes.
  10. Run npm run lint and npm run typecheck for mobile code changes.

20. Traceability

Source Architecture evidence
mobile/package.json Stack, dependencies and scripts
mobile/app.json Expo app identity, plugins and release metadata
mobile/babel.config.js Alias and Reanimated plugin
mobile/tsconfig.json Strict TypeScript and path alias
mobile/src/main.tsx Expo root registration
mobile/src/App.tsx Provider and root navigator composition
mobile/src/core/components/AppProviders.tsx Provider tree and launch loading
mobile/src/core/navigation/** Auth, root, role and tab navigation
mobile/src/core/config/api-client.ts Axios client and refresh queue
mobile/src/core/config/env.ts API URL and app env behavior
mobile/src/core/config/query-client.ts TanStack Query defaults
mobile/src/core/store/auth.store.ts Zustand auth state and SecureStore refresh token flow
mobile/src/core/services/api/** API service wrappers
mobile/src/core/hooks/** Domain hooks and cache invalidation
mobile/src/core/theme/** Theme provider and tokens
mobile/src/core/types/** Auth, navigation, API and domain types
mobile/src/features/** Role/feature screens and components
mobile/scripts/deploy_android_playstore.sh Android Play Store release flow