OnTime is a Flutter app for schedule preparation, alarms, and arrival-time planning. The app is organized with clean architecture: presentation widgets and BLoCs depend on domain use cases, while data sources, Drift DAOs, and repository implementations live behind domain contracts.
Primary supported targets are web, Android, and iOS. Desktop platform folders are present in the Flutter project, but Firebase options are currently configured only for web, Android, and iOS.
- Requirements
- Project Structure
- First-Time Setup
- Runtime Configuration
- Firebase Configuration
- Development Commands
- Build and Release
- Widgetbook
- Troubleshooting
- Further Reading
- Flutter stable. CI uses Flutter
3.32.6; use that version for release parity when possible. - Dart SDK compatible with
pubspec.yaml(^3.5.4). - Java and Android SDK for Android builds.
- Xcode and CocoaPods for iOS builds.
- Firebase CLI and FlutterFire CLI when regenerating Firebase config.
- Access to the project secrets/configuration values listed below.
Check your local toolchain with:
flutter doctor
flutter --version
dart --versionlib/
core/ platform services, database, dependency injection, Dio, utilities
data/ data sources, DAOs, models, tables, repository implementations
domain/ entities, repository contracts, use cases
l10n/ localization files
presentation/ screens, blocs, cubits, shared widgets, routing, theme
test/ tests mirroring app paths
docs/ architecture and feature documentation
assets/ shared assets and fonts
widgetbook/ component catalog app
Generated Dart files such as *.g.dart, *.freezed.dart, *.config.dart, and *.mocks.dart are not committed. Regenerate them locally after dependency changes or code-generator changes.
-
Install dependencies:
flutter pub get
-
Generate code:
dart run build_runner build --delete-conflicting-outputs
-
Provide environment values and platform config. At minimum, local app runs need
REST_API_URL; some flows may also require Firebase and native sign-in config. See Runtime Configuration and Firebase Configuration. -
Run the app:
flutter run -d chrome --dart-define=REST_API_URL=<api-base-url>
For Android or iOS, replace chrome with the device id from flutter devices.
The app reads compile-time values from Dart defines in lib/core/constants/environment_variable.dart.
| Define | Required | Used for |
|---|---|---|
ENV |
Optional | App environment label. Use dev, staging, or prod; defaults to dev. |
REST_API_URL |
Yes | Base URL for Dio API calls. |
REST_AUTH_TOKEN |
Optional | Static auth token override for development/test scenarios. |
GOOGLE_RESERVED_CLIENT_ID_IOS |
iOS release/archive only | Reversed iOS Google client ID used as the iOS URL scheme for Google Sign-In. |
Pass defines directly on Flutter commands:
flutter run -d chrome \
--dart-define=ENV=dev \
--dart-define=REST_API_URL=<api-base-url>
flutter build web --release \
--dart-define=ENV=staging \
--dart-define=REST_API_URL=<api-base-url>For iOS release and archive builds, include the Google URL scheme define:
flutter build ios --release \
--dart-define=ENV=prod \
--dart-define=REST_API_URL=<api-base-url> \
--dart-define=GOOGLE_RESERVED_CLIENT_ID_IOS=<reversed-ios-client-id>The iOS Xcode scheme decodes DART_DEFINES into ios/Flutter/Dart-Defines.xcconfig. Release builds fail if GOOGLE_RESERVED_CLIENT_ID_IOS is missing or if the built Info.plist does not contain the Google Sign-In URL scheme.
lib/firebase_options.dart is generated by FlutterFire and currently supports web, Android, and iOS. macOS, Windows, and Linux throw UnsupportedError unless Firebase is reconfigured for those targets.
Tracked Firebase-related files:
lib/firebase_options.dartfirebase.jsonweb/firebase-messaging-sw.js
Native Firebase files are intentionally not committed and must come from project secret/config access:
- Android:
android/app/google-services.json, or a variant-specific file underandroid/app/src/debug/orandroid/app/src/release/. - iOS:
ios/Runner/GoogleService-Info.plist.
Android local builds skip the Google Services Gradle plugin when no google-services.json file is present, which is useful for non-Firebase development. Firebase-dependent features and production builds should use the correct native config files.
To regenerate Firebase configuration, use the FlutterFire CLI with the ontime-c63f1 Firebase project and keep the outputs aligned with firebase.json.
Install dependencies:
flutter pub getRegenerate Drift, JSON, Injectable, Freezed, Mockito, and Widgetbook code:
dart run build_runner build --delete-conflicting-outputsFormat Dart code:
dart format lib testRun analyzer:
flutter analyzeRun tests:
flutter testRun tests with coverage:
flutter test --coverageRun the web app locally:
flutter run -d chrome \
--dart-define=ENV=dev \
--dart-define=REST_API_URL=<api-base-url>Do not use npm test; the root package.json script is a placeholder that intentionally fails.
This repository uses trunk-based development with release branches:
main = always test-deployable
release/* = store candidate
v* tag = production release source of truth
hotfix/* = emergency production repair
Normal changes should land through short-lived feature/* or fix/* branches
into main. Create release/x.y.z from main for final store QA, cut
vX.Y.Z tags from approved release branches, then merge the release branch back
to main. See docs/Git.md for the full branch and deployment
flow.
Preview and staging web deployments are handled by GitHub Actions and Firebase
Hosting. Pull requests build with ENV=dev; merges to main build with
ENV=staging. CI uses the REST_API_URL GitHub environment variable and builds
with:
flutter build web --release \
--dart-define=ENV=staging \
--dart-define=REST_API_URL=<api-base-url>Firebase Hosting deploys build/web to project ontime-c63f1.
Build a release APK:
flutter build apk --release \
--dart-define=ENV=staging \
--dart-define=REST_API_URL=<api-base-url>Build an app bundle for Play Console upload:
flutter build appbundle --release \
--dart-define=ENV=prod \
--dart-define=REST_API_URL=<api-base-url>Before production upload, confirm the release google-services.json, signing configuration, version name, and version code. The current Gradle release block uses the debug signing config as a local-build fallback, so production signing must be configured before store release.
Build locally:
flutter build ios --release \
--dart-define=ENV=prod \
--dart-define=REST_API_URL=<api-base-url> \
--dart-define=GOOGLE_RESERVED_CLIENT_ID_IOS=<reversed-ios-client-id>Create an App Store archive from Xcode or CI with the same Dart defines. See docs/iOS-Release-Configuration.md for the release-only validation flow.
Before production upload, confirm ios/Runner/GoogleService-Info.plist, Apple signing, bundle id, app capabilities, push notification entitlement, build number, and App Store Connect metadata.
Widgetbook is a separate Flutter project under widgetbook/.
Run locally:
cd widgetbook
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter run -d chromeBuild for Firebase Hosting:
cd widgetbook
flutter build web --releasePublished Widgetbook:
https://on-time-front-widgetbook.web.app/
Run:
dart run build_runner build --delete-conflicting-outputsIf generation still fails, clean generated state and fetch dependencies again:
flutter clean
flutter pub get
dart run build_runner build --delete-conflicting-outputsConfirm REST_API_URL was passed to the flutter run or flutter build command. String.fromEnvironment values are compile-time constants, so changing a shell variable after launch does not update the app.
Firebase options are not configured for macOS, Windows, or Linux. Use web, Android, or iOS, or regenerate Firebase options for desktop platforms before enabling those targets.
Add the appropriate google-services.json file under android/app/ or a variant directory. Without that file, the Gradle build intentionally skips the Google Services plugin.
Pass the reversed iOS Google client ID with --dart-define=GOOGLE_RESERVED_CLIENT_ID_IOS=<value>. The release build validates both the Dart define extraction and the final Info.plist URL scheme.
Confirm the browser has notification permission, the Firebase web config in web/firebase-messaging-sw.js matches the active Firebase project, and the app is served over HTTPS or localhost.
Install SQLite system libraries before running tests. The GitHub Actions workflow installs sqlite3 and libsqlite3-dev before flutter test.