devendra-skill-package 1.0.2
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.
- package/.github/skills/boiler-project-generator/SKILL.md +103 -0
- package/.github/skills/boiler-project-generator/assets/templates/android/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/angular/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/flutter/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/ios/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/api-setup.ts +76 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/component-primary-button.tsx +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/env-config.env +4 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-auth-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-dashboard-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-profile-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/hook-use-app-boot.ts +11 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/navigation-setup.tsx +25 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/project-structure.md +24 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-hooks.ts +5 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-session-slice.ts +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-store.ts +15 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/theme-index.ts +23 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/utils-helpers.ts +7 -0
- package/.github/skills/boiler-project-generator/metadata.yaml +29 -0
- package/.github/skills/boiler-project-generator/references/android.md +19 -0
- package/.github/skills/boiler-project-generator/references/angular.md +14 -0
- package/.github/skills/boiler-project-generator/references/flutter.md +17 -0
- package/.github/skills/boiler-project-generator/references/ios.md +17 -0
- package/.github/skills/boiler-project-generator/references/react-native.md +103 -0
- package/.github/skills/boiler-project-generator/references/react.md +17 -0
- package/.github/skills/boiler-project-generator/scripts/angular.js +43 -0
- package/.github/skills/boiler-project-generator/scripts/generate-project.mjs +107 -0
- package/.github/skills/boiler-project-generator/scripts/init.js +105 -0
- package/.github/skills/boiler-project-generator/scripts/react-native.js +1041 -0
- package/.github/skills/boiler-project-generator/scripts/react.js +32 -0
- package/.github/skills/clean-architecture-generator/SKILL.md +235 -0
- package/.github/skills/clean-architecture-generator/references/architecture-core.md +126 -0
- package/.github/skills/clean-architecture-generator/references/platform-angular.md +374 -0
- package/.github/skills/clean-architecture-generator/references/platform-flutter.md +366 -0
- package/.github/skills/clean-architecture-generator/references/platform-react-native.md +590 -0
- package/.github/skills/clean-architecture-generator/references/platform-react.md +261 -0
- package/.github/skills/code-test-coverage-analyzer/SKILL.md +1358 -0
- package/.github/skills/code-test-coverage-analyzer/assets/config-questionnaire.md +118 -0
- package/.github/skills/code-test-coverage-analyzer/assets/conflict-resolution-protocol.md +99 -0
- package/.github/skills/code-test-coverage-analyzer/assets/coverage-calculation-rules.md +294 -0
- package/.github/skills/code-test-coverage-analyzer/assets/multi-strategy-search.md +145 -0
- package/.github/skills/code-test-coverage-analyzer/assets/output-file-contracts.md +651 -0
- package/.github/skills/code-test-coverage-analyzer/assets/status-definitions.md +273 -0
- package/.github/skills/code-test-coverage-analyzer/examples/example-invocation.md +208 -0
- package/.github/skills/code-test-coverage-analyzer/references/android-patterns.md +229 -0
- package/.github/skills/code-test-coverage-analyzer/references/angular-patterns.md +177 -0
- package/.github/skills/code-test-coverage-analyzer/references/backend-patterns.md +383 -0
- package/.github/skills/code-test-coverage-analyzer/references/flutter-patterns.md +254 -0
- package/.github/skills/code-test-coverage-analyzer/references/ios-patterns.md +228 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-native-patterns.md +431 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-patterns.md +206 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/detect-platform.ps1 +261 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/scan-repository.ps1 +242 -0
- package/.github/skills/code-test-coverage-analyzer/templates/brd-compliance-row.md +107 -0
- package/.github/skills/code-test-coverage-analyzer/templates/test-case-row.md +130 -0
- package/.github/skills/code-test-coverage-analyzer/templates/user-story-compliance-row.md +170 -0
- package/.github/skills/custom-font-integrator/SKILL.md +373 -0
- package/.github/skills/custom-font-integrator/assets/FontTestScreen.js +150 -0
- package/.github/skills/custom-font-integrator/references/example-info-plist.xml +21 -0
- package/.github/skills/custom-font-integrator/scripts/setup-fonts.sh +99 -0
- package/.github/skills/encryption-decryption-utility/Instructions.md +282 -0
- package/.github/skills/encryption-decryption-utility/README.md +222 -0
- package/.github/skills/encryption-decryption-utility/SKILL.md +645 -0
- package/.github/skills/encryption-decryption-utility/assets/encryption-config-template.json +13 -0
- package/.github/skills/encryption-decryption-utility/assets/platform-matrix.json +180 -0
- package/.github/skills/encryption-decryption-utility/metadata.yaml +51 -0
- package/.github/skills/encryption-decryption-utility/references/android-crypto.md +157 -0
- package/.github/skills/encryption-decryption-utility/references/angular-crypto.md +130 -0
- package/.github/skills/encryption-decryption-utility/references/approach-1-webcrypto.md +95 -0
- package/.github/skills/encryption-decryption-utility/references/approach-2-rsa-aes-cbc.md +111 -0
- package/.github/skills/encryption-decryption-utility/references/approach-3-aes-sharedkey.md +114 -0
- package/.github/skills/encryption-decryption-utility/references/architecture.md +233 -0
- package/.github/skills/encryption-decryption-utility/references/backend-alignment.md +506 -0
- package/.github/skills/encryption-decryption-utility/references/dependency-guidance.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/ec-implementation.md +832 -0
- package/.github/skills/encryption-decryption-utility/references/error-handling-playbook.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/flutter-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/ios-crypto.md +338 -0
- package/.github/skills/encryption-decryption-utility/references/native-rsa-implementation.md +373 -0
- package/.github/skills/encryption-decryption-utility/references/node-crypto.md +86 -0
- package/.github/skills/encryption-decryption-utility/references/react-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/react-native-crypto.md +1001 -0
- package/.github/skills/encryption-decryption-utility/references/react-web-crypto.md +668 -0
- package/.github/skills/encryption-decryption-utility/references/security-checklist.md +176 -0
- package/.github/skills/encryption-decryption-utility/references/web-crypto.md +74 -0
- package/.github/skills/encryption-decryption-utility/scripts/detect.js +128 -0
- package/.github/skills/encryption-decryption-utility/scripts/install.js +1713 -0
- package/.github/skills/encryption-decryption-utility/scripts/setup.js +800 -0
- package/.github/skills/encryption-decryption-utility/template.md +241 -0
- package/.github/skills/encryption-decryption-utility/templates/config-questionnaire.md +467 -0
- package/.github/skills/encryption-decryption-utility/templates/delivery-checklist.md +206 -0
- package/.github/skills/encryption-decryption-utility/templates/implementation-plan.md +304 -0
- package/.github/skills/feature-generator/SKILL.MD +2741 -0
- package/.github/skills/feature-generator/assets/fingerprint-schema.json +385 -0
- package/.github/skills/feature-generator/assets/spec-template.md +172 -0
- package/.github/skills/feature-generator/assets/transform-rules.json +82 -0
- package/.github/skills/feature-generator/references/api-envelope-patterns.md +327 -0
- package/.github/skills/feature-generator/references/screen-logic-patterns.md +399 -0
- package/.github/skills/feature-generator/references/state-library-patterns.md +464 -0
- package/.github/skills/figma-ui-mapper/README.md +34 -0
- package/.github/skills/figma-ui-mapper/SKILL.md +101 -0
- package/.github/skills/figma-ui-mapper/assets/templates/component-map-template.md +30 -0
- package/.github/skills/figma-ui-mapper/assets/templates/generation-report-template.md +49 -0
- package/.github/skills/figma-ui-mapper/metadata.yaml +22 -0
- package/.github/skills/figma-ui-mapper/references/android.md +11 -0
- package/.github/skills/figma-ui-mapper/references/angular.md +18 -0
- package/.github/skills/figma-ui-mapper/references/capacitor.md +18 -0
- package/.github/skills/figma-ui-mapper/references/common.md +23 -0
- package/.github/skills/figma-ui-mapper/references/expo.md +18 -0
- package/.github/skills/figma-ui-mapper/references/flutter.md +18 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/angular/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/capacitor/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/expo/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/flutter/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/ionic/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/kotlin-multiplatform/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-android/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-ios/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/next/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/nuxt/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react/rules.md +19 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react-native/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/svelte/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/vue/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/ionic.md +18 -0
- package/.github/skills/figma-ui-mapper/references/ios.md +11 -0
- package/.github/skills/figma-ui-mapper/references/kotlin-multiplatform.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-android.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-ios.md +18 -0
- package/.github/skills/figma-ui-mapper/references/next.md +18 -0
- package/.github/skills/figma-ui-mapper/references/nuxt.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react-figma-guideline.md +21 -0
- package/.github/skills/figma-ui-mapper/references/react-native.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react.md +18 -0
- package/.github/skills/figma-ui-mapper/references/script-usage.md +46 -0
- package/.github/skills/figma-ui-mapper/references/svelte.md +18 -0
- package/.github/skills/figma-ui-mapper/references/vue.md +18 -0
- package/.github/skills/figma-ui-mapper/references/workflow.md +74 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-page-through-figma.js +635 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-react-page-through-figma.js +4 -0
- package/.github/skills/frontend-task-breakdown/SKILL.md +734 -0
- package/.github/skills/md-file-converter/SKILL.md +291 -0
- package/.github/skills/md-file-converter/config/formats.json +114 -0
- package/.github/skills/md-file-converter/extractors/extract-docx.sh +120 -0
- package/.github/skills/md-file-converter/extractors/extract-eml.py +108 -0
- package/.github/skills/md-file-converter/extractors/extract-pdf.sh +97 -0
- package/.github/skills/md-file-converter/extractors/extract-pptx.py +143 -0
- package/.github/skills/md-file-converter/extractors/extract-xlsx.py +175 -0
- package/.github/skills/md-file-converter/scripts/check-tools.sh +47 -0
- package/.github/skills/md-file-converter/scripts/extract-archive.sh +83 -0
- package/.github/skills/md-file-converter/scripts/extract-ocr.sh +77 -0
- package/.github/skills/md-file-converter/scripts/get-metadata.sh +57 -0
- package/.github/skills/md-file-converter/templates/output.md +73 -0
- package/.github/skills/md-file-converter/templates/unsupported-object.md +6 -0
- package/.github/skills/mockAPI-contract-generator/SKILL.md +607 -0
- package/.github/skills/test-case-validator/CHANGELOG.md +155 -0
- package/.github/skills/test-case-validator/CONFIGURATION.md +130 -0
- package/.github/skills/test-case-validator/EXAMPLES.md +50 -0
- package/.github/skills/test-case-validator/QUALITY_SCORING.md +98 -0
- package/.github/skills/test-case-validator/README.md +111 -0
- package/.github/skills/test-case-validator/REPORT_TEMPLATE.md +116 -0
- package/.github/skills/test-case-validator/SKILL.md +209 -0
- package/.github/skills/test-case-validator/SYSTEM_PROMPT.md +127 -0
- package/.github/skills/test-case-validator/TRACEABILITY_ENGINE.md +152 -0
- package/.github/skills/test-case-validator/VALIDATION_RULES.md +411 -0
- package/.github/skills/test-case-validator/config/default.config.yaml +62 -0
- package/.github/skills/test-case-validator/docs/ARCHITECTURE.md +66 -0
- package/.github/skills/test-case-validator/docs/EXTENDING.md +85 -0
- package/.github/skills/test-case-validator/docs/FAQ.md +88 -0
- package/.github/skills/test-case-validator/docs/VERSIONING.md +55 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-brd.md +43 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-test-cases.csv +9 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-user-story.md +29 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/output-report.md +303 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-spec.md +43 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-test-files-index.md +56 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/output-report.md +274 -0
- package/.github/skills/test-case-validator/prompts/00-applicability-resolution.md +61 -0
- package/.github/skills/test-case-validator/prompts/01-extraction-user-story.md +58 -0
- package/.github/skills/test-case-validator/prompts/02-extraction-brd.md +64 -0
- package/.github/skills/test-case-validator/prompts/03-extraction-test-cases.md +92 -0
- package/.github/skills/test-case-validator/prompts/04-traceability-matrix.md +41 -0
- package/.github/skills/test-case-validator/prompts/05-coverage-analysis.md +46 -0
- package/.github/skills/test-case-validator/prompts/06-missing-scenario-detection.md +32 -0
- package/.github/skills/test-case-validator/prompts/07-duplicate-detection.md +36 -0
- package/.github/skills/test-case-validator/prompts/08-risk-analysis.md +39 -0
- package/.github/skills/test-case-validator/prompts/09-gated-wiring-validation.md +53 -0
- package/.github/skills/test-case-validator/prompts/10-observation-report.md +56 -0
- package/.github/skills/test-case-validator/prompts/11-final-report-assembly.md +57 -0
- package/.github/skills/test-case-validator/templates/coverage-table.md +25 -0
- package/.github/skills/test-case-validator/templates/executive-summary.md +38 -0
- package/.github/skills/test-case-validator/templates/final-summary-block.md +87 -0
- package/.github/skills/test-case-validator/templates/observation-entry.md +41 -0
- package/.github/skills/test-case-validator/templates/rtm-row.md +25 -0
- package/.github/skills/validation-engine-builder/README.md +50 -0
- package/.github/skills/validation-engine-builder/SKILL.md +241 -0
- package/.github/skills/validation-engine-builder/references/core.md +158 -0
- package/.github/skills/validation-engine-builder/references/platform-angular.md +166 -0
- package/.github/skills/validation-engine-builder/references/platform-flutter.md +118 -0
- package/.github/skills/validation-engine-builder/references/platform-react-native.md +170 -0
- package/.github/skills/validation-engine-builder/references/platform-react.md +94 -0
- package/.github/skills/validation-engine-builder/scripts/apply-to-project.js +80 -0
- package/.github/skills/validation-engine-builder/scripts/generate-angular.js +271 -0
- package/.github/skills/validation-engine-builder/scripts/generate-flutter.js +298 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react-native.js +217 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react.js +163 -0
- package/.github/skills/validation-engine-builder/scripts/install-deps.js +53 -0
- package/.github/skills/validation-engine-builder/scripts/shared/detect-platform.js +68 -0
- package/.github/skills/validation-engine-builder/scripts/shared/npm-deps.js +103 -0
- package/.github/skills/validation-engine-builder/scripts/shared/rhf-hook.js +43 -0
- package/.github/skills/validation-engine-builder/scripts/shared/ts-messages-regex.js +62 -0
- package/.github/skills/validation-engine-builder/scripts/shared/util.js +44 -0
- package/.github/skills/validation-engine-builder/scripts/shared/yup-schemas.js +80 -0
- package/.github/skills/validation-engine-builder/template.md +73 -0
- package/.github/skills/validation-engine-builder/templates/messages.json +22 -0
- package/.github/skills/validation-engine-builder/templates/regex.json +16 -0
- package/.github/skills/validation-engine-builder/templates/schemas.json +48 -0
- package/bin/index.js +145 -0
- package/package.json +22 -0
- package/readme.md +0 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Platform File — Flutter
|
|
2
|
+
|
|
3
|
+
Read `architecture-core.md` first. Flutter differs from the other three platforms in language
|
|
4
|
+
(Dart, not TypeScript) and in file-naming convention — Dart's own style guide (Effective Dart) is
|
|
5
|
+
the authority here, not the RN/React/Angular conventions in the other platform files.
|
|
6
|
+
|
|
7
|
+
Everything under "Stack Fingerprint Defaults" applies **only** when Phase 1 detection found nothing
|
|
8
|
+
in `pubspec.yaml` / existing feature code in the target repo.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Stack Fingerprint Defaults (greenfield only)
|
|
13
|
+
|
|
14
|
+
| Concern | Detect first (search `pubspec.yaml` dependencies + existing code) | Default if nothing detected |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| State management | `flutter_riverpod`/`hooks_riverpod` (Riverpod), `flutter_bloc` (Bloc/Cubit), `provider` package, `get` (GetX) | `flutter_bloc` (Bloc for complex event-driven state, or its `Cubit` subset for simpler feature state) |
|
|
17
|
+
| DI mechanism | `get_it`, Riverpod's own provider graph (if Riverpod is the detected state lib, its providers also serve as DI — do not add `get_it` on top), `injectable` codegen | `get_it` — lazy singleton service locator (see DI Pattern below) |
|
|
18
|
+
| HTTP client | `Dio(`, `package:http/http.dart`, `chopper`, `retrofit` annotations | `dio` with interceptors |
|
|
19
|
+
| Local storage | `shared_preferences`, `flutter_secure_storage`, `hive`, `sqflite`, `drift` | `flutter_secure_storage` for tokens/secrets, `shared_preferences` for non-sensitive prefs |
|
|
20
|
+
| Navigation | `go_router`, `auto_route`, raw `Navigator.push`/`Navigator.of(context).push` | `go_router` |
|
|
21
|
+
| Functional error handling | `dartz` / `fpdart` `Either<Failure, T>` return types on repository methods | plain `Future<T>` that throws a typed `Exception`/`Failure` — only introduce `Either` if the project already uses it, since it's a deliberate, project-wide functional-style choice, not a default to impose |
|
|
22
|
+
| Test runner | — | `flutter_test` + `mocktail`/`mockito` for mocks (whichever is already in `pubspec.yaml` dev_dependencies) |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Folder Tree
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
lib/
|
|
30
|
+
├── main.dart
|
|
31
|
+
├── app/
|
|
32
|
+
│ ├── app.dart # MaterialApp.router root widget
|
|
33
|
+
│ ├── di/
|
|
34
|
+
│ │ └── injection_container.dart # get_it registrations, called once from main()
|
|
35
|
+
│ └── routing/
|
|
36
|
+
│ └── app_router.dart # go_router configuration, mounts each feature's routes
|
|
37
|
+
│
|
|
38
|
+
├── core/ # Infrastructure — shared by all features
|
|
39
|
+
│ ├── network/
|
|
40
|
+
│ │ ├── dio_client.dart # Singleton Dio instance + interceptors
|
|
41
|
+
│ │ └── network_info.dart # connectivity_plus wrapper
|
|
42
|
+
│ ├── error/
|
|
43
|
+
│ │ ├── failures.dart # sealed Failure hierarchy
|
|
44
|
+
│ │ └── exceptions.dart
|
|
45
|
+
│ ├── storage/
|
|
46
|
+
│ │ ├── secure_storage_service.dart
|
|
47
|
+
│ │ └── shared_prefs_service.dart
|
|
48
|
+
│ ├── usecase/
|
|
49
|
+
│ │ └── usecase.dart # abstract UseCase<Type, Params> base class
|
|
50
|
+
│ └── theme/
|
|
51
|
+
│ └── app_theme.dart
|
|
52
|
+
│
|
|
53
|
+
├── features/
|
|
54
|
+
│ └── [feature_name]/ # snake_case folder — see Naming Extensions
|
|
55
|
+
│ ├── domain/ # Pure Dart — ZERO Flutter/Dio/state-lib imports
|
|
56
|
+
│ │ ├── entities/
|
|
57
|
+
│ │ │ └── [item]_entity.dart
|
|
58
|
+
│ │ ├── repositories/
|
|
59
|
+
│ │ │ └── [feature]_repository.dart # abstract class, no `I` prefix
|
|
60
|
+
│ │ └── usecases/
|
|
61
|
+
│ │ └── get_[item]_usecase.dart
|
|
62
|
+
│ ├── data/
|
|
63
|
+
│ │ ├── models/ # DTOs — Flutter convention calls these "Models"
|
|
64
|
+
│ │ │ └── [item]_model.dart
|
|
65
|
+
│ │ ├── datasources/
|
|
66
|
+
│ │ │ └── [feature]_remote_data_source.dart
|
|
67
|
+
│ │ └── repositories/
|
|
68
|
+
│ │ └── [feature]_repository_impl.dart
|
|
69
|
+
│ ├── presentation/
|
|
70
|
+
│ │ ├── pages/
|
|
71
|
+
│ │ │ └── [feature]_page.dart
|
|
72
|
+
│ │ ├── widgets/
|
|
73
|
+
│ │ └── bloc/ # or riverpod/ or provider/ — matches detected state lib
|
|
74
|
+
│ │ ├── [feature]_bloc.dart
|
|
75
|
+
│ │ ├── [feature]_event.dart
|
|
76
|
+
│ │ └── [feature]_state.dart
|
|
77
|
+
│ └── [feature]_injection.dart # get_it registrations for this feature only
|
|
78
|
+
│
|
|
79
|
+
└── shared/
|
|
80
|
+
└── widgets/ # Reusable presentational widgets with no feature dependency
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Naming Extensions (Flutter/Dart-specific — Effective Dart, not invented)
|
|
86
|
+
|
|
87
|
+
Effective Dart specifies **snake_case for file names**, **PascalCase (UpperCamelCase) for class
|
|
88
|
+
names**, and explicitly recommends **against** an `I`-prefix on abstract/interface classes
|
|
89
|
+
("AVOID prefixing interface names with I—just use the plain name"). Follow this exactly — it is
|
|
90
|
+
different from the RN/React `I`-prefix convention and must not be mixed in:
|
|
91
|
+
|
|
92
|
+
| Artifact | Convention | Example |
|
|
93
|
+
|----------|------------|---------|
|
|
94
|
+
| Feature folder | snake_case | `portfolio_summary`, `user_profile` |
|
|
95
|
+
| Entity file | snake_case + `_entity.dart` | `holding_entity.dart` (class `HoldingEntity`) |
|
|
96
|
+
| Repository abstraction | snake_case + `_repository.dart`, **no `I` prefix** | `holding_repository.dart` (abstract class `HoldingRepository`) |
|
|
97
|
+
| Repository implementation | snake_case + `_repository_impl.dart` | `holding_repository_impl.dart` (class `HoldingRepositoryImpl`) |
|
|
98
|
+
| Use case file | snake_case + `_usecase.dart` | `get_holding_summary_usecase.dart` (class `GetHoldingSummaryUseCase`) |
|
|
99
|
+
| Model/DTO file | snake_case + `_model.dart` | `holding_summary_model.dart` (class `HoldingSummaryModel`) |
|
|
100
|
+
| Mapper | a `toEntity()` method on the Model, or a top-level `mapTo…` function — see Data Layer Pattern | `HoldingSummaryModel.toEntity()` |
|
|
101
|
+
| Remote data source | snake_case + `_remote_data_source.dart` | `holding_remote_data_source.dart` |
|
|
102
|
+
| Page/widget file | snake_case + `_page.dart` / `_widget.dart` | `holding_detail_page.dart` |
|
|
103
|
+
| Bloc files | snake_case + `_bloc.dart` / `_event.dart` / `_state.dart` | `holding_bloc.dart` |
|
|
104
|
+
| Riverpod provider file (if Riverpod detected) | snake_case + `_provider.dart` | `holding_provider.dart` |
|
|
105
|
+
| DI registration file | snake_case + `_injection.dart` | `holding_injection.dart` |
|
|
106
|
+
| Test file | mirrors source path under `test/`, `_test.dart` suffix | `holding_repository_impl_test.dart` |
|
|
107
|
+
| Loading/state status | a sealed class or enum with explicit named states (`Initial`, `Loading`, `Success`, `Failure`) | never a raw `bool isLoading` on a Bloc/Cubit state |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## DI Pattern — `get_it` Lazy Service Locator (default when nothing else detected)
|
|
112
|
+
|
|
113
|
+
```dart
|
|
114
|
+
// features/[feature_name]/[feature]_injection.dart
|
|
115
|
+
import 'package:get_it/get_it.dart';
|
|
116
|
+
import '../../core/network/dio_client.dart';
|
|
117
|
+
import 'data/datasources/[feature]_remote_data_source.dart';
|
|
118
|
+
import 'data/repositories/[feature]_repository_impl.dart';
|
|
119
|
+
import 'domain/repositories/[feature]_repository.dart';
|
|
120
|
+
import 'domain/usecases/get_[item]_usecase.dart';
|
|
121
|
+
|
|
122
|
+
final sl = GetIt.instance;
|
|
123
|
+
|
|
124
|
+
void init[Feature]Dependencies() {
|
|
125
|
+
sl.registerLazySingleton<[Feature]RemoteDataSource>(
|
|
126
|
+
() => [Feature]RemoteDataSourceImpl(sl<DioClient>()),
|
|
127
|
+
);
|
|
128
|
+
sl.registerLazySingleton<[Feature]Repository>(
|
|
129
|
+
() => [Feature]RepositoryImpl(sl<[Feature]RemoteDataSource>()),
|
|
130
|
+
);
|
|
131
|
+
sl.registerFactory<Get[Item]UseCase>(
|
|
132
|
+
() => Get[Item]UseCase(sl<[Feature]Repository>()),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Call `init[Feature]Dependencies()` once from `app/di/injection_container.dart`'s top-level `init()`,
|
|
138
|
+
which itself runs once in `main()` before `runApp()`.
|
|
139
|
+
|
|
140
|
+
**If Riverpod is detected** in the target repo, do not add `get_it` on top of it — Riverpod's own
|
|
141
|
+
provider graph already serves this role. Express the same wiring as providers instead:
|
|
142
|
+
|
|
143
|
+
```dart
|
|
144
|
+
// features/[feature_name]/domain/repositories/[feature]_repository.dart
|
|
145
|
+
final [feature]RepositoryProvider = Provider<[Feature]Repository>(
|
|
146
|
+
(ref) => [Feature]RepositoryImpl(ref.watch(dioClientProvider)),
|
|
147
|
+
);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Domain Layer Pattern
|
|
151
|
+
|
|
152
|
+
```dart
|
|
153
|
+
// domain/repositories/[feature]_repository.dart
|
|
154
|
+
import '../entities/[item]_entity.dart';
|
|
155
|
+
|
|
156
|
+
abstract class [Feature]Repository {
|
|
157
|
+
Future<[Item]Entity> get[Item]([RequestArgs] args);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// domain/usecases/get_[item]_usecase.dart
|
|
161
|
+
import '../entities/[item]_entity.dart';
|
|
162
|
+
import '../repositories/[feature]_repository.dart';
|
|
163
|
+
|
|
164
|
+
class Get[Item]UseCase {
|
|
165
|
+
final [Feature]Repository repository;
|
|
166
|
+
Get[Item]UseCase(this.repository);
|
|
167
|
+
|
|
168
|
+
Future<[Item]Entity> call([RequestArgs] args) => repository.get[Item](args);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Note the `call()` method convention: Dart classes with a single `call()` method can be invoked like
|
|
173
|
+
a function (`get[Item]UseCase(args)`), which is the idiomatic Flutter clean-architecture equivalent
|
|
174
|
+
of the RN/React `.execute(args)` method name. Use `call()`, not `execute()`, for Flutter use cases.
|
|
175
|
+
|
|
176
|
+
## Data Layer Pattern
|
|
177
|
+
|
|
178
|
+
```dart
|
|
179
|
+
// data/models/[item]_model.dart
|
|
180
|
+
import '../../domain/entities/[item]_entity.dart';
|
|
181
|
+
|
|
182
|
+
class [Item]Model {
|
|
183
|
+
final String id;
|
|
184
|
+
// ...other raw fields exactly as the API returns them
|
|
185
|
+
|
|
186
|
+
[Item]Model({required this.id});
|
|
187
|
+
|
|
188
|
+
factory [Item]Model.fromJson(Map<String, dynamic> json) =>
|
|
189
|
+
[Item]Model(id: json['id'] as String);
|
|
190
|
+
|
|
191
|
+
[Item]Entity toEntity() => [Item]Entity(id: id);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// data/datasources/[feature]_remote_data_source.dart
|
|
195
|
+
import '../../../../core/network/dio_client.dart';
|
|
196
|
+
import '../models/[item]_model.dart';
|
|
197
|
+
|
|
198
|
+
abstract class [Feature]RemoteDataSource {
|
|
199
|
+
Future<[Item]Model> get[Item]([RequestArgs] args);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
class [Feature]RemoteDataSourceImpl implements [Feature]RemoteDataSource {
|
|
203
|
+
final DioClient dioClient;
|
|
204
|
+
[Feature]RemoteDataSourceImpl(this.dioClient);
|
|
205
|
+
|
|
206
|
+
@override
|
|
207
|
+
Future<[Item]Model> get[Item]([RequestArgs] args) async {
|
|
208
|
+
final response = await dioClient.dio.post('/[endpoint]', data: args.toJson());
|
|
209
|
+
return [Item]Model.fromJson(response.data);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// data/repositories/[feature]_repository_impl.dart
|
|
214
|
+
import '../../domain/entities/[item]_entity.dart';
|
|
215
|
+
import '../../domain/repositories/[feature]_repository.dart';
|
|
216
|
+
import '../datasources/[feature]_remote_data_source.dart';
|
|
217
|
+
|
|
218
|
+
class [Feature]RepositoryImpl implements [Feature]Repository {
|
|
219
|
+
final [Feature]RemoteDataSource remoteDataSource;
|
|
220
|
+
[Feature]RepositoryImpl(this.remoteDataSource);
|
|
221
|
+
|
|
222
|
+
@override
|
|
223
|
+
Future<[Item]Entity> get[Item]([RequestArgs] args) async {
|
|
224
|
+
final model = await remoteDataSource.get[Item](args);
|
|
225
|
+
return model.toEntity();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Presentation Layer Pattern — Bloc (default when nothing else detected)
|
|
231
|
+
|
|
232
|
+
```dart
|
|
233
|
+
// presentation/bloc/[feature]_event.dart
|
|
234
|
+
sealed class [Feature]Event {}
|
|
235
|
+
class Fetch[Item]Requested extends [Feature]Event {
|
|
236
|
+
final [RequestArgs] args;
|
|
237
|
+
Fetch[Item]Requested(this.args);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// presentation/bloc/[feature]_state.dart
|
|
241
|
+
sealed class [Feature]State {}
|
|
242
|
+
class [Feature]Initial extends [Feature]State {}
|
|
243
|
+
class [Feature]Loading extends [Feature]State {}
|
|
244
|
+
class [Feature]Success extends [Feature]State {
|
|
245
|
+
final [Item]Entity data;
|
|
246
|
+
[Feature]Success(this.data);
|
|
247
|
+
}
|
|
248
|
+
class [Feature]Failure extends [Feature]State {
|
|
249
|
+
final String message;
|
|
250
|
+
[Feature]Failure(this.message);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// presentation/bloc/[feature]_bloc.dart
|
|
254
|
+
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
255
|
+
import '../../domain/usecases/get_[item]_usecase.dart';
|
|
256
|
+
import '[feature]_event.dart';
|
|
257
|
+
import '[feature]_state.dart';
|
|
258
|
+
|
|
259
|
+
class [Feature]Bloc extends Bloc<[Feature]Event, [Feature]State> {
|
|
260
|
+
final Get[Item]UseCase get[Item]UseCase;
|
|
261
|
+
|
|
262
|
+
[Feature]Bloc(this.get[Item]UseCase) : super([Feature]Initial()) {
|
|
263
|
+
on<Fetch[Item]Requested>((event, emit) async {
|
|
264
|
+
emit([Feature]Loading());
|
|
265
|
+
try {
|
|
266
|
+
final data = await get[Item]UseCase(event.args);
|
|
267
|
+
emit([Feature]Success(data));
|
|
268
|
+
} catch (e) {
|
|
269
|
+
emit([Feature]Failure(e.toString()));
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Widget consumes via `BlocProvider`/`BlocBuilder` — never call the use case or repository directly
|
|
277
|
+
from a widget's `build()` method.
|
|
278
|
+
|
|
279
|
+
**If Riverpod, Provider, or GetX is detected**, use that project's existing pattern instead of Bloc
|
|
280
|
+
— follow the same `presentation/[state-lib-name]/` subfolder convention shown in the folder tree,
|
|
281
|
+
and do not introduce a second state-management library alongside the existing one.
|
|
282
|
+
|
|
283
|
+
## Routing Pattern — `go_router` (default when nothing else detected)
|
|
284
|
+
|
|
285
|
+
```dart
|
|
286
|
+
// app/routing/app_router.dart
|
|
287
|
+
import 'package:go_router/go_router.dart';
|
|
288
|
+
import '../../features/[feature_name]/presentation/pages/[feature]_page.dart';
|
|
289
|
+
|
|
290
|
+
final appRouter = GoRouter(
|
|
291
|
+
routes: [
|
|
292
|
+
GoRoute(
|
|
293
|
+
path: '/[feature]',
|
|
294
|
+
builder: (context, state) => const [Feature]Page(),
|
|
295
|
+
routes: [
|
|
296
|
+
GoRoute(
|
|
297
|
+
path: ':id',
|
|
298
|
+
builder: (context, state) => [Feature]DetailPage(id: state.pathParameters['id']!),
|
|
299
|
+
),
|
|
300
|
+
],
|
|
301
|
+
),
|
|
302
|
+
],
|
|
303
|
+
);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
`app/app.dart` uses `MaterialApp.router(routerConfig: appRouter)`.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Security Rules (mobile-specific — on top of architecture-core.md)
|
|
311
|
+
|
|
312
|
+
1. Tokens and other secrets go in `flutter_secure_storage` (backed by Keychain on iOS, EncryptedSharedPreferences/Keystore on Android) — never `shared_preferences`, which stores plaintext.
|
|
313
|
+
2. Certificate pinning (if required) is configured on the `Dio` client's `HttpClientAdapter` — never disable certificate validation (`badCertificateCallback` returning `true` unconditionally) in production code.
|
|
314
|
+
3. Encryption keys are managed via the platform Keychain/Keystore — never embedded as a Dart string constant.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Anti-Patterns (Flutter/Dart-specific, on top of architecture-core.md)
|
|
319
|
+
|
|
320
|
+
- **Never** call `Dio`/`http` directly from a widget or a Bloc/Cubit event handler — always go through the feature's `[Feature]Repository`.
|
|
321
|
+
- **Never** put business logic inside a widget's `build()` method — it belongs in a use case.
|
|
322
|
+
- **Never** use `dynamic` to avoid modeling a type — use an explicit type or a sealed class.
|
|
323
|
+
- **Never** store tokens or secrets in `shared_preferences` — use `flutter_secure_storage`.
|
|
324
|
+
- **Never** prefix an abstract class with `I` (e.g. `IHoldingRepository`) — Effective Dart forbids
|
|
325
|
+
Hungarian-notation interface prefixes; use the plain name (`HoldingRepository`).
|
|
326
|
+
- **Never** name a use case's entry method `execute()` — Flutter clean-architecture convention uses
|
|
327
|
+
`call()` so the use case is invokable like a function.
|
|
328
|
+
- **Never** rebuild an entire widget subtree when only a small piece of state changed — scope
|
|
329
|
+
`BlocBuilder`/`Consumer`/`Selector` listeners narrowly (`buildWhen`, `select`) instead of wrapping
|
|
330
|
+
the whole page.
|
|
331
|
+
- **Never** mix two state-management libraries in the same feature (e.g. Bloc for one screen,
|
|
332
|
+
Riverpod for another in the same feature) — one feature, one state-management approach.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Worked Example
|
|
337
|
+
|
|
338
|
+
**Request**: "Add a watchlist feature with ability to fetch and display watchlist items."
|
|
339
|
+
|
|
340
|
+
**Artifacts**:
|
|
341
|
+
- Domain: `watchlist_item_entity.dart` → `WatchlistItemEntity`; `watchlist_repository.dart` (abstract) → `WatchlistRepository`; `get_watchlist_usecase.dart` → `GetWatchlistUseCase`
|
|
342
|
+
- Data: `watchlist_item_model.dart`, `watchlist_remote_data_source.dart`, `watchlist_repository_impl.dart`
|
|
343
|
+
- Presentation: `watchlist_bloc.dart`/`_event.dart`/`_state.dart`, `watchlist_page.dart`
|
|
344
|
+
- DI: `watchlist_injection.dart` (get_it)
|
|
345
|
+
|
|
346
|
+
**Output**:
|
|
347
|
+
```
|
|
348
|
+
Created:
|
|
349
|
+
lib/features/watchlist/domain/entities/watchlist_item_entity.dart
|
|
350
|
+
lib/features/watchlist/domain/repositories/watchlist_repository.dart
|
|
351
|
+
lib/features/watchlist/domain/usecases/get_watchlist_usecase.dart
|
|
352
|
+
lib/features/watchlist/data/models/watchlist_item_model.dart
|
|
353
|
+
lib/features/watchlist/data/datasources/watchlist_remote_data_source.dart
|
|
354
|
+
lib/features/watchlist/data/repositories/watchlist_repository_impl.dart
|
|
355
|
+
lib/features/watchlist/presentation/bloc/watchlist_bloc.dart
|
|
356
|
+
lib/features/watchlist/presentation/bloc/watchlist_event.dart
|
|
357
|
+
lib/features/watchlist/presentation/bloc/watchlist_state.dart
|
|
358
|
+
lib/features/watchlist/presentation/pages/watchlist_page.dart
|
|
359
|
+
lib/features/watchlist/watchlist_injection.dart
|
|
360
|
+
|
|
361
|
+
Updated:
|
|
362
|
+
lib/app/di/injection_container.dart (called initWatchlistDependencies())
|
|
363
|
+
lib/app/routing/app_router.dart (added /watchlist route)
|
|
364
|
+
|
|
365
|
+
Dependency check: PASS — no layer boundary violations detected
|
|
366
|
+
```
|