EngineeringDone

nestjs-nuxt-realtime-chat — دردشة فورية بـ NestJS وNuxt

مثال مرجعي مختصر يوضّح كيف تُربط بوابة المقابس في NestJS بواجهة Nuxt، مع مسارات REST محمية للرسائل ومسارات مفتوحة للتسجيل والدخول.

٢٢ يوليو ٢٠٢٦
4 التقنيات
English
nestjs-nuxt-realtime-chat — دردشة فورية بـ NestJS وNuxt

عن هذا المشروع

مثال عملي مصغّر لدردشة بزمن حقيقي: بوابة WebSocket فوق NestJS مع مصادقة JWT، وواجهة Nuxt وVue وTailwind CSS تستمع لحدث conversation.

التقنيات

NestJSSocket.IONuxtVue

i99dev_project_nestjs-nuxt-chat_cover_1200x630_v1.0.1.svg

مثال مرجعي مقصود البساطة — غرضه توضيح نقطة واحدة: كيف تتكلّم بوابة Socket.IO في NestJS مع عميل Nuxt.

نظرة عامة

تطبيق دردشة مصغّر يتكوّن من طرفين: خادم NestJS يجمع بين مسارات REST وبوابة Socket.IO، وواجهة Nuxt مبنية بـ Vue ومنسّقة بـ Tailwind CSS.

ليس الهدف منتجاً كاملاً بل مرجعاً قابلاً للنسخ: أقلّ قدر من الشيفرة يجعل الرسالة تظهر عند الطرف الآخر لحظة إرسالها.

المشكلة

ربط طبقة مقابس بمشروع يستخدم مسبقاً مصادقة ومسارات HTTP يصطدم عادةً بثلاث عقبات:

  • منشأ مختلف. الواجهة تعمل على منفذ، والخادم على منفذ آخر، وCORS لـ WebSocket ليس إعداد CORS نفسه المعتاد لـ REST.
  • الهوية على قناتين. المستخدم نفسه يُصادَق على طلبات REST وعلى اتصال المقبس، ويجب ألا تتفرّع الهويتان.
  • التاريخ مقابل اللحظة. الرسائل القديمة تُجلب عند فتح المحادثة، والجديدة تصل دفعاً — مساران لنفس البيانات.

التخطيط

قُسّمت الواجهة البرمجية إلى مسارات مفتوحة وأخرى تتطلب رمزاً، قبل كتابة أي منطق للدردشة:

المسار الغرض محمي
POST v1/api/auth/signup إنشاء حساب لا
POST v1/api/auth/signin تسجيل الدخول لا
GET v1/api/users قائمة المستخدمين نعم
POST v1/api/chat/:receiverId/sendMessage إرسال رسالة نعم
GET v1/api/chat/:receiverId/messages رسائل محادثة معيّنة نعم
GET v1/api/chat/messages كل الرسائل نعم

وفي الواجهة أربع صفحات فقط: / و/login و/register مفتوحة، و/chat خلف تسجيل الدخول.

القرارات المعمارية

الإرسال عبر REST، والاستقبال عبر المقبس. كان بالإمكان تمرير كل شيء داخل أحداث المقبس، لكن إبقاء الإرسال على POST يجعل العملية قابلة للاختبار بـ curl، ويورّثها حراس المصادقة والتحقق الموجودين أصلاً. يبقى للمقبس دور واحد: إيصال الجديد إلى المتلقّي.

مجال أسماء مخصص للدردشة. البوابة معزولة تحت namespace: 'chat' بدل المجال الافتراضي، لأن أي توسيع لاحق (إشعارات، حضور) سيحتاج مجاله الخاص، وتقسيم مجال مزدحم لاحقاً أصعب من فصله من البداية.

@WebSocketGateway({
  namespace: class="token string">'chat',
  cors: {
    origin: class="token string">'http:class="token comment">//localhost:3000',
    credentials: true,
    allowedHeaders: class="token string">'Content-Type, Authorization, Origin, X-Requested-With, Accept',
  },
})

credentials: true مقصودة لا نسخاً ولصقاً. منشأ الواجهة مذكور صراحةً لا بـ *، وهذا شرط لعبور الاعتمادات مع الاتصال ولوصول ترويسة Authorization إلى الخادم.

حدث بثّ واحد باسم conversation****. الواجهة تستمع إلى قناة واحدة وتوجّه الحمولة حسب محتواها، فلا تتضخّم قائمة المستمعين مع كل ميزة جديدة.

التنفيذ

دورة الاستخدام قصيرة ومكتملة: يُنشئ المستخدم حساباً من /register، ثم يسجل دخوله فيأخذ رمز JWT، ثم يفتح /chat فيرى قائمة المستخدمين ويختار من يحادثه.

عند فتح المحادثة تُجلب الرسائل السابقة من مسار messages، ويُفتح اتصال المقبس في الوقت نفسه. كل رسالة تُرسل تمرّ عبر الخادم لتُحفظ، ثم تُبثّ على conversation ليلتقطها الطرف الآخر دون إعادة تحميل.

النتيجة والدروس

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

  1. أغلب أعطال المقابس أخطاء CORS لا أخطاء منطق. المشكلة نادراً ما تكون في معالجات الأحداث، وغالباً في إعداد المنشأ والترويسات المسموحة.
  2. الفصل بين الكتابة والبثّ يبسّط المصادقة. ما دامت الكتابة تمرّ عبر HTTP، تبقى قواعد الصلاحيات في مكان واحد.
  3. المثال الصغير يستحقّ أن يبقى صغيراً. إضافة القنوات والحضور ومؤشر الكتابة كانت ستخفي الفكرة التي أُنشئ من أجلها.

الروابط

روابط المشروع

تاريخ البداية٢٢ يوليو ٢٠٢٦
الحالةDone

مشاركة المشروع