پنل مدیریت لایسنس — دفتر دستک
================================
نیازمندی: PHP 8.0+ با افزونه‌های pdo_sqlite ، openssl ، mbstring  (در سی‌پنل: Select PHP Version)

ساختار
------
public/   ← محتوای وب‌سایت (این پوشه باید از اینترنت باز شود)
app/      ← کد برنامه   (نباید از اینترنت باز شود)
storage/  ← دیتابیس + کلید خصوصی (نباید از اینترنت باز شود)

نصب روی سی‌پنل (تست‌شده)
------------------------
ساختار پیشنهادی:
  /home/USER/daftar-panel/app/        ← کد (بیرون از وب)
  /home/USER/daftar-panel/storage/    ← دیتابیس و کلید خصوصی (بیرون از وب)
  /home/USER/public_html/panel-x7k2/  ← محتوای پوشه public (نام دلخواه و غیرقابل‌حدس)

مراحل:
1) پوشه‌های app و storage را در /home/USER/daftar-panel آپلود کنید (کنار public_html، نه داخلش).
2) همه‌ی فایل‌های پوشه public را داخل public_html/panel-x7k2 آپلود کنید
   (فایل‌های مخفی .htaccess و _path.php را هم فراموش نکنید؛ در File Manager گزینه Show Hidden Files را بزنید).
3) فایل panel-x7k2/_path.php را باز کنید و CHANGE_ME را با نام کاربری سی‌پنل خود عوض کنید.
4) پوشه storage باید قابل نوشتن باشد (دسترسی 755؛ اگر خطای دسترسی دیدید 775).
5) آدرس panel-x7k2 را باز کنید:  نام کاربری admin   رمز اولیه ChangeMe#2026
   سیستم همان لحظه شما را مجبور می‌کند رمز را عوض کنید.
6) در Select PHP Version نسخه 8.0 یا بالاتر را انتخاب و افزونه‌های pdo_sqlite ، sqlite3 ، openssl ، mbstring را فعال کنید.

اگر می‌خواهید همه‌چیز در یک پوشه باشد (ساده‌تر): کل پوشه daftar-panel را داخل home بگذارید و
در cPanel ← Domains ریشه‌ی یک زیردامنه را روی daftar-panel/public تنظیم کنید؛ نیازی به تغییر _path.php نیست.

اگر پشت Cloudflare هستید: در app/config.php مقدار behind_cloudflare را true کنید.
اگر SSL دارید: خطوط RewriteRule انتهای public/.htaccess را از حالت کامنت خارج کنید.

مهم — امنیت
-----------
- storage/activation-private.pem همان کلید خصوصی صدور کد است. هرکس به آن برسد می‌تواند کد معتبر بسازد.
- storage و app حتماً نباید از مرورگر قابل دسترسی باشند. تست کنید:
  https://دامنه/storage/activation-private.pem  باید 403 یا 404 بدهد.
- روی وب‌سرور Nginx فایل‌های .htaccess کار نمی‌کنند؛ آنجا storage و app را حتماً بیرون از ریشه‌ی وب بگذارید.
- از پوشه storage بکاپ منظم بگیرید (منوی تنظیمات → دانلود بکاپ).

محدودیت مهم لایسنس آفلاین
--------------------------
برنامه اینترنت ندارد (حتی مجوز INTERNET را هم در اپ فعلی ندارد)؛ «لغو» در پنل فقط ثبت
می‌شود و کد قبلی روی گوشی مشتری تا تاریخ انقضا کار می‌کند. این یک محدودیت فنیِ قطعی است:
هیچ سروری نمی‌تواند به گوشی‌ای که هرگز به اینترنت وصل نمی‌شود پیام برساند.

راه‌های موجود برای کم‌کردن این ریسک:
1) کدها را کوتاه‌مدت‌تر صادر کنید (دکمه‌های «۱ روز» / «۱ هفته» در صفحات صدور و تمدید
   اضافه شده‌اند) تا اگر لازم شد لغو کنید، مشتری دیرتر از چند روز به کدِ قبلی دسترسی نداشته باشد.
2) اگر روزی به سورس اپ اندروید (نه فقط APK کامپایل‌شده) دسترسی پیدا کردید، یک اندپوینت
   آماده در public/api/check.php ساخته شده که وضعیت لغو/انقضای یک کد را برمی‌گرداند.
   کافی‌ست اپ (وقتی اینترنت دارد) این آدرس را با پارامتر code صدا بزند و اگر
   revoked=true بود، خودش را قفل کند. این کار را IMMEDIATE.md در همین پوشه با نمونه
   کد Kotlin توضیح داده — می‌توانید آن فایل را مستقیماً به برنامه‌نویس اندروید بدهید.
   توجه: این روش هم فقط برای گوشی‌هایی اثر دارد که گاهی اینترنت وصل می‌شوند؛ باز هم
   برای گوشیِ کاملاً بدون اینترنت هیچ راهی برای قطعِ لحظه‌ای وجود ندارد.
