All authors

Claude Skills by HoangNguyen0403
github.com/HoangNguyen04031,434 skills30 installs1,975 views
- Common Web Visual TestingAssumption: a Before capture and the fixed build are available at the same header route. Verification: 1. **Before**: capture `playwright-cli snapshot --aria` and a screenshot at desktop, 375px mobile, and 768px tablet. 2. **After**: repeat the same captures on the fixed build. 3. Compare the dropdown border in each viewport: - Border is visible, continuous, and aligned with the dropdown. - No color, thickness, radius, clipping, or z-index regression. - No neighboring-element movement or layo...Votes: 0GitHub stars: 549
- Common Web Visual TestingMask the dynamic clock in visual tests. ```bash playwright-cli screenshot --mask="header .clock" ``` Or hide it only during the screenshot: ```js await page.locator('header .clock').evaluate(el => { el.style.opacity = '0'; }); ``` Then verify comparatively: 1. **Before**: capture `snapshot --aria` and screenshot from prod/main. 2. **After**: capture the same from the fixed branch. 3. Compare the diff and check neighboring header elements for layout shift or accidental masking. 4. Repeat at mo...Votes: 0GitHub stars: 549
- Common Workflow WritingThe request should be rewritten as a compact workflow, not a detailed walkthrough with examples. Goal: Complete a code review and return clear findings with severity, evidence, and decision. Steps - Gather context: collect PR description, changed files, related requirements, and test evidence. - Inspect risk areas: review correctness, security, performance, maintainability, and test coverage. - Validate claims: check whether changed behavior is supported by code, tests, or linked evidence. - ...Votes: 0GitHub stars: 549
- Common Workflow WritingThose explanation paragraphs should be removed. Why: the workflow-writing standard says steps should be imperative and compact. If a bullet or command does the job, prose preambles are excess. Use this structure instead: Goal: State the outcome in one sentence. Steps - Use an action verb for each step. - Keep each step to the command, check, or decision the agent must perform. - Merge steps that always happen together. - Move deep rationale to a reference file only if it is truly needed. Outp...Votes: 0GitHub stars: 549
- Common Workflow WritingDo not keep a 15-line inline code block in `SKILL.md`. Per the standard, inline code blocks must stay at 10 lines or fewer. Update it like this: - Replace the long inline example with a short template or minimal snippet. - Move the full 15-line configuration example into a `references/` file. - Keep `SKILL.md` focused on the rule, trigger, and usage pattern. Recommended rewrite pattern: ```md Use this configuration shape: ```yaml key: <value> section: nested_key: <value> ``` Full example: `re...Votes: 0GitHub stars: 549
- Common Workflow WritingGoal: Report feature delivery status and the exact verification blocker when runtime access is unavailable. Steps - Gather implementation evidence: changed files, tests run, build results, and linked requirement IDs. - Attempt verification: run available checks and note which runtime-dependent checks could not execute. - Classify status: set `feature_status` to `verified`, `partially_verified`, `blocked`, or `not_started`. - Record blocker truth: name the missing runtime access, blocked check...Votes: 0GitHub stars: 549
- Dart Best PracticesYes. The main fixes are: - remove top-level mutable globals - prefer `const` and `final` over `var` - use tear-offs when the lambda only forwards its argument - keep naming consistent with Effective Dart - `await` async work unless fire-and-forget is intentional A good refactor usually looks like this: ```dart class UserFormatter { const UserFormatter(); String formatName(User user) => user.name.trim(); List<String> formatAll(List<User> users) => users.map(formatName).toList(); } ``` Instead ...Votes: 0GitHub stars: 549
- Dart Best PracticesYes, often you can make it more idiomatic Dart. If the loop is only: - filtering items - transforming them - collecting the result then a pipeline with `where`, `map`, and `toList` is usually clearer than manually pushing into a list. For example, instead of: ```dart List<String> activeNames(List<User> users) { final result = <String>[]; for (final user in users) { if (user.isActive) { result.add(user.name.trim()); } } return result; } ``` prefer: ```dart List<String> activeNames(List<User> u...Votes: 0GitHub stars: 549
- Dart Best PracticesUsually no — if those files are inside the same Dart package, prefer relative imports instead of `package:myapp/...` imports. Example: ```dart import '../models/user.dart'; import 'formatters.dart'; ``` Prefer that over: ```dart import 'package:myapp/models/user.dart'; import 'package:myapp/utils/formatters.dart'; ``` Why: - relative imports make it obvious the dependency is local to the same package - they avoid mixing external-style and internal-style imports - they match the style rule: do...Votes: 0GitHub stars: 549
- Dart LanguageUse a Dart record. For a lightweight “success value + error message” return without introducing a custom class, the modern Dart 3 approach is to return a record and destructure it at the call site. Prefer named fields when the meaning of each value matters. Example: ```dart (String? data, String? error) parseUsername(String input) { if (input.trim().isEmpty) { return (data: null, error: 'Username cannot be empty'); } return (data: input.trim(), error: null); } void main() { final (:data, :err...Votes: 0GitHub stars: 549
- Dart LanguageMake the base type a `sealed class`, then switch on it using pattern matching. In Dart, `sealed` tells the compiler that all subclasses must be known within the same library. That lets a `switch` become exhaustiveness-checked: if you forget one subtype, the compiler can flag it. Example: ```dart sealed class Result {} final class Success extends Result { const Success(this.value); final String value; } final class Failure extends Result { const Failure(this.message); final String message; } S...Votes: 0GitHub stars: 549
- Dart LanguageThe safer approach is to stop force-unwrapping and make the null case explicit in your control flow. In modern Dart, `!` should be the exception, not the default. Prefer one of these patterns instead: 1. Guard early with an `if` ```dart void greet(String? name) { if (name == null) { print('Missing name'); return; } print('Hello, $name'); } ``` 2. Use `??` for a fallback value ```dart String displayName(String? name) => name ?? 'Guest'; ``` 3. Use `?.` when accessing members on a nullable valu...Votes: 0GitHub stars: 549
- Dart ToolingUse `analysis_options.yaml` as the single source of truth for linting and analyzer behavior, and add `dart_code_metrics` so complexity checks run alongside normal analysis. Example setup: ```yaml analyzer: errors: missing_required_param: error todo: ignore linter: rules: - prefer_single_quotes - require_trailing_commas - always_use_package_imports - unawaited_futures ``` Then add `dart_code_metrics` to `dev_dependencies` and configure it so complexity violations are visible in CI and local ch...Votes: 0GitHub stars: 549
- Dart ToolingThe fix is to run code generation with `--delete-conflicting-outputs`. Use: ```bash dart run build_runner build --delete-conflicting-outputs ``` Or for Flutter projects: ```bash flutter pub run build_runner build --delete-conflicting-outputs ``` Why this happens: - `build_runner` found generated files such as `.g.dart` outputs that no longer match the current builder state. - This usually comes from renamed models, changed annotations, switching branches, or previously generated artifacts lef...Votes: 0GitHub stars: 549
- Dart ToolingSet up `lefthook` so every commit runs formatting first and analysis second. That blocks unformatted or analyzer-broken Dart code before it ever reaches a PR. Example `lefthook.yml`: ```yaml pre-commit: parallel: false commands: dart-format: run: dart format . --line-length 80 flutter-analyze: run: flutter analyze --fatal-infos --fatal-warnings ``` Why this shape is good: - `dart format . --line-length 80` enforces the project formatting standard automatically. - `flutter analyze --fatal-info...Votes: 0GitHub stars: 549
- Database MigrationsDo not do a one-shot `RENAME COLUMN` on a busy `orders` table. Use an expand -> backfill -> contract rollout so old and new code paths can safely coexist. Recommended plan: 1. Expand - Add a new nullable column: `lifecycle_status`. - If queries filter on status, add the matching index for `lifecycle_status` before cutover. - Deploy this schema change first so nothing breaks while application code is still using `status`. 2. Dual-write - Update application writes so any create/update of an ord...Votes: 0GitHub stars: 549
- Database MongodbDesign it from the read path first: - If posts are read with only a small, bounded preview of comments, keep `posts` and `comments` in separate collections and optionally embed a tiny cached summary on the post document. - Do not embed all comments directly inside the post if each post can accumulate many comments over time. That creates an unbounded array, larger documents, slower writes, and eventually document-size pressure. A practical schema is: ```js // posts { _id: ObjectId, authorId: ...Votes: 0GitHub stars: 549
- Database MongodbStart with `explain()`, not guesswork. A query can still be slow with “an index present” if the index does not match the actual filter and sort pattern, if it scans too many keys, or if MongoDB still has to fetch too many documents. Use this process: 1. Capture the exact query shape - filter - sort - projection - limit - skip Example: ```js db.orders .find({ customerId: 123, status: "paid", createdAt: { $gte: someDate } }) .sort({ createdAt: -1 }) .project({ total: 1, createdAt: 1, status: 1 ...Votes: 0GitHub stars: 549
- Database MongodbUse cursor-based pagination, not deep `skip()`. Why: - `skip(n)` gets slower as `n` grows because MongoDB still has to walk past earlier results. - Cursor pagination uses an indexed boundary from the last seen row, so each next page stays efficient even on large collections. Recommended pattern Choose a stable sort, usually: - `createdAt` - plus `_id` as a tiebreaker Create an index that matches the query: ```js db.posts.createIndex({ createdAt: -1, _id: -1 }) ``` First page: ```js db.posts ....Votes: 0GitHub stars: 549
- Database PostgresqlUse an expand -> backfill -> contract rollout. In PostgreSQL, the safe pattern is to make the schema change non-breaking first, deploy code that can handle both old and new states, backfill gradually, then remove the old path only after production traffic is fully moved. Recommended sequence: 1. Expand the schema with a backward-compatible change. - Add the new column as nullable, or with a default that does not force a risky table rewrite on your PostgreSQL version and table shape. - Do not ...Votes: 0GitHub stars: 549
- Database PostgresqlPrevent N+1 in TypeORM by shaping queries up front instead of lazily loading relations inside loops. The core rule is: fetch the data you know you need in one intentional query or a small fixed number of queries, not one extra query per row. Good approaches: 1. Use `leftJoinAndSelect` or `innerJoinAndSelect` for relations you need immediately. ```ts const users = await dataSource .getRepository(User) .createQueryBuilder('user') .leftJoinAndSelect('user.posts', 'post') .where('user.org_id = :o...Votes: 0GitHub stars: 549
- Database PostgresqlImplement Row Level Security by making the database enforce tenant or actor visibility, while the application sets the request context explicitly for each transaction or connection scope. Keep the RLS predicate simple, index-supported, and aligned with real read/write paths. Recommended design: 1. Put the tenant or ownership column directly on the protected table. - Example: `tenant_id uuid not null` - Simpler predicates perform better than policies that depend on heavy joins. 2. Enable RLS o...Votes: 0GitHub stars: 549
- Database Query PerformanceNot yet. Do not add “another index” until you know the exact query shape and access path. Start with evidence: - capture the exact SQL (or ORM-generated SQL), - include real filter parameters, - check how the list is sorted and paginated, - run `EXPLAIN` or `EXPLAIN ANALYZE`. That tells you whether the slowdown is actually caused by: - a full table scan, - an inefficient sort, - a bad join order, - missing index coverage, - offset pagination scanning too deeply, - or an N+1 fetch pattern arou...Votes: 0GitHub stars: 549
- Database RedisFor a multi-tenant Redis design, make the key name encode tenant, domain, entity, and purpose so ownership and invalidation scope are obvious at a glance. A good default pattern is: `<product>:tenant:<tenantId>:<domain>:<entity>:<identifier>[:<variant>]` Examples: - `app:tenant:t_42:user-profile:user:123` - `app:tenant:t_42:catalog:product:987:summary` - `app:tenant:t_42:rate-limit:api-key:abc123` Why this shape works: - It prevents tenant collisions. - It makes bulk reasoning safer because t...Votes: 0GitHub stars: 549
- Database RedisDo not use `KEYS <pattern>` followed by mass `DEL`. That approach is blocking and can hurt Redis latency badly. The safe pattern is: 1. Iterate with `SCAN` 2. Delete in batches 3. Prefer `UNLINK` over `DEL` so memory reclamation happens in the background Why: - `SCAN` is cursor-based and does not block Redis like `KEYS` does. - `UNLINK` is better for large values or large delete waves because it avoids synchronous freeing cost on the main thread. Example with `redis-cli` shell loop: ```bash c...Votes: 0GitHub stars: 549
- Database RedisFor a general-purpose cache, the best default Redis eviction policy is `allkeys-lru`. Why `allkeys-lru` is usually the right choice: - It allows Redis to evict any key when memory is full. - It matches cache-oriented workloads where all cached entries are disposable. - It favors keeping recently used keys in memory, which usually improves hit rate for normal application traffic. Use `allkeys-lru` when: - Redis is being used mainly as a cache - Cached data can be recomputed or reloaded from a ...Votes: 0GitHub stars: 549
- Database Schema DesignStart from the hot reads and ownership model: - A ticket detail page needs: ticket fields, ordered comments, attachment list, and recent audit history. - A write path needs: add comment, upload attachment, update ticket status/assignee/priority, and record every material change in audit history. - Ownership should be explicit: tickets own comments and attachments; audit history records changes against a ticket and optionally against a child record. Recommended relational shape 1. `tickets` - ...Votes: 0GitHub stars: 549
- Database TransactionsTreat this as one business action with two different consistency zones: 1. the atomic part: create the order record and reserve inventory 2. the eventual part: publish the event The key transaction question is whether inventory reservation is part of the same correctness rule as order creation. If an order must never exist without a matching inventory hold, those two writes belong in one short database transaction. If they succeed or fail together, you avoid a mixed atomicity story where the ...Votes: 0GitHub stars: 549
- Flutter Auto Route NavigationUse an `AutoRouteGuard` on the cart route so the routing layer, not the UI, enforces authentication. In `auto_route`, the guard can check auth state and redirect unauthenticated users to `LoginRoute()`. ```dart import 'package:auto_route/auto_route.dart'; class AuthGuard extends AutoRouteGuard { final AuthService authService; AuthGuard(this.authService); @override void onNavigation(NavigationResolver resolver, StackRouter router) { final isLoggedIn = authService.isLoggedIn; if (isLoggedIn) { ...Votes: 0GitHub stars: 549
- Flutter Auto Route NavigationWith `auto_route`, you pass route parameters by defining them on the page constructor and then navigating with the generated typed route class. First, annotate the page and give it an `orderId` parameter: ```dart import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; @RoutePage() class OrderDetailPage extends StatelessWidget { const OrderDetailPage({ super.key, required this.orderId, }); final String orderId; @override Widget build(BuildContext context) { return ...Votes: 0GitHub stars: 549
- Flutter Auto Route NavigationTo preserve tab state with `auto_route`, structure the bottom bar as nested routes under a parent tabs route. That lets each tab keep its own navigation stack and widget tree alive instead of rebuilding from scratch on every tab switch. A typical setup looks like this: ```dart @RoutePage() class HomeTabsPage extends StatelessWidget { const HomeTabsPage({super.key}); @override Widget build(BuildContext context) { return AutoTabsScaffold( routes: const [ FeedRoute(), OrdersRoute(), ProfileRoute...Votes: 0GitHub stars: 549
- Flutter Bloc State ManagementAssumption: `ProductRepository.search` accepts a Dio `CancelToken`. ```dart import 'package:bloc/bloc.dart'; import 'package:bloc_concurrency/bloc_concurrency.dart'; import 'package:dio/dio.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'product_search_bloc.freezed.dart'; @freezed sealed class ProductSearchEvent with _$ProductSearchEvent { const factory ProductSearchEvent.queryChanged(String query) = QueryChanged; } @freezed sealed class ProductSearchState with _$Pro...Votes: 0GitHub stars: 549
- Flutter Bloc State ManagementAssumption: the app uses `flutter_bloc`, `freezed`, and an `OrderRepository.fetchOrders()` API method. ```dart // orders_event.dart @freezed sealed class OrdersEvent with _$OrdersEvent { const factory OrdersEvent.started() = _Started; const factory OrdersEvent.retryRequested() = _RetryRequested; } ``` ```dart // orders_state.dart @freezed sealed class OrdersState with _$OrdersState { const factory OrdersState.initial() = _Initial; const factory OrdersState.loading() = _Loading; const factory ...Votes: 0GitHub stars: 549
- Flutter Bloc State Management`emit()` is not a `Future`, and BLoC state must be emitted inside an `on<Event>` handler. ```dart sealed class CounterEvent {} final class CounterIncremented extends CounterEvent {} class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0) { on<CounterIncremented>((event, emit) { emit(state + 1); print('done'); }); } void increment() => add(CounterIncremented()); } ``` Remove `.then()`. If the handler performs asynchronous work, use `async`/`await` before calling `emit()`.Votes: 0GitHub stars: 549
- Flutter CicdA good PR workflow for Flutter should fail fast, cache the expensive parts, and produce the Android artifact only after analysis and tests pass. For pull requests, I would structure it in this order: 1. Check out the repo. 2. Install a stable Flutter SDK. 3. Cache Pub packages and Gradle state. 4. Run formatting/analyze checks first. 5. Run tests. 6. Build the Android App Bundle (`.aab`). 7. Upload the build artifact so reviewers can inspect or reuse it. Example GitHub Actions workflow: ```ya...Votes: 0GitHub stars: 549
- Flutter CicdIf Flutter CI is taking 45 minutes and timing out, the usual fix is not one change but a pipeline redesign around fail-fast execution, caching, and job separation. The biggest improvements typically come from these steps: 1. Run cheap checks first. Put `dart format` and `flutter analyze` before tests and builds. If code quality fails, the workflow should stop before spending time compiling Android or running long test suites. 2. Set explicit job timeouts. Add `timeout-minutes` to every job. T...Votes: 0GitHub stars: 549
- Flutter CicdDo not commit the Play Store signing keystore to the repository. In GitHub Actions, the standard pattern is to store the keystore as an encrypted GitHub secret, recreate it during the workflow, and inject the signing passwords through secrets as well. Recommended approach: 1. Base64-encode the keystore locally. 2. Save the encoded value in GitHub Secrets. 3. Save the alias, store password, and key password as separate GitHub Secrets. 4. In the workflow, decode the secret back into a temporary...Votes: 0GitHub stars: 549
- Flutter ConcurrencyYour app is freezing because large JSON parsing is CPU-bound work, and by default that work runs on Flutter's main isolate. When the main isolate spends too long decoding JSON, it blocks the event loop and the UI cannot paint frames, which shows up as jank or a full freeze. The fix is to move the parsing work off the main isolate. For a one-off heavy computation like decoding a large JSON payload, `Isolate.run()` is the right choice. Use this shape: ```dart import 'dart:convert'; import 'dart...Votes: 0GitHub stars: 549
- Flutter ConcurrencyUse the choice based on what kind of work you are doing and how long it lives: | Situation | Best tool | | --- | --- | | Waiting on network, disk, database, or other I/O | `async` / `await` | | Small CPU work that finishes quickly and will not block a frame | stay on main isolate, optionally with `async` structure | | One-off heavy CPU work | `Isolate.run()` | | Repeated or continuous background processing with message passing | `Isolate.spawn()` | The key distinction is: - `async`/`await` is...Votes: 0GitHub stars: 549
- Flutter ConcurrencyWhat is wrong is that your `FutureBuilder` is probably receiving a newly created `Future` every time `build()` runs. `FutureBuilder` does not cache the computation for you. It listens to the `Future` instance you pass in. If you do this inside `build()`: ```dart FutureBuilder<String>( future: fetchData(), builder: ... ) ``` then every rebuild creates a brand new future, so the async work starts again. Rebuilds can happen for many normal reasons: parent updates, theme changes, `setState`, inhe...Votes: 0GitHub stars: 549
- Flutter Dependency InjectionRegister it in three layers, following the skill’s DI rules: 1. Put third-party dependencies like `Dio` and Hive objects behind an `@module` 2. Register the repository as a `@LazySingleton`, because repositories should usually be shared and initialized on demand 3. Inject the repository through its abstraction, not the concrete class Example: ```dart import 'package:dio/dio.dart'; import 'package:hive/hive.dart'; import 'package:injectable/injectable.dart'; abstract class IOrderRepository { F...Votes: 0GitHub stars: 549
- Flutter Dependency InjectionThis usually means `CartBloc` was registered with too long a lifetime. Per the skill, BLoCs should be factories, not singletons, so they start with fresh state every time the screen creates them. The fix is: 1. Register `CartBloc` with `@injectable` so injectable treats it as a factory 2. Do not use `@Singleton()` or `@LazySingleton()` for a BLoC 3. Create the bloc at the page/route level so it is disposed when the page is removed Example registration: ```dart import 'package:injectable/injec...Votes: 0GitHub stars: 549
- Flutter Dependency InjectionThe simplest approach is to replace the `AuthRepository` registration in `GetIt` before you pump the widget, then reset the locator after the test. That matches the skill’s test-mock swap pattern. If production code looks like this: ```dart abstract class IAuthRepository { Future<bool> isLoggedIn(); } @LazySingleton(as: IAuthRepository) class AuthRepository implements IAuthRepository { @override Future<bool> isLoggedIn() async => true; } ``` Then your widget test can override it with a mock: ...Votes: 0GitHub stars: 549
- Flutter Design SystemAssuming the checkout screen uses a theme-driven Flutter DLS with `VButton`, `VColors`, and `VSpacing`: ```dart VButton( label: 'Confirm', onPressed: _confirmCheckout, backgroundColor: VColors.error, foregroundColor: VColors.onError, textStyle: Theme.of(context).textTheme.labelLarge, // configured to 16px ) ``` Add it with tokenized spacing: ```dart Column( children: [ // Checkout content SizedBox(height: VSpacing.md), VButton( label: 'Confirm', onPressed: _confirmCheckout, backgroundColor: V...Votes: 0GitHub stars: 549
- Flutter Design SystemUse the design token for 8 px spacing between items: ```dart ListView.separated( itemCount: items.length, separatorBuilder: (_, __) => const SizedBox(height: VSpacing.s8), itemBuilder: (_, index) => buildItem(items[index]), ); ``` Assumption: the project defines `VSpacing.s8` as the 8-pixel token. Avoid a hardcoded `8` magic number.Votes: 0GitHub stars: 549
- Flutter Design SystemAssuming a theme-driven Flutter app, define tokens and apply them through `ThemeData`: ```dart class VTypography { static const sectionHeading = TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ); } class VColors { static const textPrimary = Color(0xFF1A1A1A); } ``` Configure the theme with `VTypography.sectionHeading` and `VColors.textPrimary`, then render: ```dart Text( 'Section heading', style: Theme.of(context).textTheme.headlineSmall, ) ``` Keep `24` and `#1A1A1A` in design tokens—n...Votes: 0GitHub stars: 549
- Flutter Error HandlingHandle it in the infrastructure/repository layer: map the `DioException` with status 401 to a typed `UnauthorizedFailure`, log it using a stable template, and return `Left` rather than throwing. ```dart Future<Either<AuthFailure, User>> getCurrentUser() async { try { final dto = await _api.getCurrentUser(); return Right(dto.toDomain()); } on DioException catch (e, st) { AppLogger.error( 'getCurrentUser request failed', error: e, stackTrace: st, ); if (e.response?.statusCode == 401) { return c...Votes: 0GitHub stars: 549
- Flutter Error HandlingNo. A BLoC should not catch repository exceptions or expose `e.toString()` to users. Repositories should convert infrastructure exceptions into typed `Failure` values and return `Either<Failure, T>`. Consume the result with `fold` instead: ```dart final result = await _loadProfile(); result.fold( (failure) => emit(ProfileError(failure.failureMessage)), (profile) => emit(ProfileLoaded(profile)), ); ``` If a UI/BLoC catch is unavoidable for an unexpected boundary error, route it through `AppLog...Votes: 0GitHub stars: 549
- Flutter Error HandlingDefine a typed, domain-specific `@freezed` failure and expose a localized UI message rather than returning a raw string: ```dart @freezed class ProductFailure with _$ProductFailure { const factory ProductFailure.outOfStock({ required String productName, }) = OutOfStockFailure; } extension ProductFailureMessage on ProductFailure { TRObject get failureMessage => when( outOfStock: (productName) => TR.productOutOfStock(productName: productName), ); } ``` The repository can return `Left(ProductFai...Votes: 0GitHub stars: 549
- Flutter Feature Based Clean ArchitecturePut the feature in a flat directory: ```text lib/features/promotions/ ├── domain/ │ ├── entities/ │ ├── failures/ │ └── repositories/ ├── data/ │ ├── models/ │ ├── datasources/ │ └── repositories/ └── presentation/ ├── bloc/ # or cubit/ ├── pages/ └── widgets/ ``` Use the layers as follows: - `domain/`: promotion entities, failures, and repository interfaces; zero external dependencies. - `data/`: DTOs/models, data sources, and repository implementations; depends only on Do...Votes: 0GitHub stars: 549