Skip to content
جميع المقالات

تصميم منتجك بناءً على نتائج التحقق غير المتزامن

تشارلز أرشيبونغ

, المؤسس المشارك

تعامل مع عملية الإرسال كبداية لآلة حالة، وليس كنهاية لطلب. اعرض حالة معلقة مرتبطة بمعرف التحقق، وقم بتحديثها من خلال روابط الويب، واسمح بتغيير الحالة أكثر من مرة.

عنوان "التصميم للتحقق غير المتزامن" بجانب رسم توضيحي لمسار من الخطوات المتصلة، على تدرج لوني نيلي داكن.

أهم النقاط

  • يشير onSubmit إلى أنه تم إنشاء عملية التحقق، وليس إلى أنها نجحت.
  • تصرف بناءً على الحالة واحفظ checkStatus بجانبها؛ فمن حقهم أن يختلفوا.
  • يمكن أن تتغير حالة التحقق بعد استقرارها، لذا خذ آخر تغيير، وليس الحدث الأول.
  • إعادة التقديم تحتفظ بنفس رقم التحقق؛ قم بتحديث السجل بدلاً من إنشاء سجل جديد.

بين لحظة تقديم الطلب وظهور النتيجة النهائية، يجب أن يكون تطبيقك في حالة انتظار تعتمد على معرّف التحقق، وتُدار بواسطة أحداث من خادمك، ومستعدة لتغيير الحالة أكثر من مرة. SDK المكالماتonSubmitيخبرك هذا بأن عملية التحقق قد تم إنشاؤها، لكنه لا يخبرك ما إذا كانت قد نجحت أم لا.

يبدو هذا بديهيًا إلى أن تخضع عملية التحقق للمراجعة ليوم كامل، ثم تُرسل مرة أخرى لطلب صورة شخصية جديدة، ثم تعود وتُعتمد. المنتج المبني على آلية رد نداء واحدة تُحدد النجاح أو الفشل لا يُتيح أيًا من هذه العمليات. أما المنتج المبني على نظام آلي بسيط، فيتعامل معها دون الحاجة إلى حالات خاصة.

لماذا لا يمكن أن تصل النتيجة مع الطلب؟

تستغرق عمليات التحقق من الهوية أوقاتًا متفاوتة لأسباب وجيهة. إذ يتطلب الأمر قراءة وثيقة، والبحث في سجل حكومي، ومقارنة وجه. بعد ذلك، قد ينتظر مخطط القرار (يفتح في علامة تبويب جديدة) على شاشة قائمة المراقبة، وقد تنتظر شركة ما تأكيد أعضاء مجلس إدارتها لهويتهم، وقد يحتاج أحد أعضاء فريقك إلى مراجعة الأمر. بعض هذه العمليات يستغرق ثوانٍ، وبعضها الآخر يستغرق أيامًا.

لذا Toden يعود بمجرد إنشاء التحقق، بحالةprocessingويُخبر نظامك الخلفي بكيفية تسوية الأمور عبر روابط الويب (يفتح في علامة تبويب جديدة) أو استطلاع الحالة (يفتح في علامة تبويب جديدة) . السؤال التصميمي لمنتجك هو ما الذي يجب عرضه، وما الذي يجب السماح به، خلال تلك الفترة الفاصلة.

مجالان، سؤالان

كل عملية تحقق يتم إرسالها تحتوي على حقلين للحالة، وأنت بحاجة إلى كليهما.

statusهي النتيجة. إنها المجال الذي تعمل عليه، وتستخدم عشر قيم عبر دورة الحياة بأكملها:not_started،in_progress،processing،in_review،awaiting_resubmission،approved،declined،abandoned،expiredوerror.

checkStatusهذا ما توصلت إليه الفحوصات الآلية:pending،verified،failed،not_foundأوerrorقواعد اتخاذ القرار والمراجعون لا يغيرونها أبداً.

يختلفون كلما تم اتخاذ قرار بشأن أمر آخر غير عمليات التحقق. ويمكن إجراء عملية تحقق.approvedمعcheckStatus: "failed"لأن أحد المراجعين قبل صورة سيلفي حصلت على تقييم أقل بقليل من الحد الأدنى المطلوب في إضاءة سيئة. احتفظ بالصورتين. في اليوم الذي يسأل فيه أحدهم عن سبب السماح لهذا الزبون بالمرور،checkStatusوreasonCodeهذا هو جوابك.

يتم تحديد الحالة بترتيب ثابت: قرار المراجع هو الذي يفوز، ثم قرار سير العمل الخاص بك، ثم عمليات التحقق وحدها.

ربط الحالة بما يراه المستخدم

لا تحتاج معظم المنتجات إلا إلى عدد قليل من الحالات التي يراها المستخدم. إليك رسم بياني للقيم الموثقة كنقطة انطلاق:

status

ما يعرضه تطبيقك

ما يسمح به تطبيقك

processing

"نحن بصدد التحقق من بياناتك"

التصفح، وليس النشاط المحصور

in_review

"نحن بصدد مراجعة بياناتك؛ قد يستغرق هذا وقتاً أطول"

نفس عملية المعالجة

awaiting_resubmission

"نحتاج منك إعادة خطوة واحدة" باستخدام الرابط

إعادة التقديم فقط

approved

تم التحقق

الحركة المحصورة

declined

الخطوة التالية، بصيغة منreasonCode

أعد المحاولة أو اتصل بالدعم

error

"حدث خطأ ما من جانبنا، يرجى المحاولة مرة أخرى"

إعادة المحاولة

abandoned،expired

"ابدأ من جديد"

رابط جديد أو محاولة جديدة

ينطبق نفس المبدأ في الكود، كدالة واحدة يمكن لشاشاتك مشاركتها:

type UiState = "checking" | "action_needed" | "verified" | "not_verified" | "start_again";

function uiStateFor(status: string): UiState {
  switch (status) {
    case "approved": return "verified";
    case "declined": return "not_verified";
    case "awaiting_resubmission": return "action_needed";
    case "abandoned":
    case "expired":
    case "error": return "start_again";
    default: return "checking"; // processing, in_review and anything unrecognised
  }
}

الفرع الافتراضي مقصود. وهو يغطيnot_started،in_progress،processingوin_reviewوإذا وصلت قيمة لا تتعرف عليها، فإن "التحقق المستمر" هو إجابة أكثر أمانًا من "التجاوز".

صياغة الرفض

فيfailedأوnot_foundحصيلة،reasonهي جملة مكتوبة للمتقدم، بدون أي درجات أو عتبات، ويمكنك عرضها كما هي.reasonCodeهو الرمز المميز الثابت الذي يمكن التفرع عليه:document_expiredقد يؤدي ذلك إلى تشغيل "تحميل المستند الحالي".selfie_mismatchتنبيه لإعادة التقاط صورة السيلفي في إضاءة أفضل.errorنتيجة لذلكreasonإذا كانت الرسالة موجهة إليك، على سبيل المثال بشأن رصيدك الائتماني، فأظهر للشخص رسالة عامة وقم بتوجيه السبب إلى فريقك.

التمييز بين "بضع ثوانٍ" و"بضعة أيام"

processingيشمل ذلك كلاً من المستند الذي تتم قراءته والقرار المُعلق على شاشة قائمة المراقبة. نقطة نهاية الحالةwaitingOnيُحدد الحقل أيهما:nullأثناء استمرار عمليات الفحص،"screening"،"key_people"بالنسبة لشركة تنتظر مديريها ومالكيها، أو"address_presence"لإجراء فحص عنوان يستغرق عدة أيام عند تفعيله. استخدمه لتحديد التوقعات ("عادةً ما ينتهي هذا في غضون دقيقة" بدلاً من "سنرسل لك بريدًا إلكترونيًا")، وتعامل مع أي قيمة غير مألوفة على أنها فترة انتظار لم تكن على علم بها بعد.

أي إشارة يجب الوثوق بها، ومتى؟

تصلك ثلاث إشارات، وليست جميعها متساوية في الأهمية.

  1. إشارة العميل.SDK 'sonSubmitأو صفحة مستضافةsubmittedيتم تفعيل هذا الحدث عند انتهاء مقدم الطلب من العملية. استخدمه لنقل المستخدم إلى شاشة الانتظار فورًا. لا تستخدمه لمنح أي شيء.

  2. يتم ربط هذه الروابط بخادمك الخلفي. هذه هي السجلات. قم بتحديث قاعدة البيانات من خلالها، ثم انقل التغيير إلى شاشة المستخدم من هناك.

  3. نقطة نهاية الحالة. GET /api/kyc/status/:verificationIdيُعيد هذا الأمر الحالة الحالية مع مفتاح قابل للنشر، ولا يحمل أي بيانات شخصية أو نتائج أو درجات. استخدمه لسدّ ثغرة، مثلاً عندما يُعاد فتح التطبيق قبل أن يقوم خادمك بإرسال أي بيانات.

ليس بالضرورة أن يكون أول رابط ويب هو الأخير

إذا كانت عملية سير العمل لديك تتضمن قواعد اتخاذ القرار،verification.completedيتم إرسالها عند انتهاء عمليات التحقق، قبل أن يتخذ سير العمل قراره.statusيعكس ذلك عمليات التحقق فقط. ويأتي حكم سير العمل لاحقًا كـverification.status_updatedمعsource: "workflow"وهذا هو الوضع الذي يجب اتخاذ إجراء بشأنه. لاحقًا، قد يُقرر المراجع أو يُعدّل قرارًا سابقًا، ويأتي كل تغيير على أنه قرار آخر.verification.status_updated.

تُعاد محاولات التسليم بشكل مستقل، وقد تصل الطلبات بترتيب خاطئ، لذا احتفظ بـchangedAtاستخدم التغيير الذي لديك وتجاهل أي تغيير أقدم. بدون قواعد اتخاذ القرار، تكون عمليات التحقق هي القرار، والحالة هي التي تحدد القرار.verification.completedيبقى هذا الرأي سارياً ما لم يقم أحد المراجعين بتغييره لاحقاً.

تحتفظ عمليات إعادة التقديم بنفس المعرف

عندما يُرسل المُراجع طلب التحقق، يُعيد المُتقدم تنفيذ الخطوات المطلوبة فقط، وتُكمل إعادة تقديمه عملية التحقق نفسها. ستتلقى نتيجة أخرى بنفس الرمز.verificationId،attemptتم إحصاؤها، وcheckStatusالعودة إلىpendingأثناء إعادة تشغيل عمليات التحقق، قم بتحديث السجل الذي لديك. سيؤدي إنشاء صف جديد لكل حدث إلى ظهور عميلين بدلاً من عميل واحد.

استطلاعات الرأي، إذا كان لا بد منها

يجب أن تدعم Webhooks بيئة الإنتاج. أما الاستقصاء فهو مخصص للثغرات: كشاشة الهاتف المحمول التي تُعاد فتحها، أو بيئة لا يمكنك فيها استقبال Webhooks بعد. إذا قمت بالاستقصاء:

  • تراجع، بدءًا من بضع ثوانٍ ثم توسع تدريجيًا، وتوقف بمجرد استقرار الوضع.

  • تذكر الحد الافتراضي الموثق وهو 100 طلب لكل 15 دقيقة لكل عميل، واقرأRateLimit-RemainingوRateLimit-Resetاستخدم العناوين بدلاً من التخمين.

  • قم بإجراء الاستطلاع من أقل عدد ممكن من المواقع. إن فتح اثنتي عشرة شاشة، كل منها تستطلع نفس المعلومات، يعني زيادة في حركة المرور بمقدار اثني عشر ضعفاً للحصول على إجابة واحدة.

محاولات إضافية في الطريق إلى الداخل

توجد هذه الثغرة أيضًا في جانب الإرسال. إذ تتجاهل شبكة الهاتف المحمول الاستجابة لطلب الإنشاء، ولا يعلم التطبيق ما إذا كان التحقق قد تم. أرسل استجابة مستقرةmetadata.requestIdلكل عملية تحقق منطقية، وإعادة استخدامها في أي محاولة لاحقة. API يقوم بإرجاع التحقق الحالي بدلاً من إنشاء تحقق ثانٍ، ولا يتم تحصيل الرسوم مرتين.

جولة تعريفية

لنفترض وجود تطبيق ادخار افتراضي مزود بآلية عمل تفحص كل مستخدم تم التحقق منه. يقوم أحد المتقدمين بتقديم طلبه عبر هاتفه في تمام الساعة 9:00 صباحًا. يتلقى التطبيقonSubmitويظهر "نحن نتحقق من بياناتك". وبعد ثوانٍ، يستقبل النظام الخلفيverification.completedمعcheckStatus: "verified". إنهstatusيقرأapprovedلأن هذا الحدث يعكس عمليات التحقق فقط، لذا فإن النظام الخلفي لا يمنح أي شيء بعد: لا يزال سير العمل ينتظر على الشاشة، ويظهر استطلاع الحالةprocessingمعwaitingOn: "screening"تعرض الشاشة تطابقًا محتملاً، ويقوم سير العمل بتوجيهه للمراجعة،verification.status_updatedيأتي معin_reviewيُغيّر التطبيق رسالته ليُشير إلى أن المراجعة قد تستغرق وقتًا أطول. في تمام الساعة 2:30 ظهرًا، يُزيل مسؤول الامتثال الإنذار الكاذب ويُوافق عليه؛ ثم يأتي مسؤول ثانٍ.verification.status_updatedيأتي معapprovedوتتيح الواجهة الخلفية عمليات الإيداع وترسل إشعارات فورية.

لم يكن هناك أي شيء في تلك السلسلة يحتاج إلى حالة خاصة. إنه سجل واحد، مرتبط بمعرف واحد، ويتم تحديثه بواسطة كل حدث بدوره.

قائمة مراجعة لحالتك المعلقة

  1. إنشاء سجل محلي مُفهرس علىverificationIdاللحظةonSubmitحرائق.

  2. قم بتحديثه فقط من الواجهة الخلفية الخاصة بك، وذلك عن طريق روابط الويب.

  3. العمل علىstatus؛ محلcheckStatus،reasonوreasonCodeبجانبه.

  4. احتفظ بأحدث المعلوماتchangedAtوتجاهل التغييرات القديمة.

  5. علاج الحالات غير المعروفة وwaitingOnالقيم "لا تزال قيد التحقق".

  6. عند إعادة التقديم، قم بتحديث نفس السجل وأظهر المحاولة.

  7. تراجعت الكلمة منreasonCodeولا تُظهر أبدًاerrorالسبب للمتقدم.

  8. إعادة الاستخدامrequestIdعند إعادة المحاولات، والاستطلاع فقط لملء الفجوات.

المصادر

تشارلز أرشيبونغ

عن الكاتب

Charles Archibong

المؤسس المشارك

شارك تشارلز أرتشيبونغ في تأسيس شركة Toden. وهو يكتب عن التحقق من الهوية، والتكنولوجيا المالية، والعمل العملي لبناء خدمات رقمية موثوقة.

  • المطورون

    المفاتيح العامة والسرية: إبقاء بيانات التحقق بعيدة عن العميل

    ضع المفتاح العام في تطبيقك، واحتفظ بالمفتاح السري على خادمك. يمكن للمفتاح العام بدء عملية التحقق وقراءة الحد الأدنى من البيانات، وليس بيانات الهوية، لذا ضع في اعتبارك احتمالية تسريبه، وقلل من تكلفة هذا التسريب.

  • Identity Verification

    أين تفشل عمليات التحقق، وكيفية إصلاح كل خطوة

    يتخلى المستخدمون عن عملية التحقق في لحظات متوقعة: بداية غير مبررة، طلب إذن استخدام الكاميرا، التقاط المستندات، سطح مكتب بدون كاميرا، ومطالبتهم بإعادة كل شيء بعد فشل واحد. قِس معدل التخلي عن العملية في كل خطوة، ثم عالج الخطوة، لا العملية بأكملها.

ابنِ منتجك.وسنتولى الباقي.

الهوية والامتثال من البداية إلى النهاية، وفق معايير عالمية وبأسعار تناسب المؤسسين.