# Comwell App Monorepo
A Flutter monorepo containing:
- `comwell_key_app`: The customer-facing mobile app (Flutter).
- `mobilekeys_sdk_plugin`: A Flutter plugin (Assa Abloy Seos Mobile Keys SDK wrapper) used to open hotel doors.
## Repository structure
```
.
├─ comwell_key_app/ # Flutter app
├─ mobilekeys_sdk_plugin/ # Seos Mobile Keys Flutter plugin
├─ azure/ # CI pipelines (Azure DevOps)
└─ README.md # This file
```
## Tech stack
- Flutter (Dart >= 3.5)
- State & navigation: `bloc`, `flutter_bloc`, `go_router`
- Localization: `intl`
- Analytics: `firebase_core`, `firebase_analytics`
- Error monitoring: `sentry_flutter`
- Payments: `adyen_checkout`
- Secure storage & DB: `flutter_secure_storage`, `drift` + `sqlcipher_flutter_libs`
- Networking: `dio`
- Auth: Azure AD B2C via `aad_b2c_webview`
- Seos Mobile Keys via `mobilekeys_sdk_plugin` (Assa Abloy)
## Prerequisites
- Flutter SDK and platform tooling:
- macOS + Xcode for iOS
- Android Studio + Android SDK for Android
- Java 17
- CocoaPods for iOS
- Access to:
- Adyen test/prod credentials
- Azure AD B2C tenant credentials
- Firebase projects (Dev/Stage/Prod)
- Seos Mobile Keys SDK binaries (iOS `.xcframework`, Android `.aar`)
- Sentry DSN (per environment)
## Environments and flavors
The app uses three flavors:
- Android flavors: `Develop`, `Stage`, `Prod`
- iOS schemes: correspond to the above flavors (select the matching scheme in Xcode)
Firebase configs are generated per flavor; see `comwell_key_app/flutterfire-config.sh`.
The app also expects an `appFlavor` value at runtime to choose the correct Firebase options and `.env` file.
## Quick start
1) Clone and install dependencies
```bash
cd comwell_key_app
flutter pub get
```
2) Seos Mobile Keys SDK (required)
- iOS:
- Create `mobilekeys_sdk_plugin/XCFrameworks/` and place `SeosMobileKeysSDK.xcframework` inside.
- Open iOS workspace and ensure the XCFramework is added to:
- Runner target: Frameworks, Libraries, and Embedded Content → Embed & Sign
- seos_mobile_keys_plugin target: Do Not Embed
- Pods-Runner target: Do Not Embed
- Refer to `mobilekeys_sdk_plugin/README.md` for details.
- Android:
- Place `.aar` files under `mobilekeys_sdk_plugin/android/libs/`.
- App build references these via Gradle:
- `debugImplementation .../mobilekeys-android-sdk-debug-*.aar`
- `releaseImplementation .../mobilekeys-android-sdk-release-*.aar`
3) Firebase configuration
- Ensure you have appropriate `google-services.json` and `GoogleService-Info.plist` files for each flavor.
- If you need to regenerate, install FlutterFire CLI and run the helper script:
```bash
dart pub global activate flutterfire_cli
./flutterfire-config.sh # from comwell_key_app/
```
4) Environment files
Add the following files in `comwell_key_app` and include them in `pubspec.yaml` assets:
- `.env.dev`
- `.env.stage`
- `.env.prod`
- Optionally `.env` for shared/defaults
Example (`.env.dev`):
```
# Backend
SERVICE_URL=https://api.dev.example.com
OCP_APIM_SUBSCRIPTION_KEY=...
# Azure AD B2C
AAD_B2C_USER_AUTH_FLOW=https://<tenant>.b2clogin.com
AAD_B2C_USER_FLOW_NAME_LOGIN=B2C_1_signin
AAD_B2C_USER_FLOW_NAME_CREATE_USER=B2C_1_signup
AAD_B2C_USER_FLOW_NAME_CHANGE_PASSWORD=B2C_1_password
AAD_B2C_CLIENT_ID=...
AAD_B2C_REDIRECT_URL=com.comwell.phoenix://auth
AAD_B2C_SCOPES=openid,offline_access,https://<tenant>/<api>/read
# Payments
ADYEN_TEST_KEY=...
# Seos Mobile Keys
MOBILEKEYSOPTIONAPPLICATIONID=...
MOBILEKEYSOPTIONAPPDESCRIPTION=Comwell App
MOBILEKEYSOPTIONVERSION=1
MOBILEKEYSOPTIONLOGSMAIL=logs@example.com
# Monitoring
SENTRY_DSN=...
```
5) Run the app
Android
```bash
# Develop
flutter run -d android --flavor Develop --dart-define=appFlavor=Develop
# Stage
flutter run -d android --flavor Stage --dart-define=appFlavor=Stage
# Prod
flutter run -d android --flavor Prod --dart-define=appFlavor=Prod
```
iOS
```bash
# From comwell_key_app/
open ios/Runner.xcworkspace
# In Xcode: select scheme (Develop/Stage/Prod) and a device, then run.
# Or via CLI (requires a matching scheme)
flutter run -d ios --flavor Develop --dart-define=appFlavor=Develop
```
Note:
- Sentry DSN is required at startup (`SENTRY_DSN`), otherwise the app will crash on init.
- Ensure `.env.prod` is also added under `flutter.assets` in `pubspec.yaml` if you plan to run Prod.
## Building
Android
```bash
# APK
flutter build apk --flavor Develop --dart-define=appFlavor=Develop
# AppBundle
flutter build appbundle --flavor Prod --dart-define=appFlavor=Prod
```
iOS
```bash
# Debug build for specific flavor
flutter build ios --flavor Stage --dart-define=appFlavor=Stage
# Then archive and distribute via Xcode
```
## Development tasks
- Code generation (JSON serializable, Drift):
```bash
dart run build_runner build --delete-conflicting-outputs
```
- Lint and tests:
```bash
flutter analyze
flutter test
```
- Splash screen and app icons:
```bash
# Splash
dart run flutter_native_splash:create
# Icons
dart run flutter_launcher_icons
```
## Notable directories (app)
- `lib/main.dart`: flavor dispatching and app bootstrap (Firebase, Sentry, env)
- `lib/utils/firebase.dart`: Firebase init per flavor
- `lib/utils/locator.dart`: Dependency injection (GetIt)
- `lib/routing/app_router.dart`: Routes (go_router)
- `lib/services/`: Networking, interceptors, and Adyen integration
- `lib/check_out/`: Checkout flow and Adyen Drop-in integration
- `lib/tracking/`: Analytics events
## Troubleshooting
- App exits early with “Invalid appFlavor”:
- Ensure you pass `--dart-define=appFlavor=<Develop|Stage|Prod>` when running or building.
- Sentry initialization error:
- Provide a valid `SENTRY_DSN` in the corresponding `.env.*` file.
- Adyen/Payments errors:
- Verify `ADYEN_TEST_KEY` and backend `SERVICE_URL` are correct for the flavor.
- Mobile keys linking issues:
- Confirm XCFramework on iOS and AARs on Android are placed as described and visible to the targets.
- Firebase config mismatch:
- Re-run `./flutterfire-config.sh` and check the generated files under `android/app/src/<flavor>/` and `ios/flavors/<flavor>/`.
## License and attribution
- Comwell App © Comwell Hotels
- Seos Mobile Keys SDK by Assa Abloy; license and distribution per their terms.