diff --git a/database/sql/DEPLOY_CHECKLIST.md b/database/sql/DEPLOY_CHECKLIST.md index fdcf419..b01cc9e 100644 --- a/database/sql/DEPLOY_CHECKLIST.md +++ b/database/sql/DEPLOY_CHECKLIST.md @@ -1,234 +1,109 @@ # چک‌لیست Deploy — برنچ ماژولار -بر اساس تجربه deploy روی **abshode_rahimi** (و الگوی مشابه برای groosy، abaeigold، bazre_tala، ...). +## قبل از شروع + +- [ ] بکاپ DB +- [ ] کد + SQLهای جدید روی سرور (`baseline_migrations.sql` حتماً نسخه جدید — **۱۱ ردیف**) +- [ ] `database/migrations/` فقط ۸ فایل `2026_*` +- [ ] `php artisan config:clear` --- -## قبل از deploy - -- [ ] **بکاپ کامل DB** (mysqldump) — اجباری روی production -- [ ] کد جدید روی سرور (git pull / rsync) و `composer install` در صورت نیاز -- [ ] `.env` سرور درست است (`DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`) -- [ ] `php artisan config:clear` بعد از تغییر `.env` - ---- - -## بررسی پوشه migrations (خیلی مهم) - -روی سرور فقط این **۸ فایل** باید در `database/migrations/` باشد: - -``` -2026_05_25_163201_add_provider_fields_to_orders_table.php -2026_06_02_000001_add_price_offset_percent_to_products_table.php -2026_06_06_000001_add_total_referrals_to_customers_table.php -2026_06_06_000002_alter_logs_data_to_longtext.php -2026_06_06_000003_add_order_limit_columns_to_products_table.php -2026_06_09_000001_add_show_in_assets_to_products_table.php -2026_06_10_000001_add_use_last_price_if_zero_to_products_table.php -2026_06_10_000002_add_type_column_to_settings_table.php -``` - -- [ ] فایل‌های قدیمی **حذف** شده‌اند (`2014_*`, `2019_*`, `2021_*`, `2023_*` create_*) -- [ ] اگر migration legacy مخصوص همان سرور مانده (مثلاً `wallet_moudle`) → در بخش «legacy» پایین چک‌لیست +## DB موجود — ترتیب ```bash -ls database/migrations/*.php -``` +cd /opt/PROJECT/server ---- +DB_HOST=$(grep ^DB_HOST= .env | cut -d= -f2- | tr -d '\r"') +DB_PORT=$(grep ^DB_PORT= .env | cut -d= -f2- | tr -d '\r"') +DB_DATABASE=$(grep ^DB_DATABASE= .env | cut -d= -f2- | tr -d '\r"') +DB_USERNAME=$(grep ^DB_USERNAME= .env | cut -d= -f2- | tr -d '\r"') +DB_PASSWORD=$(grep ^DB_PASSWORD= .env | cut -d= -f2- | tr -d '\r"') -## سناریو A — DB موجود (production با داده) - -> ⚠️ اگر جدول `migrations` خالی باشد و مستقیم `php artisan migrate` بزنید، Laravel کل -> `database/schema/mysql-schema.sql` را load می‌کند (**DROP TABLE + CREATE**) و داده‌ها از بین می‌رود. - -### ترتیب اجرا - -```bash -cd /path/to/server - -# ۱) baseline — حتماً قبل از migrate -mysql -h DB_HOST -P DB_PORT -u DB_USER -p DB_NAME \ +# ۱ baseline +mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" \ < database/sql/baseline_migrations.sql +# باید ۱۱ ردیف چاپ شود (شامل 2019 و 2021) -# ۲) schema incremental +# ۲ چک DB — اگر کمتر از ۲ بود baseline قدیمی است +mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" -N -e \ + "SELECT COUNT(*) FROM migrations WHERE migration LIKE '2019%' OR migration LIKE '2021%';" +# باید: 2 + +# ۳ status — ۱۰ تا همه Yes php artisan migrate:status + +# ۴ migrate php artisan migrate -# ۳) settings + const -mysql -h DB_HOST -P DB_PORT -u DB_USER -p DB_NAME \ +# ۵ settings +mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" \ < database/sql/deploy_settings_const.sql ``` -- [ ] `baseline_migrations.sql` اجرا شد **قبل از** `migrate` -- [ ] `migrate:status` — همه migrationها **Ran** (یا فقط موارد جدید **Pending**) -- [ ] `deploy_settings_const.sql` اجرا شد +**یا:** `bash database/sql/run_deploy_existing_db.sh` -### مقادیر mysql +### چک بعد از مرحله ۲ -`HOST`, `PORT`, `USER`, `DATABASE` placeholder نیستند — از `.env` بخوانید: +| خروجی `migrate:status` | کار | +|------------------------|-----| +| ۱۰ تا همه **Yes** | ادامه مرحله ۴ | +| `2019`/`2021` هنوز **No** | `fake_package_migrations.sql` بزن → دوباره status | ```bash -grep ^DB_ .env +mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" \ + < database/sql/fake_package_migrations.sql +php artisan migrate:status +php artisan migrate ``` -مثال: - -```bash -mysql -h 91.212.174.137 -P 3030 -u root -p abshode_rahimi < database/sql/baseline_migrations.sql -``` - -پسورد = همان `DB_PASSWORD` در `.env`. - --- -## سناریو B — DB خالی (نصب از صفر) +## soroushgold — الان (بعد از خطا) ```bash -php artisan migrate # schema dump + ۸ migration +cd /opt/soroushgold/server + +mysql -h 127.0.0.1 -P 3030 -u root -p soroushgold \ + < database/sql/fake_package_migrations.sql + +php artisan migrate:status +php artisan migrate + +mysql -h 127.0.0.1 -P 3030 -u root -p soroushgold \ + < database/sql/deploy_settings_const.sql +``` + +--- + +## DB خالی + +```bash +php artisan migrate mysql ... < database/sql/deploy_settings_const.sql ``` -- [ ] بعد از migrate جدول‌ها ساخته شدند -- [ ] settings/const با SQL پر شدند -- [ ] مقادیر tenant (نام، URL، توکن، main_product، ...) دستی در پنل یا UPDATE تنظیم شدند +`baseline_migrations.sql` **نزنید**. --- -## migrationهای legacy سرور +## خطاها -بعضی سرورها فایل PHP قدیمی دارند که در repo ماژولار نیست: - -| migration | جدول | -|-----------|------| -| `2019_12_14_000001_create_personal_access_tokens_table` | `personal_access_tokens` | -| `2021_12_02_065938_create_wallet_moudle_table` | `wallet_moudle` (اختیاری) | - -اگر جدول **از قبل هست** و فایل PHP هنوز روی سرور است: - -- [ ] یا فایل PHP را حذف کنید -- [ ] یا در جدول `migrations` ثبت کنید (fake): - -```sql -INSERT INTO migrations (migration, batch) VALUES -('2019_12_14_000001_create_personal_access_tokens_table', 1), -('2021_12_02_065938_create_wallet_moudle_table', 1); -``` - -یا یک‌جا: - -```bash -mysql -u root -p DB_NAME < database/sql/fix_migrations_after_failed_migrate.sql -``` - -(این اسکریپت legacy بالا را هم شامل می‌شود — migrationهای اضافی سرور را در انتهای فایل اضافه کنید.) +| خطا | فیکس | +|-----|------| +| `Table already exists` | `fake_package_migrations.sql` → `migrate` | +| `Loading stored database schema` | restore بکاپ → `baseline` قبل از `migrate` | +| `2019`/`2021` No بعد از baseline | baseline قدیمی → `fake_package_migrations.sql` | +| `Unknown host HOST` | از `.env` بخوان نه placeholder | --- -## بعد از deploy — تأیید - -```bash -php artisan migrate:status # همه Ran یا Nothing to migrate -php artisan migrate # Nothing to migrate - -# داده -mysql -e "SELECT COUNT(*) FROM customers;" DB_NAME -mysql -e "SELECT COUNT(*) FROM settings;" DB_NAME - -# کلیدهای مهم -mysql -e "SELECT \`key\`, LEFT(value,40) FROM settings WHERE \`key\` IN ('price_provider','main_product','name_fa');" DB_NAME -``` - -- [ ] سایت / API بالا می‌آید -- [ ] پنل ادمین settings را نشان می‌دهد -- [ ] `value`های قبلی tenant حفظ شده (مثلاً `price_provider`, توکن‌ها, `main_product`) - ---- - -## deploy_settings_const — رفتار روی value - -| وضعیت | نتیجه | -|--------|--------| -| کلید از قبل هست | `value` **حفظ** — فقط title/type/description آپدیت | -| کلید جدید | INSERT با مقدار پیش‌فرض اسکریپت | -| کلید legacy/test | **DELETE** (`test*`, `goldir*`, `is_requaire_referral`, ...) | - -- [ ] قبل از SQL، لیست DELETE را در `deploy_settings_const.sql` مرور کردید -- [ ] اگر tenant به کلید legacy وابسته است، DELETE را comment کنید - ---- - -## اگر اشتباه شد — بازیابی - -### خطا: `Table 'personal_access_tokens' already exists` - -علت: `migrations` خالی بود یا migration قدیمی Pending مانده. - -```bash -# ۱) migrate نزنید -# ۲) فیکس migrations -mysql ... < database/sql/fix_migrations_after_failed_migrate.sql -# ۳) migrationهای قدیمی را از پوشه حذف یا fake کنید -php artisan migrate:status -``` - -### داده‌ها پاک شد (schema dump اجرا شد) - -```bash -# restore بکاپ — fix_migrations داده برنمی‌گرداند -mysql ... < backup.sql -# سپس از اول با baseline_migrations.sql -``` - -### خطا: `Unknown MySQL server host 'HOST'` - -مقادیر واقعی `.env` را جایگزین placeholder کنید. - -### خطا: `3030\r` هنگام source .env - -فایل `.env` خط Windows (`\r\n`) دارد — دستی mysql بزنید یا: - -```bash -DB_PORT=$(grep ^DB_PORT= .env | cut -d= -f2- | tr -d '\r"') -``` - ---- - -## tenantهای خاص (اختیاری) - -بعد از `deploy_settings_const.sql`، در صورت نیاز اسکریپت مخصوص همان مشتری: - -| پروژه | فایل اضافی | -|--------|------------| -| groosi | `garoosi_gold_settings_finish.sql` | -| bazre_tala | `bazre_tala_settings_update.sql` | -| goldali | `goldali_post_merge_settings.sql` | -| abshode_rahimi | `abshode_rahimi_merge_goldali_catalog.sql` | - -- [ ] فقط اسکریپت **همان tenant** اجرا شد (نه همه SQLها روی همه DBها) - ---- - -## خلاصه یک‌خطی (DB موجود) - -``` -بکاپ → baseline_migrations.sql → migrate → deploy_settings_const.sql → تست -``` - -**هرگز:** `php artisan migrate` روی DB پر بدون `baseline_migrations.sql` وقتی `migrations` خالی است. - ---- - -## فایل‌های مرجع +## فایل‌ها | فایل | کار | |------|-----| -| `database/schema/mysql-schema.sql` | baseline schema (نصب از صفر) | -| `database/sql/baseline_migrations.sql` | قبل از migrate روی DB موجود | -| `database/sql/fix_migrations_after_failed_migrate.sql` | بعد از خطای migrate | -| `database/sql/deploy_settings_const.sql` | settings + const | -| `database/sql/deploy_safe_schema.sql` | جایگزین قدیمی schema-only (بدون settings) | - ---- - -*آخرین به‌روزرسانی: بر اساس deploy abshode_rahimi — ژوئن ۲۰۲۶* +| `baseline_migrations.sql` | ۱۱ migration یکجا | +| `fake_package_migrations.sql` | فقط 2019 + 2021 | +| `deploy_settings_const.sql` | settings + const | +| `fix_migrations_after_failed_migrate.sql` | reset کامل migrations | +| `run_deploy_existing_db.sh` | اجرای خودکار + چک | diff --git a/database/sql/baseline_migrations.sql b/database/sql/baseline_migrations.sql index 7007106..e4e78ae 100644 --- a/database/sql/baseline_migrations.sql +++ b/database/sql/baseline_migrations.sql @@ -1,27 +1,12 @@ --- ============================================================================= --- baseline_migrations.sql — حتماً قبل از migrate روی DB موجود اجرا کنید --- ============================================================================= --- اگر جدول migrations خالی باشد، Laravel کل mysql-schema.sql را load می‌کند --- (DROP TABLE + CREATE) و داده‌های production پاک می‌شود! --- --- workflow DB موجود (abshode_rahimi, groosy, ...): --- 1) بکاپ --- 2) SOURCE baseline_migrations.sql --- 3) php artisan migrate ← فقط ۸ migration incremental --- 4) SOURCE deploy_settings_const.sql --- +-- baseline_migrations.sql — قبل از php artisan migrate روی DB موجود -- USE `نام_دیتابیس`; --- ============================================================================= TRUNCATE TABLE `migrations`; --- جلوگیری از load مجدد schema dump -INSERT INTO `migrations` (`migration`, `batch`) VALUES -('0000_00_00_000000_baseline_schema', 1); - --- اگر schema از قبل کامل است (همه ستون‌ها هست)، این ۸ تا را هم marked کنید --- تا migrate فقط migrationهای جدید بعد از deploy را اجرا کند: INSERT INTO `migrations` (`migration`, `batch`) VALUES +('0000_00_00_000000_baseline_schema', 1), +('2019_12_14_000001_create_personal_access_tokens_table', 1), +('2021_12_02_065938_create_wallet_moudle_table', 1), ('2026_05_25_163201_add_provider_fields_to_orders_table', 1), ('2026_06_02_000001_add_price_offset_percent_to_products_table', 1), ('2026_06_06_000001_add_total_referrals_to_customers_table', 1), @@ -31,5 +16,4 @@ INSERT INTO `migrations` (`migration`, `batch`) VALUES ('2026_06_10_000001_add_use_last_price_if_zero_to_products_table', 1), ('2026_06_10_000002_add_type_column_to_settings_table', 1); --- اگر ستونی کم است، خطوط بالا (۸ migration) را comment کنید و فقط baseline بماند، --- بعد php artisan migrate ستون‌های کم را اضافه می‌کند. +SELECT migration, batch FROM migrations ORDER BY migration; diff --git a/database/sql/fake_package_migrations.sql b/database/sql/fake_package_migrations.sql new file mode 100644 index 0000000..85a7910 --- /dev/null +++ b/database/sql/fake_package_migrations.sql @@ -0,0 +1,8 @@ +-- فقط 2019 + 2021 — وقتی baseline قدیمی بود و migrate خطا می‌دهد +-- INSERT IGNORE = امن برای اجرای مجدد + +INSERT IGNORE INTO `migrations` (`migration`, `batch`) VALUES +('2019_12_14_000001_create_personal_access_tokens_table', 1), +('2021_12_02_065938_create_wallet_moudle_table', 1); + +SELECT migration, batch FROM migrations WHERE migration LIKE '2019%' OR migration LIKE '2021%'; diff --git a/database/sql/fix_migrations_after_failed_migrate.sql b/database/sql/fix_migrations_after_failed_migrate.sql index b544a5c..6143e59 100644 --- a/database/sql/fix_migrations_after_failed_migrate.sql +++ b/database/sql/fix_migrations_after_failed_migrate.sql @@ -1,26 +1,8 @@ --- ============================================================================= --- fix_migrations_after_failed_migrate.sql --- ============================================================================= --- بعد از خطای «Table already exists» روی abshode_rahimi یا سرور مشابه: --- --- 1) مطمئن شوید پوشه database/migrations فقط ۸ فایل 2026_* دارد --- (فایل‌های 2014_* و 2019_* و 2023_* create_* باید حذف شده باشند) --- --- 2) اگر migrate قبلاً schema dump را load کرده و داده‌ها پاک شده: --- اول بکاپ را restore کنید — این اسکریپت داده برنمی‌گرداند. --- --- 3) USE دیتابیس; سپس: --- SOURCE fix_migrations_after_failed_migrate.sql; --- --- 4) php artisan migrate:status ← باید همه Ran باشند --- 5) SOURCE deploy_settings_const.sql; --- ============================================================================= - +-- بعد از خطای Table already exists TRUNCATE TABLE `migrations`; INSERT INTO `migrations` (`migration`, `batch`) VALUES ('0000_00_00_000000_baseline_schema', 1), --- legacy Laravel / wallet — جدول از قبل روی DB هست؛ فقط ثبت می‌شود ('2019_12_14_000001_create_personal_access_tokens_table', 1), ('2021_12_02_065938_create_wallet_moudle_table', 1), ('2026_05_25_163201_add_provider_fields_to_orders_table', 1), @@ -32,4 +14,4 @@ INSERT INTO `migrations` (`migration`, `batch`) VALUES ('2026_06_10_000001_add_use_last_price_if_zero_to_products_table', 1), ('2026_06_10_000002_add_type_column_to_settings_table', 1); -SELECT 'migrations fixed — run: php artisan migrate:status' AS info; +SELECT migration, batch FROM migrations ORDER BY migration; diff --git a/database/sql/run_deploy_existing_db.sh b/database/sql/run_deploy_existing_db.sh new file mode 100644 index 0000000..e5613cc --- /dev/null +++ b/database/sql/run_deploy_existing_db.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" + +read_env() { + grep "^${1}=" .env | cut -d= -f2- | tr -d '\r"' | head -1 +} + +DB_HOST=$(read_env DB_HOST) +DB_PORT=$(read_env DB_PORT) +DB_DATABASE=$(read_env DB_DATABASE) +DB_USERNAME=$(read_env DB_USERNAME) +DB_PASSWORD=$(read_env DB_PASSWORD) + +mysql_cmd() { + mysql -h "$DB_HOST" -P "$DB_PORT" -u "$DB_USERNAME" -p"$DB_PASSWORD" "$DB_DATABASE" "$@" +} + +echo "==> 1/5 baseline_migrations.sql" +mysql_cmd < database/sql/baseline_migrations.sql + +echo "==> 2/5 check package migrations in DB" +PKG=$(mysql_cmd -N -e "SELECT COUNT(*) FROM migrations WHERE migration IN ( + '2019_12_14_000001_create_personal_access_tokens_table', + '2021_12_02_065938_create_wallet_moudle_table' +);") +if [[ "$PKG" != "2" ]]; then + echo "ERROR: 2019/2021 not in migrations table. Run: mysql ... < database/sql/fake_package_migrations.sql" + exit 1 +fi + +echo "==> 3/5 php artisan migrate:status" +php artisan migrate:status + +echo "==> 4/5 php artisan migrate" +php artisan migrate + +echo "==> 5/5 deploy_settings_const.sql" +mysql_cmd < database/sql/deploy_settings_const.sql + +php artisan migrate:status +echo "==> done"