المعمارية English

ADR-0005 — منصة الاستشارات المرئية

الحالة: مُقترَح — مشروط بـ OQ-08 وقرار قانوني · التاريخ: 2026-07-20 · صاحب القرار: أمير هارون (القائد التقني) ذو صلة: SEAM-02 · QAS-AVL-01 · QAS-SCL-02 · QAS-MOD-02 · R-10 · ADR-0001


السياق#

يتطلب SRC-MOM FR-1 / REQ-03 استشارات مرئية داخل التطبيق، "مستقرة من البداية إلى النهاية". اقترح محضر الاجتماع (§11) استضافة Jitsi ذاتيًا لأسباب تتعلق بالتكلفة والمصدر المفتوح. يفرض CON-13 إقامة البيانات في السعودية؛ والهدف هو مئات الجلسات المتزامنة خلال 12–18 شهرًا، انطلاقًا من الصفر تقريبًا عند الإطلاق.

نقض البحث ثلاثة افتراضات شائعة، اثنان منها كانا لدى المعماري نفسه. تُوثَّق بشكل بارز لأن العمل بالافتراضات الأصلية كان سيُنتج نظامًا أسوأ بشكل ملموس.


⚠ ثلاثة افتراضات مُصحَّحة#

التصحيح 1 — LiveKit لا يحلّ مشكلة hostNetwork#

الافتراض: أن LiveKit "أصيل لـ Kubernetes" بخلاف Jitsi، فيتيح autoscaling على مستوى الـ pod عبر UDP mux.

الواقع: توثيق LiveKit الخاص بـ Kubernetes ينصّ على أنه يتطلب host networking، وأن ذلك "يحصر النشر في pod واحد لكل عقدة". ومخطط Helm الرسمي يضع podHostNetwork: true افتراضيًا مع التعليق "يمكنك تشغيل نسخة واحدة فقط من LiveKit لكل عقدة فيزيائية". والإعلان عن عنوان الوسائط (rtc.use_external_ip) مطابق معماريًا لآلية NAT_HARVESTER_PUBLIC_ADDRESS في Jitsi.

UDP mux حقيقي (rtc.udp_port، عادةً 7882، يدمج كل الوسائط على منفذ واحد ويفصلها عبر SSRC) — لكن تفعيله لا يلغي بذاته الحاجة إلى hostNetwork. وثائق LiveKit ومخططها لا تشحن ذلك التكوين. بناؤه يعني الخروج عن المسار المدعوم.

النتيجة: عبارة "LiveKit يتوسّع أفضل على Kubernetes" غير صحيحة بصيغتها الشائعة. كلا المنتجين لهما نفس وحدة التوسّع — العقدة، لا الـ pod.

التصحيح 2 — الحل الفعلي لمشكلة hostNetwork هو STUNner، وهو محايد تجاه المزوّد#

STUNner (رخصة MIT، مبني على Kubernetes Gateway API) يعرض منفذ دخول واحدًا ويتيح تشغيل خوادم الوسائط في "pods عادية غير مُميَّزة". ويشحن تكاملات موثّقة مع LiveKit وJitsi وJanus وmediasoup وغيرها.

النتيجة: STUNner ليس حجة لصالح LiveKit على Jitsi — فهو يحلّ المشكلة لكليهما بالتساوي. وإذا كان تجنّب hostNetwork متطلبًا صارمًا، فهو الأداة، ويصبح اختيار خادم الوسائط مستقلًا عنه.

⚠️ غير مُتحقَّق منه: نضج الإنتاج، وعبء الأداء، ونطاق التبنّي. تأليف المساهمات شبه محصور في مطوّر واحد. مسار واعد لا إجابة مُثبتة.

التصحيح 3 — وضع P2P في Jitsi رافعة تكلفة أكبر مما افتُرض، والتسجيل يدمّرها#

يشحن Jitsi الإعداد p2p: { enabled: true } افتراضيًا: عند وجود مشاركَين اثنين بالضبط يحاول اتصالًا مباشرًا، وعند النجاح تتوقف الوسائط عن المرور عبر الـ bridge كليًا. ويبقي اتصال الـ bridge حيًا كخيار احتياطي غير مُفقِد للجودة، ويعود إليه عند انضمام مشارك ثالث.

LiveKit لا يملك وضع P2P إطلاقًا — فهو SFU خالص. كل بايت من كل مكالمة ثنائية يعبر بنيتك التحتية.

بالنسبة لمنصة منتجها الأساسي استشارات ثنائية، هذا هو بند التكلفة المهيمن:

Jitsi (نجاح P2P) Jitsi (فشل P2P) LiveKit (دائمًا)
نطاق وسائط الخادم 0 ترحيل كامل ترحيل كامل
تكلفة الخادم للمكالمة الثنائية ~0 كاملة كاملة

لكن — وهذه هي النتيجة التي تحسم مسألة التسجيل — يسجّل Jibri بالانضمام إلى المؤتمر كمشارك ثالث. والمؤتمر بمشارك ثالث لم يعد ثنائيًا، فيعود قسرًا إلى الـ bridge. لذا فالتسجيل الشامل يلغي وفر P2P كليًا و يضيف أغلى طبقة. الأثران يتراكبان، وكلاهما ينبع من قرار منتج واحد.

لذا فإن OQ-08 (هل تُسجَّل الاستشارات؟) ليس سؤال منتج ثانويًا. إنه المحدّد الأكبر منفردًا لتكلفة البنية التحتية للفيديو، وقد يُرجّحها بنحو 80%. يجب الإجابة عليه قبل بدء أي عمل على الفيديو.


اقتصاديات التسجيل — حيث يفوز LiveKit بوضوح#

إذا كان التسجيل مطلوبًا، تنقلب المقارنة بحدّة:

Jibri (Jitsi) LiveKit Egress
التزامن "تسجيل واحد فقط في المرة على jibri واحد" مهام متعددة لكل نسخة
بيئة التشغيل دائمًا Chrome كامل + X + ffmpeg، على جهاز مخصّص 2–6 وحدات معالجة للتركيب؛ وتسجيل المسارات المفردة لا يحتاج Chrome ولا إعادة ترميز
المسار الاقتصادي لا يوجد "مئات مهام TrackEgress المتزامنة على نسخة واحدة"
إشارة التوسّع تنسيق خارجي مؤشر livekit_egress_available عبر Prometheus

عند 300 جلسة مسجّلة متزامنة، يعني Jibri نحو 300 نسخة مخصّصة. هذا أكثر بند تُقدَّر ميزانيته بأقل من الواقع في استضافة Jitsi الذاتية، وهو أقوى حجة منفردة لصالح LiveKit.

فوارق أخرى مُتحقَّق منها#

العامل الفائز التفصيل
عدد المكوّنات LiveKit لا حزمة XMPP. Jitsi يحتاج Prosody + Jicofo + JVB + Jibri + coturn
TURN مدمج LiveKit TURN مبني داخل الخادم — يحذف coturn كليًا من المعمارية
الإغلاق السلس LiveKit مبني داخل الخادم؛ ويضبط المخطط terminationGracePeriodSeconds: 18000. Jitsi يتطلب تنسيقًا خارجيًا.
الغرف الكبيرة Jitsi Octo (تتالي الـ bridges) مفتوح المصدر. أما شبكة LiveKit الموزّعة فهي حصرية للسحابة؛ والاستضافة الذاتية محدودة بنحو 3,000 لكل غرفة. غير ذي صلة للمكالمات الثنائية.
تجاوز الخادم للثنائية Jitsi P2P. LiveKit لا يملك مقابلًا.
توفّر طبقة الإشارة لا أحد Prosody/Jicofo في Jitsi عمليًا مكوّنات مفردة — وهو خطر التوفّر الذي يغفله الجميع بينما يركّزون على توسّع JVB
مخطط Helm لا أحد مخطط LiveKit رسمي لكنه متأخر ~3 أشهر وإصدارين ثانويين عن الخادم، بثلاث مساهمات جوهرية خلال 18 شهرًا. توقّع أن تنسخه وتتولّاه.
الترخيص تعادل LiveKit تحت Apache 2.0، مُتحقَّق منه — دون إعادة ترخيص BSL/SSPL. وEgress وIngress وSIP غير محجوبة كميزات.

LiveKit Cloud يشغّل نفس الـ SFU مفتوح المصدر — مُتحقَّق منه مرتين من مصادر LiveKit نفسها. المملوك هو طبقة التنسيق المحيطة (الشبكة العالمية، التوجيه الطرفي، الوكلاء المُدارون)، لا خادم الوسائط.


TURN#

TURN إلزامي في الإنتاج، لا اختياري. بدون TURN عبر TLS على المنفذ 443، لن يتمكن المستخدمون خلف CGNAT وشبكات الشركات الحاجبة لـ UDP من الاتصال إطلاقًا. وبالنسبة لاستشارة مدفوعة، المكالمة غير القابلة للاتصال تعني استردادًا وعميلًا مفقودًا.

حول نسب الترحيل — الموقف الصادق#

الرقم الشائع "8–20% من الجلسات تحتاج TURN" هو معرفة متداولة بلا مصدر أولي يمكن تتبّعه. القياس الموثوق الوحيد هو مجموعة بيانات Philipp Hancke لنحو 10 ملايين مكالمة على Chrome: 17.7% مُرحَّلة للاتصال الند-للند، لكن ~4% فقط مقابل SFU — ومن تلك، 78% كانت TURN/TCP، أي شبكات حاجبة لـ UDP لا تماثل NAT.

⚠️ تلك البيانات من 2017 ومهيمن عليها من سطح المكتب. لا توجد بيانات منشورة موثوقة لنسب الترحيل على شبكات المحمول، ولا شيء إطلاقًا للسعودية أو الخليج. والأرقام المنسوبة إلى Cloudflare في مقالات متداولة غير موجودة على صفحات Cloudflare — لا تستخدمها.

حقيقتان هيكليتان تتعاكسان: شبكات المحمول السعودية مثقلة بـ CGNAT، ما يرفع نسب الترحيل؛ لكن الـ SFU يملك IP عامًا، ما يجعل اجتياز العميل←الخادم أسهل بكثير من العميل←العميل. توقّع أن يكون القيد الحاكم هو الشبكات الحاجبة لـ UDP لا تماثل NAT — لذا فإن TURN/TLS على المنفذ 443 هو أعلى استثمار قيمةً في الاتصالية.

إجراء: قِس RTCIceCandidatePair على الزوج المختار منذ اليوم الأول، مصنّفًا حسب المشغّل (STC / موبايلي / زين) ونوع الوصول. خلال أسبوع من حركة حقيقية ستملك بيانات أفضل من أي منشور.

coturn — السمعة قديمة#

coturn مُصان بنشاط: إصدارات شهرية أو أفضل خلال 2026، والحالي 4.14.0. رواية "coturn مهجور" غير صحيحة اعتبارًا من 2026.

⚠️ لكن شغّل ≥ 4.13.1. تشمل ثغرات CVE عالية الخطورة الأخيرة هجوم حجب خدمة عن بُعد بحزمة واحدة دون مصادقة على ARM64 (CVE-2026-40613، مُصلَحة في 4.10.0)، وقابلية التنبؤ بالـ nonces بسبب عشوائية LCG (CVE-2025-69217، مُصلَحة في 4.8.0). واثنتان من آخر أربع ثغرات عالية هما تجاوز لقوائم التحكم عبر عناوين IPv4 المُخطَّطة على IPv6 — فإن نشرت dual-stack، امنع نطاقات ::ffff: صراحةً.

يعاني coturn من نفس مشكلة hostNetwork بل أسوأ — إذ يوصي مطوّروه بشبكة المضيف بسبب نطاق منافذ الترحيل الافتراضي البالغ 16,384 منفذًا (قابل للتقييد عبر min-port/max-port). التخصيصات محصورة بالعملية؛ وRedis يشارك بيانات الاعتماد والقياسات فقط، لا حالة التخصيص — لذا فقدان نسخة يُسقِط كل جلسة عليها.

وهذه حجة قوية لصالح TURN المدمج في LiveKit: فهو يزيل من المعمارية خدمة كاملة ذات حالة، ومعرّضة لثغرات، ومُقيَّدة بـ hostNetwork.


التكلفة#

الـ egress هو المهيمن. أما الحوسبة فتكاد لا تُذكر.

لكل ساعة مكالمة ثنائية مُرحَّلة عند 1 ميغابت/ث (~0.9 غيغابايت egress قابل للفوترة):

المزوّد $/ساعة مكالمة
خوادم فعلية بحركة ثابتة (مثلًا €1/تيرابايت) ~0.001$
Cloudflare Realtime TURN (0.05$/غيغابايت) ~0.045$
egress لدى مزوّدي السحابة الكبار (~0.09$/غيغابايت) ~0.081$
Twilio (0.40$/غيغابايت أمريكا/أوروبا) ~0.36$

لا تشغّل TURN على مزوّد سحابي كبير — ستدفع egress بسعر مرتفع و تدير الخادم بنفسك. أسوأ ربع في المصفوفة.

الطبقة المجانية من Cloudflare للـ TURN هي 1,000 غيغابايت شهريًا (~1,100 ساعة مكالمة مُرحَّلة)، ومجانية بالكامل عند اقترانها بـ SFU الخاص بهم. عند حجم الإطلاق يُرجَّح أن تغطي المنصة كليًا — ما يلتفّ على كامل العبء التشغيلي وثغرات coturn.

نقطة التعادل بين الاستضافة الذاتية والمُدارة: البنية التحتية وحدها تتعادل تقريبًا عند ~300 جلسة متزامنة. وبإضافة مهندس SRE ملمّ بـ WebRTC — وهو تخصّص نادر، وأندر في السوق السعودي — ترتفع نقطة التعادل الفعلية إلى ما فوق 300 بكثير. عند حجم الإطلاق، تعني الاستضافة الذاتية دفع كامل التكلفة الثابتة لقدرة تشغيل وسائط من أجل خدمة حركة شبه معدومة.


القرار#

تجريد الفيديو خلف منفذ (port) محايد تجاه المزوّد (SEAM-02) وتأجيل اختيار المزوّد حتى الإجابة على OQ-08 وصدور القرار القانوني بشأن إقامة البيانات.

شجرة القرار — لا تتخطَّ الخطوة الأولى#

  1. احصل على قرار قانوني: هل يُشكّل الترحيل العابر عبر SFU أجنبي نقلًا عابرًا للحدود بموجب PDPL؟ كل شيء يتوقف على هذا. التسجيلات وبيانات الجلسات الوصفية تبقى داخل المملكة بأي حال — فهي بيانات شخصية مخزَّنة قطعًا، وقد تكون بيانات صحية حساسة (R-04).
  2. أجب على OQ-08 (التسجيل). يُرجّح التكلفة بنحو 80% ويقلب المقارنة بين Jitsi وLiveKit.
  3. إن كان الترحيل الأجنبي مقبولًا ← CPaaS مُدار في أقرب نقطة تواجد خليجية، مع كتابة التسجيلات إلى مخزنك داخل المملكة. أسرع إطلاق، وأقل تكلفة ثابتة.
  4. إن كان الترحيل الأجنبي غير مقبول، أو كان التسجيل شاملًااستضف LiveKit ذاتيًا على الـ cluster داخل المملكة (ADR-0001)، مع STUNner إن وجب تجنّب hostNetwork.
  5. Jitsi هو الخيار الأخير — إلا إذا استُبعد التسجيل. فإذا كانت الاستشارات غير مسجّلة، يجعل وضع P2P من Jitsi خيارًا أرخص بشكل هائل لمنتج ثنائي المكالمات ويصبح منافسًا فعليًا. هذا هو السيناريو الوحيد الذي يكون فيه اقتراح محضر الاجتماع الأصلي صحيحًا، وينبغي إعادة تقييمه على هذا الأساس لا رفضه.

CPaaS المُدار — بوابة فرز تُطبَّق قبل السعر#

⚠️ لا يوجد مزوّد CPaaS كبير بتواجد وسائط مؤكَّد داخل السعودية. قيّم إقامة البيانات قبل النظر إلى التسعير:

  1. نقاط تواجد وسائط في السعودية / الإمارات / البحرين؟
  2. ضمان تعاقدي لإقامة البيانات أو التسييج الجغرافي — لا مجرد "لدينا نقطة قريبة"؟
  3. أين تستقر التسجيلات، وهل يمكن تثبيتها داخل المملكة؟

ملاحظات: Twilio Video في نهاية العمر — استبعده، ولاحظ أن خروج مزوّد كبير من هذا السوق تحديدًا هو أقوى مبرر متاح لوجود المنفذ. وAmazon Chime SDK ليس مهجورًا (تطبيق Chime انتهى في 2026-02-20؛ أما الـ SDK فيشحن بنشاط) — طبقة التحكم الخادمية لديه قوية فعلًا، لكن قصته مع React Native ضعيفة (لا مكتبة رسمية؛ فقط عيّنة تنسخها وتتولّاها) ومسألة ثغرة في OpenSSL/libvpx مفتوحة منذ نوفمبر 2024. لمنتج mobile-first، هذا خطر جوهري.


واجهة المنفذ#

مفاهيم مجال محايدة تجاه المزوّد فقط. المنفذ يملك الهويةsessionId معرّف في مجال الحجز؛ ومعرّفات غرف المزوّد تعيش في جدول ربط يملكه الـ adapter.

createSession(bookingId, {maxParticipants, recordingPolicy, maxDurationMinutes, region?})
getSession(sessionId) / endSession(sessionId, reason) / extendSession(...)

issueAccessToken(sessionId, {userId, displayName, role, permissions, ttlSeconds})
  -> {token, connectionUrl, iceHints?}
revokeAccess(sessionId, userId)

startRecording(sessionId, {layout, audioOnly?, destination: StorageRef})
stopRecording / getRecording / listRecordings / deleteRecording

Events (normalised): ParticipantJoined/Left · SessionStarted/Ended
                     RecordingStarted/Ready/Failed
                     QualityDegraded · ConnectionFailed

خمسة متطلبات تحدّد فعليًا قابلية الاستبدال:

  1. destination: StorageRef ضابط امتثال لا وسيلة راحة. التسجيلات يجب أن تستقر في المخزن داخل المملكة. وأي مزوّد لا يستطيع الكتابة إلى مخزنك في منطقتك يسقط عند البوابة.
  2. connectionUrl يُعاد مع الرمز — ترميز نقطة النهاية داخل العميل هو أكثر ما يعطّل استبدال المزوّد. اشحن هذا من اليوم الأول حتى مع مزوّد واحد.
  3. التسوية (reconciliation)، لأن الـ webhooks تفقد رسائل. الفوترة على مدة الجلسة؛ وفقدان SessionEnded يعني خطأ فوترة أو جلسة مدفوعة مفتوحة إلى ما لا نهاية. غير قابل للتفاوض.
  4. ConnectionFailed / QualityDegraded أحداث عمل لا قياسات تقنية — فهي تغذّي سياسة الاسترداد (OQ-05) وعدالة تقييم المستشارين. معظم الفرق تضيفها بعد أول نزاع.
  5. SDK الجوال هو الجزء المتسرّب. المنفذ الخادمي يمثّل ~70% من عملية الاستبدال؛ والـ SDK يمثّل الـ 30% المتبقية ولا يستطيع المنفذ تجريدها. غلّف SDK المزوّد خلف واجهة جوال رقيقة خاصة بك، وخصّص لها ميزانية صراحةً.

محفّزات التبديل — عرّفها الآن، بينما لا يوجد ضغط#

المحفّز الإجراء
فاتورة الخدمة المُدارة > ~8–10 آلاف دولار شهريًا لثلاثة أشهر متصلة ابدأ تجربة استكشافية للاستضافة الذاتية
تزامن مستدام > 200 ابدأ تخطيط الترحيل جديًا
تشدّد المستشار القانوني بشأن ترحيل الوسائط رحّل داخل المملكة فورًا — أبقِ مسار الاستضافة الذاتية جاهزًا لهذا السبب وحده
إعلان المزوّد عن نهاية العمر أو إعادة التسعير فعّل المنفذ (حدث فعلًا مرة في هذا السوق)
نسبة ترحيل TURN المقيسة > ~20% أعِد تشغيل نموذج التكلفة كاملًا
تكلفة التسجيل تتجاوز تكلفة الوسائط ادرس تسجيل المسارات المفردة قبل توسيع أي مسار

النتائج#

إيجابية: يُؤجَّل القرار دون تعطيل العمل؛ وتستطيع قرارات إقامة البيانات والتسجيل الوصول متأخرة؛ وخروج المزوّد قابل للنجاة منه؛ وبناء المنفذ رخيص الآن.

سلبية / مقبولة: المنفذ عمل مسبق بلا قيمة ميزة فورية؛ ويلزم تفاوض على القدرات للتدهور بسلاسة؛ وغلاف SDK الجوال ضريبة مستمرة.


⚠ فجوات التحقق#

الفجوة الأثر
هل يقدّم أي CPaaS تواجد وسائط في السعودية/الخليج بضمان تعاقدي؟ يحكم خيار الخدمة المُدارة بالكامل
القرار القانوني حول الترحيل العابر كنقل بموجب PDPL يحكم شجرة القرار كاملة — استشارة قانونية لا بحث
نضج STUNner في الإنتاج وعبء أدائه يحدّد إمكانية تجنّب hostNetwork
سلوك LiveKit عند فشل العقدة — غير موثّق الغرف مثبّتة على عقدة واحدة دون نسخ؛ ويُرجّح أن الفقد يُسقط كل غرفها. اختبر قبل الالتزام.
نسبة ترحيل TURN الحقيقية لمشغّلي المحمول السعوديين لا توجد بيانات منشورة — قِس بنفسك
عدد الأفراد اللازم لتشغيل أي من المنصتين لا بيانات موثوقة؛ نتائج البحث كانت محتوى SEO مولّدًا آليًا، ولم تُقتبس عن قصد
نطاق منافذ الترحيل 1024–30000 لـ TURN المدمج في LiveKit مقابل Kubernetes بلا hostNetwork غير محسوم — يعيد إدخال مشكلة نطاق المنافذ التي كان UDP mux يُفترض أن يحلها
القائد التقني · أمير هارون مسودة v0.1 · بحث وتصميم فقط