# SKANDER servertelegram v3.9.1 — إصلاح عدم وصول توصيات Telegram إلى التطبيق

## المشكلة
بعد تحديث v3.9.0 ظهرت حالة يكون فيها السيرفر قادراً على قراءة/تحليل توصية Telegram، لكن التطبيق لا يستقبل أي `signal` وبالتالي لا يصل أمر التنفيذ إلى الجهاز.

## السبب الذي تم العثور عليه في السورس
السيرفر يعمل على cPanel / CloudLinux / Passenger، وهذه البيئة يمكن أن تشغل أكثر من عملية Node.js للتطبيق نفسه.

في v3.9.0 كانت قنوات التوصيل التالية موجودة في ذاكرة **كل Worker فقط**:

- `wsFollowers`
- `pollWaiters`
- `recentEvents`

مثال للمشكلة:

1. Worker A يستقبل رسالة Telegram ويحوّلها إلى توصية.
2. التطبيق متصل WebSocket أو HTTP Poll بـ Worker B.
3. Worker A يرى `followers: 0` لأنه لا يملك اتصال التطبيق الموجود داخل Worker B.
4. التوصية تبقى داخل ذاكرة Worker A ولا تصل إلى Worker B.
5. التطبيق لا يستقبل أي إشارة رغم أن parser والسيرفر قد سجلا التوصية بنجاح.

إصلاح حفظ الإعدادات في v3.9.0 كان بالفعل Cross-Worker عن طريق ملفات الإعدادات، لكن Relay للأوامر بقي Process-Local. هذه هي الفجوة التي تم إصلاحها هنا.

## إصلاح v3.9.1

### 1. Shared Relay Bus بين كل Passenger Workers
تم إضافة:

```text
data/relay_bus/events.jsonl
data/relay_bus/sequence.txt
data/relay_bus/claims/
```

أي Worker يستقبل توصية Telegram يكتب Envelope واحداً في Shared Relay Bus.
كل Worker آخر يقرأ الأحداث الجديدة بسرعة ويقوم بتسليمها إلى الأجهزة المتصلة به.

وبالتالي:

```text
Telegram -> Worker A -> Shared Relay Bus -> Worker B -> Android App
```

لم يعد مطلوباً أن تكون Telegram والجهاز على نفس عملية Node.

### 2. WebSocket + HTTP fallback يعملان على نفس الـBus
الإصلاح لا يعتمد فقط على WebSocket.

- `/ws` يستقبل الإشارات القادمة من أي Worker.
- `/api/client/poll` يعمل مزامنة للـShared Bus قبل الرد.
- التطبيق الذي سقط إلى HTTP fallback يستقبل الإشارة أيضاً.

### 3. Sequence عالمي بين Workers
`sequence` أصبح يُحجز عبر ملف مشترك وقفل ذري، لذلك لا يمكن لاثنين من Workers إنشاء نفس Sequence بسهولة أو إعادة ترتيب الأوامر بسبب اختلاف الذاكرة المحلية.

### 4. منع تكرار Telegram بين Workers
Passenger يمكن أن يجعل أكثر من Worker لديه Telegram polling/event handler.
تمت إضافة Shared Claim على `signalFingerprint` حتى أول Worker يعالج نفس Revision، والبقية تمنع النسخة المطابقة.

تعديل نفس رسالة Telegram ما زال مسموحاً لأن التعديل يملك Fingerprint مختلفاً، وبذلك تبقى سياسة Cancel -> Replace من v3.8.2 شغالة.

### 5. إصلاح مهم أثناء اختبار Cross-Worker
خلال اختبار Process A -> Process B تم اكتشاف خطأ إضافي في قارئ JSONL:
بعد أول `sync`، كان أي Read جديد يبدأ عند Offset أكبر من صفر فيُعامل خطأً كأنه بدأ في منتصف سطر، فيتم حذف أول Event جديد بالكامل.

تم إصلاح ذلك: حذف أول Partial Line يحدث فقط عند **أول Tail preload** أو بعد truncation، وليس في كل read لاحق.

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

## التوافق مع التطبيق
تمت مطابقة بروتوكول السيرفر مع سورس التطبيق v1.25.38:

- Endpoint: `/ws`
- HTTP fallback: `/api/client/register`, `/api/client/poll`, `/api/client/ack`
- Envelope type: `signal`
- الحقول: `pair`, `direction`, `expiry_seconds`, `execute_at`, `execution_key`

لذلك إصلاح هذا العطل موجود في **السيرفر** ولا يتطلب تغيير بروتوكول التطبيق.

مهم: يجب أن يكون `RELAY_ACCESS_KEY` في `.env` هو نفس مفتاح Relay المبني داخل التطبيق. ولا يتم نشر قيمة المفتاح داخل ملفات الشرح.

## الاختبارات
تم تشغيل:

```text
npm run check
npm test
```

ونجحت اختبارات parser + formats + edit/cancel + cancel/replace + persistence + cross-worker bus.

كما تم تشغيل اختبار تكامل فعلي بعمليتي Node منفصلتين:

```text
Worker A : port 19101
Worker B : port 19102
Shared STATE_FILE / data directory
```

تم تسجيل الجهاز على Worker B، ثم تم إرسال توصية يدوية على Worker A.
Worker A كان بدون follower محلي، ومع ذلك استقبل Worker B الحدث من Shared Relay Bus وأعاد للتطبيق:

```text
type      = signal
pair      = EURUSD
direction = CALL
sequence  = 2
```

النتيجة:

```text
CROSS_WORKER_SIGNAL_DELIVERED = true
sharedBus.lastError = null
```

## طريقة الرفع على cPanel
احتفظ بهذه الملفات من السيرفر الحالي ولا تستبدلها:

```text
.env
data/state.json
data/state.json.bak
data/settings.json
data/settings.json.bak
```

ثم ارفع ملفات v3.9.1 إلى:

```text
public_html/servertelegram
```

بعدها:

1. Setup Node.js App.
2. Run NPM Install.
3. Restart Application.
4. افتح `/servertelegram/health`.

يجب أن ترى:

```text
version: 3.9.1
relay.enabled: true
relay.sharedBus.lastError: null
persistence.writable: true
```

وعند وصول توصية يجب أن تزيد:

```text
relay.sharedBus.lastSequence
```

إذا كان `data` غير قابل للكتابة لنفس مستخدم cPanel لن يعمل الـBus المشترك. لا تستخدم 777؛ صحح Owner/Permissions للمجلد.
