All authors

Claude Skills by HoangNguyen0403
github.com/HoangNguyen04031,434 skills30 installs1,975 views
- Flutter Feature Based Clean ArchitectureOrders should consume loyalty through loyalty’s domain layer only. - Define a domain entity such as `LoyaltyPoints` and a domain use case, e.g. `GetLoyaltyPoints`, in `lib/features/loyalty/domain/`. - Inject `GetLoyaltyPoints` into the orders use case/BLoC. - Configure the concrete loyalty data repository through dependency injection at the composition root. ```dart // loyalty/domain/entities/loyalty_points.dart class LoyaltyPoints { final int value; const LoyaltyPoints(this.value); } // loya...Votes: 0GitHub stars: 549
- Flutter Feature Based Clean ArchitectureNo. Put utilities shared across multiple features in `lib/shared/` or `lib/core/`, not `lib/features/shared/`. Keep `lib/features/` flat, with each feature organized as: - `domain/` — entities, failures, repository interfaces - `data/` — DTOs, data sources, implementations - `presentation/` — BLoC/Cubit, pages, widgets Maintain `Presentation -> Domain <- Data`; domain has zero external dependencies. Features may share domain entities, but never import another feature’s data or presentation la...Votes: 0GitHub stars: 549
- Flutter Getx NavigationUse a `GetMiddleware` guard and attach it to every protected `GetPage` in `AppPages`. Keep the login route public, otherwise a redirect to login can recurse. ```dart // app_routes.dart abstract class Routes { static const login = '/login'; static const home = '/home'; static const profile = '/profile'; } class AuthMiddleware extends GetMiddleware { AuthMiddleware(this.authService); final AuthService authService; @override int? get priority => 1; @override RouteSettings? redirect(String? route...Votes: 0GitHub stars: 549
- Flutter Getx NavigationUse `Get.offAllNamed` with the checkout route constant. It removes every existing route from the navigation stack and makes checkout the new root, so the system back action cannot return to the cart. ```dart abstract class Routes { static const cart = '/cart'; static const checkout = '/checkout'; } class CartController extends GetxController { void beginCheckout() { Get.offAllNamed(Routes.checkout); } } ``` Call `beginCheckout()` from the cart screen, such as from the checkout button's `onPre...Votes: 0GitHub stars: 549
- Flutter Getx NavigationDefine a `Bindings` class for the home feature, then assign it to the home `GetPage`. GetX creates the controller when the route is resolved and disposes it when the route is removed, provided it is not registered as permanent or retained by another binding. ```dart // app_routes.dart abstract class Routes { static const home = '/home'; } // home_binding.dart class HomeBinding extends Bindings { @override void dependencies() { Get.lazyPut<HomeController>(() => HomeController()); } } // app_pa...Votes: 0GitHub stars: 549
- Flutter Getx State Management```dart import 'package:get/get.dart'; class UserProfile { const UserProfile({required this.id, required this.name}); final String id; final String name; } abstract class UserRepository { Future<UserProfile> fetchProfile(); } class UserController extends GetxController { UserController(this._repository); final UserRepository _repository; final isLoading = false.obs; final user = Rxn<UserProfile>(); final errorMessage = RxnString(); @override void onInit() { super.onInit(); loadProfile(); } Fu...Votes: 0GitHub stars: 549
- Flutter Getx State ManagementRegister the controller through a Binding with `Get.lazyPut`, then let route ownership determine its lifetime. Do not create it with `Get.put()` inside a widget and do not mark it `permanent: true` merely to share it across screens. ```dart class CheckoutBinding extends Bindings { @override void dependencies() { Get.lazyPut<CheckoutController>(() => CheckoutController()); } } GetPage( name: '/checkout', page: () => const CheckoutView(), binding: CheckoutBinding(), ), ``` All checkout screens ...Votes: 0GitHub stars: 549
- Flutter Getx State Management`Get.snackbar` is a GetX API, so a `GetxController` can show an error without receiving or storing a `BuildContext`. ```dart import 'package:get/get.dart'; abstract class ProfileRepository { Future<void> updateDisplayName(String displayName); } class ProfileController extends GetxController { ProfileController(this._repository); final ProfileRepository _repository; final isSaving = false.obs; Future<void> saveDisplayName(String displayName) async { isSaving.value = true; try { await _reposito...Votes: 0GitHub stars: 549
- Flutter Go Router NavigationUse a `GoRouteData` route with a required constructor parameter. The `go_router_builder` generator maps `orderId` to the `:orderId` segment and makes an untyped navigation call unnecessary. ```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; part 'app_router.g.dart'; @TypedGoRoute<OrderDetailRoute>(path: '/orders/:orderId') class OrderDetailRoute extends GoRouteData { const OrderDetailRoute({required this.orderId}); final String orderId; @override Widget...Votes: 0GitHub stars: 549
- Flutter Go Router NavigationPut authentication policy on the single root `GoRouter` through its `redirect` callback. Pages should render their UI only; they must not redirect from `build`. ```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; part 'app_router.g.dart'; abstract interface class AuthSession { bool get isLoggedIn; } @TypedGoRoute<LoginRoute>(path: '/login') class LoginRoute extends GoRouteData { const LoginRoute({this.from}); final String? from; @override Widget build(Bu...Votes: 0GitHub stars: 549
- Flutter Go Router NavigationUse a typed `StatefulShellRoute` with one branch per tab. Each branch has its own navigator key, so navigating within Orders does not discard its stack when the user switches to Home or Profile. ```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; part 'app_router.g.dart'; @TypedStatefulShellRoute<AppShellRoute>( branches: [ TypedStatefulShellBranch<HomeBranch>( routes: [TypedGoRoute<HomeRoute>(path: '/home')], ), TypedStatefulShellBranch<OrdersBranch>( r...Votes: 0GitHub stars: 549
- Flutter Idiomatic Flutter`setState` must not run after the widget has been disposed. Any `await` is an async gap: the user may navigate away while the operation is running. Check `context.mounted` immediately after the await and before every later use of the context or state. ```dart Future<void> _saveProfile() async { setState(() => _isSaving = true); try { await repository.save(_draft); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Profile saved')), ); } cat...Votes: 0GitHub stars: 549
- Flutter Idiomatic FlutterSplit the large `build` method by visual responsibility, not into `_buildXxx()` helper methods. Extract each meaningful section into a small `StatelessWidget`, pass only the data and callbacks it needs, and make widgets `const` where possible. This flattens nesting, makes rebuild boundaries clearer, and makes sections independently testable. ```dart class AccountPage extends StatelessWidget { const AccountPage({super.key, required this.account, required this.onSave}); final Account account; f...Votes: 0GitHub stars: 549
- Flutter Idiomatic Flutter`Padding(all: 16)` adds inset around a child; it is not a gap between siblings. For a uniform 16px gap in Flutter 3.27 or later, use the built-in `spacing` parameter on `Column` or `Row`. ```dart Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 16, children: const [ Text('Name'), TextField(), Text('Email'), TextField(), ], ) ``` Use outer `Padding` once for the screen or card inset, and `spacing: 16` for sibling separation: ```dart Padding( padding: const EdgeInsets.all(16), chi...Votes: 0GitHub stars: 549
- Flutter Layer Based Clean ArchitectureKeep the public contract in the domain layer and put both API and local-storage details behind infrastructure data sources. The UI and application layers depend only on `User` and `UserRepository`; neither imports Dio nor SharedPreferences. ```dart // lib/domain/entities/user.dart @freezed class User with _$User { const factory User({required String id, required String name}) = _User; } // lib/domain/failures/failure.dart @freezed sealed class Failure with _$Failure { const factory Failure.ne...Votes: 0GitHub stars: 549
- Flutter Layer Based Clean ArchitectureRemove the HTTP call from the widget. Define an order domain contract, implement the request and DTO mapping in infrastructure, and have a Cubit/BLoC coordinate the use case. The widget should only trigger the event and render state. ```dart // lib/domain/repositories/order_repository.dart abstract interface class OrderRepository { Future<Either<Failure, List<Order>>> fetchOrders(); } ``` ```dart // lib/infrastructure/datasources/order_remote_data_source.dart class DioOrderRemoteDataSource im...Votes: 0GitHub stars: 549
- Flutter Layer Based Clean ArchitecturePut that rule in the **domain layer** as a checkout policy/use case because it is business behavior, not UI behavior. It should operate on domain entities/value objects and return a domain result or `Failure`; it must not depend on Flutter widgets, BLoC, Dio, or a DTO. ```dart // lib/domain/entities/cart.dart @freezed class Cart with _$Cart { const factory Cart({required Money total}) = _Cart; } // lib/domain/entities/customer_credit.dart @freezed class CustomerCredit with _$CustomerCredit { ...Votes: 0GitHub stars: 549
- Flutter LocalizationUse `easy_localization` with CSV assets, since your translators work in Google Sheets. Recommended setup: - Store translations in `assets/langs/langs.csv` - Support `en` and `vi` - Initialize with `await EasyLocalization.ensureInitialized()` before `runApp` - Wrap the app with `EasyLocalization` - Use translation keys in UI with `.tr()` - Switch language with `context.setLocale(const Locale('vi'))` - If you sync from Google Sheets, use `sheet_loader_localization` Example shape: ```dart await ...Votes: 0GitHub stars: 549
- Flutter LocalizationUse a localization key with a named placeholder, then pass the name dynamically. ```json { "welcome_user": "Hello, {name}!" } ``` ```dart final name = 'John'; Text( 'welcome_user'.tr(namedArgs: {'name': name}), ); ```Votes: 0GitHub stars: 549
- Flutter LocalizationUse a pluralized translation entry and call `plural()` with the count. Example JSON: ```json { "cart": { "item_count": { "zero": "No items", "one": "1 item", "other": "{} items" } } } ``` Then in Flutter: ```dart Text('cart.item_count'.plural(cartCount)) ``` If you want the number inserted for plural forms: ```dart Text('cart.item_count'.plural(cartCount, args: ['$cartCount'])) ``` That gives you: - `1 item` when `cartCount == 1` - `3 items` when `cartCount == 3` If you use CSV instead of JSO...Votes: 0GitHub stars: 549
- Flutter Navigationdependencies: go_router: ^14.2.0 ``` ```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; abstract final class Routes { static const orderDetail = '/orders/:orderId'; } final router = GoRouter( initialLocation: '/', routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), GoRoute( path: Routes.orderDetail, redirect: (context, state) { final orderId = state.pathParameters['orderId']; if (orderId == null || orderId.isEmpty) return '...Votes: 0GitHub stars: 549
- Flutter NavigationUse nested navigation so each tab has its own back stack, and keep the tab container stateful. With `go_router`, the usual fix is `StatefulShellRoute.indexedStack`. That preserves each tab’s navigation history and lets back behave inside the active tab first instead of exiting immediately. Expected behavior: - If the current tab has inner pages, back pops within that tab. - If you are on a root page of a non-default tab, back can switch to the default tab. - Only exit when already at the root...Votes: 0GitHub stars: 549
- Flutter NavigationUse `go_router` redirect logic on the cart route so unauthenticated users are sent to login before the page builds. ```dart class Routes { static const login = '/login'; static const cart = '/cart'; } final goRouter = GoRouter( redirect: (context, state) { final loggedIn = context.read<AuthCubit>().state.isAuthenticated; final goingToCart = state.matchedLocation == Routes.cart; if (!loggedIn && goingToCart) { return Routes.login; } return null; }, routes: [ GoRoute( path: Routes.login, builde...Votes: 0GitHub stars: 549
- Flutter NotificationsFrom scratch, the usual package set is: - `firebase_core` — initialize Firebase first - `firebase_messaging` — FCM token, permission, foreground/background/terminated delivery - `flutter_local_notifications` — show local notifications, especially for foreground messages Typical setup flow: 1. Add the packages and install native Firebase config - Flutter: `firebase_core`, `firebase_messaging`, `flutter_local_notifications` - Android: add `google-services.json` - iOS: add `GoogleService-Info.pl...Votes: 0GitHub stars: 549
- Flutter NotificationsUse `FirebaseMessaging.instance.getInitialMessage()` during app startup. That is the API that tells you whether the app was cold-started from a notification tap while terminated. Example: ```dart final navigatorKey = GlobalKey<NavigatorState>(); Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp(navigatorKey: navigatorKey)); final initialMessage = await FirebaseMessaging.instance.getInitialMessage(); if (initialMessage != null) ...Votes: 0GitHub stars: 549
- Flutter NotificationsDon't trigger the system notification permission dialog on first launch. Show a custom primer screen or modal first that explains the benefit of notifications and let the user opt in from there. Only after they tap a clear CTA like “Enable notifications” should you call the platform permission request. This usually improves consent rates and avoids the “aggressive popup” complaint.Votes: 0GitHub stars: 549
- Flutter PerformanceThe lag is likely because `Column` builds all 500 `ProductCard`s at once, so Flutter has to layout, paint, and keep every child alive during scroll. Use `ListView.builder` instead so items are built lazily and recycled: ```dart ListView.builder( itemCount: products.length, itemBuilder: (context, index) { final product = products[index]; return ProductCard( key: ValueKey(product.id), product: product, ); }, ) ``` Also make sure: - `ProductCard` uses `const` where possible - each row has a stab...Votes: 0GitHub stars: 549
- Flutter PerformanceThe issue is that the cart count change is coupled to the whole page state, so the expensive product grid rebuilds too. Fix it by isolating the header update from the grid: - Do not call `setState()` at the page/root level for cart count changes. - Put the cart badge/header in its own `BlocBuilder` with `buildWhen`, or use `context.select()` / `BlocSelector` so only the count widget rebuilds. - Keep the product grid as a separate widget with stable inputs; make static children `const` where p...Votes: 0GitHub stars: 549
- Flutter PerformanceThe memory spike is most likely from decoding and caching too many full-resolution catalog images at once. Recommended fixes: - Resize images at load time instead of keeping original dimensions in memory. Set `memCacheWidth` / `memCacheHeight` or `maxWidth` / `maxHeight` based on the rendered card size. - Use `CachedNetworkImage` so repeated scrolling does not redownload assets, but keep cache dimensions constrained. - Render catalog items with `ListView.builder` so off-screen items are recyc...Votes: 0GitHub stars: 549
- Flutter Retrofit Networking```dart import 'package:dio/dio.dart'; import 'package:retrofit/retrofit.dart'; part 'orders_api_client.g.dart'; @RestApi(baseUrl: 'https://api.example.com') abstract class OrdersApiClient { factory OrdersApiClient(Dio dio, {String baseUrl}) = _OrdersApiClient; @GET('/orders') Future<List<OrderDto>> getOrders(); @GET('/orders/{id}') Future<OrderDto> getOrder(@Path('id') String id); @POST('/orders') Future<OrderDto> createOrder(@Body() CreateOrderRequest body); } class AuthInterceptor extends ...Votes: 0GitHub stars: 549
- Flutter Retrofit NetworkingUse a Dio auth interceptor and handle refresh in `onError` when the response is `401`. The usual flow is: 1. Add the access token in `onRequest` 2. If a request fails with `401`, pause or serialize retries 3. Call `refreshToken()` with your refresh token 4. Save the new access token 5. Clone and retry the original request with the updated `Authorization` header 6. If refresh also fails, clear auth state and force logout Example: ```dart class AuthInterceptor extends Interceptor { AuthIntercep...Votes: 0GitHub stars: 549
- Flutter Retrofit NetworkingUse a fallback enum case and tell JSON decoding to route unknown values to it. ```dart enum Status { active, inactive, unknown, } @freezed class UserDto with _$UserDto { const factory UserDto({ required String id, @JsonKey(unknownEnumValue: Status.unknown) required Status status, }) = _UserDto; factory UserDto.fromJson(Map<String, dynamic> json) => _$UserDtoFromJson(json); } ``` Why this works: - if the backend adds a new enum string you do not know yet, deserialization uses `Status.unknown` ...Votes: 0GitHub stars: 549
- Flutter Riverpod State Management```dart import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'product_provider.g.dart'; class Product { const Product({ required this.id, required this.name, required this.price, }); final String id; final String name; final double price; } abstract class ProductRepository { Future<List<Product>> fetchProducts(); } @riverpod ProductRepository productRepository(ProductRepositoryRef ref) { throw UnimplementedError('Override productRepositoryProvider in ProviderScope'); } @riverpo...Votes: 0GitHub stars: 549
- Flutter Riverpod State ManagementUse `ref.listen()` in the widget layer to react to provider state changes and perform navigation as a side effect. Keep navigation out of the provider/notifier itself. ```dart @riverpod class AuthController extends _$AuthController { @override AsyncValue<User?> build() => const AsyncData(null); Future<void> signIn() async { state = const AsyncLoading(); state = await AsyncValue.guard(() async { return User(id: '1'); }); } } class LoginPage extends ConsumerWidget { const LoginPage({super.key})...Votes: 0GitHub stars: 549
- Flutter Riverpod State ManagementOverride it at the root `ProviderScope` in your test using the provider’s override API. ```dart testWidgets('uses mocked repository', (tester) async { await tester.pumpWidget( ProviderScope( overrides: [ userRepositoryProvider.overrideWithValue(FakeUserRepository()), ], child: const MyApp(), ), ); // assertions... }); ``` For notifier-based providers, use the matching override method (`overrideWith`, `overrideWithValue`, etc.) depending on the provider type. This keeps providers global and sw...Votes: 0GitHub stars: 549
- Flutter SecurityNo — `SharedPreferences` is not appropriate for auth tokens. It’s fine for non-sensitive app settings, but tokens should go in secure OS-backed storage such as `flutter_secure_storage` (Keychain on iOS, Keystore on Android). Use this instead: ```dart final storage = FlutterSecureStorage(); await storage.write(key: 'auth_token', value: token); final token = await storage.read(key: 'auth_token'); ``` A few related security points: - Don’t hardcode API secrets in Dart code; pass them via `--dart...Votes: 0GitHub stars: 549
- Flutter SecurityUse environment-specific configuration, not hardcoded values. - Store the API base URL per environment via `--dart-define` (for example `API_BASE_URL`), with separate values for staging and production in your CI/CD or build commands. - Do not embed the API key in Dart source. Inject it the same way (`--dart-define=API_KEY=...`) or load it from a secure backend-managed config flow if possible. - For highly sensitive keys, prefer moving the secret off-device entirely and have the app obtain sho...Votes: 0GitHub stars: 549
- Flutter SecurityFor a Play Store release build, I’d take these security steps: - Build the app in release mode with obfuscation enabled, for example: `flutter build appbundle --release --obfuscate --split-debug-info=./symbols` - Keep API keys, tokens, and other secrets out of Dart source. Inject them with `--dart-define` or a secure environment mechanism. - Make sure sensitive data like auth tokens, refresh tokens, and PII are stored in `flutter_secure_storage`, not `shared_preferences`. - Remove or mask any...Votes: 0GitHub stars: 549
- Flutter TestingAssumptions: `CheckoutScreen` receives `CheckoutBloc` through `BlocProvider`, `MockCheckoutBloc` is defined in `test/shared/`, and these `WidgetKeys` exist. ```dart // test/checkout_button_test.dart import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:mocktail/mocktail.dart'; import 'package:app/core/keys/widget_keys.dart'; import 'package:app/features/checkout/checkout_bloc....Votes: 0GitHub stars: 549
- Flutter TestingAssume `LoginScreen` creates its bloc from GetIt: ```dart BlocProvider( create: (_) => getIt<AuthBloc>(), child: const LoginScreenView(), ) ``` Register a shared mock before the widget is built: ```dart // test/shared/mocks.dart class MockAuthBloc extends Mock implements AuthBloc {} ``` ```dart late MockAuthBloc authBloc; setUpAll(() { TestWrapper.init(); authBloc = MockAuthBloc(); getIt.registerFactory<AuthBloc>(() => authBloc); }); setUp(() { when(() => authBloc.state).thenReturn(const Auth...Votes: 0GitHub stars: 549
- Flutter TestingAdd `integration_test/orders_integration_test.dart`: ```dart import 'package:patrol/patrol.dart'; import 'robots/orders_robot.dart'; import 'helpers/integration_auth_helper.dart'; patrolTest( 'should show first order card when logged in and opening orders tab', ($) async { final robot = OrdersRobot($.tester); // Uses configured test credentials. await IntegrationAuthHelper.loginOrSkip($); await robot.tapOrdersTab(); await robot.expectFirstOrderVisible(); }, ); ``` Assumptions: - `IntegrationA...Votes: 0GitHub stars: 549
- Flutter Widgets```dart import 'package:flutter/material.dart'; class ProductCard extends StatelessWidget { const ProductCard({ super.key, required this.title, required this.price, required this.imageUrl, required this.onAddToCart, }); final String title; final double price; final String imageUrl; final VoidCallback onAddToCart; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Card( clipBehavior: Clip.antiAlias, child: Padding( padding: const EdgeInsets.all(12), child: C...Votes: 0GitHub stars: 549
- Flutter WidgetsBreak it into small `const` widgets and let the screen become mostly composition. Good target split: - `OrdersScreen` keeps scaffold, app bar, and top-level layout only - `_OrdersHeader` - `_OrderSummaryCard` - `_OrderList` - `_OrderTile` - `_OrderActions` Rules I’d use: - Prefer `StatelessWidget` unless you truly need local controller or ephemeral UI state - If the file is 350 lines, it is already past the extraction threshold - Replace private `_buildX()` helpers with private widget classes...Votes: 0GitHub stars: 549
- Flutter Widgets```dart import 'package:flutter/material.dart'; class OrdersEmptyState extends StatelessWidget { const OrdersEmptyState({super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ _EmptyStateIcon(color: theme.colorScheme.primary), const SizedBox(height: 12), Text( 'No orders yet', style: theme.textTheme.titleMedium, textAlign: TextAlign...Votes: 0GitHub stars: 549
- Golang Api ServerUse a thin HTTP handler for `POST /orders`: require JSON, bind and validate the request, call an injected `OrderService`, map service errors to HTTP responses, and return the created order as JSON. Business rules such as pricing, stock checks, and order creation belong in the service or domain layer, not in the handler. ```go type OrderHandler struct { service OrderService } func (h *OrderHandler) Create(c echo.Context) error { if c.Request().Header.Get(echo.HeaderContentType) != "application...Votes: 0GitHub stars: 549
- Golang Api ServerCreate the Echo router, wrap it in an `http.Server`, start it in a goroutine, and shut it down on `SIGINT` or `SIGTERM` with a bounded context. Treat `http.ErrServerClosed` as a normal server exit. ```go func run() error { e := echo.New() e.Use(middleware.Logger(), middleware.Recover()) e.GET("/health", healthHandler) e.GET("/ready", readyHandler) srv := &http.Server{Addr: ":8080", Handler: e} serverErr := make(chan error, 1) go func() { serverErr <- e.StartServer(srv) }() ctx, stop := signal...Votes: 0GitHub stars: 549
- Golang Api ServerNo—avoid a global Echo router. Create the router during application composition and pass it to route registration or the component that owns the server lifecycle. This keeps dependencies explicit, prevents shared mutable state between tests, and supports multiple server instances. ```go type App struct { Echo *echo.Echo } func NewApp(deps Dependencies) *App { e := echo.New() e.Use(middleware.Logger(), middleware.Recover()) registerRoutes(e, deps) e.GET("/health", healthHandler) e.GET("/ready"...Votes: 0GitHub stars: 549
- Golang ArchitectureA practical Clean Architecture layout for a Go microservice is: - `cmd/<service>/` - App entrypoint only. - Parse config, build logger/DB/HTTP server, wire dependencies, start the app. - Keep business logic out of `main.go`. - `internal/` - Private application code for this service. - Organize by domain or capability, not by generic layer buckets. - Example: - `internal/orders/` - Entities, use cases, service orchestration, domain interfaces owned by callers. - `internal/customers/` - `intern...Votes: 0GitHub stars: 549
- Golang ArchitectureNo. The domain layer should not import the DB package directly. Keep the domain/service code focused on business rules and define a small repository interface on the consumer side instead. Then wire the concrete database implementation at startup, typically from `cmd/<app>/main.go` through constructors in `internal/...`. Example shape: ```go type UserRepository interface { FindByID(ctx context.Context, id string) (User, error) } type UserService struct { repo UserRepository } func NewUserServ...Votes: 0GitHub stars: 549
- Golang ArchitectureNot usually. If orders, inventory, and notifications are separate capabilities, putting them all into one big service struct often creates a god service and blurs ownership. A better Go shape is: - keep separate domain-focused services or packages, such as `orders`, `inventory`, and `notifications` - define small interfaces where one capability depends on another - wire them together in `main` or constructors For example: - `internal/orders.Service` - `internal/inventory.Service` - `internal/...Votes: 0GitHub stars: 549