خطة البنية التحتية والنشر — نظام إدارة المغسلة
معلومات الوثيقة
| الحقل |
القيمة |
| المشروع |
نظام إدارة المغسلة |
| الإصدار |
1.0 |
| اللغة |
العربية |
| التقنيات |
ASP.NET Core, Angular, Tauri, PostgreSQL, Docker, Traefik, Seq |
| نوع الوثيقة |
دليل البنية التحتية والنشر |
جدول المحتويات
- نظرة عامة على معمارية النشر
- ملف docker-compose.yml الموحد
- مواصفات الأجهزة
- نوع النشر أ — الخادم المتصل (Type 1)
- نوع النشر ب — الفرع غير المتصل (Type 2)
- نوع النشر ج — فرع غير متصل مع مزامنة (Type 3)
- تكوين Traefik — HTTPS لجميع النشرات
- منع الوصول عبر المتصفح (الفروع غير المتصلة)
- معالج التثبيت (Installation Wizard)
- حزمة USB إعداد الفرع
- استراتيجية النسخ الاحتياطي
- المراقبة عبر Seq
- إجراء التراجع (Rollback)
- استراتيجية البيئات
- إعداد الأجهزة الطرفية
1. نظرة عامة على معمارية النشر
كل نسخة من النظام — خادم متصل، فرع غير متصل، أو فرع بمزامنة — تشغل نفس حزمة docker-compose.yml. السلوك يتحكم به ملف .env واحد.
flowchart TB
subgraph Docker["حزمة Docker Compose"]
Traefik["Traefik<br/>:80 :443 :8080<br/>وكيل عكسي<br/>SSL عبر Let's Encrypt / mkcert"]
API["ASP.NET Core API<br/>:5000<br/>يقدم /api + ملفات Angular"]
PG["PostgreSQL 16<br/>:5432 (داخلي)<br/>قرص مشفر"]
Seq["Seq<br/>:5341<br/>سجلات وتتبع"]
end
Internet["الإنترنت / تطبيق Tauri"] -->|HTTPS| Traefik
Traefik -->|توجيه: /api/*| API
Traefik -->|توجيه: /logs| Seq
Traefik -->|توجيه: static| API
API -->|SQL| PG
API -->|سجلات وتتبع| Seq
ENV["ملف .env<br/>BRANCH_MODE<br/>DOMAIN<br/>CERT_MODE<br/>BRANCH_ID"] -.- Docker
subgraph Types["أنواع النشر"]
T1["نوع أ: خادم متصل<br/>CERT_MODE=acme<br/>DOMAIN=customer.com"]
T2["نوع ب: فرع غير متصل<br/>CERT_MODE=static<br/>DOMAIN=laundry.local"]
T3["نوع ج: فرع بمزامنة<br/>CERT_MODE=static<br/>DOMAIN=laundry.local<br/>+ تصدير/استيراد"]
end
ENV ==> Types
أنواع النشر الثلاثة
| النوع |
وضع BRANCH_MODE |
النطاق |
الشهادات |
الإنترنت |
العميل |
| أ — خادم متصل |
online |
نطاق العميل الحقيقي |
Let's Encrypt |
مطلوب |
Tauri أو متصفح |
| ب — فرع غير متصل |
offline |
laundry.local |
mkcert |
لا يوجد |
Tauri فقط |
| ج — فرع بمزامنة |
offline_sync |
laundry.local |
mkcert |
لا (عدا النقل اليدوي) |
Tauri فقط |
2. ملف docker-compose.yml الموحد
services:
traefik:
image: traefik:v3
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/certs:ro
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: laundry
POSTGRES_USER: laundry
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
- ./backups:/backups
api:
image: ghcr.io/${GITHUB_ORG}/laundry-api:${VERSION:-latest}
restart: unless-stopped
depends_on: [postgres]
environment:
ConnectionStrings__Default: "Host=postgres;Database=laundry;Username=laundry;Password=${DB_PASSWORD}"
BranchMode: ${BRANCH_MODE}
BranchId: ${BRANCH_ID}
Domain: ${DOMAIN}
SeqServerUrl: "http://seq:5341"
LicensePath: "/license/license.dat"
volumes:
- ./license:/license:ro
- ./backups:/backups
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`${DOMAIN}`)"
seq:
image: datalust/seq:2024.1
restart: unless-stopped
environment:
ACCEPT_EULA: "Y"
volumes:
- seqdata:/data
volumes:
pgdata:
seqdata:
3. مواصفات الأجهزة
الخادم المتصل (Type A — VPS)
| المورد |
الحد الأدنى |
الموصى به |
| المعالج |
2 vCPU |
4 vCPU |
| الذاكرة |
4 GB |
8 GB |
| القرص |
40 GB SSD |
80 GB SSD |
| النظام |
Ubuntu 24.04 LTS |
|
| مزودون مقترحون |
Hetzner CX22 (~8$/شهر)، DigitalOcean (24$/شهر) |
|
أجهزة الفروع غير المتصلة (Type B & C)
| المورد |
الحد الأدنى |
الموصى به |
| المعالج |
Intel Core i3 / AMD Ryzen 3 |
Intel Core i5 |
| الذاكرة |
8 GB |
16 GB |
| القرص |
256 GB SSD |
512 GB SSD |
| النظام |
Windows 10/11 Pro، Ubuntu 24.04، macOS 13+ |
|
| مزود طاقة |
UPS موصى به للحماية |
|
4. نوع النشر أ — الخادم المتصل (Type 1)
4.1 تجهيز الخادم
# 1. توفير VPS جديد بنظام Ubuntu 24.04.
# 2. الاتصال عبر SSH.
ssh root@<ip-الخادم>
# 3. تثبيت Docker
curl -fsSL https://get.docker.com | sh
# 4. توجيه DNS:
# laundry.customer-domain.com → <ip-الخادم>
# 5. إنشاء بنية المجلدات
mkdir -p /opt/laundry/{certs,license,backups}
4.2 ملف .env
BRANCH_MODE=online
BRANCH_ID=00000000-0000-0000-0000-000000000000
BRANCH_CODE=MAIN
DB_PASSWORD=<توليد-تلقائي-32-حرف>
DOMAIN=laundry.customer-domain.com
CERT_MODE=acme
ACME_EMAIL=admin@customer-domain.com
VERSION=1.0.0
4.3 التشغيل والتحديث
cd /opt/laundry
docker compose up -d # تشغيل
docker compose pull # تحديث الصور
docker compose up -d # إعادة تشغيل بالإصدار الجديد
5. نوع النشر ب — الفرع غير المتصل (Type 2)
5.1 نظرة عامة
الفرع غير المتصل يشغل حزمة Docker كاملة محلياً. كل الحركة على localhost. HTTPS عبر شهادات mkcert. تطبيق Tauri المكتبي يتصل بـ https://laundry.local.
5.2 المتطلبات (تثبت عبر USB الإعداد)
| المكون |
طريقة التثبيت |
| Docker Engine |
Docker Desktop للتثبيت عبر USB |
| mkcert |
نسخة محمولة على USB |
| صور Docker |
docker load < laundry-images.tar |
docker-compose.yml |
نسخ من USB |
| مثبت Tauri |
تشغيل .msi / .dmg / .deb من USB |
license.dat |
نسخ إلى C:\Laundry\license\ |
5.3 ملف .env
BRANCH_MODE=offline
BRANCH_ID=<uuid-الفرع>
BRANCH_CODE=CAIRO-01
DB_PASSWORD=<توليد-تلقائي-32-حرف>
DOMAIN=laundry.local
CERT_MODE=static
VERSION=1.0.0
5.4 إعداد mkcert (مرة واحدة)
mkcert -install
mkcert laundry.local localhost 127.0.0.1 ::1
# ينتج: laundry.local+3.pem و laundry.local+3-key.pem
# ينسخان إلى C:\Laundry\certs\
6. نوع النشر ج — فرع غير متصل مع مزامنة (Type 3)
مطابق للنوع ب، مع الإضافات التالية:
6.1 الاختلاف في .env
6.2 خصائص إضافية
| الخاصية |
التنفيذ |
| تصدير بيانات المزامنة |
زر في تطبيق Tauri: "تصدير بيانات المزامنة" → ضغط الصفوف المعلقة إلى ملف .lndsync مشفر بـ AES-256 على USB |
| استيراد بيانات المزامنة (الخادم المركزي) |
لوحة الإدارة ← "استيراد بيانات فرع" ← رفع الملف ← تحقق ← دمج |
| استيراد تحديثات رئيسية (الفرع) |
استلام ملف .lndmaster (قوائم أسعار جديدة، خدمات) ← استيراد عبر التطبيق |
| تقرير الصحة |
مضمّن تلقائياً في كل ملف .lndsync |
6.3 تنسيق ملف المزامنة
sync_cairo-01_2026-05-09.lndsync (ملف ZIP مشفر بـ AES-256 يحتوي:
├── journal_entry_lines.json
├── invoices.json
├── payments.json
├── customers.json
├── ... (جميع الجداول بحالة sync_status='pending')
└── health_report.json
)
مفتاح التشفير = SHA-256(مفتاح_الترخيص + معرف_الفرع)
7. تكوين Traefik — HTTPS لجميع النشرات
7.1 الخادم المتصل: Let's Encrypt
شهادات تلقائية عبر ACME. Traefik يجددها تلقائياً كل 60 يوماً.
7.2 الفروع غير المتصلة: شهادات mkcert ثابتة
ينشئ معالج التثبيت ملف traefik.yml خاصاً:
tls:
certificates:
- certFile: /certs/laundry.local+3.pem
keyFile: /certs/laundry.local+3-key.pem
8. منع الوصول عبر المتصفح (الفروع غير المتصلة)
طبقة 1: وسيط ASP.NET Core
يتحقق من وجود رأس X-Laundry-Client-Token. إذا كان مفقوداً أو غير صالح → 403 مع رسالة: "الرجاء استخدام تطبيق Laundry System المكتبي."
طبقة 2: Tauri يحقن الرمز
تطبيق Tauri يحسب HMAC يومياً من (مفتاح الترخيص + معرف الفرع) ويضيفه تلقائياً لكل طلب HTTP. لا يظهر في كود Angular أبداً.
9. معالج التثبيت (Installation Wizard)
9.1 نظرة عامة
مدمج في تطبيق Tauri. عند التشغيل الأول، تظهر شاشات المعالج بدلاً من صفحة الدخول.
9.2 شاشات المعالج
| الشاشة |
المحتوى |
| 1: الترحيب |
اختيار نوع النشر + اللغة (عربي/English) |
| 2: معلومات الفرع |
اسم الفرع، الكود، العملة، بداية السنة المالية |
| 3: الترخيص |
رفع ملف license.dat، عرض اسم العميل وتاريخ الانتهاء |
| 4: النطاق (للخادم المتصل فقط) |
إدخال النطاق والبريد الإلكتروني |
| 5: Docker والخدمات |
تثبيت Docker، تحميل الصور، إنشاء المجلدات، بدء الخدمات، تطبيق الترحيلات، نسخ احتياطي قبل الترقية |
| 6: حساب المدير |
اسم مستخدم + خياران: توليد تلقائي لكلمة مرور (16 حرفاً) أو تخصيص (8 أحرف كحد أدنى، حرف كبير، رقم، رمز خاص). تأكيد الحفظ إجباري. |
| 7: اكتمال |
عرض الرابط وبيانات الدخول وزر "تشغيل النظام" |
10. حزمة USB إعداد الفرع
Laundry_Setup_USB/
├── README.txt # تعليمات بالعربية والإنجليزية
├── setup.bat / setup.sh # سكربت التشغيل التلقائي
├── docker/
│ ├── Docker Desktop Installer.exe
│ └── laundry-images_v1.0.0.tar # حفظ صور Docker
├── mkcert/ # ثنائيات mkcert
├── app/
│ ├── LaundrySystem_*.msi # Tauri - Windows
│ ├── LaundrySystem_*.dmg # Tauri - macOS
│ └── laundry-system_*.deb # Tauri - Linux
├── docker-compose.yml
└── license.dat
11. استراتيجية النسخ الاحتياطي
11.1 الخادم المركزي
| الطريقة |
التكرار |
pg_dump عبر cron |
يومي الساعة 2 صباحاً |
| نسخة احتياطية خارج الموقع |
يومياً إلى S3 أو تخزين سحابي |
11.2 الفروع غير المتصلة
| الطريقة |
التفصيل |
| نسخ آلي مجدول |
مهمة Quartz.NET يومياً → pg_dump ← تشفير AES-256 ← حفظ في ./backups/ |
| نسخ قبل الترقية |
المعالج ينشئ نسخة كاملة قبل تطبيق ترحيلات EF Core |
| نسخ قبل المزامنة |
Type 3 فقط — تلقائي قبل التصدير |
| نسخ يدوي |
زر في واجهة المدير: "إنشاء نسخة احتياطية" |
11.3 إجراء الاستعادة
docker compose stop api
docker exec -i laundry-postgres psql -U laundry < backup.sql
docker compose up -d
12. المراقبة عبر Seq
- Seq حاوية Docker على كل نسخة — متصلة وغير متصلة.
- الوصول:
https://logs.customer-domain.com (أونلاين) أو http://localhost:5341 (أوفلاين).
- الدعم عن بُعد: TeamViewer ← فتح Seq ← البحث عن الأخطاء.
- تسجيل: جميع طلبات API، الأخطاء، الأحداث المحاسبية، عمليات المزامنة، المصادقة.
13. إجراء التراجع (Rollback)
# الخادم المتصل:
cd /opt/laundry
docker compose down
# تعديل .env: VERSION=1.0.1 (الإصدار السابق)
docker compose up -d
# الفرع غير المتصل:
cd C:\Laundry
docker compose down
docker load -i laundry-images_v1.0.1.tar
# تعديل .env: VERSION=1.0.1
docker compose up -d
ملاحظة: ترحيلات EF Core إضافية فقط (لا تحذف أعمدة). الإصدار السابق متوافق مع المخطط الأحدث.
14. استراتيجية البيئات
| البيئة |
الغرض |
الاستضافة |
| Dev (محلي) |
تطوير |
Docker Desktop |
| Staging |
اختبار ما قبل الإنتاج |
VPS صغير (~10$/شهر) |
| Production |
خوادم العملاء |
لكل عميل خادمه الخاص |
15. إعداد الأجهزة الطرفية
15.1 طابعة حرارية (80mm)
- تثبيت تعريف الطابعة. تسميتها "LaundryReceipt".
- الطباعة عبر
window.print() مع CSS مخصص لعرض 80mm.
15.2 ماسح باركود (USB)
- أي ماسح باركود USB بوضع محاكاة لوحة المفاتيح.
- يدعم أكواد Code 128 المولدة من النظام.
سجل المراجعة
| التاريخ |
الإصدار |
المعد |
التغييرات |
| 2026-05-10 |
1.0 |
مهندس النظم |
الإصدار الأولي لخطة البنية التحتية والنشر |