# خطة تنفيذ مُصادَق — Flutter Mobile App
## خارطة الطريق الشاملة بالأولويات والمكتبات والتفاصيل

---

## أولاً: قرارات المكتبات النهائية

### هيكل `pubspec.yaml` الكامل

```yaml
dependencies:
  flutter:
    sdk: flutter

  # ─── State Management ───────────────────────────────
  get: ^4.6.6                          # GetX — state + routing + DI

  # ─── Networking ─────────────────────────────────────
  dio: ^5.4.0                          # HTTP client
  flutter_secure_storage: ^9.0.0       # تخزين JWT + secrets آمن

  # ─── Local Database (Isar > Hive للمشروع هذا) ──────
  isar: ^3.1.0+1                       # قاعدة بيانات محلية — أسرع من Hive
  isar_flutter_libs: ^3.1.0+1          # Flutter bindings
  path_provider: ^2.1.2                # مسارات الملفات

  # ─── Authentication & Security ──────────────────────
  local_auth: ^2.1.8                   # Fingerprint + FaceID
  device_info_plus: ^10.1.0            # Device fingerprinting
  crypto: ^3.0.3                       # HMAC-SHA256

  # ─── Camera & Scanning ──────────────────────────────
  camerawesome: ^2.0.0                 # كاميرا متقدمة مع تحكم كامل
  cunning_document_scanner: ^0.2.0     # Edge detection + Auto-crop (iOS/Android)
  image_picker: ^1.0.7                 # Gallery fallback

  # ─── Image Processing ───────────────────────────────
  image: ^4.1.7                        # معالجة صور Dart-native (offline)
  opencv_dart: ^1.3.2                  # Adaptive thresholding + advanced ops
  flutter_image_compress: ^2.1.0       # ضغط JPEG بجودة قابلة للضبط

  # ─── PDF Generation ─────────────────────────────────
  pdf: ^3.10.8                         # إنشاء PDF بدعم العربية
  printing: ^5.12.0                    # مشاركة + طباعة + preview

  # ─── Voice & Audio ──────────────────────────────────
  record: ^5.1.0                       # تسجيل صوتي (OGG/WAV) — أخف من flutter_sound
  permission_handler: ^11.3.0          # صلاحيات Mic + Camera + Storage

  # ─── Connectivity & Background ──────────────────────
  connectivity_plus: ^6.0.3            # كشف الإنترنت
  workmanager: ^0.5.2                  # Background sync jobs

  # ─── UI & UX ────────────────────────────────────────
  cached_network_image: ^3.3.1         # صور من الشبكة
  shimmer: ^3.0.0                      # Loading skeleton
  lottie: ^3.1.0                       # Animations

  # ─── Utilities ──────────────────────────────────────
  uuid: ^4.3.3                         # Batch IDs
  intl: ^0.19.0                        # تنسيق التواريخ والأرقام العربية
  package_info_plus: ^8.0.0            # App version

dev_dependencies:
  isar_generator: ^3.1.0+1
  build_runner: ^2.4.8
  flutter_test:
    sdk: flutter
```

### لماذا Isar وليس Hive؟

| المعيار | Hive | Isar |
|---------|------|------|
| السرعة | جيد | أسرع 10x على الـ queries |
| Type Safety | يدوي (TypeAdapters) | تلقائي عبر code generation |
| Queries | محدود | Full query engine مع indexes |
| الحجم | خفيف | أكبر قليلاً |
| الاستخدام | بسيط جداً | يحتاج build_runner مرة واحدة |
| الاختيار | MVP بسيط | **مُصادَق** — لأننا نحتاج queries معقدة على الفواتير المحلية |

---

## المرحلة 1 — أساس المشروع والأمان (الأسبوع 1-3)

### 1.1 هيكل مجلدات Flutter

```
lib/
├── main.dart
├── app/
│   ├── bindings/           # GetX bindings
│   ├── routes/             # AppPages + AppRoutes
│   └── theme/              # AppColors, AppStyles
├── core/
│   ├── network/
│   │   ├── dio_client.dart          # Dio instance
│   │   └── hmac_interceptor.dart    # HMAC signing
│   ├── storage/
│   │   ├── isar_service.dart        # Isar instance singleton
│   │   └── secure_storage.dart     # flutter_secure_storage wrapper
│   ├── services/
│   │   ├── auth_service.dart
│   │   ├── biometric_service.dart
│   │   └── device_service.dart     # fingerprint + hardware check
│   └── constants/
│       ├── app_link.dart            # API endpoints
│       ├── app_color.dart
│       └── box_name.dart            # Isar collection names
├── features/
│   ├── auth/               # Login + OTP + Biometric
│   ├── scanner/            # Batch camera + image processing
│   ├── invoices/           # Invoice list + detail
│   ├── voice/              # Voice assistant
│   └── dashboard/          # Main dashboard
└── shared/
    ├── widgets/
    └── models/
```

### 1.2 HMAC Interceptor (أمان الـ API)

```dart
// core/network/hmac_interceptor.dart
class HmacInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
    final body = options.data != null ? jsonEncode(options.data) : '';
    final apiSecret = SecureStorage.read(BoxName.apiSecret);
    
    // HMAC-SHA256: timestamp + method + path + body
    final message = '$timestamp|${options.method}|${options.path}|$body';
    final hmac = Hmac(sha256, utf8.encode(apiSecret ?? ''));
    final signature = hmac.convert(utf8.encode(message)).toString();
    
    options.headers['X-Timestamp'] = timestamp;
    options.headers['X-Signature'] = signature;
    options.headers['Authorization'] = 'Bearer ${SecureStorage.read(BoxName.jwt)}';
    
    handler.next(options);
  }
}
```

### 1.3 نظام المصادقة — SMS OTP + Biometric

**التدفق الكامل:**

```
[المدير يُضيف محاسب + رقم هاتفه في Web Dashboard]
        ↓
[المحاسب يفتح التطبيق → يدخل رقم الهاتف]
        ↓
[Backend يرسل OTP عبر SMS (Twilio أو منصة محلية أردنية)]
        ↓
[المحاسب يدخل OTP → Backend يتحقق → يرجع JWT]
        ↓
[التطبيق يحفظ JWT + يطلب تفعيل البصمة/FaceID]
        ↓
[عمليات الدخول التالية: بصمة فقط (أو PIN كـ fallback)]
```

```dart
// features/auth/controllers/auth_controller.dart
class AuthController extends GetxController {
  final _biometricService = Get.find<BiometricService>();
  final _authService = Get.find<AuthService>();
  final _deviceService = Get.find<DeviceService>();

  Future<void> requestOtp(String phone) async {
    final deviceFingerprint = await _deviceService.getFingerprint();
    // إرسال OTP مع fingerprint للتحقق منه في Backend
    await _authService.requestOtp(phone: phone, deviceId: deviceFingerprint);
  }

  Future<void> verifyOtp(String phone, String otp) async {
    final deviceFingerprint = await _deviceService.getFingerprint();
    final result = await _authService.verifyOtp(
      phone: phone,
      otp: otp,
      deviceId: deviceFingerprint,
    );
    // حفظ JWT في secure storage
    await SecureStorage.write(BoxName.jwt, result.token);
    await SecureStorage.write(BoxName.apiSecret, result.apiSecret);
    
    // عرض شاشة تفعيل البصمة
    if (await _biometricService.isAvailable()) {
      Get.toNamed(AppRoutes.biometricSetup);
    }
  }

  Future<void> loginWithBiometric() async {
    final authenticated = await _biometricService.authenticate();
    if (authenticated) {
      // التحقق من JWT مخزن + تجديده إذا انتهت صلاحيته
      final token = await SecureStorage.read(BoxName.jwt);
      if (token != null) Get.offAllNamed(AppRoutes.dashboard);
    }
  }
}
```

```dart
// core/services/device_service.dart
class DeviceService extends GetxService {
  Future<String> getFingerprint() async {
    final info = DeviceInfoPlugin();
    if (Platform.isAndroid) {
      final android = await info.androidInfo;
      // Combination of stable device identifiers
      final raw = '${android.brand}|${android.model}|${android.id}';
      return sha256.convert(utf8.encode(raw)).toString();
    } else {
      final ios = await info.iosInfo;
      final raw = '${ios.model}|${ios.identifierForVendor}';
      return sha256.convert(utf8.encode(raw)).toString();
    }
  }

  Future<DeviceCapability> checkCapability() async {
    final info = DeviceInfoPlugin();
    if (Platform.isAndroid) {
      final android = await info.androidInfo;
      final sdkInt = android.version.sdkInt;
      // Android 10+ (API 29) = متوافق
      if (sdkInt >= 29) return DeviceCapability.full;
      if (sdkInt >= 26) return DeviceCapability.limited;
      return DeviceCapability.unsupported;
    }
    // iOS 14+ = متوافق
    return DeviceCapability.full;
  }
}

enum DeviceCapability { full, limited, unsupported }
```

**Backend PHP — التحقق من OTP + Device:**

```php
// api/auth/verify_otp.php
function verifyOtpAndIssueToken($phone, $otp, $deviceId) {
    // 1. تحقق من OTP
    $storedOtp = Redis::get("otp:$phone");
    if ($storedOtp !== $otp) return ['error' => 'OTP غير صحيح'];
    
    // 2. جلب المستخدم
    $user = User::where('phone', $phone)->first();
    if (!$user) return ['error' => 'المستخدم غير موجود'];
    
    // 3. تسجيل/تحديث الجهاز
    UserDevice::updateOrCreate(
        ['user_id' => $user->id, 'device_fingerprint' => $deviceId],
        ['last_seen' => now(), 'is_trusted' => true]
    );
    
    // 4. توليد JWT مع device_id مضمّن
    $payload = [
        'user_id' => $user->id,
        'tenant_id' => $user->tenant_id,
        'device_id' => $deviceId,
        'exp' => time() + (30 * 24 * 3600) // 30 يوم
    ];
    $token = JWT::encode($payload, config('jwt_secret'), 'HS256');
    
    // 5. توليد API Secret خاص بهذا الجهاز للـ HMAC
    $apiSecret = hash('sha256', $user->id . $deviceId . config('app_key'));
    
    Redis::del("otp:$phone");
    return ['token' => $token, 'api_secret' => $apiSecret];
}
```

**جدول `user_devices` المطلوب إضافته:**

```sql
CREATE TABLE user_devices (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    device_fingerprint VARCHAR(64) NOT NULL,
    device_name VARCHAR(100),
    is_trusted TINYINT(1) DEFAULT 0,
    last_seen TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id),
    UNIQUE KEY unique_device (user_id, device_fingerprint)
);
```

---

## المرحلة 2 — الماسح الذكي ومعالجة الصور (الأسبوع 3-7)

### 2.1 وضع الدفعة (Batch Scan Mode)

```dart
// features/scanner/controllers/batch_scanner_controller.dart
class BatchScannerController extends GetxController {
  final images = <File>[].obs;
  final isProcessing = false.obs;
  final processedCount = 0.obs;
  
  // Pipeline: Scan → Process → Queue → Upload
  Future<void> addAndProcessImage(File rawImage) async {
    final capability = await DeviceService().checkCapability();
    
    File processed;
    if (capability == DeviceCapability.full) {
      // معالجة كاملة على الجهاز
      processed = await ImageProcessor.processLocally(rawImage);
    } else {
      // ضغط فقط — المعالجة على السيرفر
      processed = await ImageProcessor.compressOnly(rawImage);
    }
    
    images.add(processed);
    processedCount.value = images.length;
  }
  
  Future<void> generateAndUpload(String companyId) async {
    isProcessing.value = true;
    
    // 1. دمج الصور في PDF
    final pdf = await PdfGenerator.fromImages(images, companyName: companyId);
    
    // 2. حفظ في Isar كـ pending batch
    final batch = InvoiceBatch(
      id: Uuid().v4(),
      companyId: companyId,
      pdfPath: pdf.path,
      status: BatchStatus.pending,
      imageCount: images.length,
      createdAt: DateTime.now(),
    );
    await IsarService.instance.writeTxn(() async {
      await IsarService.instance.invoiceBatchs.put(batch);
    });
    
    // 3. محاولة رفع فورية إذا في إنترنت
    final hasConnection = await ConnectivityService.isConnected();
    if (hasConnection) {
      await _uploadBatch(batch);
    }
    // وإلا WorkManager سيتولى الرفع لاحقاً
    
    isProcessing.value = false;
  }
}
```

### 2.2 معالجة الصور — Pipeline كامل

```dart
// core/services/image_processor.dart
class ImageProcessor {
  /// Full pipeline: Edge → Perspective → Grayscale → Threshold → Compress
  static Future<File> processLocally(File input) async {
    // 1. تحميل الصورة
    final bytes = await input.readAsBytes();
    img.Image image = img.decodeImage(bytes)!;
    
    // 2. تدرج الرمادي
    image = img.grayscale(image);
    
    // 3. زيادة التباين (يساعد OCR)
    image = img.adjustColor(image, contrast: 1.5);
    
    // 4. تحسين الحدة
    image = img.sharpen(image, amount: 1.0);
    
    // 5. Binarization بسيط عبر image package
    image = _applyThreshold(image, threshold: 128);
    
    // ملاحظة: لـ Adaptive Thresholding الحقيقي → استخدم opencv_dart
    // final mat = await opencv.imread(input.path);
    // final processed = await opencv.adaptiveThreshold(mat, 255,
    //   opencv.ADAPTIVE_THRESH_GAUSSIAN_C, opencv.THRESH_BINARY, 11, 2);
    
    // 6. ضغط JPEG بجودة 85%
    final compressed = img.encodeJpg(image, quality: 85);
    
    // حجم متوقع: 4MB → ~200KB
    final output = File('${input.parent.path}/processed_${input.path.split('/').last}');
    await output.writeAsBytes(compressed);
    return output;
  }
  
  static img.Image _applyThreshold(img.Image src, {int threshold = 128}) {
    return img.adjustColor(src,
      hueRotation: 0,
      saturation: 0,
      exposure: 0,
      gamma: threshold / 128.0,
    );
  }
  
  static Future<File> compressOnly(File input) async {
    final compressed = await FlutterImageCompress.compressAndGetFile(
      input.path,
      '${input.parent.path}/compressed_${input.path.split('/').last}',
      quality: 70,
      minWidth: 1200,
      minHeight: 1600,
    );
    return compressed ?? input;
  }
}
```

### 2.3 توليد PDF من الصور

```dart
// core/services/pdf_generator.dart
class PdfGenerator {
  static Future<File> fromImages(
    List<File> images, {
    required String companyName,
  }) async {
    final pdf = pw.Document();
    
    for (final imageFile in images) {
      final imageBytes = await imageFile.readAsBytes();
      final pdfImage = pw.MemoryImage(imageBytes);
      
      pdf.addPage(pw.Page(
        pageFormat: PdfPageFormat.a4,
        margin: const pw.EdgeInsets.all(0),
        build: (ctx) => pw.Image(pdfImage, fit: pw.BoxFit.contain),
      ));
    }
    
    final date = DateTime.now().toString().split(' ')[0];
    final filename = 'فواتير_${companyName}_$date.pdf';
    final dir = await getApplicationDocumentsDirectory();
    final file = File('${dir.path}/$filename');
    await file.writeAsBytes(await pdf.save());
    return file;
  }
}
```

### 2.4 Isar Schema للـ Offline Queue

```dart
// shared/models/invoice_batch.dart
@collection
class InvoiceBatch {
  Id get isarId => fastHash(id);
  
  late String id;          // UUID
  late String companyId;
  late String pdfPath;
  late int imageCount;
  
  @enumerated
  late BatchStatus status; // pending | uploading | done | failed
  
  late DateTime createdAt;
  DateTime? uploadedAt;
  int retryCount = 0;
  String? errorMessage;
}

@collection
class LocalInvoice {
  Id get isarId => fastHash(id);
  
  late String id;
  late String batchId;
  late String imagePath;
  late String companyId;
  
  @enumerated
  late InvoiceStatus status; // pending | extracted | validated | submitted
  
  // بيانات مستخرجة من AI
  String? invoiceNumber;
  double? totalAmount;
  double? taxAmount;
  String? supplierName;
  
  late DateTime createdAt;
  bool isSynced = false;
}
```

---

## المرحلة 3 — المساعد الصوتي (الأسبوع 7-10)

### 3.1 معمارية كاملة: Record → Groq → Gemini → Command

```dart
// features/voice/controllers/voice_controller.dart
class VoiceController extends GetxController {
  final _recorder = AudioRecorder();
  final isRecording = false.obs;
  final lastCommand = ''.obs;
  final commandResult = Rxn<VoiceCommandResult>();
  
  static const maxDurationSeconds = 15;
  Timer? _autoStopTimer;
  
  Future<void> startRecording() async {
    if (!await _recorder.hasPermission()) return;
    
    final dir = await getTemporaryDirectory();
    final path = '${dir.path}/voice_${DateTime.now().millisecondsSinceEpoch}.m4a';
    
    await _recorder.start(
      const RecordConfig(encoder: AudioEncoder.aacLc, sampleRate: 16000),
      path: path,
    );
    isRecording.value = true;
    
    // إيقاف تلقائي بعد 15 ثانية
    _autoStopTimer = Timer(Duration(seconds: maxDurationSeconds), stopAndProcess);
  }
  
  Future<void> stopAndProcess() async {
    _autoStopTimer?.cancel();
    if (!isRecording.value) return;
    
    final path = await _recorder.stop();
    isRecording.value = false;
    
    if (path == null) return;
    
    final file = File(path);
    final result = await VoiceService.processCommand(file);
    commandResult.value = result;
    
    await _executeCommand(result);
  }
  
  Future<void> _executeCommand(VoiceCommandResult result) async {
    switch (result.action) {
      case VoiceAction.listInvoices:
        Get.toNamed(AppRoutes.invoices, arguments: result.params);
        break;
      case VoiceAction.checkQuota:
        Get.toNamed(AppRoutes.subscription);
        break;
      case VoiceAction.openScanner:
        Get.toNamed(AppRoutes.scanner, arguments: result.params);
        break;
      // ... باقي الأوامر
    }
  }
}
```

### 3.2 Voice Service — Groq STT + Gemini Intent

```dart
// features/voice/services/voice_service.dart
class VoiceService {
  static Future<VoiceCommandResult> processCommand(File audioFile) async {
    // Step 1: STT via Groq Whisper
    final text = await _groqTranscribe(audioFile);
    if (text.isEmpty) return VoiceCommandResult.failed('لم أفهم الأمر');
    
    // Step 2: Intent parsing via Gemini Flash Lite Latest
    final intent = await _parseIntent(text);
    return intent;
  }
  
  static Future<String> _groqTranscribe(File audio) async {
    final dio = DioClient.instance; // بدون HMAC (Groq خارجي)
    
    final formData = FormData.fromMap({
      'file': await MultipartFile.fromFile(audio.path, filename: 'voice.m4a'),
      'model': 'whisper-large-v3-turbo',
      'language': 'ar',
      'response_format': 'text',
    });
    
    final response = await Dio().post(
      'https://api.groq.com/openai/v1/audio/transcriptions',
      data: formData,
      options: Options(headers: {
        'Authorization': 'Bearer ${AppConfig.groqApiKey}',
      }),
    );
    
    return response.data.toString().trim();
  }
  
  static Future<VoiceCommandResult> _parseIntent(String text) async {
    const systemPrompt = '''
أنت محلل أوامر لنظام مُصادَق للفوترة الأردني.
استخرج النية والمعاملات من النص وأرجع JSON فقط.

الأوامر المتاحة:
- list_invoices: { company?: string, from?: date, to?: date, status?: string }
- check_quota: {}
- open_scanner: { company?: string }
- search_invoice: { amount?: number, company?: string, number?: string }
- get_report: { type: "tax"|"monthly", period?: string }
- check_status: { invoice_id?: string, company?: string }
- export_pdf: { invoice_id?: string, company?: string }
- navigate: { screen: string }

أرجع: { "action": "...", "params": {...}, "confirmation": "نص قصير تأكيد" }
''';
    
    final response = await Dio().post(
      'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite-latest:generateContent',
      queryParameters: {'key': AppConfig.geminiApiKey},
      data: {
        'contents': [{'parts': [{'text': text}]}],
        'systemInstruction': {'parts': [{'text': systemPrompt}]},
        'generationConfig': {
          'responseMimeType': 'application/json',
          'maxOutputTokens': 200,
        },
      },
    );
    
    final json = jsonDecode(
      response.data['candidates'][0]['content']['parts'][0]['text']
    );
    
    return VoiceCommandResult(
      action: VoiceAction.fromString(json['action']),
      params: json['params'] ?? {},
      confirmation: json['confirmation'] ?? '',
      rawText: text,
    );
  }
}
```

### 3.3 الأوامر الصوتية الـ 10

```dart
enum VoiceAction {
  listInvoices,    // "فواتير شركة X لشهر كذا"
  checkQuota,      // "كم باقي من رصيدي"
  openScanner,     // "صور فاتورة لشركة X"
  searchInvoice,   // "ابحث عن فاتورة 150 دينار"
  getReport,       // "تقرير ضريبة الشهر الماضي"
  checkStatus,     // "حالة فاتورة شركة X"
  exportPdf,       // "حوّل فاتورة 300 لـ PDF"
  listRejected,    // "الفواتير المرفوضة هذا الأسبوع"
  subscriptionInfo,// "حالة اشتراكي"
  navigate,        // "افتح لوحة التحكم"
  unknown,
}
```

---

## المرحلة 4 — AI Pre-Audit الضريبي (الأسبوع 10-13)

### 4.1 تحديث Backend — نظام Queue للفواتير

**المطلوب إضافته في الـ schema:**

```sql
-- جدول جديد: invoice_processing_queue
CREATE TABLE invoice_processing_queue (
    id INT AUTO_INCREMENT PRIMARY KEY,
    batch_id VARCHAR(36) NOT NULL,
    invoice_id INT,                    -- بعد الاستخراج
    tenant_id INT NOT NULL,
    image_path VARCHAR(500) NOT NULL,
    status ENUM('pending','processing','done','failed') DEFAULT 'pending',
    attempts INT DEFAULT 0,
    error_message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    processed_at TIMESTAMP NULL,
    INDEX idx_status_tenant (status, tenant_id),
    INDEX idx_batch (batch_id)
);

-- جدول جديد: invoice_batches
CREATE TABLE invoice_batches (
    id VARCHAR(36) PRIMARY KEY,
    tenant_id INT NOT NULL,
    company_id INT NOT NULL,
    pdf_path VARCHAR(500),
    total_images INT,
    processed_images INT DEFAULT 0,
    status ENUM('uploading','processing','done','partial_fail') DEFAULT 'uploading',
    created_by INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    completed_at TIMESTAMP NULL
);
```

### 4.2 تحديث InvoiceExtractionService.php

```php
// services/InvoiceExtractionService.php
class InvoiceExtractionService {
    // قواعد الضريبة الأردنية
    private array $taxRules = [
        // معفيات صفر
        'zero_rated' => ['أدوية', 'دواء', 'خبز', 'طحين', 'سكر', 'أرز'],
        // ضريبة خاصة
        'special' => ['سيارات' => 0.15, 'سجائر' => 0.32, 'كحول' => 0.30],
        // معدل عام
        'standard_rate' => 0.16, // 16% ضريبة مبيعات أردن
    ];
    
    public function extractAndAudit(string $imagePath, int $tenantId): array {
        // 1. استخراج البيانات من Gemini Vision
        $extracted = $this->extractWithVision($imagePath);
        
        // 2. AI Pre-Audit
        $audit = $this->performPreAudit($extracted);
        
        // 3. حساب Hash لمنع التكرار
        $hash = $this->calculateInvoiceHash($extracted);
        
        // 4. التحقق من التكرار
        $duplicate = Invoice::where('invoice_hash', $hash)
            ->where('tenant_id', $tenantId)->first();
        
        if ($duplicate) {
            $audit['warnings'][] = [
                'code' => 'DUPLICATE_INVOICE',
                'message' => 'هذه الفاتورة مرفوعة مسبقاً (رقم ' . $duplicate->id . ')',
                'severity' => 'critical'
            ];
        }
        
        return [
            'extracted' => $extracted,
            'audit' => $audit,
            'hash' => $hash,
            'jofotara_readiness' => $this->assessJoFotaraReadiness($extracted, $audit),
        ];
    }
    
    private function performPreAudit(array $data): array {
        $warnings = [];
        $errors = [];
        
        // فحص الضريبة
        if (isset($data['items'])) {
            foreach ($data['items'] as $item) {
                $expectedTax = $this->calculateExpectedTax($item['name'], $item['amount']);
                if (abs($item['tax'] - $expectedTax) > 0.01) {
                    $warnings[] = [
                        'code' => 'TAX_MISMATCH',
                        'message' => "ضريبة غير صحيحة لـ '{$item['name']}': المتوقع {$expectedTax} الموجود {$item['tax']}",
                        'severity' => 'high'
                    ];
                }
            }
        }
        
        // فحص اكتمال البيانات الإلزامية
        $required = ['supplier_name', 'invoice_number', 'invoice_date', 'total_amount'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                $errors[] = ['code' => 'MISSING_FIELD', 'field' => $field, 'severity' => 'critical'];
            }
        }
        
        return ['warnings' => $warnings, 'errors' => $errors];
    }
    
    private function assessJoFotaraReadiness(array $data, array $audit): array {
        $errorCount = count($audit['errors']);
        $highWarnings = array_filter($audit['warnings'], fn($w) => $w['severity'] === 'high');
        
        $score = 100 - ($errorCount * 30) - (count($highWarnings) * 15);
        return [
            'score' => max(0, $score),
            'ready' => $score >= 70,
            'message' => $score >= 70 ? 'جاهزة للإرسال' : 'تحتاج مراجعة قبل الإرسال'
        ];
    }
}
```

---

## المرحلة 5 — فحص الجهاز + Offline Architecture (الأسبوع 12-14)

### 5.1 Device Capability Check عند أول تشغيل

```dart
// features/auth/views/device_check_screen.dart
class DeviceCheckScreen extends GetView<DeviceCheckController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Obx(() {
        if (controller.isChecking.value) {
          return _buildCheckingUI();
        }
        return _buildResultUI(controller.capability.value);
      }),
    );
  }
  
  Widget _buildResultUI(DeviceCapability cap) {
    return switch (cap) {
      DeviceCapability.full => _buildFullModeUI(),
      DeviceCapability.limited => _buildLimitedModeUI(),
      DeviceCapability.unsupported => _buildUnsupportedUI(),
    };
  }
}

class DeviceCheckController extends GetxController {
  final isChecking = true.obs;
  final capability = DeviceCapability.full.obs;
  
  @override
  void onInit() {
    super.onInit();
    _runCheck();
  }
  
  Future<void> _runCheck() async {
    final result = await DeviceService().checkCapability();
    
    // حفظ النتيجة محلياً
    GetStorage().write(BoxName.deviceCapability, result.name);
    
    capability.value = result;
    isChecking.value = false;
  }
}
```

### 5.2 WorkManager للـ Background Sync

```dart
// main.dart
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) async {
    switch (task) {
      case 'syncPendingBatches':
        await _syncPendingBatches();
        break;
      case 'retryFailedUploads':
        await _retryFailedUploads();
        break;
    }
    return Future.value(true);
  });
}

// في main():
Workmanager().initialize(callbackDispatcher);
Workmanager().registerPeriodicTask(
  'syncTask',
  'syncPendingBatches',
  frequency: const Duration(minutes: 15),
  constraints: Constraints(networkType: NetworkType.connected),
);
```

---

## الملخص التنفيذي بالأسابيع

| الأسبوع | التركيز | المخرجات |
|---------|---------|----------|
| 1-2 | هيكل المشروع + HMAC + Isar setup | بنية مجلدات نظيفة، DioClient محمي |
| 2-3 | SMS OTP + Biometric Auth | تسجيل دخول آمن كامل |
| 3-5 | Batch Scanner + camerawesome | تصوير متسلسل يعمل |
| 5-7 | Image Processing (image + opencv) | صور مضغوطة ومحسّنة |
| 7-8 | PDF Generator + Offline Queue | دفعات محفوظة محلياً |
| 8-10 | Voice: Record → Groq → Gemini | 10 أوامر صوتية تعمل |
| 10-12 | AI Pre-Audit في Backend | تحذيرات ضريبية قبل JoFotara |
| 12-13 | Device Check + WorkManager Sync | مزامنة خلفية موثوقة |
| 13-14 | Testing + Beta (10 مكاتب عمان) | إطلاق تجريبي |

---

## قرارات نهائية سريعة

| القرار | الاختيار | السبب |
|--------|---------|-------|
| STT | Groq Whisper | الأرخص 9x + الأسرع |
| Intent LLM | Gemini 2.0 Flash Lite Latest | ما ينوقف، مجاني بحد معقول |
| Local DB | Isar | Queries معقدة على الفواتير |
| Camera | camerawesome | تحكم أفضل في Batch Mode |
| Image Processing | image (Dart) + opencv_dart | مرونة: Dart للبسيط، OpenCV للمعقد |
| PDF | pdf (pub.dev) | دعم RTL + عربية |
| Recording | record | أخف من flutter_sound، كافٍ للمهمة |
| Background Sync | WorkManager | الأكثر موثوقية لـ iOS + Android |
| Security Storage | flutter_secure_storage | Keychain/Keystore native |