الفصل 03Chapter 03

هيكل المشروع والتنظيم Project Structure & Organization

دليل شامل لتنظيم ملفات MRE CashBook وتطبيق مبادئ Clean Architecture. A comprehensive guide to MRE CashBook file organization and Clean Architecture principles.

🌳 مستكشف المجلدات (Root Explorer) Root Explorer

تطبيق MRE CashBook مش بس كود Dart، ده بيحتوي على ملفات لإعدادات منصات كتير زي أندرويد و iOS و Shorebird.

MRE CashBook isn't just Dart code; it contains configuration files for many platforms like Android, iOS, and Shorebird.

🖥️ Terminal Command: Project Overview
ls -F
ls -F
🔍 بتعمل إيه؟🔍 What does it do?

بتعرض كل الملفات والمجلدات في الجذر مع علامة مميزة (مثل / للمجلدات) عشان تفرق بينهم بسهولة.

Lists all files and folders in the root with symbols (like / for folders) for quick identification.

Folder/FileImportanceDetails (AR)
lib/Criticalقلب التطبيق، هنا كل كود الـ Dart والـ Logic.
assets/Highالصور، الأيقونات، والخطوط اللي التطبيق بيعتمد عليها.
android/Highملفات إعدادات نظام الأندرويد (Gradle, Manifest).
ios/Highملفات إعدادات نظام الـ iOS (Xcode Project, Info.plist).
test/Mediumاختبارات الوحدة (Unit Tests) واختبارات الـ UI.
pubspec.yamlCritical"هوية" المشروع وقائمة المكاتب المستخدمة.
shorebird.yamlMediumإعدادات الـ Code Push لتحديث التطبيق بدون رفع نسخة جديدة.
🧠 فلسفة تنظيم مجلد الـ lib The lib Folder Philosophy

بنستخدم في المشروع ده Clean Architecture مقرونة بـ Modular Structure. يعني الكود متقسم لجزئين كبار:

We use Clean Architecture combined with Modular Structure in this project. The code is split into two major parts:

1
CORE Layer

ده الأساس اللي كل ميزات التطبيق بتعتمد عليه. لو الـ Core باظ، التطبيق كله بيقف.

The foundation upon which all app features rely. If Core breaks, the entire app fails.

2
FEATURES Layer

دي ميزات التطبيق المستقلة (زي الكتب، الإحصائيات، الإعدادات). المفروض إن كل ميزة تكون معزولة بقدر الإمكان.

Independent business features (Books, Statistics, Settings). Every feature should be as isolated as possible.

قاعدة ذهبية: الميزة (Feature) مسموح لها تكلم الـ Core، بس الـ Core ممنوع نهائياً يكلم ميزة محددة.

Golden Rule: A Feature is allowed to talk to Core, but Core is strictly forbidden from talking to a specific Feature.

⚛️ التعمق في الـ Core: عصب التطبيق Core Deep Dive: The App's Nerve System

مجلد lib/core/ هو المخ اللي بيحرك الدنيا. تعالو نشوف تقسيمته من جوه:

The lib/core/ folder is the brain that runs everything. Let's look at its internal structure:

C1
config/

هنا بنحط الإعدادات العامة زي app_config.dart اللي فيها أسماء الثوابت (Constants).

📁 lib/core/config/app_config.dart
class AppConfig {
  static const String appName = 'MRE CashBook';
  static const String devEmail = 'dev@mrecode.net';
}
C2
extensions/

الإضافات اللي بتسهل علينا الكود. أهم واحدة هي BuildContextExtension اللي بتخلينا نوصل للألوان والترجمة بسهولة.

📁 lib/core/extensions/context_extension.dart
extension BuildContextHelper on BuildContext {
  AppColors get colors => Theme.of(this).extension()!;
  TextTheme get textTheme => Theme.of(this).textTheme;
}

ليه بنستخدمها؟ عشان بدل ما نكتب Theme.of(context).textTheme نكتب بس context.textTheme. كود أنضف وأسرع!

C3
widgets/

هنا بنحط الـ Widgets اللي بنستخدمها في كل حته، زي AppTextField و AppCustomScrollView. دي اللبنات الأساسية لبناء الـ UI.

🧱 نظام الـ Widgets الموحد Global Widgets System

ممنوع نستخدم Raw Material Widgets في الـ Screens. كل حاجة لازم تمر من خلال الـ Core Widgets عشان نضمن شكل موحد.

Raw Material Widgets are forbidden in Screens. Everything must go through Core Widgets to ensure a consistent look.

📁 lib/core/widgets/app_text_field.dart
class AppTextField extends StatelessWidget {
  // تغليف للـ TextFormField بتصميم المشروع
  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: InputDecoration(
        borderRadius: AppSizes.radiusSm,
        fillColor: context.colors.surface,
        // ... إعدادات تانية كتير
      ),
    );
  }
}
🖥️ Terminal Command: List Widgets
ls lib/core/widgets
🏗️ تشريح الميزات (Feature Anatomy) Feature Anatomy

كل ميزة في MRE CashBook هي تطبيق صغير لوحده. تعالو نشوف ميزة "الكتب" (Books) كمثال:

Every feature in MRE CashBook is a mini-app. Let's look at the "Books" feature as an example:

1
Data Layer

المسؤولة عن التعامل مع الداتا الحقيقية. فيها الـ Models والـ DataSources.

books/data/
├── models/         # BookDTO, BookMapper
└── datasources/    # local_data_source.dart (Drift)
2
Domain Layer

دي "المنطقة المحايدة". فيها شكل الداتا بالنسبة لليوزر والـ Business Rules.

books/domain/
├── entities/       # Pure Book class
└── repositories/   # Abstract interface
3
Presentation Layer

الواجهة اللي اليوزر بيشوفها. الـ Screens والـ Logic بتاعها (BLoC).

books/presentation/
├── bloc/           # state, event, bloc files
├── screens/        # books_screen.dart
└── widgets/        # book_card.dart, delete_dialog.dart
📏 قواعد البناء الصارمة Strict Architectural Rules

عشان نحافظ على نضافة الكود، حطينا قواعد ممنوع كسرها:

  • ممنوع ميزة تستورد ملفات من ميزة تانية (Cross-Feature Import).
  • ممنوع الـ Screen يكلم الـ Database مباشرة.
  • ممنوع الـ Business Logic يكون موجود في الـ UI.
  • دائماً افصل الـ BLoC في 3 ملفات (State, Event, Bloc).

تنبيه: أي خرق للقواعد دي هيخلي التطبيق صعب جداً في الـ Debugging بعدين ومستحيل في الـ Testing.

🎨 الأصول والإعدادات (Assets & Config) Assets & Config

مجلد assets/ هو مخزن المواد الخام للتصميم.

assets/
├── icon/           # App icons (icon.png)
├── images/         # Splash and backgrounds
├── fonts/          # Custom typography (Inter, Cairo)
└── translations/   # en.dart, ar.dart (Easy Localization)

وعشان نستخدم الـ Assets دي، لازم نسجلها في pubspec.yaml:

📁 pubspec.yaml
flutter:
  uses-material-design: true
  assets:
    - assets/icon/
    - assets/images/
    - assets/translations/
  fonts:
    - family: Inter
      fonts:
        - asset: assets/fonts/Inter-Regular.ttf
💉 تسجيل حقن التبعيات (DI Registration) Dependency Injection Registration

حقن التبعيات هو اللي بيربط الطبقات ببعض. في MRE CashBook، كل ميزة عندها ملف `_injection.dart` خاص بيها عشان منعملش زحمة في الملف الرئيسي.

Dependency Injection (DI) is what glues the layers together. In MRE CashBook, every feature has its own `_injection.dart` file to avoid cluttering the main entry point.

📁 lib/features/dashboard_injection.dart
final dashboardInjection = DashboardInjection();

class DashboardInjection {
  void init() {
    // تسجيل المستودعات (Repositories)
    sl.registerLazySingleton(
      () => DashboardRepositoryImpl(sl()),
    );
    // تسجيل الـ BLoCs
    sl.registerFactory(() => DashboardBloc(sl()));
  }
}
1
registerLazySingleton

بيعمل نسخة واحدة بس من الكلاس ده، وبيعملها "لما نحتاجها" (Lazy). دي بتوفر ميموري كتير.

Creates a single instance of the class only when needed (Lazy), saving significant memory.

2
registerFactory

بيعمل نسخة جديدة كل ما نطلبها. ده ممتاز للـ BLoCs عشان نضمن إن الـ State بتبدأ من الصفر دايماً.

Creates a new instance every time requested. Perfect for BLoCs to ensure state starts from scratch.

📱 غوص في مجلدات المنصات (Android/iOS) Platform Folders Deep Dive

رغم إن Flutter هو تطبيق Cross-Platform، بس أحياناً بنحتاج نظبط حاجات في الكود الأصلي (Native).

Even though Flutter is cross-platform, sometimes we need to tweak the native code.

A
Android Folder

أهم ملف هو build.gradle اللي بنحدد فيه الـ SDK versions والـ App Signing.

  • app/src/main/AndroidManifest.xml: لتصاريح الإنترنت والبيومتريكس.
  • key.properties: بيانات مفتاح التوقيع لرفع التطبيق للستور.
I
iOS Folder

بنعدل هنا الـ Info.plist عشان نضيف رسايل طلب الإذن (زي الكاميرا أو الجاليري).

  • Podfile: لإدارة المكتبات الخاصة بـ iOS.
  • Runner.xcworkspace: الملف اللي بنفتحه في Xcode.
🖥️ Terminal Command: Native Permissions Check
cat android/app/src/main/AndroidManifest.xml
🛠️ ملفات الأدوات والإعدادات (Tooling Config) Configuration & Tooling

جذر المشروع مليان ملفات .yaml و .json. كل واحد ليه وظيفة مهمة جداً.

analysis_options.yaml
🔍 بتعمل إيه؟🔍 What does it do?

دي "دستور الكود". بنحدد فيها القواعد اللي Dart لازم يمشي عليها (Linter rules). مثلاً إن لازم نحط const قبل الـ Widgets.

The "Code Constitution". Defines Linter rules that Dart must follow, like requiring const before Widgets.

shorebird.yaml
🔍 بتعمل إيه؟🔍 What does it do?

بتربط مشروعك بـ Shorebird عشان تقدر تبعت تحديثات للمستخدمين (Over-the-air updates) من غير ما يستنوا موافقة الستور.

Links your project to Shorebird for over-the-air updates, bypassing store review wait times.

🖥️ Terminal Command: Check Flutter Version
fvm flutter --version
fvm flutter --version
🔍 بتعمل إيه؟🔍 What does it do?

بنستخدم fvm قبل أمر flutter عشان نتأكد إننا شغالين بنفس النسخة اللي اتبرمج بيها التطبيق (في حالتنا 3.41.2).

We use fvm before the flutter command to ensure we are using the exact version the app was coded with (3.41.2).

🧪 طبقة الاختبارات (The Test Layer) The Test Layer

مجلد test/ مش للديكور، ده الضمان إننا متبوظش حاجة وإحنا بنطور.

test/
├── core/           # Testing shared utils
└── features/       # Feature-specific unit tests
    └── books/
        └── books_bloc_test.dart

قاعدة: أي Logic معقد في الـ BLoC لازم يكون ليه Test يقابله في مجلد الـ test/ بنفس المسار.

🚀 خطوات بناء ميزة جديدة (الـ Workflow) Building a New Feature Workflow

لو طلبنا منك تضيف ميزة "التقارير" (Reports)، دي الخطوات اللي لازم تمشي عليها بالظبط عشان تحافظ على الهيكل:

If we asked you to add a "Reports" feature, these are the exact steps you must follow to maintain the structure:

1
إنشاء المجلدات (Folders)
mkdir -p lib/features/reports/{data,domain,presentation}/{models,datasources,entities,repositories,bloc,screens,widgets}

الأمر ده بيعملك كل الفولدرات اللي محتاجها في سطر واحد.

2
تعريف الـ Entity

تبدأ بالـ Pure Dart Object في الـ domain/entities.

class Report {
  final String id;
  final DateTime date;
  // ...
}
3
إنشاء الـ Injection

تعمل ملف lib/features/reports_injection.dart وتربط الميزة بالـ injection_container.dart.

4
بناء الـ UI

تبدأ ترص الـ Widgets في presentation/widgets وتعمل الـ Screen الأساسية.

📱💻 الاستجابة الدقيقة (Micro-Responsiveness) Micro-Responsiveness Folder Pattern

تطبيق MRE مصمم يشتغل على الموبايل والتابلت والـ iPad Pro. عشان كده بنستخدم تقسيم خاص في الـ widgets:

MRE is designed for mobile, tablet, and iPad Pro. That's why we use a specific split in widgets:

widgets/mobile/ & widgets/tablet/
🔍 ليه التقسيم ده؟🔍 Why this split?

عشان في التابلت ممكن نحتاج نعرض فورم (Form) في Dialog كبير، لكن في الموبايل بتتعرض في BottomSheet. التقسيم ده بيمنع الـ if (isTablet) كتير جوه الكود.

On tablets, we might show a Form in a large Dialog, but on mobile, it's a BottomSheet. This split prevents messy if (isTablet) checks in the UI code.

نصيحة: دايماً استخدم الـ AdaptiveOverlays.showAdaptiveModal() اللي موجودة في الـ core عشان هي اللي بتعرف تختار بين الـ Dialog والـ BottomSheet أوتوماتيك.

أسئلة شائعة حول الهيكل Structure FAQ
Q
ليه الـ BLoC موجود في الـ Presentation مش الـ Domain؟ Why is BLoC in Presentation not Domain?

لأن الـ BLoC وظيفته إدارة حالة الواجهة (UI State). الـ Domain لازم يفضل "خالي من أي اعتماديات" (Pure Dart) عشان تقدر تنقله لأي مشروع تاني بسهولة.

Because BLoC manages UI State. Domain must remain dependency-free (Pure Dart) so it can be ported to other projects easily.

Q
إيه الفرق بين Model و Entity في المشروع؟ Model vs Entity?

الـ Entity هو الكائن البسيط (id, name). الـ Model هو الكود اللي بيعرف يتعامل مع الـ JSON أو الـ Database (toJson, fromJson). الـ Data layer بتستخدم الـ Model، والـ Presentation بتستخدم الـ Entity.

Q
فين بنحط الـ Utilities؟ Where do Utils go?

في lib/core/utils/. بنحط هناك الـ Formatters، الـ Validators، وأي كود Logic بسيط بيستخدم في أكتر من ميزة.

Q
إمتى أعمل Feature جديدة؟ When to create a new Feature?

لما يكون عندك منطق عمل (Business Logic) جديد تماماً ومستقل، زي "نظام النسخ الاحتياطي" (Backup System). لو هي مجرد تعديل في الشاشة، كمل في الميزة الموجودة.

⚖️ حوكمة المشروع وقواعد الكود (Governance) Project Governance & Linting

عشان المشروع يفضل "Clean"، إحنا مش بنعتمد بس على شطارة المبرمج، إحنا بنستخدم Linter قوي بيراقب كل سطر بيتكتب في الـ analysis_options.yaml.

To keep the project clean, we don't just rely on dev skill; we use a powerful Linter that monitors every line in analysis_options.yaml.

1
Prefer Const

دي أشهر قاعدة، بتجبرك تحط const لما يكون الكائن ثابت. ده بيوفر ميموري كتير في Flutter.

2
No Leading Underscore for Local Variables

قاعدة عشان شكل الكود يكون موحد (Consistency)، الـ _ بنستخدمها بس للثوابت أو الكلاسات الخاصة (Private).

3
Always Specify Return Types

لازم تحدد الفانكشن بترجع إيه (void, String, Future) عشان الكود يكون واضح لأي حد بيقرأه.

🖥️ Terminal Command: Run Linter
dart analyze
🔧 تشغيل محرك حقن التبعيات (The sl Engine) Dependency Injection Initiation

الـ sl (Service Locator) هو اللي بيشيل كل المفاتيح بتاعة التطبيق. بيتم تشغيله في ملف lib/core/di/injection_container.dart.

📁 lib/core/di/injection_container.dart
final sl = GetIt.instance; // المحرك الأساسي (GetIt)

Future init() async {
  // 1. الأساسيات (Core)
  sl.registerLazySingleton(() => AppConfig());
  
  // 2. الميزات (Features)
  dashboardInjection.init();
  booksInjection.init();
  settingsInjection.init();
}
Future<void> init() async
🔍 بتعمل إيه؟🔍 What does it do?

دي أول فانكشن بتتنده في الـ main.dart. لازم تستنى لما تخلص (await) عشان التطبيق ميبدأش ومن غير ما تكون الداتا جاهزة.

للمحترفين: لاحظ إننا بنقسم الـ init لـ sub-init لكل ميزة، ده نوع من الـ Separation of Concerns.

🗺️ خريطة تدفق البيانات والهيكل Structure & Data Flow Map

ازاي الطلب بيمشي جوه المشروع؟ من الشاشة لحد قاعدة البيانات والرجوع تاني:

[UI Screen] 
    |--> [BLoC/Cubit] (Presentation)
           |--> [Repository Interface] (Domain)
                  |--> [Repository Implementation] (Data)
                         |--> [Local DataSource] (Data/Drift)
                                |--> [SQLite DB]
      

الرجوع (Response) بيمشي العكس تماماً، بس بشهادة "Entity" مش "Model".

🎯 تمرين تفاعلي: صيد الملفات Interactive Exercise: Folder Hunt

اختبر نفسك! حاول تلاقي مسار الملفات دي من غير ما تبص على الشرح تاني:

1
ملف ترجمة الكلمات للعربي

الإجابة: assets/translations/ar.dart

2
الكلاس اللي بيعرف شكل الجدول في الداتابيز (Table)

الإجابة: lib/core/database/tables/

3
ملف الـ Bloc بتاع ميزة الإعدادات

الإجابة: lib/features/settings/presentation/bloc/settings_bloc.dart

4
مكان وضع صور الـ Splash Screen

الإجابة: assets/images/

5
ملف إعدادات أيقونة الأندرويد

الإجابة: android/app/src/main/res/

📦 قلب المشروع النابض: pubspec.yaml The pubspec.yaml Powerhouse

الملف ده هو المسؤول عن استيراد كل العضلات اللي التطبيق بيستخدمها. تعالو نشوف أهم المكاتب (Dependencies) اللي فيه:

drift & sqlite3_flutter_libs
🔍 بتعمل إيه؟🔍 What does it do?

دي قاعدة البيانات العملاقة اللي بتشيل كل حساباتك. Drift هي اللي بتخلينا نكتب SQL بطريقة Dart السهلة.

flutter_bloc
🔍 بتعمل إيه؟🔍 What does it do?

المسؤول عن إدارة الحالة (State Management). هو اللي بيعرف الشاشة إن فيه داتا جديدة وصلت ولازم تتحدث.

get_it
🔍 بتعمل إيه؟🔍 What does it do?

مكتبة حقن التبعيات (DI). هي اللي بتخلينا نوصل لأي كلاس في التطبيق من أي مكان بسهولة واحترافية.

easy_localization
🔍 بتعمل إيه؟🔍 What does it do?

المسؤولة عن تحويل التطبيق بين العربي والإنجليزي بلمسة واحدة.

معلومة: أي مكتبة بنضيفها هنا بتزود حجم التطبيق، عشان كده بنختار المكاتب "الرشيقة" والمدعومة بقوة بس.

🖥️ Terminal Command: Refresh dependencies
fvm flutter pub get
🎉 إنجاز: 1000 سطر من الفهم! Milestone: 1000 Lines of Understanding!

لو وصلت لحد هنا، فأنت دلوقتي مبرمج فاهم كل "سنتيمتر" في هيكل مشروع MRE CashBook. أنت جاهز تدخل في عمق الكود وتغير أي حاجة وأنت مطمن.

If you reached this far, you now understand every "centimeter" of the MRE CashBook structure. You are ready to dive deep into the code and change anything with confidence.

تهانينا! لقد أتممت أطول فصل في هذه الدورة التعليمية. الهيكل هو الأساس، والقادم هو البناء.

Congratulations! You've completed the longest chapter in this course. Structure is the foundation; the rest is building.

الأداء وعلاقته بالهيكل (Tree Shaking) Performance & Tree Shaking

هل كنت تعرف إن الطريقة اللي بننظم بيها الفولدرات بتأثر على سرعة التطبيق؟

Did you know that how we organize folders affects app speed?

Tree Shaking
🔍 يعني إيه؟🔍 What is it?

لما بنقسم الكود لميزات (Features) مفصولة، الـ Flutter Compiler بيقدر "يهز الشجرة" ويشيل أي كود مش مستخدم في النسخة النهائية. لو الكود كله فوق بعضه، العملية دي بتكون صعبة جداً.

Lazy Initialization
🔍 يعني إيه؟🔍 What is it?

بفضل الـ Dependency Injection اللي شرحناه، إحنا مش بنحمل كل الميزات في الميموري أول ما التطبيق يفتح. إحنا بنحمل الميزة لما اليوزر يفتحها بس.

📊 جدول ملخص الهيكل الكامل Ultimate Structure Summary Table
Layer / Folder Main Purpose (AR) Key Files
core/config الثوابت والإعدادات العامة app_config.dart
core/extensions تسهيل الوصول للثيم والترجمة context_extension.dart
core/widgets الـ Widgets الموحدة للمشروع ككل app_text_field.dart
core/database تعريف الجداول وعلاقات الداتا app_database.dart
features/*/data تحويل الداتا من الداتابيز للغة Dart *_model.dart
features/*/domain القواعد الصافية للميزة (المنطق) *_entity.dart
features/*/presentation واجهات المستخدم وإدارة حالتها *_screen.dart, *_bloc.dart
assets/translations ملفات اللغات (عربي/إنجليزي) ar.dart, en.dart
android/app إعدادات نظام الأندرويد والنشر AndroidManifest.xml
ios/Runner إعدادات نظام الـ iOS والنشر Info.plist
🕯️ كلمة أخيرة عن هذا الفصل Final Words on This Chapter

لقد كانت رحلة طويلة عبر الملفات والمجلدات. لا تنظر إلى هذا الهيكل كقيود، بل انظر إليه كخريطة كنز ترشدك إلى كود مستقر، قابل للاختبار، وسهل التطوير. في الفصل القادم، سنبدأ بالتعامل مع البيانات الحقيقية في "قاعدة البيانات".

It's been a long journey through files and folders. Don't look at this structure as a restriction, but as a treasure map guiding you to stable, testable, and easy-to-develop code. In the next chapter, we'll start dealing with real data in the "Database".

📝 ملخص هيكل المشروع Project Structure Summary

دلوقتي بقيت عارف إزاي MRE CashBook بيحافظ على نظافة وترتيب ملفاته. الفصل ده هو حجر الأساس لفهم باقي الفصول.

Now you know how MRE CashBook maintains its file cleanliness and order. This chapter is the foundation for understanding the rest of the course.

الفصل السابقPrevious الفصل التاليNext