Skip to content

Latest commit

 

History

History
212 lines (187 loc) · 6.31 KB

File metadata and controls

212 lines (187 loc) · 6.31 KB

GetX Pattern Guide — AppVentas

Based on kauemurakami/getx_pattern. ALL code generated for this project MUST strictly follow this pattern.

📁 Required Folder Structure

lib/
├── main.dart                          # App entry point, runApp(GetMaterialApp(...))
└── app/
    ├── data/                          # Shared data layer (available to ALL modules)
    │   ├── models/                    # Isar collection classes
    │   │   ├── product_model.dart
    │   │   ├── cost_lot_model.dart
    │   │   ├── sale_model.dart
    │   │   ├── sale_item_model.dart
    │   │   ├── daily_balance_model.dart
    │   │   └── note_model.dart
    │   ├── providers/                 # Data sources (DB, API)
    │   │   └── database_provider.dart # Isar singleton
    │   ├── services/                  # Business logic services
    │   │   ├── cost_calculation_service.dart
    │   │   └── export_service.dart
    │   └── enums/
    │       ├── promotion_type.dart
    │       └── export_period.dart
    │
    ├── modules/                       # One module per screen/feature
    │   ├── home/
    │   │   ├── home_page.dart
    │   │   ├── home_controller.dart
    │   │   └── home_binding.dart
    │   ├── products/
    │   │   ├── products_page.dart
    │   │   ├── products_controller.dart
    │   │   ├── products_binding.dart
    │   │   └── repository/
    │   │       └── products_repository.dart
    │   └── ... (same pattern for each module)
    │
    ├── routes/
    │   ├── app_routes.dart            # Route name constants
    │   └── app_pages.dart             # GetPage list with bindings
    │
    ├── core/
    │   ├── values/
    │   │   ├── strings.dart           # Spanish UI strings
    │   │   └── colors.dart
    │   ├── theme/
    │   │   ├── app_theme.dart         # Light + Dark ThemeData
    │   │   ├── text_theme.dart
    │   │   └── color_theme.dart
    │   └── utils/
    │       ├── currency_formatter.dart
    │       └── date_helpers.dart
    │
    └── global_widgets/                # Widgets reusable across modules
        ├── product_card.dart
        ├── price_tag.dart
        ├── quick_action_button.dart
        └── responsive_layout.dart

🔑 Core Rules

Rule 1: One Controller = One Repository

Every controller has exactly ONE repository. If a page needs data from multiple entities, use multiple GetX<Controller> widgets, each with its own controller.

// ✅ CORRECT
class SalesController extends GetxController {
  final SalesRepository repository;
  SalesController({required this.repository});
}

// ❌ WRONG — never two repositories in one controller
class SalesController extends GetxController {
  final SalesRepository salesRepo;
  final ProductsRepository productsRepo; // NO!
}

Rule 2: Always Use Bindings

Controllers are initialized via Bindings, never manually with Get.put() in pages.

class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(() => HomeController(
      repository: HomeRepository(),
    ));
  }
}

Rule 3: Pages Extend GetView

class HomePage extends GetView<HomeController> {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Obx(() => Text('${controller.totalSales.value}')),
    );
  }
}

Rule 4: Use .obs for Reactive State

class HomeController extends GetxController {
  final totalSales = 0.0.obs;
  final products = <Product>[].obs;

  void updateSales(double amount) {
    totalSales.value += amount;
  }
}

Rule 5: Repository Pattern

Repositories bridge controllers and providers. They exist INSIDE each module folder.

class ProductsRepository {
  final DatabaseProvider _db = Get.find<DatabaseProvider>();

  Future<List<Product>> getAll() => _db.getAllProducts();
  Future<void> save(Product p) => _db.saveProduct(p);
  Future<void> delete(int id) => _db.deleteProduct(id);
}

Rule 6: Providers Handle Raw Data

Providers live in data/providers/ and handle direct DB/API communication.

class DatabaseProvider extends GetxService {
  late Isar isar;

  Future<DatabaseProvider> init() async {
    final dir = await getApplicationDocumentsDirectory();
    isar = await Isar.open(
      [ProductSchema, SaleSchema, ...],
      directory: dir.path,
    );
    return this;
  }

  Future<List<Product>> getAllProducts() async {
    return await isar.products.where().findAll();
  }
}

Rule 7: Routes Are Constants

// app_routes.dart
abstract class AppRoutes {
  static const home = '/home';
  static const products = '/products';
  static const sales = '/sales';
  static const analytics = '/analytics';
  static const calendar = '/calendar';
  static const notes = '/notes';
  static const settings = '/settings';
  static const cashRegister = '/cash-register';
}
// app_pages.dart
class AppPages {
  static final pages = [
    GetPage(
      name: AppRoutes.home,
      page: () => const HomePage(),
      binding: HomeBinding(),
    ),
    // ... etc
  ];
}

Rule 8: Naming Conventions

Element Convention Example
Models snake_case_model.dart product_model.dart
Controllers snake_case_controller.dart sales_controller.dart
Pages snake_case_page.dart products_page.dart
Bindings snake_case_binding.dart home_binding.dart
Repositories snake_case_repository.dart products_repository.dart
Variables camelCase totalSales, currentStock
Classes PascalCase ProductModel, SalesController

Rule 9: No Slow Animations

// In GetMaterialApp
GetMaterialApp(
  defaultTransition: Transition.noTransition,
  transitionDuration: Duration.zero,
  // ...
)

Rule 10: Database is Isar

NEVER use SharedPreferences, GetStorage, Hive, or SQLite. All persistent data goes through Isar via DatabaseProvider.