Skip to content

Move the remaining feature bindings out of the app module - #89

Merged
AhmadKharfan merged 1 commit into
developfrom
refactor/complete-feature-encapsulation
Jul 30, 2026
Merged

Move the remaining feature bindings out of the app module#89
AhmadKharfan merged 1 commit into
developfrom
refactor/complete-feature-encapsulation

Conversation

@AhmadKharfan

Copy link
Copy Markdown
Owner

Why

After the api/presentation split, :app still registered ViewModels belonging to five features, and gitModule still bound GitPanelApiImpl. Leaving them there means the app module keeps naming feature internals — the same coupling the split was meant to remove.

Three of those bindings were also in the wrong feature's module entirely: CloneRepoViewModel (a projects screen), AssetsViewModel (an editor screen) and GitAuthSettingsViewModel (a settings screen) all sat in gitModule, presumably because they touch git repositories.

What changed

  • New gitPresentationModule in :feature:git:presentation, holding the six git ViewModels and the GitPanelApi binding.
  • CloneRepoViewModelprojectsModule, AssetsViewModeleditorModule, GitAuthSettingsViewModelsettingsModule.
  • :app's gitModule keeps only the bindings that wire :domain contracts to :data implementations.

Why some bindings stay in :app

GitRepository, GitCredentialStore, GitHubDeviceAuthenticator, GitAuthorStore and WorkspaceWriteGate bind :domain interfaces to :data:git classes. That is the composition root's job, and a feature module is not allowed to see :data:* at all — the boundary check would reject it. Pushing them into features would trade one coupling for a worse one.

So the rule is: a feature owns everything it implements; :app owns the domain-to-data wiring.

Behavior

No behavior change. The same definitions, declared by the module that owns the class.

Tests

  • 723 tests passing, 0 failures.
  • KoinModuleGraphTest verifies the whole graph still resolves after the moves — a binding dropped or landed in the wrong module fails there rather than at runtime.
  • verifyModuleBoundaries: 0 baseline entries, 0 violations.

Verification

./gradlew test detekt verifyModuleBoundaries :app:assembleDebug — BUILD SUCCESSFUL.

Verified on an emulator: project opens and the git panel renders through GitPanelApi, now bound by the git feature rather than by :app. No NoBeanDefFoundException, InstanceCreationException or crash in logcat.

Scope

:app still references a few feature types that are genuinely app-level integrations rather than DI leaks: the volume-key dispatchers (hardware key routing from the Activity), PendingInstallConfirmation (an install result arriving at the Activity), and the git destination routes it hosts in the single NavHost. Those are the composition root doing its job; moving them would need contracts that do not yet earn their keep.

@AhmadKharfan
AhmadKharfan merged commit 9c159d9 into develop Jul 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant