# Modules

These are the modules that `smf create` offers. Each one is a Dart package on pub.dev, but you never add them to an app yourself: `smf create` puts what they generate into the app.

| Module (`-m`) | Package | Kind | Role it provides | Adds to the app |
| --- | --- | --- | --- | --- |
| [`flutter_core`](https://doc.saymyframe.com/modules/flutter-core.md) | `smf_flutter_core` | scaffold | App entry | The Flutter project, `main()`, start-up and root widget, in every app, and the screen that an app starts on when no route starts it |
| [`go_router`](https://doc.saymyframe.com/modules/go-router.md) | `smf_go_router` | infrastructure | Router | The router of the features' routes, with go_router |
| [`bottom_tabs`](https://doc.saymyframe.com/modules/bottom-tabs.md) | `smf_bottom_tabs` | layout | Layout | Tabs at the bottom for the destinations of the features, in a bar that it draws in the colors of the theme |
| [`home`](https://doc.saymyframe.com/modules/home.md) | `smf_home_flutter` | feature | none | A start screen at `/home`, which welcomes the developer of the app and lists the next steps |
| [`onboarding`](https://doc.saymyframe.com/modules/onboarding.md) | `smf_onboarding` | feature | Onboarding screen | The onboarding at `/onboarding`, which the app shows on its first launch until the user finishes it, with the steps that other modules add |
| [`settings`](https://doc.saymyframe.com/modules/settings.md) | `smf_settings` | feature | Settings screen | A settings screen at `/settings`, with the settings of the modules in one group, a row for each |
| [`sign_in`](https://doc.saymyframe.com/modules/sign-in.md) | `smf_sign_in` | feature | none | The screens of sign-in, sign-up and password reset for an email address and a password, with a button for each other way to sign in of the app, and the screen of the account with its row on the settings screen, with BLoC or with Riverpod |
| [`paywall`](https://doc.saymyframe.com/modules/paywall.md) | `smf_paywall` | feature | none | The paywall at `/paywall`, which sells premium access with the plans of the current offer, the screen of the subscription at `/paywall/subscription`, its row on the settings screen and its step in the onboarding, with BLoC or with Riverpod |
| [`bloc`](https://doc.saymyframe.com/modules/bloc.md) | `smf_bloc` | infrastructure | State management | `flutter_bloc` |
| [`riverpod`](https://doc.saymyframe.com/modules/riverpod.md) | `smf_riverpod` | infrastructure | State management | `flutter_riverpod` and its `ProviderScope` |
| [`material_theme`](https://doc.saymyframe.com/modules/material-theme.md) | `smf_material_theme` | infrastructure | Theme | A light and a dark Material 3 theme with a palette, text styles and a bundled font, in `lib/core/theme/app_theme.dart` |
| [`launcher_icons`](https://doc.saymyframe.com/modules/launcher-icons.md) | `smf_launcher_icons` | infrastructure | App icon | An opaque icon on iOS and an adaptive icon with a themed variant on Android, made with flutter_launcher_icons from two images in `assets/branding/` |
| [`native_splash`](https://doc.saymyframe.com/modules/native-splash.md) | `smf_native_splash` | infrastructure | Splash screen | The screen that the system shows while the app starts, for the light and the dark mode, made with flutter_native_splash from two images in `assets/branding/` |
| [`gen_l10n`](https://doc.saymyframe.com/modules/gen-l10n.md) | `smf_gen_l10n` | infrastructure | Localization | The texts of the app in ARB files, one for each language, with gen-l10n of Flutter |
| [`get_it`](https://doc.saymyframe.com/modules/get-it.md) | `smf_get_it` | infrastructure | Dependency injection | Registration of the app's services in get_it |
| [`event_bus`](https://doc.saymyframe.com/modules/event-bus.md) | `smf_event_bus` | infrastructure | Events | A `CommunicationService` on the event_bus package |
| [`shared_preferences`](https://doc.saymyframe.com/modules/shared-preferences.md) | `smf_shared_preferences` | infrastructure | Preferences | `AppPreferences` on the shared_preferences package, for the settings that the app remembers |
| [`dart_define`](https://doc.saymyframe.com/modules/dart-define.md) | `smf_dart_define` | infrastructure | Values in .env | `AppEnv`, which gives the app the values of `.env` with `--dart-define-from-file` |
| [`local_notifications`](https://doc.saymyframe.com/modules/local-notifications.md) | `smf_local_notifications` | infrastructure | Notifications | Notifications now and at about a time to come, the permission to show them and the taps on them, with flutter_local_notifications |
| [`firebase_core`](https://doc.saymyframe.com/modules/firebase-core.md) | `smf_firebase_core` | infrastructure | none | Firebase for each flavor: options, initialization, the script `tool/configure_firebase.dart`, setup of the machine |
| [`firebase_crashlytics`](https://doc.saymyframe.com/modules/firebase-crashlytics.md) | `smf_firebase_crashlytics` | infrastructure | Crash reporting | A `CrashReporter` on Firebase Crashlytics |
| [`firebase_analytics`](https://doc.saymyframe.com/modules/firebase-analytics.md) | `smf_firebase_analytics` | infrastructure | Analytics | An `AnalyticsService` on Firebase Analytics, and screen views |
| [`firebase_messaging`](https://doc.saymyframe.com/modules/firebase-messaging.md) | `smf_firebase_messaging` | infrastructure | Push messages | Push messages with Firebase Cloud Messaging: the address of the device for the backend, the messages and the taps on them |
| [`firebase_auth`](https://doc.saymyframe.com/modules/firebase-auth.md) | `smf_firebase_auth` | infrastructure | Authentication | Sign-in with Firebase Authentication: an email address and a password, an anonymous user, or a way to sign in of Google or Apple, and a script that enables the sign-in methods in the Firebase project |
| [`google_sign_in`](https://doc.saymyframe.com/modules/google-sign-in.md) | `smf_google_sign_in` | infrastructure | none | Google sign-in on Android and iOS: `googleCredential()`, the icon of its button with the "G" of Google, and a way to sign in for the auth role |
| [`apple_sign_in`](https://doc.saymyframe.com/modules/apple-sign-in.md) | `smf_apple_sign_in` | infrastructure | none | Sign in with Apple on iOS: `appleCredential()`, the icon of its button, a way to sign in for the auth role, and the entitlement of the capability in `ios/Runner/Runner.entitlements` |
| [`dio`](https://doc.saymyframe.com/modules/dio.md) | `smf_dio` | infrastructure | REST API | The requests of `appRest` over a `Dio` |
| [`revenuecat`](https://doc.saymyframe.com/modules/revenuecat.md) | `smf_revenuecat` | infrastructure | Purchases | Premium access with RevenueCat: the plans of the default offering, a purchase, a restore, and the access of the user before the first frame |
| [`github_actions`](https://doc.saymyframe.com/modules/github-actions.md) | `smf_github_actions` | infrastructure | CI | `.github/workflows/ci.yml`: the checks on each push, and a release APK for an environment on request |

The kind of a module decides the rules it follows. A feature keeps its files in `lib/features/<id>/` and declares routes, a layout provides the main navigation, and infrastructure sets up a service or a library without screens of its own. A feature can provide a role too, as `settings` does, and it can keep its state with the state manager of the app, as `sign_in` and `paywall` do in a variant for each. See [the module model](https://doc.saymyframe.com/concepts/module-model.md).

## Roles and their files

A role generates the part of the app that other code counts on, whichever module provides it. These files belong to the roles rather than to a module:

| Role | Files | What they declare |
| --- | --- | --- |
| App entry | `AGENTS.md`, `CLAUDE.md`, `lib/core/app/status_bar_icons.dart`, `test/core/app/status_bar_icons_test.dart`, and the sections of the flavors and the steps by hand in `README.md` | The guide for coding agents that work on the app; `StatusBarIcons`, which asks for the icons of the status bar that suit the theme, and its widget test |
| Onboarding screen | `lib/core/onboarding/onboarding_steps.dart` | `OnboardingStep` and `appOnboardingSteps`, the steps that the modules add to the onboarding |
| Router | `lib/core/router/app_router.dart`, `lib/core/router/navigation.dart` | `AppRouter`, `appRouter`, the location classes and `context.nav`. In an app with guards, also `routeGuards`, `redirectOf()`, `flowIsOver()`, `guardChanges` and `GuardedNavigation` |
| Layout | `lib/core/layout/destination.dart` | `Destination`, the label and icon of an item of the main navigation, and `appDestinations`, the destinations of the app |
| Theme | `lib/core/theme/theme_mode.dart`, and `lib/core/theme/theme_mode_setting.dart` in an app with a settings screen | `appThemeMode`, the theme mode that the user selected, `AppThemeModeScope` and `restoreAppThemeMode`; `ThemeModeSetting`, the entry of the settings screen |
| Localization | `lib/core/l10n/app_locale.dart`, and `lib/core/l10n/language_setting.dart` in an app with a settings screen | `appLocales`, the languages of the app, `appLocale`, the language that the user chose, `AppLocaleScope` and `restoreAppLocale`; `LanguageSetting`, the entry of the settings screen |
| Dependency injection | `lib/core/di/service_locator.dart` | `ServiceLocator`, `resolve<T>()` |
| Events | `lib/core/events/communication_service.dart` | `AppEvent`, `CommunicationService`, `createCommunicationService()` |
| Preferences | `lib/core/preferences/app_preferences.dart` | `AppPreferences`, `initPreferences()`, `createAppPreferences()` |
| Analytics | `lib/core/analytics/analytics_service.dart` | `AnalyticsService`, `createAnalyticsService()` |
| Crash reporting | `lib/core/crash_reporting/crash_reporter.dart` | `CrashReporter`, `createCrashReporter()`, `installCrashReporting()` |
| Authentication | `lib/core/auth/app_session.dart`, `lib/core/auth/auth_service.dart`, `lib/core/auth/guest_data.dart`, `lib/core/auth/sign_in_methods.dart` | `appSession`, the session of the app, `authMode` and `initAuth()`; `AuthService`, the interface of a provider, `AuthFailure` and `SignInCredential`; `takeGuestData()`, which the developer of the app edits; `SignInMethod` and `appSignInMethods`, the ways to sign in of the app |
| Notifications | `lib/core/notifications/app_notifications.dart`, `lib/core/notifications/notifications_service.dart`, `android/app/src/main/res/drawable/ic_notification.xml`, `android/app/src/main/res/raw/notifications_keep.xml`, `lib/core/notifications/notifications_setting.dart` in an app with a settings screen, and `lib/core/notifications/notifications_step.dart` in an app with an onboarding | `appNotifications`, `NotificationPermission` and `initNotifications()`; `NotificationsService`, `AppNotification` and `NotificationTap`; the small icon of Android and the file that keeps it in a release build; `NotificationsSetting`, the entry of the settings screen; `notificationsStepShows()` and `allowNotifications()`, the functions of the step of the onboarding |
| Push messages | `lib/core/push/app_push.dart`, `lib/core/push/push_service.dart` | `appPush` and `initPush()`; `PushService`, the interface of a provider, and `PushMessage` |
| Purchases | `lib/core/purchases/app_purchases.dart`, `lib/core/purchases/purchases_service.dart`, and `lib/core/purchases/restore_purchases_setting.dart` in an app with a settings screen | `appPurchases`, the premium access of the user, and `initPurchases()`; `PurchasesService`, the interface of a provider, `AppAccess`, `Plan` and `PurchasesFailure`; `RestorePurchasesSetting`, the entry of the settings screen |
| Values in .env | `.env`, `.env.example`, a line of `.gitignore`, `.vscode/launch.json` and `.run/<flavor>.run.xml` | The values that you fill in, the same keys without values, the line that keeps `.env` out of git, and a run configuration for each flavor. Every provider generates `AppEnv` in `lib/core/env/app_env.dart`, with a getter for each key |
| REST API | `lib/core/rest/app_rest.dart`, `lib/core/rest/rest_transport.dart`, `lib/core/rest/session_tokens.dart` in an app with sign-in, `test/core/rest/rest_test_server.dart`, `test/core/rest/app_rest_test.dart`, and the permission `android.permission.INTERNET` | `appRest`, the REST client of the app, `RestFailure`, `RestResponse` and `RestCancel`; `RestTransport`, the interface of a provider; what gives the client the token of `appSession`; `RestTestServer`, a local server for the tests of the app; a real request through the provider |
| CI | `tool/write_env.dart` in an app with values in `.env` | The script that writes `.env` for a job. The commands of CI are in the README, and a provider writes them in the format of its host |

The state management role, the settings screen role, the app icon role and the splash role have no files of their own that code reads: screens use the state management libraries directly, the module that provides the settings screen generates the screen, and each module of the icon and the screen generates its two images in `assets/branding/`. Besides the files above, the files of the app entry come from `flutter_core`.

## Routes, settings and texts of the modules

A module does not reach into another module. It gives a role what the role collects from every module: a route, a guard, a restorer of a setting, a row of the settings screen, a step of the onboarding, a text, a key of `.env`. In an app with every module above, the router, the preferences, the settings screen, the onboarding and the localization get these from the modules, and from four roles. The services of the modules and what follows the screens are on the pages of the modules.

| From | Routes and guards | Restorer of the preferences | Row of the settings screen | Texts, in English and in Ukrainian |
| --- | --- | --- | --- | --- |
| `home` | `/home`, a destination | | | The label of its tab, and the 14 texts of its screen |
| `onboarding` | `/onboarding`, and the guard `onboarding.firstRun` | `restoreOnboarding` | | The six texts of its screen |
| `settings` | `/settings`, a destination | | | The title of its screen, which is the label of its tab too |
| `sign_in` | `/sign_in` with `/sign_in/sign_up` and `/sign_in/reset_password` below it, `/sign_in/account`, which asks for an account, and the guards `sign_in.gate` and `sign_in.hasAccount` | | Account | The 49 texts of its screens |
| `google_sign_in`, `apple_sign_in` | | | | The label of the button of each, Continue with Google and Continue with Apple |
| `paywall` | `/paywall`, and `/paywall/subscription`, which asks for premium access, and the guard `paywall.hasPremium` | | Subscription | The 65 texts of its screens, the three texts of its row, and the four texts of its step of the onboarding, Unlock premium |
| The theme role, with `material_theme` | | `restoreAppThemeMode` | Theme | The four texts of its row |
| The localization role, with `gen_l10n` | | `restoreAppLocale` | Language | The two texts of its row |
| The notifications role, with `local_notifications` | | `restoreNotifications` | Notifications | The three texts of its row, and the four texts of its step of the onboarding, Turn on notifications |
| The purchases role, with `revenuecat` | | | Restore purchases | The four texts of its row |

So the settings screen of such an app has the rows Account and Subscription, and after them the rows Theme, Language, Notifications and Restore purchases, in the order of the modules that provide the four roles. The onboarding shows the step of the notifications and then the step of the paywall before its last page. The preferences restore four settings before the first frame, and the router asks four guards: the gate of the onboarding, then the gate of the sign-in, then the guard of the routes that need an account, and last the guard of the routes that need premium access. Such an app starts on `/home`, so `flutter_core` gives it no texts: only an app that no route starts has the two texts of its fallback start screen. `revenuecat` gives the role of the values in `.env` the three API keys of RevenueCat, `paywall` the addresses of its terms of use and its privacy policy, and the REST role the address of the API; see [Values in .env](https://doc.saymyframe.com/guides/env.md). A module of your own gives the roles the same things; see [Extending SMF](https://doc.saymyframe.com/extending.md).

Three modules also add files that are not code, and declare them in `pubspec.yaml`: `home` the image of its screen, in `lib/features/home/assets/`, `google_sign_in` the "G" of Google for its button, in `lib/core/google_sign_in/assets/`, and `material_theme` the font of its themes with its license, in `assets/fonts/geist/`.
