forge_mvvm 1.0.0 copy "forge_mvvm: ^1.0.0" to clipboard
forge_mvvm: ^1.0.0 copied to clipboard

Opinionated MVVM + Clean Architecture framework for Flutter with runtime guardrails, typed state primitives, DI modules, and production scaffolding.

forge_mvvm #

An opinionated Flutter MVVM + Clean Architecture framework with real runtime guardrails, typed async primitives, module-based DI bootstrap, and practical CLI scaffolding.

pub.dev License: MIT

What 1.0 solves #

forge_mvvm is designed for teams that want structure without ceremony.

  • Strong architectural defaults through ForgeModule + ForgeRegistrar
  • Runtime dependency-graph validation for layer direction
  • Typed operation outcomes (ForgeResult<T>) with stack traces
  • Typed command execution (ForgeCommand<P, R>) with concurrency policies
  • ViewModel busy/error lifecycle helpers (runGuarded, keyed busy state)
  • Navigation intents from ViewModels (no BuildContext leakage)
  • Form ViewModels with field registry, validators, dirty/touched state
  • Robust pagination state for initial/load-more/refresh/retry flows
  • CLI that scaffolds complete feature modules with tests and route/module stubs

Architecture model #

UI (ForgeView / ViewModel / Command / Form / Pagination / NavigationEmitter)
  -> Domain (UseCases + Repository contracts)
    -> Data (Repository implementations + Services)

forge_mvvm enforces this with:

  • compile-time contracts (abstract methods, typed APIs)
  • runtime registration metadata (layer, dependsOn)
  • bootstrap validation errors when dependency direction is invalid

Install #

dependencies:
  forge_mvvm: ^1.0.0
flutter pub get

Quick start #

1) Define a module #

class LoginModule extends ForgeModule {
  @override
  String get name => 'login';

  @override
  void register(ForgeRegistrar registrar) {
    registrar.lazySingleton<AuthServiceImpl>(
      AuthServiceImpl.new,
      layer: ForgeLayer.service,
    );

    registrar.alias<AuthService, AuthServiceImpl>(
      layer: ForgeLayer.service,
    );

    registrar.lazySingleton<AuthRepositoryImpl>(
      () => AuthRepositoryImpl(ForgeLocator.get<AuthService>()),
      layer: ForgeLayer.repository,
      dependsOn: <Type>[AuthService],
    );

    registrar.alias<AuthRepository, AuthRepositoryImpl>(
      layer: ForgeLayer.repository,
    );

    registrar.factory<LoginViewModel>(
      () => LoginViewModel(ForgeLocator.get<AuthRepository>()),
      layer: ForgeLayer.viewmodel,
      dependsOn: <Type>[AuthRepository],
    );
  }
}

2) Bootstrap app #

await ForgeApp.bootstrap(
  modules: <ForgeModule>[
    HomeModule(),
    LoginModule(),
    ArticlesModule(),
  ],
);

3) Build a ViewModel with guarded async work #

class LoginViewModel extends ForgeViewModel with ForgeNavigationEmitter {
  LoginViewModel(this._repository);

  final AuthRepository _repository;

  Future<void> login(String email, String password) async {
    final result = await runGuarded<ForgeResult<User>>(
      () => _repository.login(email, password),
      busyKey: 'login',
    );

    result.fold(
      onSuccess: (loginResult) {
        loginResult.fold(
          onSuccess: (_) => replace('/'),
          onFailure: (error, stackTrace) =>
              setError(error.toString(), error: error, stackTrace: stackTrace),
        );
      },
      onFailure: (_, __) {},
    );
  }
}

4) Handle navigation in View #

class LoginView extends ForgeView<LoginViewModel> {
  const LoginView({super.key});

  @override
  LoginViewModel createViewModel(BuildContext context) =>
      ForgeLocator.get<LoginViewModel>();

  @override
  Widget buildView(BuildContext context, LoginViewModel vm) {
    return ForgeNavigationListener(
      stream: vm.navigationIntents,
      navigator: ForgeLocator.get<ForgeNavigatorAdapter>(),
      child: const Scaffold(body: Placeholder()),
    );
  }
}

Public APIs #

Core #

  • ForgeApp.bootstrap(...)
  • ForgeModule, ForgeRegistrar
  • ForgeBootstrapConfig, ForgeBootstrapReport
  • ForgeLocator

Result and command #

  • ForgeResult<T> (fold, map, mapError, error + stackTrace)
  • ForgeCommand<P, R> (drop/queue concurrency)

UI/ViewModel #

  • ForgeView<T extends ForgeViewModel>
  • ForgeViewModel (runGuarded, isBusy, isBusyFor(key), structured errors)
  • ForgeStateWidget
  • ForgeNavigationIntent (ForgePushIntent, ForgeReplaceIntent, ForgePopIntent)
  • ForgeNavigationEmitter mixin
  • ForgeNavigationListener
  • ForgeNavigatorAdapter
  • ForgeGoRouterNavigator

Forms #

  • ForgeFormViewModel
  • registerField, setValue, validateField, validateAll
  • errorFor, isTouched, isDirty, clearErrors, resetForm

Pagination #

  • ForgePaginatedViewModel<T> (int-page)
  • ForgeKeyedPaginatedViewModel<T, K> (cursor/token-based)
  • ForgePaginationPhase
  • ForgePageChunk<T, K>

CLI #

Run from package root:

dart run bin/forge_cli.dart <command>

Commands:

  • create feature <name>
  • check
  • test

Feature flags:

  • --path (default: lib/features)
  • --with-form
  • --with-pagination
  • --with-navigation
  • --with-tests (default: true)
  • --overwrite

Example:

dart run bin/forge_cli.dart create feature profile \
  --with-form \
  --with-pagination \
  --with-navigation

Generated output includes:

  • domain: entity, repository contract, use case
  • data: dto, service contract + implementation, repository implementation
  • ui: viewmodel + view (+ optional form/pagination vm)
  • module + route stubs
  • feature README
  • test scaffold

Guardrails (what is and is not enforced) #

Enforced:

  • runtime dependency direction validation from declared metadata
  • missing DI registration errors with actionable messages
  • duplicate registration policy handling
  • no BuildContext in ViewModels for navigation

Not fully enforceable in Dart (documented honestly):

  • complete compile-time dependency direction across arbitrary user code

Use layer + dependsOn metadata consistently for strongest protection.

Testing #

flutter analyze
flutter test

or

dart run bin/forge_cli.dart check

The repository includes tests for:

  • bootstrap/DI guardrails
  • result/command/viewmodel behavior
  • forms and pagination
  • navigation emitter flow
  • CLI scaffolding
  • example smoke paths

Example app #

The example/ project demonstrates:

  • module-first bootstrap
  • home + login feature
  • form validation feature
  • paginated list feature
  • navigation intents + listener adapter
  • repository/service layering with DI metadata

Migration #

See MIGRATION.md for 0.2.x -> 1.0.0 upgrade guidance.

License #

MIT — see LICENSE

1
likes
150
points
117
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Opinionated MVVM + Clean Architecture framework for Flutter with runtime guardrails, typed state primitives, DI modules, and production scaffolding.

Repository (GitHub)
View/report issues
Contributing

Topics

#mvvm #architecture #clean-architecture #state-management

License

MIT (license)

Dependencies

args, equatable, flutter, get_it, go_router, meta, path, provider

More

Packages that depend on forge_mvvm