Skip to content

Repository files navigation

نظام المبيعات

تطبيق مبيعات ومخزون وفواتير عربي (RTL)، يعمل بالكامل دون اتصال داخل المتصفح. بلا خادم، بلا قاعدة بيانات خارجية، بلا حسابات، وبلا أي اعتمادية وقت تشغيل.

SPA + PWA مبني على HTML5 و CSS3 و ES Modules و IndexedDB و Service Worker. يعمل بالنقر المزدوج على index.html أو عبر خادم محلي — ملفات ثابتة تُنشر كما هي.


التشغيل

الطريقة الأسهل — انقر نقراً مزدوجاً على index.html

التطبيق يعمل مباشرة من الملف. كل الوظائف والبيانات تعمل بالكامل: البيع، المخزون، الفواتير، التقارير، Excel، النسخ الاحتياطي — وكلها تبقى بعد إغلاق المتصفح.

المتصفح يحجب وحدات ES عبر file://، لذا يُحمَّل التطبيق في هذا الوضع من app.bundle.js (حزمة كلاسيكية واحدة). الاختيار تلقائي بلا أي إعداد منك.

عبر خادم محلي — لتفعيل PWA والعمل دون اتصال المُخزَّن

python -m http.server 8000     # أو: npx serve .     أو: php -S localhost:8000

ثم افتح http://localhost:8000. أو انقر نقراً مزدوجاً على تشغيل-النظام.bat (ويندوز) فيبحث عن Python/Node/PHP، يشغّل الخادم، ويفتح المتصفح تلقائياً.

في هذا الوضع تُحمَّل وحدات ES الأصلية مباشرةً بلا أي بناء.

ما الفرق بين الوضعين؟

index.html مباشرة خادم محلي / HTTPS
كل شاشات ووظائف التطبيق
البيانات تبقى بعد إغلاق المتصفح
Excel، الطباعة، النسخ الاحتياطي
تخزين الأصول مؤقتاً (Service Worker)
التثبيت كتطبيق (PWA)
طلب تخزين دائم

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

بعد تعديل أي ملف في src/ أعد بناء الحزمة حتى يعكسها وضع file://: node tools/build.mjs (أو npm run build). مجموعة الاختبارات تفشل إذا كانت الحزمة قديمة.


الاختبارات

node tools/run-tests.mjs              # كل الاختبارات (وحدة + تكامل + E2E)
node tools/run-tests.mjs --unit-only  # اختبارات الوحدة والتكامل فقط
node tools/run-tests.mjs --headed     # بمتصفح مرئي للتشخيص

أو افتح tests/index.html في المتصفح لرؤية النتائج مباشرة.

لا يحتاج npm install. يستخدم متصفح النظام (Chrome أو Edge) عبر بروتوكول CDP. عيّن CHROME_PATH إن لم يُعثر على المتصفح تلقائياً.

النتيجة الحالية

✓ 123 اختبار وحدة وتكامل  (مقابل IndexedDB حقيقي)
✓  21 فحص من طرف إلى طرف  (في متصفح حقيقي)
─────────────────────────────────
✓ 144 / 144 نجح — 0 فشل — 0 خطأ في الطرفية

التغطية: الحساب المالي والتقريب · CRUD المنتجات والقيود · منع تكرار SKU والباركود · بيع ناجح يخفض المخزون مرة واحدة · بيع فاشل لا يغيّر شيئاً (7 حالات) · إلغاء ذرّي يعيد المخزون مرة واحدة · تسويات المخزون والجرد وسجل الحركات · المدفوعات وأرصدة العملاء · فلاتر التقارير والمجاميع · قراءة وكتابة Excel واستيراد المنتجات · تصدير النسخ الاحتياطي واستعادتها · رفض النسخ التالفة وغير المدعومة (11 حالة) · ترقية IndexedDB بين الإصدارات · مسارات الموجّه والتنقل Back/Forward · البقاء بعد إعادة التحميل · العمل دون شبكة · الطباعة A4 و80mm · الاستجابة وأهداف اللمس والوصولية · التشغيل الكامل من file:// (بيع حقيقي بالنقر + بقاء البيانات بعد إعادة التحميل) · تحديث حزمة file:// مقابل المصدر.

لقطات الشاشة

node tools/screenshot.mjs             # سطح المكتب
node tools/screenshot.mjs --mobile    # الهاتف

تُحفظ في screenshots/ للمقارنة البصرية مع المراجع في UI/.


النشر (استضافة ثابتة عبر HTTPS)

ارفع محتوى المجلد كما هو إلى أي استضافة ثابتة: GitHub Pages، Netlify، Cloudflare Pages، Vercel، S3 + CloudFront، أو أي خادم ويب.

لا حاجة إلى إعادة كتابة مسارات (rewrite) — الموجّه يعتمد على الـ hash فيعمل Refresh على أي مسار بلا إعداد.

قائمة الفحص

  • HTTPS إلزامي — Service Worker والتخزين الدائم لا يعملان بدونه.
  • sw.js يُقدَّم من الجذر (أو اضبط Service-Worker-Allowed).
  • لا كاش HTTP طويل الأمد على sw.js وإلا لن تصل التحديثات.
  • نوع MIME صحيح لـ .webmanifestapplication/manifest+json.
  • أضف الترويسات الأمنية:
    Content-Security-Policy: frame-ancestors 'none'
    X-Content-Type-Options: nosniff
    Strict-Transport-Security: max-age=31536000
    
    (frame-ancestors لا تعمل عبر <meta> — يجب أن تكون ترويسة HTTP.)

إصدار جديد

عدّل CACHE_VERSION في sw.js. سيكتشف المتصفح التغيير ويعرض «تحديث متاح» للمستخدم، ولن يُعاد التحميل إلا بعد موافقته حتى لا يفقد عملاً غير محفوظ.


النسخ الاحتياطي — اقرأ هذا

بياناتك موجودة في متصفح هذا الجهاز على هذا النطاق فقط.

الحدث النتيجة
إغلاق المتصفح / إعادة تشغيل الجهاز ✅ البيانات باقية
متصفح آخر أو نطاق آخر ❌ لا توجد بيانات
«مسح بيانات التصفح» تُفقد كل البيانات نهائياً
التصفح الخفي ❌ تُمسح عند الإغلاق
ضغط مساحة القرص بلا تخزين دائم ⚠️ قد يحذف المتصفح البيانات

ما يجب فعله

  1. من الإعدادات ← البيانات والأوفلاين: اضغط «طلب تخزين دائم» بعد أول تشغيل.
  2. من النسخ الاحتياطي: أنشئ نسخة JSON بانتظام واحفظها خارج الجهاز.
  3. اضبط تذكير النسخ (يومي/أسبوعي) وسيذكّرك التطبيق تلقائياً.

الاستعادة آمنة بالتصميم

  • يُفحص الملف بالكامل (النوع، الحجم، البنية، الإصدار، كل حقل في كل سجل) قبل أي كتابة.
  • تُنشأ نسخة أمان تلقائية من بياناتك الحالية قبل الاستبدال.
  • المسح والكتابة داخل معاملة واحدة — أي خطأ يُجهضها وتبقى بياناتك كما هي بالضبط.
  • لا يُدمج سجل ناقص أو مجهول بصمت: إما ملف صالح كامل أو رفض بسبب واضح.

الشاشات

الشاشة ما تفعله
لوحة التحكم مبيعات اليوم، عدد الفواتير، متوسط الفاتورة، صافي الحركة، اتجاه 7 أيام، المصروفات حسب الفئة، الأصناف منخفضة المخزون، آخر الفواتير
نقطة البيع بحث بالاسم/SKU/باركود، تصفية بالفئة، عربة بتعديل الكمية، اختيار عميل، خصم وضريبة، دفع نقدي أو آجل، تعليق واستعادة، إتمام ذرّي
المنتجات CRUD كامل، صورة، SKU فريد، باركود، بحث وتصفية وفرز وترقيم، استيراد وتصدير Excel
المخزون تسوية بسبب إلزامي، جرد فردي وشامل، سجل حركات كامل، تصدير Excel
الفواتير فلاتر التاريخ والعميل والحالة ونوع الدفع، تفاصيل كاملة، إلغاء ذرّي، طباعة A4 و80mm، حفظ PDF
العملاء CRUD، رصيد محسوب من الحركات، تسجيل دفعات، كشف حساب برصيد تراكمي
المصروفات CRUD، فئات ملوّنة، مرفق إيصال (صورة أو PDF)، فلاتر زمنية وفئوية
التقارير 8 أنواع تقارير، مقارنة بالفترة السابقة، مخططات، تصدير Excel وطباعة
النسخ الاحتياطي تصدير JSON، فحص واستعادة آمنة، سجل النسخ، مسح البيانات، تخزين دائم
الإعدادات المتجر والعملة والتاريخ، ترقيم الفواتير، الضريبة والخصم، الفئات والأسباب، حالة Service Worker والتخزين

البنية

index.html · manifest.webmanifest · sw.js
app.bundle.js            حزمة مُولَّدة لوضع file:// (node tools/build.mjs)
تشغيل-النظام.bat          مشغّل خادم محلي بنقرة واحدة (ويندوز)
assets/css/    app.css · print.css · print-thermal.css
assets/fonts/  Tajawal (OFL 1.1) — 6 ملفات woff2 · ~72KB · fonts.css · OFL.txt
assets/icons/  favicon.svg · icon-192/512 · maskable
src/
  boot-guard.js        يختار وحدات ES أو الحزمة حسب البروتوكول
  app.js               الإقلاع
  router.js routes.js  موجّه hash
  state/               مخزن حالة مع اشتراكات وتنظيف
  db/                  مخطط IndexedDB + ترقيات + معاملات + بيانات أولية
  repositories/        وصول البيانات (منتجات، مخزون، مبيعات، عملاء، مصروفات، إعدادات)
  services/            قواعد العمل (تقارير، نسخ احتياطي، Excel، طباعة، صور، PWA)
  views/               12 شاشة — عرض وتفاعل فقط
  components/          مكوّنات مشتركة (جدول، مخططات، نوافذ، أيقونات، هيكل)
  utils/               DOM آمن، مال بوحدات صغرى، تواريخ، تنسيق، XLSX
  validation/          تحقق وتطبيع لكل المدخلات
tests/                 144 اختباراً تعمل في المتصفح
tools/                 أدوات تطوير (متصفح CDP، مشغّل اختبارات، لقطات، مُحزِّم)
docs/                  التوثيق
UI/                    الصور المرجعية (مواصفات تصميم)

قرارات تقنية

  • صفر اعتماديات وقت تشغيل. لا Bootstrap، لا Chart.js، لا مكتبة أيقونات، لا CDN. خط Tajawal مستضاف محلياً (OFL 1.1، ~72KB). الأسباب في docs/design-decisions.md.
  • Excel وليس CSV في كل الاستيراد والتصدير — بطلب المستخدم. منفَّذ بـ CompressionStream('deflate-raw') الأصلي + بانٍ ZIP يدوي، بلا أي مكتبة.
  • المال بأعداد صحيحة بوحدات صغرى. 0.1 + 0.2 !== 0.3 مشكلة حقيقية في نظام مبيعات.
  • لقطات تاريخية داخل سطر الفاتورة (السعر والتكلفة والاسم) فلا تتأثر تقارير الماضي بتغييرات اليوم.
  • رصيد العميل محسوب من الفواتير والمدفوعات، لا رقماً محفوظاً ينحرف.
  • الإلغاء تعويض لا حذف — الفاتورة تبقى في السجل بحالة «ملغاة».
  • applyMovement هو المسار الوحيد الذي يكتب كمية منتج، ومعه سجل حركة في نفس المعاملة.
  • لا innerHTML في أي مكان + CSP صارمة بلا unsafe-inline.

الحدود المعروفة

بصراحة، وبلا محاكاة مضلّلة:

  • لا مصادقة ولا صلاحيات. أي شخص يفتح المتصفح على هذا الجهاز يرى كل شيء. لم نضف PIN محلياً عمداً — يُتجاوَز من أدوات المطوّر في ثوانٍ ويعطي أماناً وهمياً.
  • لا مزامنة ولا تعدد أجهزة. البيانات في متصفح واحد على نطاق واحد.
  • لا فروع ولا مستودعات متعددة.
  • لا معالجة بطاقات. «طريقة الدفع» تصنيف محاسبي فقط؛ لا يُخزَّن أي رقم بطاقة.
  • البيانات غير مشفّرة على القرص — استخدم تشفير القرص على مستوى النظام.
  • التدقيق بلا هوية: السجل يبيّن ما حدث ومتى، لا من فعله.

التفاصيل والعقود المقترحة لكل ميزة مؤجّلة في docs/future-backend.md.


التوثيق

الملف المحتوى
ui-screen-inventory.md تحليل الصور المرجعية و Design Tokens
competitive-benchmark.md مقارنة بـ Square و Shopify و Loyverse و Odoo و Zoho مع المصادر
design-decisions.md كل قرار وسببه، وما خالف الصور ولماذا
data-model.md الكيانات والفهارس والعلاقات والترقيات
offline-strategy.md الكاش والتحديث والتخزين وحدود البقاء
security-review.md نموذج التهديد والتخفيفات والحدود
future-backend.md ما يحتاج خادماً ولماذا، مع عقود مقترحة

متطلبات المتصفح

Chrome/Edge 103+ · Firefox 113+ · Safari 16.4+

السبب: CompressionStream('deflate-raw') (Baseline منذ 2023-05) المستخدم في Excel. بقية التطبيق يعمل على متصفحات أقدم، لكن استيراد وتصدير Excel لن يعمل.

التشغيل من file:// مُختبَر على Chromium (Chrome/Edge)، حيث IndexedDB متاح ويُعتبر السياق آمناً. بعض المتصفحات الأخرى تقيّد التخزين عبر file:// — استخدم خادماً محلياً هناك.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages