نمای سرتاسری ثبت شماره، درخواست تلگرام، دریافت SMS در اندروید، تطبیق بکاند، تحویل خصوصی OTP و انقضای نشست.
flowchart TB
%% =====================================================
%% 01 — SETUP & PHONE REGISTRATION
%% =====================================================
subgraph S1["01 · راهاندازی و ثبت شمارهها"]
direction TB
ADMIN["مدیر سامانه"]
CONFIG["تنظیم اپ Android Receiver<br/>ثبت ۱ تا ۲ شماره تلفن"]
READY{"Receiver آماده است؟"}
READINESS["مجوزهای SMS<br/>اجرای پسزمینه<br/>آمادگی JobScheduler"]
TEST["TEST AND SEND<br/>POST /api/test"]
PHONE_STORE[("Phone Store<br/>شمارههای ثبتشده<br/>شمارندههای استفاده")]
ADMIN --> CONFIG
CONFIG --> READY
READY -- "خیر" --> READINESS
READINESS --> READY
READY -- "بله" --> TEST
TEST --> PHONE_STORE
end
%% =====================================================
%% 02 — TELEGRAM REQUEST & SESSION CREATION
%% =====================================================
subgraph S2["02 · درخواست تلگرام و ایجاد نشست"]
direction TB
USER["کاربر درخواستکننده"]
START["شروع چت خصوصی با ربات<br/>پیشنیاز یکباره"]
CODE["ارسال /code 09xxxxxxxxx<br/>در گروه فعال تلگرام"]
WEBHOOK["Telegram Webhook<br/>POST /telegram/webhook"]
VALIDATE["اعتبارسنجی گروه، Mode،<br/>فرمان و شماره تلفن"]
REGISTERED{"شماره ثبت شده است؟"}
REJECT_PHONE["رد درخواست<br/>شماره ثبت نشده است"]
ACTIVE{"برای این شماره<br/>نشست فعال وجود دارد؟"}
REJECT_DUP["رد درخواست تکراری<br/>نشست قبلی حفظ میشود"]
PRIVATE_READY["ارسال پیام خصوصی<br/>آماده بودن نشست"]
PRIVATE_OK{"پیام خصوصی<br/>با موفقیت ارسال شد؟"}
START_REQUIRED["درخواست از کاربر برای<br/>Start کردن ربات"]
CREATE["ایجاد نشست فعال"]
SESSION_STORE[("Session Store<br/>کاربر · شماره · Session ID<br/>CreatedAt · ExpiresAt")]
TIMER["ثبت تایمر انقضای<br/>۱۲۰ ثانیهای"]
GROUP_ACCEPT["پاسخ در گروه<br/>درخواست پذیرفته شد"]
USER --> START
START --> CODE
CODE --> WEBHOOK
WEBHOOK --> VALIDATE
VALIDATE --> REGISTERED
REGISTERED -- "خیر" --> REJECT_PHONE
REGISTERED -- "بله" --> ACTIVE
ACTIVE -- "بله" --> REJECT_DUP
ACTIVE -- "خیر" --> PRIVATE_READY
PRIVATE_READY --> PRIVATE_OK
PRIVATE_OK -- "خیر" --> START_REQUIRED
PRIVATE_OK -- "بله" --> CREATE
CREATE --> SESSION_STORE
CREATE --> TIMER
CREATE --> GROUP_ACCEPT
end
%% شمارههای ثبتشده در اعتبارسنجی درخواست استفاده میشوند
PHONE_STORE --> REGISTERED
%% =====================================================
%% 03 — DIVAR & ANDROID SMS CAPTURE
%% =====================================================
subgraph S3["03 · دیوار و دریافت SMS در اندروید"]
direction TB
DIVAR_INPUT["کاربر همان شماره تلفن را<br/>در دیوار وارد میکند"]
DIVAR["دیوار درخواست کد تأیید میدهد"]
SMS["SMS تأیید دریافت میشود"]
RECEIVER["Android SMS BroadcastReceiver"]
RECOVERY["بازیابی SMSهای اخیر<br/>مسیر جایگزین برای Broadcast ازدسترفته"]
PARSE{"پیام معتبر دیوار با<br/>OTP ششرقمی است؟"}
IGNORE["نادیده گرفتن پیام"]
EXTRACT["نرمالسازی ارقام<br/>استخراج OTP ششرقمی"]
CANDIDATES["تشخیص اطلاعات SIM<br/>ساخت شمارههای کاندید"]
DEDUP{"Fingerprint در ۲۴ ساعت<br/>گذشته دیده شده است؟"}
DISCARD["حذف پیام تکراری"]
QUEUE[("صف پایدار محلی<br/>FIFO · PendingDelivery<br/>TTL برابر ۶۰ ثانیه")]
JOB["JobScheduler<br/>نیازمند اتصال شبکه"]
SUBMIT["ارسال OTP و شمارههای کاندید<br/>POST /api/sms"]
DIVAR_INPUT --> DIVAR
DIVAR --> SMS
SMS --> RECEIVER
RECEIVER --> PARSE
RECOVERY -. "مسیر جایگزین" .-> PARSE
PARSE -- "خیر" --> IGNORE
PARSE -- "بله" --> EXTRACT
EXTRACT --> CANDIDATES
CANDIDATES --> DEDUP
DEDUP -- "بله" --> DISCARD
DEDUP -- "خیر" --> QUEUE
QUEUE --> JOB
JOB --> SUBMIT
end
GROUP_ACCEPT --> DIVAR_INPUT
%% =====================================================
%% 04 — BACKEND MATCHING & SECURE DELIVERY
%% =====================================================
subgraph S4["04 · تطبیق در بکاند و تحویل امن"]
direction TB
AUTH["احراز درخواست اپ اندروید<br/>App Secret + App Mode"]
AUTH_OK{"درخواست معتبر و<br/>احرازشده است؟"}
API_REJECT["رد درخواست API<br/>آیتم در صف باقی میماند"]
CLEAN["حذف نشستهای منقضی"]
MATCH["تطبیق شمارههای کاندید<br/>با نشستهای فعال"]
MATCH_COUNT{"تعداد نشستهای<br/>فعال منطبق"}
NO_SESSION["۰ تطبیق<br/>پذیرفته شده · بدون تحویل"]
AMBIGUOUS["چند تطبیق<br/>وضعیت مبهم · نشستها حفظ میشوند"]
ONE_MATCH["دقیقاً یک تطبیق<br/>شناسایی درخواستکننده اصلی"]
PRIVATE_OTP["ارسال خصوصی OTP<br/>از طریق تلگرام"]
DELIVERY_OK{"تحویل خصوصی<br/>موفق بود؟"}
RETRY["HTTP 502<br/>حفظ نشست و آیتم صف"]
CLOSE["بستن نشست فعال<br/>لغو تایمر انقضا"]
COUNTER["افزایش successfulDeliveries"]
AUDIT[("Audit History<br/>رخدادهای تحویل و نشست")]
GROUP_SUCCESS["پاسخ به پیام اصلی گروه<br/>کد دریافت و ارسال شد<br/>OTP هرگز در گروه نمایش داده نمیشود"]
DONE(["OTP با موفقیت تحویل شد"])
AUTH --> AUTH_OK
AUTH_OK -- "خیر" --> API_REJECT
AUTH_OK -- "بله" --> CLEAN
CLEAN --> MATCH
MATCH --> MATCH_COUNT
MATCH_COUNT -- "۰" --> NO_SESSION
MATCH_COUNT -- "چند مورد" --> AMBIGUOUS
MATCH_COUNT -- "دقیقاً ۱" --> ONE_MATCH
ONE_MATCH --> PRIVATE_OTP
PRIVATE_OTP --> DELIVERY_OK
DELIVERY_OK -- "خیر" --> RETRY
DELIVERY_OK -- "بله" --> CLOSE
CLOSE --> COUNTER
CLOSE --> AUDIT
CLOSE --> GROUP_SUCCESS
GROUP_SUCCESS --> DONE
end
SUBMIT --> AUTH
SESSION_STORE --> MATCH
API_REJECT -. "تلاش مجدد تا زمانی که آیتم تازه است" .-> JOB
RETRY -. "Exponential Backoff" .-> JOB
NO_SESSION -->|"200 · پذیرفته شد"| DEQUEUE1["حذف آیتم از صف"]
AMBIGUOUS -->|"200 · پذیرفته شد"| DEQUEUE2["حذف آیتم از صف"]
DONE -->|"200 · تحویل موفق"| DEQUEUE3["حذف آیتم از صف"]
%% =====================================================
%% 05 — SESSION EXPIRATION
%% =====================================================
subgraph S5["05 · انقضای نشست"]
direction TB
DEADLINE{"پس از ۱۲۰ ثانیه<br/>نشست هنوز فعال است؟"}
TIMER_END["بدون اقدام<br/>نشست قبلاً تکمیل شده"]
EXPIRE["منقضی کردن نشست"]
EXPIRE_AUDIT["ثبت رخداد انقضا"]
NOTIFY_PRIVATE["اعلان خصوصی به درخواستکننده"]
NOTIFY_GROUP["پاسخ Session Expired<br/>در گروه تلگرام"]
EXPIRED(["نشست منقضی شد"])
DEADLINE -- "خیر" --> TIMER_END
DEADLINE -- "بله" --> EXPIRE
EXPIRE --> EXPIRE_AUDIT
EXPIRE --> NOTIFY_PRIVATE
EXPIRE --> NOTIFY_GROUP
NOTIFY_PRIVATE --> EXPIRED
NOTIFY_GROUP --> EXPIRED
end
TIMER -. "مهلت ۱۲۰ ثانیه" .-> DEADLINE
%% =====================================================
%% STYLES
%% =====================================================
classDef actor fill:#f8fafc,stroke:#64748b,color:#0f172a,stroke-width:1.5px;
classDef telegram fill:#eff6ff,stroke:#2563eb,color:#172554,stroke-width:1.5px;
classDef backend fill:#f5f3ff,stroke:#7c3aed,color:#2e1065,stroke-width:1.5px;
classDef android fill:#f0fdf4,stroke:#16a34a,color:#14532d,stroke-width:1.5px;
classDef external fill:#fff7ed,stroke:#ea580c,color:#7c2d12,stroke-width:1.5px;
classDef store fill:#fffbeb,stroke:#d97706,color:#78350f,stroke-width:1.8px;
classDef decision fill:#ffffff,stroke:#475569,color:#0f172a,stroke-width:1.8px;
classDef warning fill:#fff7ed,stroke:#ea580c,color:#7c2d12,stroke-width:1.5px;
classDef failure fill:#fef2f2,stroke:#dc2626,color:#7f1d1d,stroke-width:1.5px;
classDef success fill:#ecfdf5,stroke:#059669,color:#064e3b,stroke-width:2px;
class ADMIN,USER actor;
class START,CODE,WEBHOOK,PRIVATE_READY,GROUP_ACCEPT,PRIVATE_OTP,GROUP_SUCCESS,NOTIFY_PRIVATE,NOTIFY_GROUP telegram;
class VALIDATE,CREATE,TIMER,AUTH,CLEAN,MATCH,ONE_MATCH,CLOSE,COUNTER,EXPIRE,EXPIRE_AUDIT backend;
class CONFIG,READINESS,TEST,RECEIVER,RECOVERY,EXTRACT,CANDIDATES,JOB,SUBMIT android;
class DIVAR_INPUT,DIVAR,SMS external;
class PHONE_STORE,SESSION_STORE,QUEUE,AUDIT store;
class READY,REGISTERED,ACTIVE,PRIVATE_OK,PARSE,DEDUP,AUTH_OK,MATCH_COUNT,DELIVERY_OK,DEADLINE decision;
class REJECT_PHONE,REJECT_DUP,START_REQUIRED,NO_SESSION,AMBIGUOUS warning;
class IGNORE,DISCARD,API_REJECT,RETRY failure;
class DONE,EXPIRED success;