.agents/skills/configure-di/SKILL.md
Configures dependency injection (GetIt) for Flutter following the project architecture. Use whenever adding or modifying registrations in lib/config/inject/**. Covers registerFactory vs registerLazySingleton, registration order, multi-flavor setup, and common mistakes. Activate even when the user says 'register this class in the injector', 'how do I inject this dependency', 'GetIt is throwing an error', 'add this to AppInjector', 'should this be a singleton or factory?', 'I created a new service, where do I register it?', or 'dependency not found' without explicitly mentioning GetIt or registerLazySingleton.
npx skillsauth add andrelucassvt/CleanMacForDevsWeb configure-diInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
AppInjector.inject.registerFactory — nunca singleton.registerLazySingleton.AppInjector.inject.get<XCubit>() e feche no dispose().lib/config/
├── app_initializer.dart # Inicialização central
└── inject/
└── app_injector.dart # Configuração de DI
import 'package:base_app/common/services/shared_preferences_service.dart';
import 'package:base_app/common/services/storage_service.dart';
import 'package:base_app/config/network/dio_client.dart';
import 'package:base_app/data/datasources/home_remote_datasource.dart';
import 'package:base_app/data/repositories/home_repository_impl.dart';
import 'package:base_app/domain/interfaces/home_repository.dart';
import 'package:base_app/presentation/home/view_model/home_cubit.dart';
import 'package:base_app/presentation/splash/view_model/splash_cubit.dart';
import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
enum AppFlavor { development, staging, production }
class AppInjector {
static GetIt inject = GetIt.instance;
static Future<void> setupDependencies({required AppFlavor flavor}) async {
// 1. Flavor
inject.registerLazySingleton<AppFlavor>(() => flavor);
final baseUrl = _getBaseUrlForFlavor(flavor);
final enableLogs = flavor != AppFlavor.production;
// 2. Services
inject.registerLazySingleton<StorageService>(
() => SharedPreferencesService(),
);
// 3. Network
inject.registerLazySingleton<Dio>(
() => makeDio(baseUrl: baseUrl, enableLogs: enableLogs),
);
// 4. DataSources
inject.registerLazySingleton<HomeRemoteDataSource>(
() => HomeRemoteDataSource(inject()),
);
// 5. Repositories
inject.registerLazySingleton<HomeRepository>(
() => HomeRepositoryImpl(inject()),
);
// 6. Cubits (SEMPRE Factory)
inject.registerFactory<HomeCubit>(() => HomeCubit(inject()));
inject.registerFactory<SplashCubit>(() => SplashCubit());
}
static String _getBaseUrlForFlavor(AppFlavor flavor) {
return switch (flavor) {
AppFlavor.development => 'https://dev-api.example.com',
AppFlavor.staging => 'https://staging-api.example.com',
AppFlavor.production => 'https://api.example.com',
};
}
}
// ✅ USE PARA:
inject.registerLazySingleton<StorageService>(() => SharedPreferencesService());
inject.registerLazySingleton<Dio>(() => makeDio(baseUrl: 'https://api.com'));
inject.registerLazySingleton<UserRepository>(() => UserRepositoryImpl(inject()));
inject.registerLazySingleton<UserRemoteDataSource>(() => UserRemoteDataSource(inject()));
// ✅ USE PARA CUBITS:
inject.registerFactory<HomeCubit>(() => HomeCubit(inject()));
inject.registerFactory<ProfileCubit>(() => ProfileCubit(inject(), inject()));
inject.registerLazySingleton<ProductRemoteDataSource>(
() => ProductRemoteDataSource(inject()),
);
// 1. Interface em lib/domain/interfaces/
// 2. Implementação em lib/data/repositories/
inject.registerLazySingleton<ProductRepository>(
() => ProductRepositoryImpl(inject()),
);
inject.registerFactory<ProductsCubit>(
() => ProductsCubit(inject()),
);
class _HomeViewState extends State<HomeView> {
final _cubit = AppInjector.inject.get<HomeCubit>();
@override
void dispose() {
_cubit.close(); // ✅ Sempre feche
super.dispose();
}
}
// No DI
inject.registerFactory<ProfileCubit>(
() => ProfileCubit(
inject<UserRepository>(), // ✅ Especifica tipo
inject<StorageService>(),
),
);
// Registro
inject.registerLazySingleton<AppFlavor>(() => flavor);
// Acesso em qualquer lugar
final flavor = AppInjector.inject<AppFlavor>();
if (flavor == AppFlavor.development) {
log('Debug mode');
}
void main() {
setUp(() {
AppInjector.inject.reset();
});
test('should load home data', () async {
final mockRepository = MockHomeRepository();
AppInjector.inject.registerLazySingleton<HomeRepository>(() => mockRepository);
final cubit = HomeCubit(AppInjector.inject<HomeRepository>());
// ... teste
});
}
registerFactory, resto com registerLazySingletoninject<UserRepository>()dispose() da View| Erro | Correto |
|---|---|
| registerLazySingleton<HomeCubit>(...) | registerFactory<HomeCubit>(...) |
| inject.get() sem tipo | inject.get<HomeCubit>() |
| Cubit registrado antes do Repository | Registre dependências ANTES de quem as usa |
| Não chamar _cubit.close() no dispose | Sempre feche o Cubit no dispose() |
Resumo das regras de ouro:
dispose()Última atualização: 28 de março de 2026
testing
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy. Activate even when the user says 'create a skill for X', 'the skill is not triggering', 'improve this skill description', 'the agent is not using the skill', 'add a skill to teach the agent how to do X', 'this skill is wrong', or 'update the skill' without explicitly mentioning evals or benchmark.
development
Implements Flutter reusable widgets following the project architecture. Use whenever creating or modifying widgets in presentation/<feature>/widgets/, presentation/<feature>/content/, or common/widgets/. Covers StatelessWidget vs StatefulWidget decision, Entity as parameter, i18n, dispose, componentization rules, and when to access the Cubit via context.read. Activate even when the user says 'extract this to a widget', 'create a list item widget', 'build a reusable card', 'factor out this UI block', 'create a component for this', or 'this View is getting too big' without explicitly mentioning StatelessWidget or reusable components.
tools
Implements Flutter View screens following the project architecture. Use whenever creating or modifying a View (StatefulWidget + Cubit + BlocBuilder), adding a new screen, wiring up BlocBuilder/BlocConsumer/BlocListener, setting up SafeArea, or navigating from the View. Covers State, Cubit, View file, route, DI registration, and common mistakes. Activate even when the user just says "create a screen" or "add a new page", without explicitly mentioning Cubit or BLoC.
testing
Implements Flutter Cubit and State (View Model layer) following the project architecture. Use whenever creating or modifying a Cubit or State class, adding an async method to a Cubit, handling form submission or validation, implementing debounce search, managing loading/error/navigation states, or wiring a Cubit to a Repository or StorageService. Covers sealed States, async patterns with Result<T>, CRUD Cubits, local persistence via StorageService, navigation states, debounce, and common mistakes. Activate even when the user says "add a method", "handle the loading state", or "save locally" without explicitly mentioning Cubit or BLoC.