Tutorials
Connect a Repository to UseCase Forge
Translate committed Repository data into regular Commands without coupling either package.
Connect a Repository to UseCase Forge
This tutorial adds background application behavior without coupling either package. The Repository remains responsible for current domain data. The UseCase remains responsible for coordinated work. A small application-owned binding translates one meaningful data commit into one typed Command.
When to use a binding
Use this pattern when a committed data change must start independent application work: rebuild a search index, refresh derived recommendations, schedule synchronization, or invalidate a presentation cache. Do not add a binding merely to mirror Repository data into another state object.
1. Define the application Command
final class CatalogChanged extends UseCaseCommand {
const CatalogChanged(this.data);
final CatalogData data;
}
The Command contains the domain snapshot needed by the handler. It does not contain the Repository or a StreamSubscription.
2. Keep translation in the Application layer
The binding belongs to the Application layer because it decides which data change becomes which Command.
final class CatalogBinding {
CatalogBinding(CatalogRepository repository, CatalogUseCase useCase)
: _subscription = repository.stream.listen(
(data) => useCase.add(CatalogChanged(data)),
);
final StreamSubscription<CatalogData> _subscription;
Future<void> close() => _subscription.cancel();
}
Listening directly processes the replayed current value. Use stream.skip(1) when only future commits should submit commands.
Choose this deliberately:
| Requirement | Subscription |
|---|---|
| Process the current Repository value and all future commits | repository.stream |
| React only to commits after the binding is created | repository.stream.skip(1) |
3. Let UseCase Forge own execution policy
The listener performs no asynchronous business work. UseCase Forge remains responsible for admission, debounce or throttle, execution grouping, cancellation, errors, history, and diagnostics.
If a burst of Repository commits should collapse into one operation, configure the receiving UseCase. Do not add timers and cancellation flags to the stream listener.
4. Compose and close in dependency order
final binding = CatalogBinding(repository, catalogUseCase);
// Application runs.
await binding.close();
await catalogUseCase.close();
await repository.close();
await remoteSource.close();
The binding closes first because it can still submit Commands. The UseCase closes before the Repository because its handlers may read Repository data. Technical sources close last under their outer owner.
What this integration does not do
- Ark Data Layer does not import UseCase Forge.
- UseCase Forge does not import Ark Data Layer.
- Repository does not know which background operation observes it.
- UseCase does not become the owner of Repository data.
- The binding does not hide concurrency or shutdown policy.