Mobile Delivery — The Super App
The mobile experience for tenant workers (managers, supervisors, and workers) is delivered through a single Flutter application called The Super App.
Why Flutter?
Section titled “Why Flutter?”Flutter lets you write one codebase that runs on both iOS and Android. More importantly for our architecture, Flutter provides a mechanism called federated plugins (and more broadly, a module system) that lets you split a single app into several independent feature modules. Each module has its own:
- Screens (pages)
- State management / controllers
- Dependencies and packages
- Business logic
These modules are combined into one deliverable app at build time, but their code stays isolated — a change in the Safety module cannot accidentally break the Productivity module.
Structure
Section titled “Structure”The Super App is composed of two layers: the Main Module and the Feature Modules.
graph TB subgraph SuperApp["The Super App (Flutter)"] direction TB
subgraph Main["Main Module — App Shell"] Auth["Authentication\n(login, token refresh, logout)"] Config["Remote Configuration\n(feature flags, environment)"] Prefs["User Preferences\n(language, theme, notifications)"] Company["Company Selection\n& License Validation"] end
subgraph Features["Feature Modules (one per domain)"] WF["Workforce\nModule"] Prod["Productivity\nModule"] Safety["Safety & Compliance\nModule"] Monitor["Worker Monitoring\nModule"] Asset["Asset Management\nModule"] end
Main -->|"provides auth context,\ncompany context, config"| Features end
User(["Worker / Supervisor / Manager"]) --> SuperAppMain Module
Section titled “Main Module”The Main Module is the entry point of the app. Think of it as the frame that holds everything together. It is responsible for:
- Authentication — handling login flows, token storage, automatic token refresh, and logout.
- Configuration — loading remote feature flags and environment settings at startup.
- Preferences — persisting user preferences like language and notification settings.
- Company selection & licensing — allowing a user who belongs to multiple companies to switch context, and enforcing which features are available based on the company’s active license.
Once the main module has resolved all of this, it makes the context available to all feature modules. Feature modules can read the current user, current company, and active license, but they do not manage these themselves.
Feature Modules
Section titled “Feature Modules”Each feature module owns the end-to-end flow for its domain. For example, the Safety & Compliance module handles everything from listing safety forms to submitting them and viewing results — it does not delegate to other modules.
Module Isolation in Practice
Section titled “Module Isolation in Practice”The key benefit of this structure is blast radius reduction: a bug introduced in one module, or a dependency upgrade inside one module, cannot crash or break another module. This means:
- Teams can work on different modules in parallel without merge conflicts.
- You can ship a fix to the Productivity module without touching the Safety module code.
- Each module can pin its own dependency versions independently.
Release Model
Section titled “Release Model”All modules are bundled together when the app is submitted to the App Store / Google Play. There is one app, one version number, one release. The module boundaries are a code organisation and team isolation concern — not a runtime isolation concern (unlike the web strategy).
sequenceDiagram participant Dev as Developer participant CI as CI/CD Pipeline participant Store as App Store / Google Play participant Device as Worker's Phone
Dev->>CI: Push changes to any module CI->>CI: Build all modules together CI->>Store: Submit single .ipa / .aab Store->>Store: Review (1–3 days) Store->>Device: App update available Device->>Device: User updates app