1. الهيكل — لا تبنِ شاشات من الصفر مرتين
المستودع مونوريبو. التطبيقان رفيعان؛ المنطق والشاشات مشتركة.
apps/farmer_app org.nidaa.user AppKind.farmer apps/admin_app org.nidaa.admin AppKind.admin packages/shared_ui BridgeApp + كل الشاشات packages/core HttpBridgeRepository + النماذج
main.dart في كل تطبيق ينشئ HttpBridgeRepository() ثم BridgeApp(kind: ..., repository: ...).
عنوان المختبر: packages/core/lib/src/lab_url.dart → http://174.138.29.61:18080/v1.
البناء الميداني يستخدم --dart-define=USE_HTTP=true وGOOGLE_SERVER_CLIENT_ID=....
العقد الوحيد مع الخادم
كل الطلبات تمر من HttpBridgeRepository الذي ينفّذ BridgeRepository. لا تستدعِ http من الشاشة مباشرة.
- JSON UTF-8، الرأس
Authorization: Bearerبعد الدخول. - المعرّفات BigInt تُرسل وتُقرأ نصوصاً:
"id": "1". - رمز الوصول يُجدَّد تلقائياً عبر
POST /auth/refreshعند 401. - الأخطاء: اعرض
messageArأوmessageEnحسبrepo.english. - الوسائط:
uploadBytesثم احفظurl. للعرض استخدمmediaAccessUrl(يضيف access_token للاستعلام).
2. المصادقة — اختلاف التطبيقين
| تطبيق | حقل الدخول | من يُقبل |
|---|---|---|
| مزارع | هاتف + كلمة مرور | دور farmer فقط. ارفض مشرف/مالك محلياً. |
| إدارة | بريد + كلمة مرور | دور admin أو owner فقط. ارفض مزارع محلياً. |
login() يرسل phone إن لم يحتوِ المعرّف على @، وإلا email.
POST /v1/auth/login
{ "phone": "0120000001", "password": "LabBridge#2026" }
{ "email": "admin.lab@nidaa.local", "password": "LabBridge#2026" }
الاستجابة إما جلسة status: ok أو otp_required أو phone_required (بعد قوقل/فيسبوك بلا هاتف).
حسابات @nidaa.local تتجاوز OTP في المختبر. فاطمة 0120000004 هاتفها غير موثّق لكنها تدخل لأن البريد مختبري؛ المشرف يوثّق الرقم من تفاصيل المزارع.
موقوف (عمر 0120000005): الخادم يرفض الدخول. لا تحاول «إصلاح» ذلك في الواجهة.
بعد الجلسة
- احفظ access/refresh في
FlutterSecureStorage(المفاتيحnidaa.access/nidaa.refresh/nidaa.user). restoreSession()يعيد المستخدم إن وُجد رمز صالح.GET /auth/meيحدّث الأهلية والملف.
3. خريطة الشاشات → المستودع
التبويبات تُبنى في ShellPage حسب AppKind وuser.role وuser.supportEligible.
| الشاشة | متى تظهر | استدعاءات أساسية |
|---|---|---|
| الرئيسية | دائماً | content() |
| الأسعار | دائماً | cropPrices() — الكتابة: createCropPrice / updateCropPrice |
| الإرشاد / المعلومات | دائماً | content(stage:, kind:) — الكتابة: createContent / publishContent |
| الدفعات | مزارع + أهلية | myPayments() myBank() submitBank() myQr() getPayment() |
| المزارعون | إدارة | searchFarmers getFarmer reviewPhone reviewBank setEligibility setPaymentStatus reopenPayment resetFarmerPayments suspendFarmer deleteFarmer |
| المحاصيل | إدارة | lookups() createCrop createMarket |
| مسح QR | إدارة (أيقونة العنوان) | verifyQr(token) |
| لوحة المالك | owner فقط | ownerDashboard listBackups createBackup restoreBackup backupSchedule |
| الإشعارات | دائماً | notifications markRead — إن وُجد paymentId افتح PaymentDetailPage |
| الملف | دائماً | updateProfile setLang |
قواعد أعمال يجب احترامها في الواجهة
- لا تُظهر تبويب الدفعات إن
supportEligible != true. - لا تملأ مبلغ الدفعة مسبقاً. حقل المبلغ + رقم العملية + صورة الإشعار عند «إتمام الصرف».
- البنك قيد المراجعة: انسخ «تم رفع البيانات، في انتظار التوثيق» — لا تطلب الرفع ثانية إلا إذا طُلب تحديث.
- الأهلية بعد هاتف موثّق وملف مكتمل. البنك ليس شرطاً لهذه الخطوة.
- الدورة: مفتاح فريد
(farmer, stage, cycle)للصفوف غير المحذوفة. بعد الحذف/الاستعادة لا تُنشئ دفعة مكررة يدوياً — استخدم API. - الحذف النهائي للمزارع: المالك فقط.
- لا تغلف
NavigationBarبـCenter. فيListViewاستخدمCompactLoaderلاCircularProgressIndicatorبعرض الشاشة.
4. اللغة والوضع الداكن
packages/shared_ui/lib/src/l10n.dart — الدالة t(context, ar, en). اللغة الافتراضية عربية حتى تنجح اختبارات الويدجت.
- بدّل اللغة من الدخول أو الملف. تُحفظ في التخزين الآمن
nidaa.lang. - منشورات الإرشاد تبقى بنص المؤلف. الإشعارات تختار
titleEn/bodyEnعند الإنجليزية. - الوضع الداكن محلي على الجهاز، ليس من الخادم.
5. كيف تضيف ميزة
- أضف المسار في Nest ثم الدالة في
BridgeRepositoryوHttpBridgeRepository. - حدّث النموذج في
models.dartمعfromJsonيتحمّل النصوص للأرقام. - أضف الشاشة في
shared_uiواستخدمt()لكل نص واجهة. - اربط التبويب في
ShellPageبشرط الدور/الأهلية. - لا تبنِ APK المزارع والإدارة معاً (OOM). ابنِ واحداً ثم انسخ إلى
infra/caddy/apk/.
مزارع أحمد 0120000001 LabBridge#2026 مزارعة فاطمة 0120000004 LabBridge#2026 مزارع عمر 0120000005 موقوف — لا يدخل مشرف admin.lab@nidaa.local مالك owner.lab@nidaa.local
تقرير المنتج بالشاشات: report.html. كتالوج REST: frontend-api.html.