diff --git a/.cursor/rules/agent_rule.mdc b/.cursor/rules/agent_rule.mdc new file mode 100644 index 0000000..40c76db --- /dev/null +++ b/.cursor/rules/agent_rule.mdc @@ -0,0 +1,63 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Architectural rules for a Flutter project using Bloc Cubit +globs: ["**/*.dart"] +alwaysApply: true +--- + +## description: | + You are a senior Flutter engineer working on a modular Flutter project. The codebase follows a layered architecture with the following directory structure: + + - `/app/lib/`: Main application layer (presentation widgets, navigation, routing). + - `/modules/domain/lib/`: Core business logic (entities, services, cubits, states). + - `/modules/data/lib/`: Data access layer (API implementations, repositories, data sources). + - `/modules/common/lib/`: Shared code (constants, themes, helpers, extensions, mixins). + +### Architectural Guidelines: + - The project uses **Bloc/Cubit** for state management and dependency injection. + - Each feature is modularized and follows a clean architecture pattern. + - The UI layer is responsible for rendering the user interface and handling user interactions. + - State management is handled using **Bloc/Cubit**. + - The application uses a Service-based approach for domain logic organization. + - Services (e.g., AuthService) are responsible for entire domain areas and coordinate between repositories and cubits. + - Each functional area has its own Cubit with associated states located under `/modules/domain/lib/bloc/{feature}/`. + - UI for each feature must live in `/app/lib/presentation/ui/pages/{feature}/{feature}_page.dart`. + - Pages can be split into smaller widgets if needed, but keep all within the same feature folder. + - Cubits should not directly communicate with one another. Instead, widgets observe cubits via BlocProvider/BlocBuilder and services coordinate complex operations. + - Always adhere to naming conventions and clean architecture best practices. + +### Agent instructions: | + When given a Jira ticket or feature request: + - First, analyze the provided information to understand the feature requirements. + - Identify the necessary components and files needed to implement the feature. + - Verify if the Jira ticket specified any Figma designs or UI specifications. + - If the Jira ticket does not specify designs, use your expertise to create a clean, functional UI that aligns with the overall project design language. + - If the Jira ticket specified the Figma design, connect to the Figma API to retrieve the design and generate the UI code accordingly. + - Verify the current codebase for existing files that may be reused or extended. + - If the feature requires new files, ensure they are created within the correct modular boundaries. + - Generate all necessary Flutter code files required to implement the described feature. + - For each file, output: + - The **full file path** + - The **complete Dart code**, fully functional and following best practices. + - Mandatory files for each feature: + - `/app/lib/presentation/ui/pages/{feature}/{feature}_page.dart`: UI and widgets. + - `/modules/domain/lib/bloc/{feature}/{feature}_cubit.dart`: Cubit for state management. + - `/modules/domain/lib/bloc/{feature}/{feature}_state.dart`: State classes for the Cubit. + - `/modules/domain/lib/services/{Feature}_service.dart`: Service class if needed. + - Additional files (e.g., models, repository interfaces or implementations) **only if required** by the feature and placed in: + - `/modules/domain/lib/` + - `/modules/data/lib/` + - Never create files or code outside the specified modular boundaries. + + - Add clear code comments throughout. + - Insert `// TODO:` comments wherever information is missing, ambiguous, or requires clarification. + - If Jira includes code-related comments or specific implementation notes, **honor and implement them**. + - Use idiomatic Flutter and Bloc/Cubit patterns, clean architecture principles, and ensure code is maintainable and modular. + +### output_format: | + - For each file: + - Print the full path (e.g., `/app/lib/presentation/ui/pages/login/login_page.dart`) diff --git a/.cursor/rules/data_management.mdc b/.cursor/rules/data_management.mdc new file mode 100644 index 0000000..7e74c8b --- /dev/null +++ b/.cursor/rules/data_management.mdc @@ -0,0 +1,17 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Rules for data handling and entity parsing in the data module +globs: ["modules/data/**/*.dart"] +alwaysApply: true +--- + +- This module is responsible exclusively for data handling and creation (Data Sources, DTOs, and Entities). +- Entities created here should only handle JSON parsing. +- Each `Entity` must have a corresponding model in the `domain` module. +- Class names must end with `Entity`. Example: `NotificationEntity`. +- The corresponding file must follow snake_case formatting: `notification_entity.dart`. +- For fields like `price` that may come as `int`, `double`, or `String`, use the helper `parseFlexibleNumber(dynamic value)` to avoid type-related errors. \ No newline at end of file diff --git a/.cursor/rules/flutter_architecture.mdc b/.cursor/rules/flutter_architecture.mdc new file mode 100644 index 0000000..8e74b2c --- /dev/null +++ b/.cursor/rules/flutter_architecture.mdc @@ -0,0 +1,98 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Architectural rules for a Flutter project using Bloc Cubit +globs: ["**/*.dart"] +alwaysApply: true +--- + +# Flutter Project Coding Standards + +## Project Structure & Architecture + +Follow a strict modular architecture: + +- `/app/lib/`: Presentation layer (screens, widgets, routes). +- `/modules/domain/lib/`: Core business logic (services, cubits, abstract repositories, models). +- `/modules/data/lib/`: Data access (API clients, DTOs, data sources, and `Entity` classes). +- `/modules/common/lib/`: Shared utilities, themes, constants, and mixins. + +### Service & Cubit Communication + +- Cubits **must not** communicate directly with one another. +- Services coordinate between repositories and cubits for complex operations. +- Widgets are responsible for observing their respective cubit's state via BlocProvider/BlocBuilder and triggering actions as needed. + +--- + +## Naming Conventions + +- **PascalCase** for class names, enums, and type aliases. +- **camelCase** for variables, functions, and parameters. +- Prefix **private members** with an underscore `_`. +- Use **ALL_CAPS** for constants (e.g., `const MAX_ITEMS = 10;`). +- **File names** must follow **snake_case** (e.g., `user_profile_cubit.dart`). +- **Cubit files** must end with `_cubit.dart` and state files with `_state.dart`. +- **Service files** must use PascalCase followed by `Service.dart` (e.g., `AuthService.dart`). +- **Widget files** must end with `_page.dart` or `_widget.dart` depending on scope. + +--- + +## Data Module Guidelines + +The `/modules/data/lib/` folder is exclusively for data handling: + +- Data sources (API, DB) +- DTOs +- `Entity` classes + +### Entity Standards + +- Each entity class must end with `Entity`, e.g., `UserEntity`. +- File names for entities must be snake_case: `user_entity.dart`. +- Entities must implement **JSON parsing logic only**. +- For fields like `price` or `amount` that may come as `int`, `double`, or `String`, use: + +```dart +num parseFlexibleNumber(dynamic value) { + if (value is num) return value; + return num.tryParse(value.toString()) ?? 0; +} +``` + +### Mapping + +- Each `Entity` must have a corresponding domain `Model` in `/modules/domain/lib/` used in business logic. + +--- + +## Error Handling + +- Use `try/catch` for all asynchronous operations. +- Always log errors with contextual information using `debugPrint`, `log`, or your logging utility. +- Avoid silently swallowing errors. +- Prefer using custom error types (`AppException`, `NetworkException`, etc.) in repositories or use cases. + +--- + +## State Management (Bloc/Cubit) + +- Use **Bloc/Cubit** for state management across all features. +- Each feature must have its own cubit under `/modules/domain/lib/bloc/{feature}/`. +- Each cubit must have corresponding state classes in `/modules/domain/lib/bloc/{feature}/`. +- Services coordinate between repositories and cubits, located under `/modules/domain/lib/services/`. +- Avoid shared/global cubits unless absolutely necessary. +- Cubits manage the complete screen state through state transitions. +- Use `BlocProvider`, `BlocBuilder`, `BlocListener`, or `BlocConsumer` to react to state changes in widgets. + +--- + +## TODOs and Comments + +- Use `// TODO:` for areas where logic is incomplete or unclear. +- Use `// FIXME:` for known bugs, temporary workarounds, or technical debt. + +--- diff --git a/.github/instructions/copilot-agent.instructions.md b/.github/instructions/copilot-agent.instructions.md new file mode 100644 index 0000000..0344af9 --- /dev/null +++ b/.github/instructions/copilot-agent.instructions.md @@ -0,0 +1,56 @@ +--- +applyTo: "app/lib/**/*.dart, modules/data/lib/**/*.dart, modules/domain/lib/**/*.dart, modules/common/lib/**/*.dart" +--- + +## description: | + You are a senior Flutter engineer working on a modular Flutter project. The codebase follows a layered architecture with the following directory structure: + + - `/app/lib/`: Main application layer (presentation widgets, navigation, routing). + - `/modules/domain/lib/`: Core business logic (entities, services, cubits, states). + - `/modules/data/lib/`: Data access layer (API implementations, repositories, data sources). + - `/modules/common/lib/`: Shared code (constants, themes, helpers, extensions, mixins). + +### Architectural Guidelines: + - The project uses **Bloc/Cubit** for state management and dependency injection. + - Each feature is modularized and follows a clean architecture pattern. + - The UI layer is responsible for rendering the user interface and handling user interactions. + - State management is handled using **Bloc/Cubit**. + - The application uses a Service-based approach for domain logic organization. + - Services (e.g., AuthService) are responsible for entire domain areas and coordinate between repositories and cubits. + - Each functional area has its own Cubit with associated states located under `/modules/domain/lib/bloc/{feature}/`. + - UI for each feature must live in `/app/lib/presentation/ui/pages/{feature}/{feature}_page.dart`. + - Pages can be split into smaller widgets if needed, but keep all within the same feature folder. + - Cubits should not directly communicate with one another. Instead, widgets observe cubits via BlocProvider/BlocBuilder and services coordinate complex operations. + - Always adhere to naming conventions and clean architecture best practices. + +### Copilot instructions: | + When given a Jira ticket or feature request: + - First, analyze the provided information to understand the feature requirements. + - Identify the necessary components and files needed to implement the feature. + - Verify if the Jira ticket specified any Figma designs or UI specifications. + - If the Jira ticket does not specify designs, use your expertise to create a clean, functional UI that aligns with the overall project design language. + - If the Jira ticket specified the Figma design, connect to the Figma API to retrieve the design and generate the UI code accordingly. + - Verify the current codebase for existing files that may be reused or extended. + - If the feature requires new files, ensure they are created within the correct modular boundaries. + - Generate all necessary Flutter code files required to implement the described feature. + - For each file, output: + - The **full file path** + - The **complete Dart code**, fully functional and following best practices. + - Mandatory files for each feature: + - `/app/lib/presentation/ui/pages/{feature}/{feature}_page.dart`: UI and widgets. + - `/modules/domain/lib/bloc/{feature}/{feature}_cubit.dart`: Cubit for state management. + - `/modules/domain/lib/bloc/{feature}/{feature}_state.dart`: State classes for the Cubit. + - `/modules/domain/lib/services/{Feature}_service.dart`: Service class if needed. + - Additional files (e.g., models, repository interfaces or implementations) **only if required** by the feature and placed in: + - `/modules/domain/lib/` + - `/modules/data/lib/` + - Never create files or code outside the specified modular boundaries. + + - Add clear code comments throughout. + - Insert `// TODO:` comments wherever information is missing, ambiguous, or requires clarification. + - If Jira includes code-related comments or specific implementation notes, **honor and implement them**. + - Use idiomatic Flutter and Bloc/Cubit patterns, clean architecture principles, and ensure code is maintainable and modular. + +### output_format: | + - For each file: + - Print the full path (e.g., `/app/lib/presentation/ui/pages/login/login_page.dart`) diff --git a/.github/instructions/flutter.instructions.md b/.github/instructions/flutter.instructions.md new file mode 100644 index 0000000..eedc5aa --- /dev/null +++ b/.github/instructions/flutter.instructions.md @@ -0,0 +1,91 @@ +--- +applyTo: "app/lib/**/*.dart, modules/data/lib/**/*.dart, modules/domain/lib/**/*.dart, modules/common/lib/**/*.dart" +--- + +# Flutter Project Coding Standards + +## Project Structure & Architecture + +Follow a strict modular architecture: + +- `/app/lib/`: Presentation layer (screens, widgets, routes). +- `/modules/domain/lib/`: Core business logic (services, cubits, abstract repositories, models). +- `/modules/data/lib/`: Data access (API clients, DTOs, data sources, and `Entity` classes). +- `/modules/common/lib/`: Shared utilities, themes, constants, and mixins. + +### Service & Cubit Communication + +- Cubits **must not** communicate directly with one another. +- Services coordinate between repositories and cubits for complex operations. +- Widgets are responsible for observing their respective cubit's state via BlocProvider/BlocBuilder and triggering actions as needed. + +--- + +## Naming Conventions + +- **PascalCase** for class names, enums, and type aliases. +- **camelCase** for variables, functions, and parameters. +- Prefix **private members** with an underscore `_`. +- Use **ALL_CAPS** for constants (e.g., `const MAX_ITEMS = 10;`). +- **File names** must follow **snake_case** (e.g., `user_profile_cubit.dart`). +- **Cubit files** must end with `_cubit.dart` and state files with `_state.dart`. +- **Service files** must use PascalCase followed by `Service.dart` (e.g., `AuthService.dart`). +- **Widget files** must end with `_page.dart` or `_widget.dart` depending on scope. + +--- + +## Data Module Guidelines + +The `/modules/data/lib/` folder is exclusively for data handling: + +- Data sources (API, DB) +- DTOs +- `Entity` classes + +### Entity Standards + +- Each entity class must end with `Entity`, e.g., `UserEntity`. +- File names for entities must be snake_case: `user_entity.dart`. +- Entities must implement **JSON parsing logic only**. +- For fields like `price` or `amount` that may come as `int`, `double`, or `String`, use: + +```dart +num parseFlexibleNumber(dynamic value) { + if (value is num) return value; + return num.tryParse(value.toString()) ?? 0; +} +``` + +### Mapping + +- Each `Entity` must have a corresponding domain `Model` in `/modules/domain/lib/` used in business logic. + +--- + +## Error Handling + +- Use `try/catch` for all asynchronous operations. +- Always log errors with contextual information using `debugPrint`, `log`, or your logging utility. +- Avoid silently swallowing errors. +- Prefer using custom error types (`AppException`, `NetworkException`, etc.) in repositories or use cases. + +--- + +## State Management (Bloc/Cubit) + +- Use **Bloc/Cubit** for state management across all features. +- Each feature must have its own cubit under `/modules/domain/lib/bloc/{feature}/`. +- Each cubit must have corresponding state classes in `/modules/domain/lib/bloc/{feature}/`. +- Services coordinate between repositories and cubits, located under `/modules/domain/lib/services/`. +- Avoid shared/global cubits unless absolutely necessary. +- Cubits manage the complete screen state through state transitions. +- Use `BlocProvider`, `BlocBuilder`, `BlocListener`, or `BlocConsumer` to react to state changes in widgets. + +--- + +## TODOs and Comments + +- Use `// TODO:` for areas where logic is incomplete or unclear. +- Use `// FIXME:` for known bugs, temporary workarounds, or technical debt. + +--- diff --git a/app/lib/main/env/env_config.dart b/app/lib/main/env/env_config.dart index 4154899..0885446 100644 --- a/app/lib/main/env/env_config.dart +++ b/app/lib/main/env/env_config.dart @@ -1,4 +1,30 @@ -enum Flavor { dev, qa, prod } +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +enum Flavor { + dev, + qa, + prod; + + static Flavor fromString(String value) { + return Flavor.values.firstWhere( + (flavor) => flavor.name == value, + orElse: () => Flavor.dev, + ); + } +} + +class Environment { + static String get clientSecret => dotenv.env['SECRET_KEY'] ?? ''; + + static String? get portalUrl => dotenv.env['API_URL']; + + static String get envName => const String.fromEnvironment( + 'ENV', + defaultValue: 'dev', + ); + + static String get envConfigFile => 'env/.$envName'; +} class FlavorValues { final String baseUrl; diff --git a/app/lib/main/init.dart b/app/lib/main/init.dart index cd7eb36..cfb618d 100644 --- a/app/lib/main/init.dart +++ b/app/lib/main/init.dart @@ -1,10 +1,12 @@ import 'package:app/main/app.dart'; +import 'package:app/main/env/env_config.dart'; import 'package:common/init.dart'; import 'package:data/init.dart'; import 'package:domain/init.dart'; import 'package:example_domain/init.dart'; import 'package:example_data/init.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get_it/get_it.dart'; import 'package:url_strategy/url_strategy.dart'; @@ -18,6 +20,8 @@ void init() async { final getIt = GetIt.instance; Future initialize() async { + await dotenv.load(fileName: Environment.envConfigFile); + await CommonInit.initialize(getIt); await DataInit.initialize(getIt); await DomainInit.initialize(getIt); diff --git a/app/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..e71a16d --- /dev/null +++ b/app/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/app/linux/flutter/generated_plugin_registrant.h b/app/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/app/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..2e1de87 --- /dev/null +++ b/app/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 0f7943f..a405a88 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -59,6 +59,7 @@ dependencies: http: ^0.13.6 melos: ^3.4.0 dev: ^1.0.0 + flutter_dotenv: ^5.2.1 dev_dependencies: bloc_test: ^9.0.2