المعمارية اللي هنشتغل بيها
نظام واحد بيخدم الموقع ولوحة الإدارة والمخازن ومحطات التقفيل: موقع نشر واحد، أربع طبقات واضحة، ووحدات (Modules) جوه كل طبقة على حسب البيزنس — المخزون، الطلبات، البضاعة الداخلة، الجملة، التسويق. الصفحة دي بتشرح الشكل العام، وبعدين كل آلية حساسة لوحدها: سجل المخزون، آلة حالات الطلب، تنبيهات «اللمبة»، الواتساب، الطباعة والسكان، العلامة المائية لصور الجملة، ومحرك الأسعار.
القرار في سطور
إيه اللي هنبنيه، وليه بالشكل ده بالذات.
مونوليث منظّم بالوحدات
تطبيق واحد وداتابيز واحدة، بس الكود متقسم وحدات واضحة (مخزون، طلبات، جملة…). ده أسرع في البناء والنشر من الخدمات المنفصلة، ومعاه حدود نضيفة تسمح نفصل أي وحدة بعدين لو احتجنا.
أربع طبقات
Domain (الكيانات والقواعد) ← Application (الخدمات وحالات الاستخدام) ← Infrastructure (الداتابيز والتكاملات) ← Web (الـ API واللوحة). النمط: واجهة + خدمة، من غير طبقات زيادة مالهاش لازمة.
موقع نشر واحد
الـ API للموقع على /api/v1، ولوحة الإدارة على /dashboard، واللحظي على /hubs، والجوبز على /hangfire — كله في نفس الاستضافة بنفس الدخول والصلاحيات.
المخزون سجل مش رقم
كل قطعة بتتحرك ليها سطر في سجل حركات مايتمسحش ولا يتعدّل (استلام، تحويل، حجز، بيع، مرتجع، تالف…). الرصيد = نتيجة السجل. ده اللي بيحل مشكلة «الفلوس مش شايفها» و«التالف بيتسرق».
الطلب آلة حالات
مفيش حد بيكتب الحالة بإيده. كل نقلة ليها شرط (مين، وإيه لازم يكون حصل) وأثر (مخزون، رسالة، سجل). الأدمن بس يقدر يتخطى، وبسبب مكتوب.
كل حاجة من اللوحة
المهلات، عدد رسائل التأكيد، حدود VIP، شرائح الجملة، نقاط الولاء، قوالب الرسائل، مفاتيح التكاملات — كلها إعدادات ليها حد أدنى وأقصى وسجل تغييرات.
الخريطة العامة
مين بيكلم السيستم، والسيستم بيكلم مين.
/api/v1/store · /merchant/dashboard/dashboard/opsprint views/dashboard/courier/api/v1/.../dashboard/hubs/ops/hangfireالطبقات ومسؤولية كل واحدة
القاعدة: الطبقة الداخلية ماتعرفش حاجة عن اللي برّاها. Domain مايعرفش EF، وApplication مايعرفش MVC.
| الطبقة | فيها إيه | ممنوع فيها | مثال من فلوكة |
|---|---|---|---|
| Domain | الكيانات، القيم (Money، Code، Quantity)، الـ Enums، قواعد الكيان نفسه، أحداث الدومين | أي مكتبة خارجية، EF، HTTP | Order.CanMoveTo(Preparing)، StockMovement، CodeRange.Contains(code) |
| Application | الخدمات (حالات الاستخدام)، الواجهات للتكاملات، الـ DTOs، التحقق (FluentValidation)، الصلاحيات المطلوبة لكل عملية | Controllers، Razor، تفاصيل SQL | IOrderWorkflow، IStockLedger، IPricingEngine، IWhatsAppSender |
| Infrastructure | EF Core و الهجرات، Dapper للتقارير، مزودي الواتساب والتخزين والإيميل، Hangfire، توليد الباركود، العلامة المائية، Excel | منطق بيزنس | HololWhatsAppSender، ImageSharpWatermarker، ClosedXmlExporter |
| Web | Controllers الـ API، لوحة MVC (Views + CSS/JS لكل صفحة)، SignalR Hubs، Middleware الأخطاء، Swagger، الإعدادات العامة | منطق بيزنس، استعلامات مباشرة | OrdersController، /dashboard/ops/packing، OpsHub |
| tests | اختبارات وحدات للحسابات والحالات، اختبارات عقد للـ API، اختبارات معمارية للحدود | — | «ماينفعش الطلب يروح جاري التحضير من غير طباعة» |
كل خدمة واجهة واضحة باسم البيزنس (IOrderWorkflow.ConfirmAsync) — أسهل في القراية والتتبع والاختبار، وأقل طبقات لمشروع حجمه زي ده. التحويل بين الكيان والـ DTO يدوي (ToDto()) عشان نتحكم بالظبط في اللي بيطلع للموقع — مهم جداً عشان منتجات Prime وسعر التكلفة مايطلعوش بالغلط.
الوحدات (Modules)
كل وحدة فولدر في Domain وApplication وInfrastructure وWeb بنفس الاسم. الرقم تحت كل وحدة = المرحلة اللي بتتبني فيها.
مستخدمي اللوحة، الأدوار، الصلاحيات بالصفحة والزرار، التحقق بخطوتين، حسابات العملاء والتجار (منفصلة)، التوكنات.
مرحلة 0المنتجات، المتغيرات (لون/مقاس/خامة)، الأقسام، البراندات، الصور، الظهور (قطاعي/جملة/Prime)، حالة المنتج (متكوّد ومنتظر ← منشور).
مرحلة 1البادئات (N، Pin، Mobile…)، نطاقات محجوزة ومقفولة، اقتراح الكود التالي، منع التكرار، طباعة الباركود.
مرحلة 1تكلفة، قطاعي، عرض بتاريخ، جملة + شرائح كمية، سجل تغيير الأسعار، محرك حساب السلة.
مرحلة 1المخازن (رئيسي، جملة، أونلاين، فرع، تالف)، الأماكن، سجل الحركات، الأرصدة، الحجز، التحويلات بالموافقة، الجرد والمراجعة.
مرحلة 1الموردين، أذون الشراء ومدفوعاتها، الشحنات/الحاويات، الاستلام، العدّاد، العينات، إعادة حساب التكلفة.
مرحلة 3دفعات الفحص لكل براند، فرز أول/تاني/تالف، حالات التالف، لجنة المراجعة، إعدام أو إصلاح، الخامات المسحوبة.
مرحلة 3إنشاء الطلب (موقع/لوحة/جملة)، آلة الحالات، الاستثناءات، الحجز بنوعيه، العاجل والوسوم، سجل الحالات والملاحظات.
مرحلة 2الطباعة وعدّادها، أقسام التجهيز، التجميع بالمكان، محطة التقفيل بالسكان، الأخطاء والأصوات، ستاند المواقف.
مرحلة 2شركات الشحن، أسعار المحافظات، دفعات التسليم بالسكان، Excel التسليم، مطابقة فريق المراجعة، دخول شركة الشحن.
مرحلة 2تسجيل المرتجع (كلي/جزئي)، فحص قطعة قطعة، القرار (للمخزون / تالف / غلط)، الإرجاع للمخزون بإيد مسؤول.
مرحلة 2حسابات العملاء، طلبات التجار ومراجعتها، Prime (يدوي)، VIP (تلقائي)، قبول الشروط بإصدارها، رقم التاجر للعلامة المائية.
مرحلة 2 + 4العروض الخمسة، الكوبونات، نقاط الولاء ومستوياتها، منتج الصور وباقاته، (المحفظة لو اتقررت).
مرحلة 5قوالب الرسائل، جدول تذكيرات التأكيد، طابور الإرسال، استقبال ردود الأزرار، سجل الرسائل وحدود الإرسال.
مرحلة 2الرئيسية الإحصائية، تقارير المبيعات والمخزون والتالف والمطابقة، الموردين، المصاريف والإيرادات المبسطة.
مرحلة 6استلام الفرع، تخفيض مدير الفرع، البيع بالباركود، البازارات كمخازن مؤقتة.
مرحلة 7الإعدادات بحدودها، مفاتيح التكاملات المشفّرة، صفحات المحتوى، الأسئلة الشائعة، البانرات، سجل التعديلات، المحذوفات.
مرحلة 0شكل الحل (Solution)
نفس أسماء الوحدات في كل طبقة — أي حد يدور على «التحويلات» يلاقيها في نفس المكان في الأربع طبقات.
التقنيات
كلها نسخ ثابتة ومحلية — مفيش مكتبات من CDN في اللوحة.
| البند | الاختيار | السبب |
|---|---|---|
| الإطار | .NET 10 LTS (net10.0) | دعم طويل لحد 2028؛ .NET 8 دعمه بينتهي نوفمبر 2026 |
| الداتابيز | SQL Server + EF Core 10 + Dapper للتقارير التقيلة | متاحة على الاستضافة، المعاملات قوية للمخزون |
| المعرّفات | Guid v7 + رقم عرض قصير للطلبات (FL-260412) | ترتيب زمني، ومناسب للباركود على الإيصال |
| الفلوس | decimal(12,2) — والتكلفة decimal(12,4) | تكلفة القطعة بتطلع كسور بعد قسمة الشحنة |
| الوقت | تخزين UTC وعرض بتوقيت القاهرة | تنبيهات الـ 24 ساعة والتقارير اليومية مظبوطة |
| اللوحة | ASP.NET MVC (Razor) + JS خفيف لكل صفحة + ApexCharts | سريعة، من غير build معقد، وكل صفحة مستقلة |
| اللحظي | SignalR | جرس الطلبات واللمبة ومحطة التقفيل |
| الجوبز | Hangfire على SQL Server | التذكيرات والتنبيهات وطابور الواتساب، بلوحة متابعة |
| الصور | ImageSharp (ضغط، WebP، علامة مائية) + تخزين محلي/ImageKit | صور المنتجات وصور العملاء وصور الجملة المعلّمة |
| الباركود | Code128 (توليد SVG في السيرفر) | بيقراه أي سكانر، ومناسب للأكواد اللي فيها حروف وشرطة |
| Excel | ClosedXML | تصدير كل القوائم + ملف التسليم + استيراد المنتجات |
| التحقق | FluentValidation + رسائل عربي | نفس الرسائل للـ API واللوحة |
| السجلات | Serilog لملفات (من غير باسوردات أو توكنات) | تتبع المشاكل |
| اللغتين | LocalizedText في الداتابيز + ملفات ترجمة (resx) للوحة والأخطاء + Accept-Language للـ API | اللوحة والموقع والتطبيق عربي وإنجليزي |
| إشعارات التطبيق | FCM HTTP v1 + جدول أجهزة + صندوق إشعارات | حالة الطلب، العروض، قبول التاجر — بلغة العميل |
| الاختبارات | xUnit + اختبارات عقد + اختبارات معمارية | الحسابات والحالات مايتكسروش |
سجل المخزون — قلب النظام
كل قطعة في فلوكة ليها قصة: اتطلبت في إذن، وصلت في شحنة، اتعدّت، اتحولت، اتفرزت، اتباعت، رجعت. السجل بيحكي القصة دي سطر سطر.
الفكرة
- جدول حركات إلحاقي: كل سطر = متغير + مخزن (+ مكان) + كمية بالموجب أو السالب + نوع الحركة + المستند (إذن/تحويل/طلب…) + مين + إمتى.
- جدول أرصدة بيتحدث في نفس المعاملة: متاح، محجوز، في الطريق.
- مفيش «تعديل رصيد» — التسوية حركة جديدة بسبب ومين وافق.
- Interceptor بيمنع أي تعديل أو مسح على جدول الحركات.
منع البيع الزيادة
- الطلب بيعمل حجز للكمية أول ما يتعمل (حتى قبل التأكيد) — المتاح للموقع = الرصيد − المحجوز.
- الحجز بيتفك لو الطلب اتلغى أو الطلب المركون عدّى مهلته (حسب الإعداد).
- الخصم الفعلي من المخزون عند التقفيل (القطع خرجت من الرف).
- قفل على مستوى الصف (
UPDLOCK) +rowversionعشان طلبين على آخر قطعة مايعدّوش الاتنين.
أنواع الحركات
| النوع | الاتجاه | المستند | بيحصل إمتى |
|---|---|---|---|
| استلام شحنة | + المخزن الرئيسي | إذن استلام | بعد العدّاد واعتماد العدد |
| عينة للمصوّر | − المخزن (+ مخزن العينات) | سند عينة | العدّاد يسحب عينة |
| تحويل خارج / داخل | − المرسل / + المستلم | طلب تحويل | الإرسال ثم تأكيد الاستلام (الفرق = عجز تحويل) |
| فرز | − انتظار الفحص / + أونلاين أو فرع أو تالف | دفعة فحص | نتيجة فحص الجودة |
| إعدام | − التالف | حالة تالف | قرار اللجنة |
| إصلاح | − التالف / + الوجهة | حالة تالف | مرتجع تالف |
| حجز / فك حجز | المتاح فقط | طلب | إنشاء الطلب / إلغاؤه |
| بيع | − مخزن الطلب | طلب | التقفيل |
| مرتجع | + «مرتجعات تحت الفحص» | حالة مرتجع | استلام المرتجع |
| إرجاع للمخزون | − تحت الفحص / + المخزن | حالة مرتجع | قرار مسؤول المرتجعات |
| تسوية جرد | ± | جرد | المراجع لقى فرق — بموافقة |
| رصيد افتتاحي | + | استيراد | نقل البيانات من النظام الحالي |
أي قطعة «تالفة» ليها كود وسطر بمين أضافها — ماينفعش تختفي. وأي إذن شراء يتقفل بالكمية اللي وصلت فعلاً، والفرق بيبان في تقرير.
آلة حالات الطلب
خدمة واحدة IOrderWorkflow هي الوحيدة اللي بتغيّر حالة الطلب. كل نقلة متعرّفة في جدول: من، إلى، مين يقدر، الشرط، الأثر.
| من ← إلى | بيحصل بـ | الشرط | الأثر |
|---|---|---|---|
| (جديد) ← بانتظار التأكيد | إنشاء من الموقع أو اللوحة | المتاح يكفي | حجز المخزون + جدولة رسائل التأكيد |
| بانتظار التأكيد ← تم التأكيد | زرار «تأكيد» في الواتساب / تأكيد يدوي | — | إلغاء التذكيرات + سجل |
| بانتظار التأكيد ← استثناء | زرار «تعديل» / يدوي | سبب | اللمبة + إشعار خدمة العملاء |
| تم التأكيد ← جاري التحضير | أول طباعة للإيصال | صلاحية الطباعة | سجل طباعة + يبدأ عدّاد الـ 24 ساعة |
| جاري التحضير ← استثناء | الأوبريشن: قطعة ناقصة | ملاحظة (كود القطعة) | علامة «على ستاند المواقف» + اللمبة |
| استثناء ← تم التأكيد | خدمة العملاء كتبت الحل | نص الحل | تطفي اللمبة + علامة «اتجمع قبل كده» |
| جاري التحضير ← تم التحضير | محطة التقفيل | كل السطور اتسكانت صح | خصم المخزون (بيع) |
| تم التحضير ← جاهز للمندوب | تلقائي بعد التقفيل | — | يظهر في شاشة التسليم |
| جاهز للمندوب ← تم الشحن | سكان في دفعة تسليم | الطلب جوه الدفعة | سطر في Excel الدفعة + رسالة للعميل |
| تم الشحن ← تم الاستلام / مرتجع | المراجعة أو استيراد ملف الشحن | — | VIP + نقاط الولاء (عند الاستلام) |
| مرتجع ← اتفحص ← رجع المخزون | مسؤول المرتجعات | قرار لكل قطعة | حركات المخزون |
| أي حالة قبل الشحن ← ملغي | خدمة العملاء / الأدمن | سبب من القايمة | فك الحجز (أو إرجاع للمخزون لو اتقفل) |
| أي ← أي | الأدمن فقط («حالة الطلب ينزل فين») | سبب مكتوب | سجل تخطي مميّز في التقارير |
عاجل، لون الشريط، قسم التجهيز (بورسعيد/محافظات/جملة/صور)، ومؤجل الشحن ومركون — دي صفات على الطلب بتأثر على الترتيب والعرض، مش بتكسر خط الحالات. كده الفلترة والتقارير تفضل بسيطة.
«اللمبة» والتنبيهات
اللمبة هي طريقة العميل إنه يطلّع الطلب اللي فيه مشكلة لأول القايمة مهما كان تاريخه. بنعملها كدرجة انتباه محسوبة.
الترتيب في كل قوائم التشغيل
- عاجل (أحمر) — يدوي.
- محتاج انتباه (اللمبة) — استثناء مفتوح أو تنبيه.
- «اتجمع قبل كده» — يطبع ويجيبه من الستاند.
- الباقي بالتاريخ.
كل طلب فيه AttentionLevel وAttentionReason، والفهرس عليهم.
جوب كل 5 دقايق Hangfire
- بانتظار التأكيد > 24 ساعة بعد آخر رسالة ← «محتاج مكالمة».
- جاري التحضير > 24 ساعة ← «الإيصال ضاع؟ اطبع تاني».
- مركون عدّى مهلته (5–7 أيام) ← أحمر وفوق.
- مؤجل الشحن: قبل الميعاد بـ X أيام ← رسالة تأكيد جديدة.
كل الأرقام من الإعدادات، والتغيير بيوصل اللوحة لحظياً بـ SignalR.
الواتساب
العميل شغال على مزود اسمه «حلول» وعنده ربط برمجي. بنحطه ورا واجهة واحدة عشان لو اتغير المزود مانلمسش البيزنس.
الخدمة بتطلب رسالة من القالب المناسب بالمتغيرات.
الرسالة تتسجل «في الانتظار» مع ميعاد الإرسال (التذكيرات بتتجدول).
فاصل بين الرسائل، إعادة محاولة، حد يومي، ساعات هدوء — من الإعدادات.
زرار «تأكيد» أو «تعديل» يوصل للنظام ويتنفذ مرة واحدة بس حتى لو اتبعت مرتين.
لينك تأكيد موقّع في الرسالة يفتح صفحة صغيرة فيها «تأكيد / تعديل».
| الإعداد | مثال | من اللوحة |
|---|---|---|
| عدد رسائل التأكيد في اليوم الأول | 2 | ✓ |
| الفاصل بين رسائل التأكيد | 6 ساعات | ✓ |
| عدد الأيام قبل اعتبار الطلب «محتاج مكالمة» | 1 (24 ساعة) | ✓ |
| تذكير مؤجل الشحن قبل الميعاد | 3 أيام | ✓ |
| نص كل رسالة + الأزرار | «أهلاً {name}، طلبك {code} بـ {total}…» | ✓ |
| ساعات الهدوء | 11 م – 9 ص | ✓ |
| تكلفة الرسالة (للتقارير) | 0.50 ج | ✓ |
السكان والطباعة
السكانر بيشتغل كأنه كيبورد — من غير برامج على الجهاز. الصفحة بتلقط الكود وتبعته للسيرفر وترد بصوت وعلامة.
🧾 الإيصال
صفحة طباعة 80 مم فيها باركود رقم الطلب، القطع بأكوادها وأماكنها (للتجميع)، والقسم. أول طباعة بتنقل الطلب «جاري التحضير»، والطباعة التانية بتتسجل وبتكتب «نسخة 2».
📟 محطة التقفيل
سكان الإيصال ← يظهر الطلب. سكان كل قطعة ← العدّاد يزيد. صنف غلط أو عدد زيادة ← صوت خطأ أحمر. سكان الإيصال تاني ← لو كله تمام: علامة صح وصوت نجاح والطلب «تم التحضير». كل سكان متسجل بمين وإمتى.
🚚 التسليم للمندوب
تفتح دفعة لشركة شحن ← سكان الطلبات واحد واحد ← العدد قدامك ← تقفل الدفعة ← Excel بالطلبات للمراجعة + نموذج توقيع بالعدد للدفتر.
🏷️ ملصقات الباركود
من صفحة المنتج أو من إذن الاستلام: اختار الأكواد والعدد ← صفحة طباعة بمقاس الملصق (افتراضي 40×25 مم) — المقاس من الإعدادات.
🔫 المراجعة بالمسدس
المراجع يختار مكان ← يسكان القطع ← السيستم يقارن بالمسجل ويعرض صورة المنتج من الموقع جنب كل سكان. الفروق تطلع جرد للموافقة.
📷 طلبات الصور
خطوة «طباعة الصور» قبل التقفيل: تحميل صور كل قطعة مرتبة باسم الطلب ورقم القطعة، وعلامة «اتطبعت» قبل ما محطة التقفيل تقبل الطلب.
حماية صور الجملة (العلامة المائية)
العميل عايز يعرف مين سرّب صورة من الجملة. منع السكرين شوت على المتصفح مش ممكن تقنياً، فالحل إن الصورة نفسها تبقى «بتشهد» على صاحبها.
إزاي
- كل تاجر ليه رقم عام قصير (مثلاً
T-0457). - صور الجملة مابتطلعش برابط ثابت: بتطلع من رابط موقّع ومؤقت خاص بالتاجر.
- السيرفر بيرسم رقم التاجر على الصورة بشفافية بسيطة في كذا مكان، ويحفظ النسخة دي (كاش) عشان مايترسمش كل مرة.
- الموقع كمان بيحط علامة عائمة برقم التاجر فوق الشاشة (للتصوير بموبايل تاني).
إيه اللي بيحميه وإيه اللي لأ
- ✓ صورة اتنزلت أو اتعمل لها سكرين شوت ← الرقم فيها.
- ✓ تصوير الشاشة بموبايل ← العلامة العائمة ظاهرة.
- ✗ منع السكرين شوت نفسه — مش ممكن في المتصفح (التطبيقات زي المحافظ بتقدر لأنها تطبيق موبايل).
- صور القطاعي العادية مش بتتأثر — بتفضل سريعة ومن غير علامة.
محرك الأسعار
مكان واحد بيحسب سعر أي سطر وأي سلة — للموقع وللوحة ولطلبات الجملة — والنتيجة بتتحفظ صورة منها على الطلب.
قطاعي ولا جملة؟ (الجملة: مخزن الجملة وأسعارها بس).
سعر القطاعي، أو سعر العرض لو جوه تاريخه = «آخر سعر».
حسب الكمية (12، 120…) لو القناة جملة.
باقة الصور لكل قطعة.
عرض واحد لكل قطعة (الأفضل للعميل) — الخمس أنواع.
بعد العروض، بحدودهم.
من جدول المحافظات (وهدية الشحن المجاني).
هل العروض بتتجمع مع الكوبون ونقاط الولاء؟ الموقع التجريبي بيقول آه. المحرك جاهز للحالتين بإعداد واحد.
الـ API للموقع
فريق الموقع بيبني على الـ API ده. البادئات بتفصل كل جمهور، والعقد بيتكتب ويتصدّر openapi.json قبل التنفيذ.
| البادئة | لمين | أمثلة |
|---|---|---|
/api/v1/public | أي حد | إعدادات الموقع، المحافظات وأسعار الشحن، صفحات المحتوى، الأسئلة الشائعة، البانرات، شروط الجملة |
/api/v1/store | عملاء القطاعي | الكتالوج والبحث والفلاتر، المنتج، السلة وحسابها، الطلب، رفع صور المنتج، المفضلة، المقارنة، النقاط، حسابي وطلباتي |
/api/v1/merchant | التجار | تقديم الطلب وحالته، كتالوج الجملة (Prime مخفي لغير الـ Prime)، الصور المعلّمة، طلبات الجملة |
/api/v1/auth | الكل | دخول، تسجيل، تجديد التوكن، لينك الدخول السحري للتجار، استعادة الباسورد |
/api/webhooks | المزودين | ردود الواتساب، (شركات الشحن لاحقاً) |
لو فريق الموقع بعت عقد ← يتنفذ حرفياً. غير كده: قوائم مترقّمة دايماً { items, page, pageSize, total, hasMore }، وأخطاء بكود ثابت وحالة HTTP صح، ورسائل بلغة الطلب (عربي أو إنجليزي). أي عملية فيها فلوس أو إنشاء طلب بتقبل Idempotency-Key عشان الضغط مرتين مايعملش طلبين.
عربي وإنجليزي في كل حاجة + التطبيق
اللوحة والموقع والتطبيق بلغتين، والعربي الافتراضي. اللغة مش «ترجمة بعدين»: بتتبني في الداتابيز والـ API واللوحة من أول يوم. ونفس الـ API بيخدم الموقع وتطبيق الموبايل.
في الداتابيز
كل نص بيظهر للعميل عمود LocalizedText فيه {ar, en}: اسم المنتج ووصفه وخامته، الألوان والمقاسات (من قوائم)، الأقسام، العروض، باقات الصور، مستويات VIP والنقاط، الشروط، صفحات المحتوى، الأسئلة الشائعة، البانرات، وقوالب الرسائل.
في الـ API
الموقع والتطبيق بيبعتوا Accept-Language: ar أو en، والرد بييجي بلغة واحدة جاهزة للعرض. لو الترجمة ناقصة بيرجع للغة التانية بدل ما يرجع فاضي. رسائل الأخطاء كمان باللغتين.
في اللوحة
زرار تبديل بيتحفظ لكل مستخدم، كل نصوص الشاشات من ملفات ترجمة (ممنوع نص ثابت في الصفحة)، الاتجاه بيتقلب لوحده، وكل حقل نص للعميل بيتكتب في تبويبين: عربي / English.
الرسائل بلغة العميل
كل عميل وتاجر ليه PreferredLanguage. رسائل الواتساب والإيميل والإشعارات بتطلع بلغته، وكل قالب ليه نسخة عربي وإنجليزي من اللوحة.
الروابط والبحث
رابط (Slug) وعنوان ووصف SEO لكل لغة للمنتجات والأقسام. البحث بيدور في الاسم العربي والإنجليزي والكود مع بعض، ومش حساس لحالة الحروف.
الطباعة
الإيصال والملصق بلغة اللوحة (الافتراضي عربي)، واسم المنتج بيطلع باللغة المتاحة.
البيانات الحالية (زي ayatul kursi ring) إنجليزي بس، ومعيارنا إن العربي إجباري. القرار المقترح: لغة واحدة على الأقل إجبارية، والناقصة بترجع للتانية، ومعاهم تقرير «منتجات ناقصها ترجمة» في اللوحة واستيراد Excel للترجمات بالجملة. الترجمة نفسها مسؤولية العميل صاحب السيستم؛ إحنا بنوفر الأدوات (التقرير والاستيراد) بس.
التطبيق: الإضافات اللي لازم تبقى موجودة
| البند | إزاي |
|---|---|
| نقطة إعدادات واحدة | GET /api/v1/public/app-config: الإصدارات، الصيانة، التواصل، السوشيال، تشغيل المزايا — بقائمة سماح |
| التحديث الإجباري | آخر إصدار وأقل إصدار مسموح، إجباري ولا لأ، وملاحظات التحديث باللغتين — لكل منصة (أندرويد / آيفون) |
| وضع الصيانة | تشغيل وإيقاف من اللوحة برسالة باللغتين |
| الإشعارات | FCM + جدول أجهزة (توكن، منصة، لغة) + صندوق إشعارات بمقروء/غير مقروء + إشعار جماعي من اللوحة |
| حذف الحساب | من التطبيق ومن صفحة ويب، بمهلة — مطلب المتاجر |
| صفحات المتاجر | الخصوصية والشروط والدعم وحذف الحساب كصفحات ويب ثابتة من السيرفر |
التطبيقات مسؤولية مطوري التطبيقات، ومش علينا. إحنا علينا الـ API اللي هيشتغلوا عليه، ومعاه كل اللي التطبيق محتاجه من السيرفر: إعدادات التطبيق، التحديث الإجباري، الصيانة، الإشعارات، وحذف الحساب. كمان الـ API بيدعم العملاء والتجار من الأول، فلو اتقرر بعدين إن التطبيق هيخدم التجار مش هنحتاج نغيّر حاجة.
اللحظي والجوبز
اللوحة بتتحدث لوحدها، والشغل المؤجل بيتعمل في الخلفية.
| حدث لحظي (SignalR) | مين يشوفه |
|---|---|
| طلب جديد (بصوت) | المودريشن، خدمة العملاء |
| لمبة اتولعت / اتطفت | خدمة العملاء، الأوبريشن |
| طلب تحويل مستني تأكيدك | مسؤول المخزن المستلم |
| طلب تاجر جديد | مسؤول الجملة |
| نتيجة السكان | نفس محطة التقفيل |
| تنبيه مخزون (نفد / قرّب يخلص) | الأدمن، إدخال البيانات |
| جوب (Hangfire) | كل قد إيه |
|---|---|
| إرسال طابور الواتساب | كل دقيقة |
| فحص التنبيهات (اللمبة) | كل 5 دقايق |
| تذكيرات مؤجل الشحن والملاحظات الداخلية | كل ساعة |
| إعادة حساب VIP | يومياً + عند الاستلام |
| تفعيل/إنهاء العروض والأسعار المؤقتة | كل 5 دقايق |
| تنضيف الكاش وصور الجملة القديمة | يومياً |
الأمان
الأسعار والتكلفة ومنتجات Prime معلومات حساسة للعميل — والحماية بتبدأ من شكل الـ DTO نفسه.
الدخول
- الموقع: JWT ساعة + تجديد بتدوير.
- اللوحة: Cookie + تحقق بخطوتين للأدمن.
- باسوردات BCrypt، وحد لمحاولات الدخول.
الصلاحيات
- كل زرار ليه كود صلاحية، والسيرفر بيتحقق عليه.
- المودريشن «جملة بس» مايشوفش زرار الجملة غير لو مسموح.
- شركة الشحن تشوف طلباتها بس.
البيانات
- سعر التكلفة مابيطلعش في أي API للموقع — اختبار بيفشّل البناء لو ظهر.
- منتجات Prime فلتر في الاستعلام نفسه.
- مفاتيح التكاملات مشفّرة في الداتابيز.
الأسرار
- مفيش سر في الكود أو
appsettings.json. - التشغيل يرفض يقوم من غير المفاتيح المطلوبة.
- الأدمن الأول من متغيرات البيئة.
السجلات
- سجل تعديلات لكل حاجة في اللوحة (قبل/بعد).
- سجل الحركات والسكان مايتعدّلش.
- مفيش باسورد أو توكن في ملفات السجل.
الحماية العامة
- حدود معدل للـ API والدخول.
- هيدرز أمان + CSP للوحة.
- Swagger مقفول في الإنتاج.
النشر والبيئات
نشر بدري على سيرفر تجريبي عشان فريق الموقع يشتغل على بيانات حقيقية من الأسبوع الأول.
| البيئة | الغرض | الداتابيز | ملاحظات |
|---|---|---|---|
| التطوير | جهاز المطور | محلية | بيانات تجريبية + مرسل واتساب وهمي بيكتب في السجل |
| التجريبي | فريق الموقع والعميل يجربوا | منفصلة | بيانات منقولة من النظام الحالي + حسابات تجريبية لكل دور |
| الإنتاج | الشغل الحقيقي | منفصلة + نسخ احتياطي يومي | بعد اختبار رحلة كاملة على التجريبي |
الهجرات بتتطبق عند التشغيل أو بسكريبت محفوظ — مفيش تعديل يدوي على الداتابيز. WebSockets متفعّلة للـ SignalR. ملف DEPLOYMENT.md فيه خطوات النشر والرجوع.
أهداف الأداء
أرقام بنقيس عليها قبل التسليم.
المخاطر وإزاي نتعامل معاها
الحاجات اللي ممكن تأخر أو تكسر، وخطتنا لكل واحدة.
| الخطر | الأثر | التعامل |
|---|---|---|
| «حلول» مايدعمش الأزرار والردود برمجياً | التأكيد التلقائي يقف | لينك تأكيد موقّع كبديل + واجهة لمزود تاني |
| بيانات النظام الحالي غير نضيفة (أكواد مكررة، أرصدة غلط) | المخزون يبدأ غلط | استيراد بتقرير أخطاء + جرد افتتاحي لكل مخزن |
| تعارض بين الموقع التجريبي وكلام العميل (الجملة، VIP، المحفظة) | شغل يتعاد | عقد API مكتوب ومعتمد قبل التنفيذ |
| كبر النطاق (مخازن + طلبات + جملة + نقطة بيع) | التسليم يتأخر | مراحل بتسليمات شغالة؛ الطلبات قبل نقطة البيع |
| أجهزة المخزن (سكانر، طابعة، تابلت) | المحطات ماتشتغلش | نحدد الأجهزة بدري ونجرب عليها في المرحلة 2 |
| القيود التفصيلية للأدوار لسه مش متحددة | صلاحيات غلط | مصفوفة افتراضية قابلة للتعديل من اللوحة |