يستطيع تطبيق Flutter أن يُبقي العمل الميداني مستمرًا حين ينقطع الاتصال بأودو. وينبغي له أن يحفظ مسودة محلية، ويضع الإجراء المقصود في قائمة الانتظار، ثم يُجري المزامنة حين يصبح الخادم متاحًا. لكن ينبغي ألّا يُخبر عامل المستودع بأن المخزون قد نُقل، أو الفني بأن أمر الخدمة قد اكتمل في أودو، قبل أن يتحقق الخادم من ذلك الإجراء ويثبّته.
هذا الفرق بين ما سُجّل محليًا وما قَبِله نظام تخطيط موارد المؤسسة (ERP) هو جوهر التصميم الموثوق الذي يعمل دون اتصال أولًا (Offline-first). وهو يفسّر أيضًا لماذا لا يكفي تخزين الشاشات مؤقتًا أو مراقبة تغيّرات شبكة Wi-Fi.
يصف دليل Flutter الرسمي لبنية التطبيقات التي تعمل دون اتصال أولًا مستودعات برمجية (Repositories) تنسّق بين التخزين المحلي والخدمات البعيدة، مع استراتيجيات مختلفة للقراءة والكتابة في وضع عدم الاتصال. أما وثائق JSON-2 API في الإصدار 20 من أودو فتشرح الجانب الآخر من الحدود: كل طلب API يُنفَّذ في معاملة مستقلة، لذا يجب التعامل بعناية مع العمليات التجارية متعددة الخطوات.
نعرض فيما يلي نهجًا تصميميًا لتطبيقات المستودعات والخدمة الميدانية والتوصيل والموظفين التي تحتاج إلى تسجيل محلي يُعتمد عليه وإلى سجلات مرجعية في أودو في آنٍ واحد.
حدّد العمليات المسموح بها في وضع عدم الاتصال
افعل ذلك قبل اختيار قاعدة بيانات أو حزمة مزامنة في Flutter. فالقدرة على العمل دون اتصال يجب أن تتبع المخاطر التجارية.
| الإجراء في التطبيق الجوال | السلوك الآمن دون اتصال | ما الذي يظل بحاجة إلى أودو |
|---|---|---|
| عرض مهمة مُسندة | عرض آخر نسخة مخزّنة مؤقتًا مصرّح بها، مع الإشارة إلى عمرها | الإسناد الحديث والإلغاء وفحوص الصلاحيات |
| صياغة مسودة تقرير خدمة | حفظ النص وإجابات قائمة التحقق ومراجع المرفقات محليًا | التحقق من حالة المهمة وملكيتها وقواعد إكمالها |
| مسح منتج وموقع | وضع عملية مسح مقترحة في قائمة الانتظار مقابل المهمة التي جرى تنزيلها | تأكيد التوفر وقواعد الدفعات والأرقام التسلسلية والكمية المحجوزة والوجهة |
| تسجيل إثبات التسليم | حفظ الدليل محليًا ووسم الرفع بأنه معلّق | التحقق من حالة الطلب وقبول الدليل |
| تسجيل الحضور في موقع العمل | عرض الحدث المسجّل على أنه بانتظار التحقق إذا كان التسجيل دون اتصال مسموحًا | التحقق من الهوية والسياسة والطوابع الزمنية ودليل الموقع |
| ترحيل تسوية مخزون أو مستند مالي | منع الترحيل النهائي دون اتصال عادةً | تنفيذ المعاملة التجارية المرجعية |
قد يدعم التطبيق الميداني الذي يعمل دون اتصال بعض هذه الإجراءات ويرفض غيرها عن قصد. فعلى سبيل المثال، يمكن التقاط صورة إثبات التسليم دون اتصال، بينما قد يعتمد إكمال التسليم على حركات مخزون وسجلات أخرى تغيّرت أثناء انقطاع الهاتف عن الشبكة.
تناقش نظرة Octivex العامة على تطوير التطبيقات الجوالة كيفية تحديد حدود سير العمل هذه. أما السؤال هنا فأضيق: كيف ينبغي لآلية المزامنة أن تنفّذها؟
البنية: مستودع برمجي محلي واحد، وصندوق صادر دائم واحد، ومرجعية واحدة على الخادم
يضم التطبيق العملي خمس مسؤوليات:
- واجهة العرض ونموذج العرض في Flutter يعرضان الحالة المعروفة محليًا، بما فيها التغييرات غير المُزامَنة.
- المستودع البرمجي الخاص بالميزة ينسّق القراءة والكتابة كي لا ترتجل عناصر الواجهة أي استدعاء للشبكة.
- قاعدة البيانات المحلية تخزّن السجلات المخزّنة مؤقتًا المسموح بها، والمسودات، وصندوق الصادر (Outbox) الذي يضم الأوامر المعلّقة.
- عامل المزامنة يرسل الأوامر المؤهلة، ويفسّر الردود، ويحدّث الحالة المحلية.
- نقطة تكامل أو خدمة في أودو تصادق على هوية المنفّذ، وتتحقق من قواعد العمل، وتطبّق الأمر مرة واحدة، وتعيد نتيجة مرجعية.
تصف إرشادات Flutter المستودعات البرمجية بأنها حدود الوصول إلى البيانات في التطبيق، كما تفضّل توصياتها لبنية التطبيقات الفصل بين اهتمامات الواجهة واهتمامات البيانات.
قاعدة البيانات المحلية على الهاتف ليست نظام ERP آخر. إنها نسخة عمل مؤقتة بصلاحيات محدودة، ومعها قائمة انتظار بالأعمال التي تنتظر نظام السجل المرجعي. ويظل أودو مسؤولًا عن المخزون والرواتب والاعتمادات والتسعير والتزامات العملاء وانتقالات الحالة التجارية.
ضع المسودة وحدث صندوق الصادر في معاملة محلية واحدة
لنفترض أن فنيًا أنهى مهمة في قبو لا تصله أي إشارة. إذا حفظ التطبيق النموذج لكنه تعطّل قبل تسجيل إجراء المزامنة المعلّق، فقد لا يصل النموذج إلى الخادم أبدًا. وإذا وضع الأمر في قائمة الانتظار دون حفظ النموذج، فقد تحمل إعادة المحاولة بيانات ناقصة.
بدلًا من ذلك، اجعل معاملة واحدة في قاعدة البيانات المحلية تؤدي الأمرين معًا:
- حفظ المسودة المحلية المعدّلة للفني؛
- إدراج أمر غير قابل للتعديل في صندوق الصادر مع معرّف فريد ثابت؛
- تعيين الحالة المحلية إلى
pending.
عندها فقط اعرض رسالة “حُفظ على هذا الجهاز · بانتظار المزامنة.” ولا ينبغي أن تؤدي إعادة تشغيل الجهاز إلى محو أي من الجزأين.
قد يبدو غلاف الأمر التوضيحي على النحو التالي:
{
"command_id": "uuid-created-once-and-persisted",
"command_type": "submit_service_report",
"record_ref": "assigned-job-427",
"base_revision": "last-server-revision-seen",
"payload": {
"checklist_complete": true,
"notes": "Inspection completed"
}
}تصميم توضيحي فقط: هذه ليست حقولًا قياسية في أودو ولا دالة مدمجة في JSON-2. فهي تتطلب عقدًا للتطبيق وتنفيذًا على جانب الخادم. وعلى وجه الخصوص، ينبغي تخزين المسودة المحلية والأمر معًا باستخدام طبقة حفظ تدعم المعاملات وتناسب الأجهزة المدعومة.
صمّم قائمة انتظار المزامنة بوصفها آلة حالات
لا تكفي قائمة الانتظار الموثوقة قيمة منطقية من نوع isSynced. والحد الأدنى المفيد هو:
pending → sending → acknowledged
مع تفرّعات من sending إلى retry_wait أو conflict أو rejected.
- pending (معلّق): محفوظ محليًا ولم يؤكده أودو بعد.
- sending (قيد الإرسال): هناك محاولة جارية. وإذا توقف التطبيق في هذه المرحلة، فلا تُعِد المحاولة إلا في ظل عقد خادم يضمن عدم التكرار.
- retry_wait (بانتظار إعادة المحاولة): عطل مؤقت، ويُحتفظ بالأمر مع موعد إعادة المحاولة المؤهلة التالية.
- acknowledged (مؤكَّد): قبل أودو الأمر وأعاد معرّف السجل أو النتيجة.
- conflict (تعارض): وجد أودو حالة أحدث أو غير متوافقة على الخادم؛ ويجب أن يحسمها مستخدم أو سياسة صريحة.
- rejected (مرفوض): فشل التحقق أو التفويض، ولن تعالج إعادة المحاولة التلقائية السبب.
احفظ معرّف الأمر، ونوع العملية، وسياق المنفّذ، ووقت الإنشاء، وعدد المحاولات، وآخر رمز خطأ آمن، وإقرار الخادم. وتجنّب حفظ الأسرار في قائمة الانتظار أو تفريغ الحمولات في سجلات التحليلات.
قد تحتاج الأوامر المتعلقة بالسجل التجاري نفسه إلى ترتيب صارم: فلا يمكن إرسال تقرير قبل رفع المرفق المطلوب له، ويجب ألا يسبق الإلغاءُ عمليةَ إنشاء يعتمد عليها. أما السجلات غير المترابطة فيمكن مزامنتها بشكل مستقل إذا سمح عقد الخادم بذلك.
اعرض النتائج الثلاث ذات المعنى للمستخدم: مخزّن على الجهاز، وبانتظار الخادم، ومؤكَّد من أودو. ويجب أن تعني علامة النجاح الخضراء الحالة الثالثة، لا الأولى فحسب.
توفر الشبكة مؤشر وليس استدعاء API ناجحًا
يحذّر القائمون على حزمة connectivity_plus صراحةً من أن الاتصال بشبكة Wi-Fi أو بالشبكة الخلوية لا يضمن الوصول إلى الإنترنت. فقد تظل بوابة تسجيل الدخول، أو خطأ DNS، أو انتهاء الجلسة، أو جدار الحماية، أو تعذّر الوصول إلى خادم أودو، عائقًا أمام المزامنة.
استخدم إشارات الاتصال من أجل جدولة المحاولة، لا للإعلان عن نجاحها. وتشمل مجموعة المشغّلات العملية ما يلي:
- عودة التطبيق إلى الواجهة؛
- ضغط المستخدم على “زامِن الآن”؛
- حدث تغيّر الشبكة؛
- فرصة تشغيل في الخلفية مقيّدة بعناية؛
- إعادة محاولة بعد مهلة تراجع قصيرة إثر عطل مؤقت.
تحتاج حلقة إعادة المحاولة إلى مهلات للطلبات، وتراجع أسّي مع تذبذب عشوائي، وسياسة لحد أقصى من المحاولات التلقائية عند تكرار الأعطال النهائية. وأبقِ قائمة الانتظار ظاهرة حين تعود الشبكة بينما لا تزال نقطة الاستقبال في أودو غير متاحة.
لا يُضمن تنفيذ المهام في الخلفية في لحظة محددة. ويحذّر دليل Flutter الرسمي من قيود البطارية والمنصة. وتدعم WorkManager في Android قيود الشبكة والبطارية، لكن المهام قد تُؤجَّل. لذا صمّم التطبيق على افتراض أن المزامنة في الواجهة عند التشغيل التالي قد تكون أول فرصة موثوقة.
امنع تكرار الطلبات وتسجيلات الحضور وإكمال المهام
يقع أصعب الأعطال حين يثبّت أودو الطلب لكن الهاتف لا يتلقى الرد أبدًا. فيرى التطبيق الجوال انتهاء المهلة ولا يستطيع معرفة ما إذا كان الخادم قد حفظ شيئًا.
ومجرد إعادة محاولة استدعاء create عام قد تُنشئ سجلًا ثانيًا.
استخدم معرّف أمر ثابتًا يُولَّد مرة واحدة على الهاتف ويُحفظ مع الإجراء الأصلي. وأرسل المعرّف نفسه في كل إعادة محاولة. ويجب أن تتعرف نقطة الاستقبال في أودو بشكل ذري على المعرّف الذي سبقت معالجته، وأن تعيد النتيجة الأصلية بدلًا من تنفيذ الإجراء مرة أخرى.
يتضمن عقد الخادم المتين ما يلي:
- معرّف أمر فريد واحد ضمن نطاق تجاري مناسب؛
- منفّذ مُصادَق عليه ومُفوَّض؛
- سجل دائم على الخادم لتنفيذ الأمر أو نتيجته؛
- قيد تفرّد أو حماية مكافئة قائمة على المعاملات؛
- عملية تجارية تُنفَّذ ضمن المعاملة ذات الصلة؛
- الرد الآمن نفسه عند تكرار معرّف الأمر.
التحقق من التكرار على جانب التطبيق وحده غير كافٍ. فقد يصل طلبان في الوقت نفسه، وقد يكون رد سابق قد فُقد.
تنص وثائق المعاملات في JSON-2 في أودو 20 على أن كل استدعاء API يُنفَّذ في معاملة SQL مستقلة. وتوصي بدالة واحدة على جانب الخادم للعمل التجاري الذي يجب أن يكتمل بشكل ذري. لذا قد تكون وحدة أودو مخصصة ومراجَعة هي الخيار المناسب حين يجب على إجراء واحد دون اتصال أن يتحقق من المهمة، ويغيّر حالتها، وينشئ الدليل، ويخزّن نتيجة الأمر معًا.
لا تخلط بين معرّف الأمر الثابت وضمان أن كل دالة في أودو تحقق منع التكرار. بل إن التنفيذ على الخادم هو الذي يجب أن يفرض هذا السلوك.
عرّف التعارضات حسب العملية التجارية، لا حسب الطابع الزمني وحده
لنفترض أن فنيًا نزّل مهمة في الصباح، وملأ تقريرًا دون اتصال، ثم عاد إلى الشبكة بعد أن ألغى منسّق العمليات المهمة. إن ترحيل التقرير القديم بصمت بوصفه “مكتملًا” سيمحو قرارًا تجاريًا له معناه.
احفظ لكل تعديل آخر مراجعة معروفة على الخادم أو مؤشر إصدار آخر متفقًا عليه في العقد. وقبل تطبيق الأمر، يقارن الخادم تلك الحالة بالسجل الحالي ويختار سياسة موثّقة.
| الحالة | النهج الموصى به |
|---|---|
| ملاحظة جديدة غير قابلة للتعديل مرتبطة بمهمة نشطة | أضِفها إن كان ذلك لا يزال مسموحًا؛ ولا تستبدل سجلًا تاريخيًا غير ذي صلة |
| مسودة نص حر معدّلة | ادمج الحقول غير المتداخلة فقط وفق سياسة محددة؛ وإلا فأحِلها إلى المراجعة |
| مهمة ملغاة يجري وسمها بأنها مكتملة | ارفضها بوصفها تعارضًا واطلب قرارًا |
| تغيّر كمية المخزون أو الحجز | أعِد التحقق مركزيًا؛ ولا تعتمد قاعدة "الكتابة الأخيرة تفوز" |
| اعتماد الإجازة أو الترحيل المالي | أبقِ الاعتماد والترحيل مرجعيين في أودو |
الطوابع الزمنية لساعة الجهاز دليل مفيد، لكنها ليست أداة شاملة لحل التعارضات. فالساعات تنحرف، والتحديثات تصل بغير ترتيبها، ولا يمكن استبدال حالة الاعتماد أو المخزون بأمان استنادًا إلى قاعدة “الأحدث يفوز.”
ينبغي أن يعرض التعارض ما أرسله العامل الميداني، وما يقوله أودو الآن، وما الخطوة التالية. وأبقِ العمل الأصلي المنجز دون اتصال قابلًا للاستعادة من قِبل المشغّلين المعنيين بدلًا من حذفه بعد رد تعارض من نوع 409. ويبقى التصميم الدقيق لردود HTTP خاصًا بكل تطبيق.
التكامل مع أودو 20: JSON-2 ووحدات التحكم المخصصة والأسرار
تصف وثائق JSON-2 الرسمية للإصدار 20.0 في أودو مسارات نقاط الاستقبال مثل /json/2/<model>/<method>، والمصادقة بمفتاح API، والمعاملات على مستوى الدالة، وفرض قواعد السجلات وفق المستخدم المُصادَق عليه. كما تنص على أن الوصول الخارجي إلى JSON-2 API متاح في خطط التسعير المخصصة (Custom)، لا في One App Free أو Standard؛ لذا تحقق من الإصدار الفعلي والاستضافة والخطة التجارية قبل الاعتماد على هذا المسار.
ولا تعني هذه الحقائق أن مفتاح API ذا الصلاحيات العالية مكانه داخل تطبيق Flutter قابل للتوزيع. إذ تشرح إرشادات OWASP بشأن التخزين في التطبيقات الجوالة وإرشاداتها بشأن الأسرار المضمّنة في الشيفرة لماذا يمكن استخراج الأسرار المضمّنة في حزم التطبيقات.
في تكاملات التطبيقات الجوالة، استخدم بنية مصادقة مناسبة للمستخدم النهائي أو طبقة وسيطة مُصادَقًا عليها. ويمكن لوحدة تحكم مخصصة في أودو أن تكشف إجراءً تجاريًا محدود النطاق ومحكوم الصلاحيات، بينما قد يناسب JSON-2 العمليات الموثوقة بين خادم وآخر. ويجب ألا تقبل نقطة المزامنة في التطبيق الجوال user_id أو company_id أو علامات “معتمد” بوصفها مرجعية لمجرد أن التطبيق يرسلها.
تحقق على الخادم من صلاحيات المستخدم الحالية وشركاته وقواعد السجلات والحالة التجارية في كل إعادة تشغيل. وإذا فقد المستخدم صلاحية الوصول أثناء انقطاع الاتصال، فقد يُرفض الإجراء المعلّق عند عودة الاتصال. وهذا سلوك صحيح، وليس عطلًا في محرك المزامنة.
وهناك أيضًا أسباب وجيهة لاستخدام تجربة أودو الأصلية المتجاوبة بدلًا من تطبيق Flutter مخصص. قيّم سير العمل المدعوم، والأجهزة الطرفية، ومتطلبات العمل دون اتصال، والمسؤولية عن الصيانة قبل إضافة تطبيق آخر. وللاطلاع على خلفية توجه أودو في API الخارجي، راجع دليل Octivex للتكامل عبر JSON-2 في أودو 20.
المرفقات تحتاج إلى تصميم استعادة خاص بها
تضيف الصور والتواقيع وملفات PDF نمط عطل منفصلًا. فقد يكون التقرير أمر JSON صغيرًا، بينما يبلغ حجم دليله عدة ميغابايتات.
حدّد ما إذا كان يمكن إرسال التقرير قبل وصول المرفقات، وما إذا كان يمكن استئناف الرفع، وكيف يُنظَّف الرفع اليتيم. وخزّن حالة المرفقات ضمن مخطط العمليات الدائم نفسه، مع الاحتفاظ بالمراجع المحلية إلى أن يؤكد الخادم قبول الملف وربطه التجاري معًا.
يجب أن يتحقق الخادم من نوع المحتوى والحجم والملكية وصلاحية الوصول إلى سجل أودو المرتبط. ولا تفترض أن “رُفع الملف” تعني “قُبل إثبات التسليم.”
وتحتاج ذاكرة التخزين المؤقت دون اتصال أيضًا إلى خطة احتفاظ. فلا ينبغي أن تبقى مستندات الرواتب وملفات الهوية وعناوين العملاء إلى أجل غير مسمى بنص غير مشفّر على جهاز قد يُفقد. استخدم تخزين بيانات الاعتماد المدعوم من المنصة حيثما كان مناسبًا، واحمِ البيانات الحساسة المحلية، وقيّد النسخ الاحتياطية، وأخفِ البيانات الحساسة في السجلات. وتغطي ضوابط التخزين في MASVS من OWASP حالات انكشاف البيانات المخزّنة المقصودة وغير المقصودة.
مصفوفة اختبارات تستحق التشغيل قبل الإطلاق
العرض التجريبي الذي يُفعَّل فيه وضع الطيران مرة واحدة ليس اختبار قبول للعمل دون اتصال. نفّذ الاختبارات التالية بأدوار موظفين ممثلة للواقع، وعلى أجهزة مختلفة، وقاعدة بيانات أودو في بيئة الاختبار المرحلية تحاكي بيئة الإنتاج.
| الاختبار | النتيجة المتوقعة |
|---|---|
| حفظ مسودة دون إشارة؛ ثم الإغلاق القسري؛ ثم إعادة التشغيل | المسودة وأمر صندوق الصادر ما زالا موجودين |
| أودو يثبّت الطلب لكن الرد يُفقد | يعيد الأمر المكرَّر نتيجة تجارية واحدة، دون أي تكرار |
| الشبكة تتذبذب مرارًا | لا إرسال مزدوج متزامن؛ وتبقى قائمة الانتظار قابلة للفحص |
| مستخدم آخر يغيّر المهمة المُسندة | يظهر تعارض الإصدار بدلًا من الاستبدال |
| انتهاء صلاحية المصادقة أثناء انقطاع الاتصال | يبقى العمل المعلّق محليًا؛ وينتظر الرفع تفويضًا صالحًا |
| سحب صلاحية الوصول إلى الشركة أو الدور | يرفض الخادم إعادة التشغيل غير المصرّح بها؛ وتحتفظ الواجهة بحالة خطأ مناسبة |
| نجاح رفع المرفق مع فشل الربط | يستأنف التطبيق العملية غير المكتملة أو يحسمها بأمان |
| مئات الإجراءات المنتظرة تُستعاد معًا | تزامن محدود، وإعادة محاولة معقولة، ودون إرهاق الخادم |
إنهاء التطبيق أثناء sending | تحدد عملية الاستعادة ما إذا كان بإمكانها إعادة المحاولة بأمان باستخدام معرّف الأمر الثابت |
| امتلاء مساحة تخزين الجهاز | يرى المستخدم رسالة فشل؛ ولا يُبلغ التطبيق أبدًا عن مسودة غير محفوظة بأنها مخزّنة |
| تسجيل الخروج أو فقدان الجهاز أو حذف الحساب | تخضع البيانات الحساسة المخزّنة دون اتصال لسياسة الاحتفاظ والحذف الموثّقة |
قِس النتائج المهمة: الزمن من التسجيل المحلي حتى الإقرار المرجعي، وحجم الأعمال المتراكمة وعمرها، ومعدل الرفض النهائي، ومعدل التعارضات، ومنع التكرار. ولا تَعِد بـ“مزامنة فورية” شاملة، فالشبكة ومجدول المنصة خارج سيطرة التطبيق.
ماذا يعني هذا لإطلاق ميداني فعلي
ابدأ بسير عمل واحد محدد النطاق. فلفريق خدمة، قد يكون ذلك: “تنزيل المهام المُسندة، وإكمال قائمة تحقق وإرفاق صورة واحدة، ثم تلقي تأكيد من الخادم.” وتجنّب البدء بكل وحدات الموارد البشرية والمخزون والمبيعات والمشاريع دفعة واحدة.
قبل الإصدار، حدّد عقد الخادم والخطوات التي يمكن للعامل الميداني إكمالها دون اتصال. واعرض حالات فقدان الشبكة المذكورة أعلاه أمام مالك العمليات، لا أمام فريق التطوير وحده. ووثّق من يحسم الأحداث المرفوضة، وما المعلومات التي يستطيع فريق الدعم فحصها بأمان.
تبني Octivex تطبيقات جوالة وتطبيقات ويب متصلة بأودو، بما في ذلك سير عمل الموظفين الميدانيين. وإذا كان سير العمل التالي في تطبيقك الجوال يعتمد على اتصال متقطع، فإن أفضل نقطة بداية هي خريطة موجزة للمعاملات في حالتي الاتصال وعدم الاتصال وعقد مزامنة قابل للاختبار، لا توصية بحزمة برمجية.
ينجح التطبيق الذي يعمل دون اتصال أولًا حين يستطيع المستخدمون مواصلة العمل دون تضليلهم بشأن ما قَبِله النظام. فالحفظ المحلي الدائم، وأمان إعادة الإرسال، والتعارضات الصريحة أهم من أيقونة اتصال خضراء.
