Install
$ agentstack add skill-aleksandr-chaika-flutter-clean-arch-skills-flutter-guide ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Flutter Guide — Clean Architecture + BLoC
Reference Guide
| Topic | Reference | Use When | |-------|-----------|----------| | Clean Architecture | references/clean-architecture.md | Layer rules, dependency direction | | BLoC Patterns | references/bloc-patterns.md | @freezed events/states, handlers, transformers | | UI Guidelines | references/ui-guidelines.md | AppColors, AppTextStyles, SVGImage | | Review Checklist | references/review-checklist.md | Code review, quality checks | | Mocking Guide | references/mocking-guide.md | Mocktail, MockBloc, ProviderContainer | | Test Patterns | references/test-patterns.md | UseCase tests, BLoC tests, widget tests |
Project Structure
lib/
├── core/ # AppError, extensions, DI (GetIt)
├── data/
│ ├── mapper/ # Entity Model mappers
│ ├── network/ # API client, models (@JsonSerializable), interceptors
│ ├── repository/ # Repository implementations
│ └── services/
├── domain/
│ ├── entity/ # Domain entities (@freezed)
│ ├── repository/ # Abstract interfaces
│ ├── services/
│ └── usecases/
├── presentation/
│ ├── {feature}/
│ │ ├── bloc.dart # FeatureBloc
│ │ ├── events.dart # @freezed events
│ │ ├── states.dart # @freezed states
│ │ └── view/ # Pages + widgets
│ └── common/
└── resources/ # Colors, text styles, localization
Dependency Rule
`Presentation -> Domain { FeatureBloc() : super(const FeatureState.initial()) { on(onStarted); on(onLoadData); }
Future onLoadData(LoadData event, Emitter emit) async { emit(const FeatureState.loading()); final result = await _repository.getData(event.id); result.fold( (error) => emit(FeatureState.error(error)), (data) => emit(FeatureState.loaded(data)), ); } }
NEVER use `event.when()` or `state.when()` in BLoC handlers.
NEVER use a single handler for all events.
### 3. Either for Error Handling
```dart
abstract class UserRepository {
Future> getUser(int id);
}
4. Type-Safe Models
// Domain Entity
@freezed
class UserEntity with _$UserEntity {
const factory UserEntity({
required String id,
required String name,
required UserRole role,
}) = _UserEntity;
}
// API Model
@freezed
@JsonSerializable()
class UserApiModel with _$UserApiModel {
const factory UserApiModel({...}) = _UserApiModel;
factory UserApiModel.fromJson(Map json) =>
_$UserApiModelFromJson(json);
}
// Mapper
extension UserApiMapper on UserApiModel {
UserEntity toDomain() => UserEntity(id: id, name: name, role: UserRole.fromString(role));
}
Dart 3.x: Use Modern Features
- Sealed classes for exhaustive state matching (alternative to @freezed unions)
- Pattern matching in switch expressions
- Records for lightweight multiple return values
- Null safety everywhere, no
!operator without justification
Performance Rules
- const constructors everywhere possible
- Keys on list items (
ValueKey(item.id)) - ListView.builder for large lists
- buildWhen in BlocBuilder for granular rebuilds
- CachedNetworkImage with
memCacheWidth/memCacheHeight - Extract expensive subtrees into separate const widgets
- No expensive operations in
build()methods
Anti-Patterns (FORBIDDEN)
| Pattern | Reason | |---------|--------| | Map for data | No type safety | | event.when() in BLoC handlers | Use individual handlers | | state.when() in BLoC handlers | Only for UI | | Single handler for all events | Hard to maintain | | Hardcoded strings in UI | Use AppLocalization | | SvgPicture.asset() | Use SVGImage() | | Redundant comments | Code must be self-documenting | | dynamic type | No type safety |
UI Patterns
// BlocBuilder with buildWhen
BlocBuilder(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
return state.when(
initial: () => const SizedBox.shrink(),
loading: () => const LoadingWidget(),
loaded: (data) => DataWidget(data: data),
error: (error) => ErrorWidget(error: error),
);
},
)
// BlocListener for side effects
BlocListener(
listenWhen: (previous, current) => current is _Error,
listener: (context, state) {
if (state is _Error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.error.message)),
);
}
},
)
Code Generation
flutter pub run build_runner build --delete-conflicting-outputs
Testing Summary
- BLoC tests (MANDATORY):
bloc_testwithblocTest<>(), seed, expect, verify - Flow tests (MANDATORY): after create -> list updated, after delete -> item removed
- Widget tests: BlocProvider + MockBloc
- Coverage: 80%+ with
flutter test --coverage
Review Summary
- Architecture compliance (correct layer, inward dependencies)
- Type safety (no dynamic, no Map)
- BLoC patterns (individual handlers, no event.when(), no state.when())
- @freezed on all events/states
- UI standards (AppColors, AppTextStyles, AppLocalization, const)
- No redundant comments
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aleksandr-chaika
- Source: aleksandr-chaika/flutter-clean-arch-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.