تطبيق مبيعات ومخزون وفواتير عربي (RTL)، يعمل بالكامل دون اتصال داخل المتصفح. بلا خادم، بلا قاعدة بيانات خارجية، بلا حسابات، وبلا أي اعتمادية وقت تشغيل.
SPA + PWA مبني على HTML5 و CSS3 و ES Modules و IndexedDB و Service Worker.
يعمل بالنقر المزدوج على index.html أو عبر خادم محلي — ملفات ثابتة تُنشر كما هي.
التطبيق يعمل مباشرة من الملف. كل الوظائف والبيانات تعمل بالكامل: البيع، المخزون، الفواتير، التقارير، Excel، النسخ الاحتياطي — وكلها تبقى بعد إغلاق المتصفح.
المتصفح يحجب وحدات ES عبر
file://، لذا يُحمَّل التطبيق في هذا الوضع منapp.bundle.js(حزمة كلاسيكية واحدة). الاختيار تلقائي بلا أي إعداد منك.
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/.
ارفع محتوى المجلد كما هو إلى أي استضافة ثابتة: GitHub Pages، Netlify، Cloudflare Pages، Vercel، S3 + CloudFront، أو أي خادم ويب.
لا حاجة إلى إعادة كتابة مسارات (rewrite) — الموجّه يعتمد على الـ hash فيعمل Refresh على أي مسار بلا إعداد.
- HTTPS إلزامي — Service Worker والتخزين الدائم لا يعملان بدونه.
-
sw.jsيُقدَّم من الجذر (أو اضبطService-Worker-Allowed). - لا كاش HTTP طويل الأمد على
sw.jsوإلا لن تصل التحديثات. - نوع MIME صحيح لـ
.webmanifest⇒application/manifest+json. - أضف الترويسات الأمنية:
(
Content-Security-Policy: frame-ancestors 'none' X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000frame-ancestorsلا تعمل عبر<meta>— يجب أن تكون ترويسة HTTP.)
عدّل CACHE_VERSION في sw.js. سيكتشف المتصفح التغيير ويعرض «تحديث متاح» للمستخدم،
ولن يُعاد التحميل إلا بعد موافقته حتى لا يفقد عملاً غير محفوظ.
بياناتك موجودة في متصفح هذا الجهاز على هذا النطاق فقط.
| الحدث | النتيجة |
|---|---|
| إغلاق المتصفح / إعادة تشغيل الجهاز | ✅ البيانات باقية |
| متصفح آخر أو نطاق آخر | ❌ لا توجد بيانات |
| «مسح بيانات التصفح» | ❌ تُفقد كل البيانات نهائياً |
| التصفح الخفي | ❌ تُمسح عند الإغلاق |
| ضغط مساحة القرص بلا تخزين دائم |
- من الإعدادات ← البيانات والأوفلاين: اضغط «طلب تخزين دائم» بعد أول تشغيل.
- من النسخ الاحتياطي: أنشئ نسخة JSON بانتظام واحفظها خارج الجهاز.
- اضبط تذكير النسخ (يومي/أسبوعي) وسيذكّرك التطبيق تلقائياً.
- يُفحص الملف بالكامل (النوع، الحجم، البنية، الإصدار، كل حقل في كل سجل) قبل أي كتابة.
- تُنشأ نسخة أمان تلقائية من بياناتك الحالية قبل الاستبدال.
- المسح والكتابة داخل معاملة واحدة — أي خطأ يُجهضها وتبقى بياناتك كما هي بالضبط.
- لا يُدمج سجل ناقص أو مجهول بصمت: إما ملف صالح كامل أو رفض بسبب واضح.
| الشاشة | ما تفعله |
|---|---|
| لوحة التحكم | مبيعات اليوم، عدد الفواتير، متوسط الفاتورة، صافي الحركة، اتجاه 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:// — استخدم خادماً محلياً هناك.