oh-my-customcode 0.30.7 → 0.30.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,431 @@
1
+ ---
2
+ name: flutter-best-practices
3
+ description: Flutter/Dart development best practices for widget composition, state management, and performance
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## Purpose
8
+
9
+ Apply Flutter and Dart best practices from official documentation and community standards. Covers widget patterns, state management (Riverpod/BLoC), performance optimization, testing, security, and Dart 3.x language patterns.
10
+
11
+ ## Core Principles
12
+
13
+ ```
14
+ Widget composition over inheritance
15
+ Unidirectional data flow
16
+ Immutable state
17
+ const by default
18
+ Platform-adaptive design
19
+ ```
20
+
21
+ ## Rules
22
+
23
+ ### 1. Widget Patterns
24
+
25
+ ```yaml
26
+ composition:
27
+ prefer: "Small, focused StatelessWidget classes"
28
+ avoid: "Helper functions returning Widget (no Element identity)"
29
+ reason: "Flutter diffing depends on widget type identity"
30
+
31
+ const_constructors:
32
+ rule: "Mark all static widgets const"
33
+ pattern: "const Text('Hello'), const SizedBox(height: 8)"
34
+ impact: "Zero rebuild cost — compile-time constant"
35
+
36
+ sizing_widgets:
37
+ prefer: "SizedBox for spacing/sizing"
38
+ avoid: "Container when only size is needed"
39
+ reason: "SizedBox is lighter, no decoration overhead"
40
+
41
+ state_choice:
42
+ StatelessWidget: "No mutable state, pure rendering"
43
+ StatefulWidget: "Local ephemeral state (animations, form input)"
44
+ InheritedWidget: "Data propagation down tree (base of Provider)"
45
+
46
+ build_context:
47
+ rule: "Never store BuildContext across async gaps"
48
+ pattern: |
49
+ // BAD
50
+ final ctx = context;
51
+ await Future.delayed(Duration(seconds: 1));
52
+ Navigator.of(ctx).push(...); // context may be invalid
53
+
54
+ // GOOD
55
+ if (!mounted) return;
56
+ Navigator.of(context).push(...);
57
+
58
+ keys:
59
+ ValueKey: "When items have unique business identity"
60
+ ObjectKey: "When items are objects without natural key"
61
+ UniqueKey: "Force rebuild on every build (rare)"
62
+ GlobalKey: "Cross-widget state access (use sparingly)"
63
+
64
+ lists:
65
+ prefer: "ListView.builder for >10 items (lazy construction)"
66
+ avoid: "ListView(children: [...]) for large lists"
67
+ optimization: "Set itemExtent to skip intrinsic layout passes"
68
+
69
+ layout:
70
+ rule: "Constraints flow down, sizes flow up"
71
+ common_error: "Unbounded constraints in Column/Row children"
72
+ fix: "Wrap with Expanded/Flexible or constrain explicitly"
73
+
74
+ repaint_boundary:
75
+ when: "Frequently repainting subtrees (animations, video, maps)"
76
+ effect: "Isolates paint scope, prevents cascade repaints"
77
+ detect: "DevTools → highlight repaints toggle"
78
+
79
+ slivers:
80
+ prefer: "CustomScrollView + SliverList.builder for complex scrolling"
81
+ use_for: "Floating headers, parallax, mixed scroll content"
82
+ avoid: "Nested ListView in ListView"
83
+ ```
84
+
85
+ ### 2. State Management
86
+
87
+ ```yaml
88
+ default_choice:
89
+ new_projects: "Riverpod 3.0"
90
+ enterprise: "BLoC 9.0"
91
+ simple_prototypes: "setState or Provider"
92
+ avoid: "GetX (maintenance crisis, runtime crashes)"
93
+
94
+ riverpod_patterns:
95
+ reactive_read: "ref.watch(provider) — in build methods only"
96
+ one_time_read: "ref.read(provider) — in callbacks, onPressed"
97
+ never: "ref.watch inside non-build methods"
98
+ async_state: "AsyncNotifier + AsyncValue (loading/data/error)"
99
+ family: "family modifier for parameterized providers"
100
+ keep_alive: "Only when justified (expensive computations)"
101
+ invalidate_vs_refresh: |
102
+ ref.invalidate(provider) // reset to loading, lazy re-fetch
103
+ ref.refresh(provider) // immediate re-fetch, return new value
104
+
105
+ bloc_patterns:
106
+ one_event_per_action: "One UI action = one event class"
107
+ cubit_vs_bloc: |
108
+ Cubit: direct emit(state) — for simple state changes
109
+ Bloc: event → state mapping — when audit trail needed
110
+ never: "Emit state in constructor body"
111
+ listener_vs_consumer: |
112
+ BlocListener: side effects (navigation, snackbar)
113
+ BlocConsumer: rebuild UI + side effects
114
+ BlocBuilder: rebuild UI only (most common)
115
+ stream_management: "Cancel subscriptions in close()"
116
+
117
+ state_immutability:
118
+ rule: "All state objects must be immutable"
119
+ tool: "freezed package for copyWith/==/hashCode generation"
120
+ pattern: |
121
+ @freezed
122
+ class UserState with _$UserState {
123
+ const factory UserState({
124
+ required String name,
125
+ required int age,
126
+ @Default(false) bool isLoading,
127
+ }) = _UserState;
128
+ }
129
+
130
+ result_type:
131
+ rule: "Return Result<T> from repositories, never throw"
132
+ pattern: |
133
+ sealed class Result<T> {
134
+ const Result();
135
+ }
136
+ final class Ok<T> extends Result<T> {
137
+ const Ok(this.value);
138
+ final T value;
139
+ }
140
+ final class Error<T> extends Result<T> {
141
+ const Error(this.error);
142
+ final Exception error;
143
+ }
144
+ ```
145
+
146
+ ### 3. Performance
147
+
148
+ ```yaml
149
+ build_optimization:
150
+ const_widgets: "Mark immutable widgets const — zero rebuild"
151
+ localize_setState: "Call setState on smallest possible subtree"
152
+ extract_widgets: "StatelessWidget class > helper method"
153
+ child_parameter: |
154
+ // GOOD: static child passed through
155
+ AnimatedBuilder(
156
+ animation: controller,
157
+ builder: (context, child) => Transform.rotate(
158
+ angle: controller.value,
159
+ child: child, // not rebuilt
160
+ ),
161
+ child: const ExpensiveWidget(), // built once
162
+ )
163
+
164
+ rebuild_avoidance:
165
+ consumer_placement: "Place Consumer/ListenableBuilder as deep as possible"
166
+ read_in_callbacks: "context.read<T>() not context.watch<T>() in handlers"
167
+ selector: "Use BlocSelector/Selector for partial state rebuilds"
168
+
169
+ rendering:
170
+ avoid_opacity: "Use color.withValues(alpha:) (Flutter 3.27+) or AnimatedOpacity instead; color.withOpacity() is deprecated"
171
+ avoid_clip: "Pre-clip static content; avoid ClipRRect in animations"
172
+ minimize_saveLayer: "ShaderMask, ColorFilter, Chip trigger saveLayer"
173
+
174
+ compute_offloading:
175
+ rule: "Isolate.run() for operations >16ms (one frame budget)"
176
+ web_compatible: "Use compute() for web-compatible apps"
177
+ use_for: "JSON parsing, image processing, complex filtering"
178
+
179
+ frame_budget:
180
+ target: "<8ms build + <8ms render = 16.67ms (60fps)"
181
+ profiling: "flutter run --profile, not debug mode"
182
+ tool: "DevTools Performance view for jank detection"
183
+ ```
184
+
185
+ ### 4. Testing
186
+
187
+ ```yaml
188
+ test_pyramid:
189
+ unit: "Single class/function — fast, low confidence"
190
+ widget: "Single widget tree — fast, medium confidence"
191
+ integration: "Full app on device — slow, high confidence"
192
+ golden: "Visual regression via matchesGoldenFile()"
193
+
194
+ widget_test_pattern: |
195
+ testWidgets('shows loading then content', (tester) async {
196
+ await tester.pumpWidget(
197
+ ProviderScope(
198
+ overrides: [productsProvider.overrideWith((_) => fakeProducts)],
199
+ child: const MaterialApp(home: ProductListScreen()),
200
+ ),
201
+ );
202
+ expect(find.byType(CircularProgressIndicator), findsOneWidget);
203
+ await tester.pumpAndSettle();
204
+ expect(find.byType(ProductCard), findsNWidgets(3));
205
+ });
206
+
207
+ mocking:
208
+ prefer: "mocktail (null-safe, no codegen)"
209
+ avoid: "Legacy mockito with build_runner"
210
+ fakes: "Use Fake implementations for deterministic tests"
211
+ pattern: |
212
+ class FakeProductRepository extends Fake implements ProductRepository {
213
+ @override
214
+ Future<Result<List<Product>>> getAll() async => Ok(testProducts);
215
+ }
216
+
217
+ bloc_testing: |
218
+ blocTest<AuthBloc, AuthState>(
219
+ 'emits [loading, success] when login succeeds',
220
+ build: () => AuthBloc(FakeAuthRepository()),
221
+ act: (bloc) => bloc.add(LoginRequested('user', 'pass')),
222
+ expect: () => [AuthLoading(), isA<AuthSuccess>()],
223
+ );
224
+
225
+ coverage_target:
226
+ widget_tests: "80%+ for UI logic"
227
+ unit_tests: "90%+ for business logic"
228
+ integration: "Critical user flows only"
229
+ ```
230
+
231
+ ### 5. Security
232
+
233
+ ```yaml
234
+ secrets:
235
+ never: "Hardcode API keys, tokens, or credentials in source"
236
+ best: "Backend proxy for all sensitive API calls"
237
+ use: "--dart-define-from-file=.env for NON-SECRET build config only (feature flags, environment URLs)"
238
+ warning: "dart-define values are embedded in compiled binary and extractable via static analysis. Use only for non-secret build configuration (feature flags, environment URLs)."
239
+
240
+ storage:
241
+ sensitive_data: "flutter_secure_storage v10+ (Keychain/Keystore)"
242
+ never: "SharedPreferences for tokens, PII, or credentials"
243
+ ios: "AppleOptions(useSecureEnclave: true) for high-value"
244
+ android: "AndroidOptions(encryptedSharedPreferences: true)"
245
+ web_warning: "flutter_secure_storage on Web uses localStorage by default, which is accessible to any JavaScript on the page (XSS vulnerable). For Web targets, use HttpOnly cookies managed by backend or in-memory-only storage for sensitive data."
246
+
247
+ network:
248
+ tls: "Certificate pinning (SPKI) for financial/health apps"
249
+ cleartext: "cleartextTrafficPermitted=false in network_security_config"
250
+ ios_ats: "NSAllowsArbitraryLoads=false (default, never override)"
251
+
252
+ release_builds:
253
+ obfuscate: "--obfuscate --split-debug-info=<path>"
254
+ proguard: "Configure android/app/proguard-rules.pro"
255
+ debug_check: "Remove all kDebugMode unguarded print() calls"
256
+ rule: "Never ship debug APK to production"
257
+
258
+ deep_links:
259
+ validate: "Allow-list all URI parameters with RegExp"
260
+ reject: "Arbitrary schemes and unvalidated paths"
261
+ prefer: "Universal Links (iOS) and App Links (Android) only"
262
+
263
+ logging:
264
+ rule: "Guard print() with kDebugMode"
265
+ prefer: "dart:developer log() for debug output"
266
+ never: "Log PII, tokens, or credentials"
267
+ ```
268
+
269
+ ### 6. Dart Language Patterns
270
+
271
+ ```yaml
272
+ naming:
273
+ types: "UpperCamelCase for classes, enums, typedefs, extensions, mixins (e.g., HttpClient, JsonParser)"
274
+ variables: "lowerCamelCase for variables, parameters, named constants (e.g., itemCount, defaultTimeout)"
275
+ libraries: "lowercase_with_underscores for libraries, packages, directories, source files (e.g., my_package, slider_menu.dart)"
276
+ constants: "lowerCamelCase for const (e.g., const defaultTimeout = 30), NOT SCREAMING_CAPS"
277
+ private: "Prefix with underscore for library-private (e.g., _internalCache, _helper())"
278
+ boolean: "Prefix with is/has/can/should for booleans (e.g., isEnabled, hasData, canScroll)"
279
+ avoid: "Hungarian notation, type prefixes (strName, lstItems), abbreviations unless universally known (e.g., ok: http, url, id; avoid: mgr, ctx, btn)"
280
+
281
+ null_safety:
282
+ default: "Non-nullable types — use ? only when null is meaningful"
283
+ avoid_bang: "Minimize ! operator — use only when null is logically impossible"
284
+ late: "Only when initialization is guaranteed before use"
285
+ pattern: |
286
+ // GOOD
287
+ final name = user?.name ?? 'Anonymous';
288
+
289
+ // AVOID
290
+ final name = user!.name; // crashes if null
291
+
292
+ sealed_classes:
293
+ use_for: "Exhaustive pattern matching on state/result types"
294
+ pattern: |
295
+ sealed class AuthState {}
296
+ class AuthInitial extends AuthState {}
297
+ class AuthLoading extends AuthState {}
298
+ class AuthSuccess extends AuthState { final User user; AuthSuccess(this.user); }
299
+ class AuthError extends AuthState { final String message; AuthError(this.message); }
300
+
301
+ // Exhaustive switch — compiler enforces all cases
302
+ return switch (state) {
303
+ AuthInitial() => LoginScreen(),
304
+ AuthLoading() => CircularProgressIndicator(),
305
+ AuthSuccess(:final user) => HomeScreen(user: user),
306
+ AuthError(:final message) => ErrorWidget(message),
307
+ };
308
+
309
+ records:
310
+ use_for: "Lightweight multi-value returns without class boilerplate"
311
+ pattern: "(String name, int age) getUserInfo() => ('Alice', 30);"
312
+ avoid: "Records for complex data — use freezed classes instead"
313
+
314
+ extension_types:
315
+ use_for: "Zero-cost type wrappers for primitive IDs"
316
+ pattern: "extension type UserId(int id) implements int {}"
317
+
318
+ immutability:
319
+ prefer: "final variables, const constructors"
320
+ collections: "UnmodifiableListView for exposed lists"
321
+ models: "freezed package for data classes"
322
+
323
+ async:
324
+ streams: "async* yield for reactive data pipelines"
325
+ futures: "async/await for sequential async operations"
326
+ isolates: "Isolate.run() for CPU-intensive work >16ms"
327
+
328
+ dynamic:
329
+ avoid: "dynamic type — use generics or Object? instead"
330
+ reason: "No compile-time type checking, reduces IDE support"
331
+ ```
332
+
333
+ ### 7. Architecture & Project Structure
334
+
335
+ ```yaml
336
+ default_structure:
337
+ small_app: |
338
+ lib/
339
+ models/
340
+ services/
341
+ screens/
342
+ widgets/
343
+ medium_app: |
344
+ lib/
345
+ ui/
346
+ core/themes/, core/widgets/
347
+ <feature>/<feature>_screen.dart
348
+ <feature>/<feature>_viewmodel.dart
349
+ data/
350
+ repositories/<entity>_repository.dart
351
+ services/<source>_service.dart
352
+ domain/ (optional)
353
+ use_cases/
354
+ large_app: |
355
+ lib/
356
+ core/ (shared)
357
+ features/<feature>/
358
+ data/datasources/, data/repositories/
359
+ domain/entities/, domain/usecases/
360
+ presentation/bloc/, presentation/pages/
361
+
362
+ navigation:
363
+ default: "go_router (official recommendation)"
364
+ pattern: |
365
+ GoRoute(
366
+ path: '/product/:id',
367
+ builder: (context, state) {
368
+ final id = state.pathParameters['id']!;
369
+ return ProductDetailScreen(id: id);
370
+ },
371
+ )
372
+ go_vs_push: |
373
+ context.go('/path') // replaces stack (navigation reset)
374
+ context.push('/path') // adds to stack (back button works)
375
+
376
+ dependency_injection:
377
+ riverpod: "Built-in — providers as DI (default)"
378
+ getit: "GetIt + injectable — for non-Riverpod projects"
379
+ rule: "Dependency direction always inward (UI → ViewModel → Repository → Service)"
380
+
381
+ environments:
382
+ pattern: "Flavors + --dart-define for multi-environment builds"
383
+ command: "flutter run --flavor development --target lib/main/main_development.dart"
384
+ rule: "Separate bundle IDs, API URLs, and Firebase config per flavor"
385
+ ```
386
+
387
+ ## Default Stack
388
+
389
+ When starting a new Flutter project, recommend this stack:
390
+
391
+ ```yaml
392
+ state_management: Riverpod 3.0
393
+ navigation: go_router
394
+ models: freezed + json_serializable
395
+ di: Riverpod (built-in)
396
+ http: dio
397
+ linting: very_good_analysis
398
+ testing: flutter_test + mocktail
399
+ structure: Official MVVM (lib/{ui,data}/)
400
+ ```
401
+
402
+ ## Enterprise Stack
403
+
404
+ For regulated or large-team projects:
405
+
406
+ ```yaml
407
+ state_management: BLoC 9.0 + Cubit
408
+ navigation: go_router or auto_route
409
+ models: freezed + json_serializable
410
+ di: GetIt + injectable (or Riverpod)
411
+ http: dio with interceptors
412
+ testing: flutter_test + bloc_test + mocktail (80%+ coverage)
413
+ structure: Clean Architecture (features/{feature}/{presentation,domain,data}/)
414
+ ```
415
+
416
+ ## Application
417
+
418
+ When writing or reviewing Flutter/Dart code:
419
+
420
+ 1. **Always** use const constructors for static widgets
421
+ 2. **Always** return Result<T> from repositories, never throw
422
+ 3. **Always** use flutter_secure_storage for sensitive data
423
+ 4. **Prefer** Riverpod 3.0 for new projects, BLoC for enterprise
424
+ 5. **Prefer** StatelessWidget classes over helper functions
425
+ 6. **Prefer** sealed classes for state/result types (exhaustive matching)
426
+ 7. **Use** freezed for all data model classes
427
+ 8. **Use** go_router for navigation with deep linking
428
+ 9. **Guard** all print() with kDebugMode
429
+ 10. **Never** use GetX for new projects (maintenance risk)
430
+ 11. **Never** store sensitive data in SharedPreferences
431
+ 12. **Never** hardcode API keys in source code
@@ -102,6 +102,14 @@ agents:
102
102
  supported_actions: [review, create, fix, refactor]
103
103
  base_confidence: 40
104
104
 
105
+ fe-flutter-agent:
106
+ keywords:
107
+ korean: [플러터, 다트, 모바일앱, 위젯]
108
+ english: [flutter, dart, riverpod, bloc, widget, pubspec, "flutter app"]
109
+ file_patterns: ["*.dart", "pubspec.yaml", "pubspec.lock", "analysis_options.yaml"]
110
+ supported_actions: [review, create, fix, refactor, test]
111
+ base_confidence: 40
112
+
105
113
  # SW Engineers - Backend
106
114
  be-fastapi-expert:
107
115
  keywords:
@@ -0,0 +1,141 @@
1
+ # Flutter Architecture
2
+
3
+ > Reference: docs.flutter.dev/app-architecture
4
+
5
+ ## Official MVVM Pattern
6
+
7
+ ```
8
+ UI Layer
9
+ ├─ View (Widget) — display only, no business logic
10
+ └─ ViewModel (ChangeNotifier / Notifier) — state + commands
11
+
12
+ Data Layer
13
+ ├─ Repository — single source of truth per domain
14
+ └─ Service — stateless external API wrapper
15
+
16
+ Domain Layer (optional)
17
+ └─ UseCase — cross-repository business logic
18
+ ```
19
+
20
+ ### Dependency Rules
21
+
22
+ - View knows only its ViewModel
23
+ - ViewModel knows Repositories (private)
24
+ - Repository knows Services (private)
25
+ - **Direction always inward** — UI depends on data, never reverse
26
+
27
+ ### ViewModel with Commands
28
+
29
+ ```dart
30
+ class HomeViewModel extends ChangeNotifier {
31
+ HomeViewModel({required BookingRepository bookingRepository})
32
+ : _bookingRepository = bookingRepository {
33
+ load = Command0(_load)..execute();
34
+ }
35
+
36
+ final BookingRepository _bookingRepository;
37
+ late final Command0 load;
38
+
39
+ List<BookingSummary> _bookings = [];
40
+ UnmodifiableListView<BookingSummary> get bookings =>
41
+ UnmodifiableListView(_bookings);
42
+
43
+ Future<Result> _load() async {
44
+ final result = await _bookingRepository.getBookingsList();
45
+ if (result case Ok(:final value)) _bookings = value;
46
+ notifyListeners();
47
+ return result;
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## Project Structure
53
+
54
+ ### Medium Apps (Official MVVM)
55
+
56
+ ```
57
+ lib/
58
+ ├── ui/
59
+ │ ├── core/
60
+ │ │ ├── themes/app_theme.dart
61
+ │ │ └── widgets/loading_indicator.dart
62
+ │ └── home/
63
+ │ ├── home_screen.dart
64
+ │ └── home_viewmodel.dart
65
+ ├── data/
66
+ │ ├── repositories/booking_repository.dart
67
+ │ └── services/api_service.dart
68
+ └── domain/ (optional)
69
+ └── use_cases/get_bookings_usecase.dart
70
+ ```
71
+
72
+ ### Large Apps (Clean Architecture)
73
+
74
+ ```
75
+ lib/
76
+ ├── core/
77
+ │ ├── error/failures.dart
78
+ │ ├── network/api_client.dart
79
+ │ └── utils/extensions.dart
80
+ └── features/
81
+ └── auth/
82
+ ├── data/
83
+ │ ├── datasources/auth_remote_datasource.dart
84
+ │ ├── models/user_model.dart
85
+ │ └── repositories/auth_repository_impl.dart
86
+ ├── domain/
87
+ │ ├── entities/user.dart
88
+ │ ├── repositories/auth_repository.dart
89
+ │ └── use_cases/login_usecase.dart
90
+ └── presentation/
91
+ ├── bloc/auth_bloc.dart
92
+ ├── pages/login_page.dart
93
+ └── widgets/login_form.dart
94
+ ```
95
+
96
+ ## Navigation (go_router)
97
+
98
+ ```dart
99
+ final router = GoRouter(
100
+ initialLocation: '/',
101
+ routes: [
102
+ GoRoute(
103
+ path: '/',
104
+ builder: (context, state) => const HomeScreen(),
105
+ ),
106
+ GoRoute(
107
+ path: '/product/:id',
108
+ builder: (context, state) {
109
+ final id = state.pathParameters['id']!;
110
+ return ProductDetailScreen(id: id);
111
+ },
112
+ ),
113
+ ShellRoute(
114
+ builder: (context, state, child) => ScaffoldWithNavBar(child: child),
115
+ routes: [/* nested tab routes */],
116
+ ),
117
+ ],
118
+ redirect: (context, state) {
119
+ final isLoggedIn = /* check auth */;
120
+ if (!isLoggedIn && state.matchedLocation != '/login') return '/login';
121
+ return null;
122
+ },
123
+ );
124
+ ```
125
+
126
+ ## Data Models (freezed)
127
+
128
+ ```dart
129
+ @freezed
130
+ class Product with _$Product {
131
+ const factory Product({
132
+ required int id,
133
+ required String name,
134
+ required double price,
135
+ @Default('') String description,
136
+ }) = _Product;
137
+
138
+ factory Product.fromJson(Map<String, dynamic> json) =>
139
+ _$ProductFromJson(json);
140
+ }
141
+ ```
@@ -0,0 +1,119 @@
1
+ # Flutter Fundamentals
2
+
3
+ > Reference: Flutter Official Documentation (docs.flutter.dev)
4
+
5
+ ## Widget System
6
+
7
+ Flutter's UI is built with a composition of widgets. Everything is a widget — including padding, alignment, and decoration.
8
+
9
+ ### Widget Types
10
+
11
+ | Type | Use Case | State |
12
+ |------|----------|-------|
13
+ | `StatelessWidget` | Pure rendering, no mutable state | Immutable |
14
+ | `StatefulWidget` | Local ephemeral state (animations, forms) | Mutable via `State<T>` |
15
+ | `InheritedWidget` | Data propagation down widget tree | Foundation of Provider |
16
+
17
+ ### Widget Lifecycle
18
+
19
+ ```dart
20
+ // StatefulWidget lifecycle
21
+ class MyWidget extends StatefulWidget {
22
+ @override
23
+ State<MyWidget> createState() => _MyWidgetState();
24
+ }
25
+
26
+ class _MyWidgetState extends State<MyWidget> {
27
+ @override
28
+ void initState() { super.initState(); /* one-time setup */ }
29
+
30
+ @override
31
+ void didChangeDependencies() { super.didChangeDependencies(); /* InheritedWidget changed */ }
32
+
33
+ @override
34
+ void didUpdateWidget(MyWidget oldWidget) { super.didUpdateWidget(oldWidget); /* parent rebuilt */ }
35
+
36
+ @override
37
+ Widget build(BuildContext context) { return Container(); /* called on every rebuild */ }
38
+
39
+ @override
40
+ void dispose() { /* cleanup controllers, subscriptions */ super.dispose(); }
41
+ }
42
+ ```
43
+
44
+ ## Three-Tree Architecture
45
+
46
+ Flutter maintains three parallel trees:
47
+
48
+ ```
49
+ Widget Tree (immutable descriptions)
50
+ ↓ createElement()
51
+ Element Tree (persistent, mutable handles)
52
+ ↓ createRenderObject()
53
+ RenderObject Tree (layout + paint primitives)
54
+ ```
55
+
56
+ - **Widget**: Lightweight, immutable configuration. Rebuilt frequently.
57
+ - **Element**: Persistent handle that manages widget lifecycle. Enables efficient diffing.
58
+ - **RenderObject**: Expensive layout/paint primitives. Only updated when properties change.
59
+
60
+ ### Layout Algorithm
61
+
62
+ **Constraints go down, sizes go up, parent decides position.**
63
+
64
+ ```dart
65
+ // Parent passes BoxConstraints to child
66
+ // Child returns its chosen Size within those constraints
67
+ // Parent positions child at an Offset
68
+ ```
69
+
70
+ Common layout errors:
71
+ - Unbounded height/width in `Column`/`Row` → wrap with `Expanded` or `Flexible`
72
+ - `Viewport was given unbounded height` → provide explicit height or use `SliverList`
73
+
74
+ ## BuildContext
75
+
76
+ `BuildContext` is a handle to the widget's location in the Element tree.
77
+
78
+ ```dart
79
+ // Access inherited data
80
+ final theme = Theme.of(context);
81
+ final mediaQuery = MediaQuery.of(context);
82
+
83
+ // NEVER store context across async gaps
84
+ // ALWAYS check mounted before using context after await
85
+ if (!mounted) return;
86
+ Navigator.of(context).push(...);
87
+ ```
88
+
89
+ ## Keys
90
+
91
+ | Key Type | When to Use |
92
+ |----------|-------------|
93
+ | `ValueKey` | Items with unique business identity (user ID, product SKU) |
94
+ | `ObjectKey` | Items without natural key (use the object itself) |
95
+ | `UniqueKey` | Force new Element every build (rare, expensive) |
96
+ | `GlobalKey` | Cross-widget state access (use sparingly — breaks encapsulation) |
97
+
98
+ ```dart
99
+ // Reorderable list MUST use keys
100
+ ListView(
101
+ children: items.map((item) => ListTile(
102
+ key: ValueKey(item.id),
103
+ title: Text(item.name),
104
+ )).toList(),
105
+ );
106
+ ```
107
+
108
+ ## Package Recommendations
109
+
110
+ | Category | Package | Notes |
111
+ |----------|---------|-------|
112
+ | State (default) | `flutter_riverpod` | Compile-time safe, built-in DI |
113
+ | State (enterprise) | `flutter_bloc` | Event-driven, audit trails |
114
+ | Navigation | `go_router` | Official, deep linking, web |
115
+ | Models | `freezed` + `json_serializable` | Immutable, code-gen |
116
+ | HTTP | `dio` | Interceptors, cancellation |
117
+ | Linting | `very_good_analysis` | Community standard rules |
118
+ | Testing | `mocktail` | Null-safe mocking, no codegen |
119
+ | Secure Storage | `flutter_secure_storage` | Keychain/Keystore |