This is a repository for an e-commerce Flutter app template. Its current behavior can be seen in the following demonstration:
- This project uses a mock GraphQL API for fetching data. Mock server can be run locally as described in documentation: https://github.com/Mindera/Alfie-Mocks
- This project uses two .env files:
.env.devand.env.prod. Both need a variableGRAPHQL_SERVERwith a URL to the mock server.
- Install Flutter and Dart on your machine. This repo uses the stable Flutter channel.
- Create the environment files in
alfie_flutter/:.env.dev.env.prod
- Add the required GraphQL endpoint variable to both files:
GRAPHQL_SERVER=<your-mock-server-url>
- From the repo root, install dependencies:
cd alfie_flutter && flutter pub get
- Run the app locally with:
cd alfie_flutter && flutter run
- Use descriptive commit messages that explain the change clearly.
- Follow a simple structure:
ALFMOB-[Ticket ID]: short summary. - Examples:
ALFMOB-111: Added Unit Tests for New AdaptersALFMOB-413: Added Dynamic Payment Card List
- See the repository commit message template commit message template.
- Keep pull requests small and focused.
- Describe what changed, why it changed, and how to test it.
- Link the relevant ticket.
- Ensure all tests pass (locally or through the CI runs) before creating a PR.
- One obligatory revision is required before merging.
- Use the PR template when opening a PR, filling only the relevant sections.
- Use branch names that describe the work and allways reference the ticket.
- Recommended prefixes:
task/for new ticketschore/for CI/CD related branchesbug/for bug fixeshotfix/for urgent production fixesrelease/for release preparation
- Example:
task/ALFMOB-[Ticket ID]-Checkout-Scree
This project uses the MVVM architecture model as reccommended by the Flutter Documentation.
- Can be composed by multiple widgets.
- Shouldn't have bussiness logic.
- Can have animation logic, simple routing logic, and if-else statements to choose wich widget to render.
- Should serve the View with presentation ready domain data.
- Should expose methods for use of the view.
Important Note: Views and View Models must have a one-to-one relationship.
- Repositories are the middleground between view models and services.
- Should transform raw data into domain objects.
- Should expose methods that ease the access of data.
- Services are the entry point of the application.
- Should abstract external factors like APIs and Local files
Note: For more detail go see the flutter documentation.
This project uses Riverpod for global state and Flutter Hooks for local widget state. We keep UI declarative, with no mutable global variables or StatefulWidgets.
- Providers own state. Views consume providers and dispatch notifier actions.
- UI is declarative. Widgets reflect state instead of mutating it directly.
- Separation of concerns: ViewModels handle presentation logic, Repositories handle data, Services handle external APIs.
- Immutable flow prevents hidden state and keeps behavior predictable.
Used for shared application state and domain logic:
- auth, bag contents, product listings
- GraphQL queries and async operations
- ViewModels exposing presentation state
Do / Don't
- Do: use
ref.watch(provider)to subscribe and rebuild. - Do: prefer
ref.watch(provider.select(...))for fine-grained updates. - Do: use
ref.listen(provider, callback)for side effects. - Don't: use
ref.read(provider)inbuild(); reserve it for callbacks and effects.
Example:
final authRepositoryProvider = NotifierProvider<AuthRepository, User?>(
AuthRepository.new,
);Used for ephemeral (local) widget state without StatefulWidget:
- controllers like
TextEditingControllerorScrollController - transient UI state and validation
- lifecycle-bound effects
Custom hook example:
ScrollController useScrollToTop(WidgetRef ref, String routeName) {
final controller = useScrollController();
ref.listen(scrollProvider(routeName), (prev, next) {
if (controller.hasClients && controller.offset > 0) {
controller.animateTo(0, duration: const Duration(milliseconds: 300));
}
});
return controller;
}This project relies on a mock GraphQL API for product and checkout data. You must run the mock server separately, as described in the Alfie-Mocks documentation.
The app reads the GraphQL endpoint from the .env.dev or .env.prod files via the GRAPHQL_SERVER variable.
GraphQL requests and responses are generated with GraphQL code generation. The generated models are not used directly across the app; instead, manual mappers convert those generated GraphQL DTOs into the apps domain models.
The mapper implementations live in alfie_flutter/lib/graphql/extensions, where generated GraphQL output is translated into the apps domain objects.
The repository includes GitHub Actions workflows to validate code, run tests, and build release artifacts:
.github/workflows/ci.yaml- Runs on push to non-main branches and on pull requests.
- Calls the shared
test-and-lintworkflow.
.github/workflows/cd.yaml- Runs on push to
mainandrelease/**branches. - Executes the same
test-and-lintworkflow first. - Runs integration tests for Android and iOS on supported runners.
- Builds Android APK and iOS IPA/archive artifacts.
- Runs on push to
Shared workflow details:
.github/workflows/test-and-lint.yaml- Checks out code and sets up Flutter.
- Runs
flutter analyzefor static analysis. - Executes
alfie_flutter/test_coverage.shto run tests and generate coverage. - Optionally runs smoke integration tests on Android when enabled.
- Uploads LCOV coverage reports as a PR message.
Helper action:
.github/actions/setup-env- Sets up Flutter using the internal setup action.
- Creates empty
.env.devand.env.prodfiles if required. - Runs
flutter pub getinalfie_flutter/.
Release builds are handled through the CD workflow. Note that these artifacts represent "raw" builds; they are neither code-signed nor ready for production. The repository can produce:
- Android APK artifact:
alfie_flutter/build/app/outputs/flutter-apk/app-release.apk - iOS archive artifact:
alfie_flutter/build/ios/archive/Runner.xcarchive
For local release builds, run:
cd alfie_flutter && flutter build apk --releasecd alfie_flutter && flutter build ipa --release --no-codesign
