Add Khanegi SMS sync inventory, batch import, and rollout helpers.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
# مراحل ساده: مهاجرت SMS و کار موازی
|
||||
|
||||
هدف: اول داده واقعی همکار/خانگی برود داخل سوپرادمین، بعد هر دو پنل با هم کار کنند تا خودت بگویی پنل محصولات حذف شود.
|
||||
|
||||
---
|
||||
|
||||
## الف) یک نسخه پایلوت (مثلاً همکار)
|
||||
|
||||
جای `DOMAIN` دامنه همان نسخه را بگذار (همان دامنه داخل سوپرادمین).
|
||||
|
||||
### ۱) اگر قبلاً روی همکار `SUPERADMIN_SMS_*` گذاشتی، موقتاً خاموش کن
|
||||
|
||||
روی سرور همکار در `.env` این خطوط را کامنت یا حذف کن:
|
||||
|
||||
```env
|
||||
# SUPERADMIN_SMS_BASE_URL=...
|
||||
# SUPERADMIN_SMS_SHARED_SECRET=...
|
||||
# SUPERADMIN_SMS_DOMAIN=...
|
||||
```
|
||||
|
||||
بعد:
|
||||
|
||||
```bash
|
||||
php artisan config:clear
|
||||
php artisan config:cache
|
||||
```
|
||||
|
||||
علت: تا قبل از مهاجرت، پنل همکار باید همان داده واقعی محلی را نشان بدهد.
|
||||
|
||||
### ۲) اعداد فعلی همکار را یادداشت کن
|
||||
|
||||
از پنل پیامک ادمین همکار:
|
||||
- موجودی
|
||||
- قیمت هر پارت
|
||||
- وضعیت بلاک
|
||||
|
||||
### ۳) سوپرادمین را با کد جدید آپدیت کن
|
||||
|
||||
روی سرور سوپرادمین (بعد از pull/build کد جدید):
|
||||
|
||||
```bash
|
||||
cd /var/www/superadmin/api
|
||||
pm2 restart superadmin-api
|
||||
```
|
||||
|
||||
### ۴) مهاجرت خشک (فقط نمایش، بدون نوشتن)
|
||||
|
||||
روی سرور سوپرادمین، با دسترسی به MySQL همان نسخه همکار:
|
||||
|
||||
```bash
|
||||
cd /var/www/superadmin/api
|
||||
|
||||
SMS_IMPORT_DRY_RUN=1 \
|
||||
SMS_IMPORT_DOMAIN=DOMAIN \
|
||||
SMS_IMPORT_PRODUCT=hamkar \
|
||||
HAMKAR_DB_HOST=IP_یا_127.0.0.1 \
|
||||
HAMKAR_DB_PORT=3306 \
|
||||
HAMKAR_DB_USER=USER \
|
||||
HAMKAR_DB_PASSWORD='PASS' \
|
||||
HAMKAR_DB_DATABASE=DBNAME \
|
||||
npm run prisma:import-sms-from-product
|
||||
```
|
||||
|
||||
اگر گفت `SKIP: sms_panel=me` → این نسخه پنل اختصاصی دارد؛ مهاجرت لازم نیست.
|
||||
اگر دامنه پیدا نشد → دامنه را با همان مقدار داخل سوپرادمین چک کن.
|
||||
|
||||
### ۵) مهاجرت واقعی
|
||||
|
||||
همان دستور بدون `SMS_IMPORT_DRY_RUN=1`:
|
||||
|
||||
```bash
|
||||
SMS_IMPORT_DOMAIN=DOMAIN \
|
||||
SMS_IMPORT_PRODUCT=hamkar \
|
||||
HAMKAR_DB_HOST=... \
|
||||
HAMKAR_DB_PORT=3306 \
|
||||
HAMKAR_DB_USER=... \
|
||||
HAMKAR_DB_PASSWORD='...' \
|
||||
HAMKAR_DB_DATABASE=... \
|
||||
npm run prisma:import-sms-from-product
|
||||
```
|
||||
|
||||
### ۶) در سوپرادمین چک کن
|
||||
|
||||
همان نسخه را باز کن؛ موجودی/تعرفه/بلاک باید با یادداشت مرحله ۲ یکی باشد.
|
||||
|
||||
### ۷) کد همکار را آپدیت کن و remote را روشن کن
|
||||
|
||||
بعد از دیپلوی کد جدید همکار، در `.env` همکار:
|
||||
|
||||
```env
|
||||
SUPERADMIN_SMS_BASE_URL=https://adm.montzar.ir/api/remote/sms
|
||||
SUPERADMIN_SMS_SHARED_SECRET=همان_رمز_سوپرادمین
|
||||
# فقط اگر APP_URL دامنه درست ندارد:
|
||||
# SUPERADMIN_SMS_DOMAIN=DOMAIN
|
||||
```
|
||||
|
||||
```bash
|
||||
php artisan config:clear
|
||||
php artisan config:cache
|
||||
```
|
||||
|
||||
### ۸) تست موازی
|
||||
|
||||
1. پنل همکار و سوپرادمین را باز کن → موجودی یکی باشد
|
||||
2. در سوپرادمین شارژ کن → در همکار رفرش → باید یکی شود
|
||||
3. در همکار تعرفه/بلاک عوض کن → در سوپرادمین همان را ببین
|
||||
4. یک SMS تست بفرست → موجودی هر دو کم شود
|
||||
|
||||
---
|
||||
|
||||
## ب) خانگی (چندنسخهای روی یک سرور)
|
||||
|
||||
قانون: هر نسخه = یک Tenant = یک MySQL = یک `.env` = یک `SUPERADMIN_SMS_DOMAIN`.
|
||||
روی یک سرور فیزیکی ممکن است چند نصب باشد؛ هرگز یک دامنه/DB مشترک برای همه نگذار.
|
||||
|
||||
### ب-۱) موجودیگیری از سوپرادمین
|
||||
|
||||
```bash
|
||||
cd /var/www/superadmin/api
|
||||
git pull
|
||||
npm run prisma:inventory-khanegi-sms
|
||||
# یا:
|
||||
SMS_INVENTORY_FORMAT=json SMS_INVENTORY_OUT=/tmp/khanegi-sms-inventory.json \
|
||||
npm run prisma:inventory-khanegi-sms
|
||||
```
|
||||
|
||||
خروجی `syncStatus` / `nextAction` و لیست `multiVersionHosts` را نگه دار.
|
||||
|
||||
### ب-۲) فایل اهداف ایمپورت
|
||||
|
||||
از روی موجودی، فایل واقعی بساز (از روی نمونه):
|
||||
|
||||
`prisma/khanegi-sms-targets.example.json` → مثلاً `prisma/khanegi-sms-targets.json`
|
||||
|
||||
برای هر دامنه، MySQL **همان نسخه** را بگذار. پایلوت را `"pilot": true` کن.
|
||||
|
||||
### ب-۳) پایلوت: dry-run سپس import
|
||||
|
||||
```bash
|
||||
cd /var/www/superadmin/api
|
||||
|
||||
# فقط پایلوت، خشک
|
||||
SMS_IMPORT_TARGETS=./prisma/khanegi-sms-targets.json \
|
||||
SMS_IMPORT_ONLY_PILOT=1 \
|
||||
SMS_IMPORT_DRY_RUN=1 \
|
||||
npm run prisma:import-sms-batch
|
||||
|
||||
# واقعی
|
||||
SMS_IMPORT_TARGETS=./prisma/khanegi-sms-targets.json \
|
||||
SMS_IMPORT_ONLY_PILOT=1 \
|
||||
npm run prisma:import-sms-batch
|
||||
```
|
||||
|
||||
یا تکدامنه:
|
||||
|
||||
```bash
|
||||
bash deploy/khanegi-sms-import-one.sh DOMAIN 127.0.0.1 DB_USER 'DB_PASS' DB_NAME
|
||||
bash deploy/khanegi-sms-import-one.sh DOMAIN 127.0.0.1 DB_USER 'DB_PASS' DB_NAME --apply
|
||||
```
|
||||
|
||||
بعد در UI سوپرادمین موجودی/تعرفه/بلاک را با پنل خانگی قبل از روشن کردن remote چک کن.
|
||||
ایمپورت موفق `tenants.sms_synced_at` را هم پر میکند.
|
||||
|
||||
### ب-۴) روشن کردن remote فقط روی `.env` همان نسخه
|
||||
|
||||
مقدار `SMS_REMOTE_SHARED_SECRET` را از `/var/www/superadmin/api/.env` بردار، بعد روی سرور خانگی:
|
||||
|
||||
```bash
|
||||
# مسیر server همان نسخه
|
||||
bash /path/to/khanegi-sms-enable-remote.sh /var/www/CUSTOMER/server DOMAIN 'SHARED_SECRET'
|
||||
# یا دستی:
|
||||
# SUPERADMIN_SMS_BASE_URL=https://adm.montzar.ir/api/remote/sms
|
||||
# SUPERADMIN_SMS_SHARED_SECRET=...
|
||||
# SUPERADMIN_SMS_DOMAIN=DOMAIN
|
||||
php artisan config:clear && php artisan config:cache
|
||||
php artisan sms:superadmin-probe
|
||||
```
|
||||
|
||||
### ب-۵) rollout بقیه
|
||||
|
||||
همان چرخه نسخه به نسخه (یا batch بدون `ONLY_PILOT`).
|
||||
`skip` / `sms_panel=me` / بدون wallet را جدا نگه دار.
|
||||
|
||||
---
|
||||
|
||||
## ج) نسخههایی که هنوز فعال نشدهاند
|
||||
|
||||
- جدول `sms_wallets` ندارند یا خالیاند → اسکریپت skip میکند
|
||||
- `sms_panel=me` → skip
|
||||
- برای آنها فعلاً کاری نکن تا خودت بگویی
|
||||
|
||||
---
|
||||
|
||||
## کار موازی تا اعلام تو
|
||||
|
||||
تا وقتی بگویی «پنل همکار/خانگی لازم نیست»:
|
||||
|
||||
- تغییر در **سوپرادمین** → با باز کردن پنل محصول هم دیده میشود (و در MySQL محلی هم mirror میشود)
|
||||
- تغییر در **پنل همکار/خانگی** → در سوپرادمین ذخیره میشود
|
||||
- ارسال SMS → کسر از سوپرادمین + mirror محلی
|
||||
|
||||
بعد از اطمینان نهایی، پنل محصولات حذف میشود و فقط سوپرادمین میماند.
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on the Khanegi install for ONE sold version (its own .env).
|
||||
# Never point multiple installs on the same server at the same SUPERADMIN_SMS_DOMAIN.
|
||||
#
|
||||
# Usage:
|
||||
# bash deploy/khanegi-sms-enable-remote.sh /path/to/khanegi/server DOMAIN SHARED_SECRET
|
||||
set -euo pipefail
|
||||
|
||||
INSTALL_SERVER_DIR="${1:-}"
|
||||
DOMAIN="${2:-}"
|
||||
SHARED_SECRET="${3:-}"
|
||||
BASE_URL="${SUPERADMIN_SMS_BASE_URL:-https://adm.montzar.ir/api/remote/sms}"
|
||||
|
||||
if [[ -z "$INSTALL_SERVER_DIR" || -z "$DOMAIN" || -z "$SHARED_SECRET" ]]; then
|
||||
echo "Usage: $0 /path/to/khanegi/server DOMAIN SHARED_SECRET" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ENV_FILE="$INSTALL_SERVER_DIR/.env"
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "Missing .env: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
backup="$ENV_FILE.bak.sms-sync.$(date +%Y%m%d%H%M%S)"
|
||||
cp "$ENV_FILE" "$backup"
|
||||
echo "Backup: $backup"
|
||||
|
||||
tmp="$(mktemp)"
|
||||
grep -vE '^(SUPERADMIN_SMS_BASE_URL|SUPERADMIN_SMS_SHARED_SECRET|SUPERADMIN_SMS_DOMAIN|SUPERADMIN_REMOTE_TOKEN)=' "$ENV_FILE" > "$tmp" || true
|
||||
mv "$tmp" "$ENV_FILE"
|
||||
|
||||
{
|
||||
echo ""
|
||||
echo "# SuperAdmin SMS sync — per sold version (domain=$DOMAIN)"
|
||||
echo "SUPERADMIN_SMS_BASE_URL=$BASE_URL"
|
||||
echo "SUPERADMIN_SMS_SHARED_SECRET=$SHARED_SECRET"
|
||||
echo "SUPERADMIN_SMS_DOMAIN=$DOMAIN"
|
||||
} >> "$ENV_FILE"
|
||||
|
||||
cd "$INSTALL_SERVER_DIR"
|
||||
php artisan config:clear
|
||||
php artisan config:cache || true
|
||||
|
||||
if php artisan list --raw 2>/dev/null | grep -q '^sms:superadmin-probe'; then
|
||||
php artisan sms:superadmin-probe
|
||||
else
|
||||
echo "Env written. Deploy code with sms:superadmin-probe, then run: php artisan sms:superadmin-probe"
|
||||
fi
|
||||
|
||||
echo "OK: remote enabled for domain=$DOMAIN in $ENV_FILE"
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on SuperAdmin host. Imports one Khanegi version MySQL → SuperAdmin SmsAccount.
|
||||
#
|
||||
# Usage:
|
||||
# bash deploy/khanegi-sms-import-one.sh DOMAIN DB_HOST DB_USER DB_PASSWORD DB_NAME [--apply]
|
||||
#
|
||||
# Default is dry-run. Pass --apply for real write.
|
||||
set -euo pipefail
|
||||
|
||||
DOMAIN="${1:-}"
|
||||
DB_HOST="${2:-127.0.0.1}"
|
||||
DB_USER="${3:-}"
|
||||
DB_PASSWORD="${4:-}"
|
||||
DB_NAME="${5:-}"
|
||||
MODE="${6:-}"
|
||||
|
||||
if [[ -z "$DOMAIN" || -z "$DB_USER" || -z "$DB_NAME" ]]; then
|
||||
echo "Usage: $0 DOMAIN DB_HOST DB_USER DB_PASSWORD DB_NAME [--apply]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
if [[ -d /var/www/superadmin/api ]]; then
|
||||
API_DIR=/var/www/superadmin/api
|
||||
elif [[ -f "$SCRIPT_DIR/../package.json" ]]; then
|
||||
API_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
else
|
||||
API_DIR="$(cd "$SCRIPT_DIR/../apps/api" && pwd)"
|
||||
fi
|
||||
|
||||
cd "$API_DIR"
|
||||
|
||||
export SMS_IMPORT_DOMAIN="$DOMAIN"
|
||||
export SMS_IMPORT_PRODUCT=khanegi
|
||||
export SMS_IMPORT_DB_HOST="$DB_HOST"
|
||||
export SMS_IMPORT_DB_PORT=3306
|
||||
export SMS_IMPORT_DB_USER="$DB_USER"
|
||||
export SMS_IMPORT_DB_PASSWORD="$DB_PASSWORD"
|
||||
export SMS_IMPORT_DB_DATABASE="$DB_NAME"
|
||||
|
||||
if [[ "$MODE" == "--apply" ]]; then
|
||||
unset SMS_IMPORT_DRY_RUN || true
|
||||
echo "APPLY import for $DOMAIN"
|
||||
else
|
||||
export SMS_IMPORT_DRY_RUN=1
|
||||
echo "DRY-RUN import for $DOMAIN"
|
||||
fi
|
||||
|
||||
npm run prisma:import-sms-from-product
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Convenience: inventory + write JSON on SuperAdmin host.
|
||||
set -euo pipefail
|
||||
cd /var/www/superadmin/api
|
||||
npm run prisma:inventory-khanegi-sms
|
||||
SMS_INVENTORY_FORMAT=json SMS_INVENTORY_OUT=/tmp/khanegi-sms-inventory.json \
|
||||
npm run prisma:inventory-khanegi-sms
|
||||
echo "JSON: /tmp/khanegi-sms-inventory.json"
|
||||
Reference in New Issue
Block a user