# WhatsApp Notification Gateway — بوابة إشعارات واتساب للـ LMS

بوابة تواصل تعمل بـ Docker. الـ LMS (Moodle أو غيره) يرسل `POST /notify` فقط، والبوابة تتولى: القوالب، الطابور، الإرسال المتدرج، إعادة المحاولة، opt-out، حالة التسليم، والـ fallback للإيميل.

```
Moodle ──POST /notify──▶ gateway (FastAPI) ──▶ Postgres queue ──▶ worker ──▶ Evolution API ──▶ WhatsApp
                              ▲                                                    │
                              └──────────── webhook (delivered / read / STOP) ─────┘
```

| Service | الدور | Port |
|---|---|---|
| `gateway` | الـ API اللي يكلمه الـ LMS + webhook + صفحة الـ QR | `GATEWAY_PORT` (8882) → 8000 |
| `worker` | يرسل رسالة واحدة كل مرة بفاصل عشوائي وسقف يومي | — |
| `evolution` | Evolution API (اتصال واتساب غير رسمي) | 127.0.0.1:8080 |
| `postgres` / `redis` | قاعدتا بيانات (evolution + gateway) / كاش Evolution | — |

> ⚠️ Evolution API يستخدم بروتوكول WhatsApp Web بشكل غير رسمي. الرقم معرّض للحظر. استخدم رقماً مخصصاً، والتزم بقسم "تقليل خطر الحظر". لا يصلح لعميل حكومي/جامعة — لهم بدّل إلى `PROVIDER=cloud_api`.

## 1) التشغيل

دليل النشر المفصّل (بالإنجليزية): [DEPLOYMENT.md](DEPLOYMENT.md)، ويشمل ربط Moodle العامل في Docker عبر `docker-compose.lms-network.yml`، والوكيل العكسي، والنسخ الاحتياطي، واستكشاف الأعطال.

```bash
cp .env.example .env
# غيّر كل القيم change-me-*  (مثلاً: openssl rand -hex 24)
docker compose up -d --build
docker compose ps            # الكل healthy / running
```

## 2) ربط رقم الواتساب (مرة واحدة)

افتح: `http://SERVER:8882/admin/qr?key=ADMIN_KEY`

الصفحة تنشئ الـ instance، تضبط الـ webhook، وتعرض الـ QR. من الجوال: WhatsApp ← الأجهزة المرتبطة ← ربط جهاز. بعد المسح ستظهر "✅ WhatsApp connected".

لو الـ QR ما ظهرش: `docker compose logs evolution` — غالباً نسخة الـ image قديمة؛ ثبّت آخر tag في `EVOLUTION_IMAGE` ثم `docker compose pull evolution && docker compose up -d`. بديل: لوحة Evolution على `http://localhost:8080/manager` (محلي فقط — استخدم SSH tunnel) بالـ `EVOLUTION_API_KEY`.

## 3) اختبار

```bash
curl -X POST http://SERVER:8882/notify \
  -H "X-API-Key: change-me-lms-key" -H "Content-Type: application/json" \
  -d '{"event":"course_enrolled","to":"05XXXXXXXX","locale":"ar",
       "vars":{"firstname":"رضا","course":"مقدمة في بايثون","url":"https://lms.example.com"},
       "email":"user@example.com","idempotency_key":"test-1"}'

curl http://SERVER:8882/health
curl -H "X-API-Key: change-me-lms-key" "http://SERVER:8882/messages?limit=10"
docker compose logs -f worker
```

حالات الرسالة: `queued → sending → sent → delivered → read` أو `failed` / `skipped`.
توثيق الـ API التفاعلي: `http://SERVER:8882/docs`.

## 4) Moodle plugin

1. انسخ `moodle-plugin/local/wagateway` إلى `MOODLE_ROOT/local/wagateway` (أو اضغطه zip وارفعه من Site administration → Plugins → Install plugins).
2. Site administration → Notifications لإتمام التثبيت.
3. Plugins → Local plugins → **WhatsApp notification gateway**: فعّل، وضع Gateway URL (كما يراه سيرفر Moodle، مثل `http://10.0.0.5:8882`، أو `http://wa-gateway:8000` لو Moodle في Docker على نفس الشبكة) والـ API key، واختر حقل الجوال.
4. تأكد أن الـ cron شغال (الإرسال يتم عبر adhoc task): `php admin/cli/adhoc_task.php --execute` للتجربة الفورية.

الأحداث المغطاة:

| Moodle event | gateway event |
|---|---|
| `\core\event\user_created` | `user_registered` |
| `\core\event\user_enrolment_created` | `course_enrolled` |
| نفس الحدث + وجود سجل في جدول `payments` (enrol_fee) | `payment_received` |
| `\core\event\course_completed` | `course_completed` |

ملاحظة الدفع: Moodle core لا يطلق حدثاً مستقلاً عند نجاح الدفع؛ الـ plugin يكتشف الدفع من جدول `payments` لحظة التسجيل (enrol_fee). لو تستخدم بوابة دفع خارج core payment (مثلاً plugin مخصص لـ Moyasar/HyperPay/Paymob)، استدعِ `/notify` بحدث `payment_received` من كود الـ callback عندك مباشرة.

**إضافة حدث جديد** (تذكير واجب، شهادة، ...): أضف الحدث في `gateway/templates.yml` (يُقرأ تلقائياً بدون restart)، ثم observer جديد في `db/events.php` + `classes/observer.php`، وارفع رقم `version.php`.

**أي نظام آخر غير Moodle** (ناهل، Redmine، ...): يكفيه HTTP POST إلى `/notify` بمفتاح خاص به — أضف `nahel:KEY` في `GATEWAY_API_KEYS`.

## 5) تقليل خطر الحظر — الأهم

- رقم مخصص للإشعارات فقط، واستخدمه يدوياً أسبوع–أسبوعين قبل التشغيل الآلي.
- ابدأ بـ `DAILY_CAP=50` وارفعه تدريجياً كل أسبوع (50 → 100 → 200 → ...).
- لا تقلل `MIN_DELAY_SECONDS` عن 5.
- اجعل الطالب يبدأ المحادثة: ضع في صفحة التسجيل زر
  `https://wa.me/9665XXXXXXXX?text=تفعيل` — أي رسالة واردة تسجّل الرقم كـ opted-in ويصله تأكيد. للتشدد: `REQUIRE_OPT_IN=true` (من لم يراسلك تصله الإشعارات بالإيميل فقط).
- رسائل transactional فقط. لا حملات تسويقية من هذا الرقم إطلاقاً.
- نوّع صياغات القوالب (كل حدث له أكثر من variant ويُختار عشوائياً).
- "إيقاف / STOP" يوقف الإرسال للرقم فوراً، و"تفعيل / START" يعيده.
- فعّل SMTP ليعمل الـ fallback تلقائياً عند: انقطاع الاتصال أكثر من `FALLBACK_AFTER_MINUTES`، رقم غير موجود على واتساب، أو فشل كل المحاولات.
- راقب `/health` من Uptime Kuma أو ما شابه: `ok:false` يعني الجلسة انفصلت (غالباً حظر أو logout من الجوال) — احتفظ برقم احتياطي مسخَّن.

## 6) أمان ونشر

- لا تعرّض منفذ البوابة (8882) للإنترنت. لو Moodle على سيرفر آخر: شبكة خاصة/VPN، أو reverse proxy بـ HTTPS مع IP allowlist.
- port 8080 (Evolution) مربوط على 127.0.0.1 عمداً.
- النسخ الاحتياطي: volume `pgdata` (الرسائل وجهات الاتصال) و`evolution_instances` (جلسة واتساب — فقدانه = مسح QR من جديد).

## 7) الترقية لاحقاً إلى الرسمي (Meta Cloud API)

غيّر في `.env`: `PROVIDER=cloud_api` + `CLOUD_API_TOKEN` + `CLOUD_API_PHONE_NUMBER_ID`، واعتمد في WhatsApp Manager قوالب بنفس أسماء `cloud_template` وترتيب `cloud_params` في `templates.yml`. لا تغيير في Moodle. (الـ adapter مكتوب لكنه غير مجرَّب على حساب حي.)

## هيكل الملفات

```
docker-compose.yml  .env.example  postgres-init/
gateway/            Dockerfile, requirements.txt, templates.yml
  app/main.py       API + webhook + admin/qr
  app/worker.py     طابور الإرسال
  app/adapters/     evolution.py | cloud_api.py  (adapter pattern)
moodle-plugin/local/wagateway/
```
