ifnex/04_Laravel/scripts/deploy.sh
Kazem Alghasi f1d5667fe8 feat(deploy): preflight + smoke-test + UAT checklist (phases 3.9.1–3.11)
Prepare the project for production deployment and final client
acceptance testing. Adds preflight fail-fast command, hardened FX rate
importer, currency seeder, deploy scripts, E2E smoke test, and the
43-item UAT checklist document with sign-off form.

Key changes:

- Phase 3.9.1 — hotfix (AddressBookEntry):
  - Add $attributes defaults (use_count=0, is_default=false) so
    instance values are populated right after create() without
    refresh(). Resolves the red test
    `it_increments_use_count_and_sets_last_used_at`.

- Phase 3.10 — deploy infrastructure (Laravel):
  - Add `ifnex:preflight` command: fail-fast audit of production
    environment (APP_ENV, APP_DEBUG, APP_KEY, IFNEX_API_KEY,
    IFNEX_BRIDGE_API_KEY, ZARINPAL_SANDBOX, DB_CONNECTION, CORS,
    currencies seeded, PHP extensions, storage writable). Exits 1
    if any check fails; supports --skip-db for pre-migrate runs.
  - Add `ifnex:import-fx-rates` command: replacement for
    `ifnex:update-rates`. Fetches USD/AED from Exir.io + EUR/CNY
    from FreeCurrencyAPI. Supports --auto-approve (cron use) and
    --threshold (max change % for auto-approve). Logs critical on
    HTTP failure. URL configurable via EXIR_API_URL env.
  - Add `CurrencySeeder`: creates 5 base currencies (USD/AED/EUR/
    CNY/IRR) with rate=0 (IRR=1). Idempotent — does not overwrite
    real rates already set by admin or cron.
  - Update `DatabaseSeeder`: skip super_admin with password
    'password' in production (still created in local/testing).
  - Fix `bootstrap/app.php`: remove dead `use ApiKeyAuth` import
    (actual class is ApiKeyMiddleware). Latent fatal if api_key
    alias was used.
  - Add `config/ifnex.php` exir block + preflight config.
  - Harden `.env.example`: MySQL default, EXIR_API_URL,
    SANCTUM_STATEFUL_DOMAINS, APP_TIMEZONE, LOG_DAILY_DAYS, fix
    duplicate CURRENCY_API_KEY.

- Phase 3.10 — deploy scripts (Linux):
  - Add `scripts/deploy.sh`: idempotent 13-step deploy (composer
    install → key:generate → preflight → migrate → seed → FX import
    → cache → chown). Fail-fast with set -e.
  - Add `scripts/cron-exir-rates.sh`: daily cron wrapper for
    `ifnex:import-fx-rates --source=all --auto-approve`.

- Phase 3.10.1 — preflight hotfix:
  - Make expected DB connection configurable
    (ifnex.preflight.expected_db_connection) instead of hardcoded
    'mysql'. Prevents cascade test failure when tests would have to
    mutate database.default to mysql in a sqlite test environment
    (Unknown database ':memory:' → broken connection pool → 22
    previously-green tests fail with "There is already an active
    transaction").
  - Rewrite IfnexPreflightTest to use config() rather than mutating
    database.default.

- Phase 3.11 — UAT:
  - Add `ifnex:smoke-test` command: E2E post-deploy automated test
    (25+ checks: DB connection, core tables, currencies with
    non-zero rates, countries count, roles, admin user, system
    settings, storage writable, config/route cache, 4 API
    endpoints: /up, /countries, /track/{invalid}, /customer/profile
    without token).
  - Add 9 feature tests for smoke-test (PASS + 6 FAIL + custom URL
    + 422/500 handling + auth bypass detection).
  - Add `UAT-3.11.md`: 43-item Persian checklist for client
    acceptance testing across 15 feature areas. Includes sign-off
    form for both parties (client + VernaSoft).
  - Update `CLIENT_DELIVERY.md` to record phases 3.10 and 3.11.

Tests:
- Total: 51 → 82 tests, 150 → 220+ assertions, all green.
- New: IfnexPreflightTest (9), IfnexImportFxRatesTest (9),
  CurrencySeederTest (4), IfnexSmokeTestTest (9) = 31 new tests.

Documentation:
- DEPLOYMENT_HANDOFF.md §2.4: add CurrencySeeder + import-fx-rates.
- DEPLOYMENT_HANDOFF.md §2.8: update cron to use cron-exir-rates.sh.
- UAT-3.11.md: new 43-item client acceptance checklist + sign-off.
- CLIENT_DELIVERY.md: record phases 3.10 and 3.11 completion.
2026-10-31 22:18:15 +03:30

143 lines
7.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────
# IFNEX — فاز ۳.۱۰ — اسکریپت استقرار Production
# ─────────────────────────────────────────────────────────────────────────
# این اسکریپت را فقط یک‌بار روی سرور Production اجرا کنید.
# پیش‌فرض: در مسیر /var/www/system.ifnex.ir قرار دارید (یا هر مسیری که
# کلون کرده‌اید). اسکریپت idempotent است؛ دوباره اجرا هم مشکلی ندارد.
#
# مراحل (به‌ترتیب):
# 1. composer install (no-dev)
# 2. اگه APP_KEY خالی بود → key:generate
# 3. ifnex:preflight (fail-fast اگر محیط hardened نباشد)
# 4. migrate --force
# 5. seed های امن برای Production
# 6. import نرخ ارز اولیه (auto-approve)
# 7. storage:link
# 8. config/route/view cache
# 9. دسترسی پوشه‌ها
#
# خروجی با کد غیرصفر در صورت شکست هر مرحله (set -e).
# ─────────────────────────────────────────────────────────────────────────
set -euo pipefail
# رنگ‌ها برای خروجی خوانا
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
step() {
echo -e "\n${BLUE}▶ $1${NC}"
}
ok() {
echo -e "${GREEN}✓ $1${NC}"
}
warn() {
echo -e "${YELLOW}⚠ $1${NC}"
}
err() {
echo -e "${RED}✗ $1${NC}" >&2
}
# بررسی حضور PHP و Composer
if ! command -v php >/dev/null 2>&1; then
err "PHP یافت نشد. نصب: apt install php8.2-cli php8.2-{mysql,mbstring,xml,gd,zip,curl,bcmath}"
exit 1
fi
if ! command -v composer >/dev/null 2>&1; then
err "Composer یافت نشد. نصب: https://getcomposer.org/download/"
exit 1
fi
# ─── مرحله ۱: نصب پکیج‌ها ─────────────────────────────────────────
step "نصب وابستگی‌ها (no-dev، optimize)"
composer install --no-dev --optimize-autoloader --no-interaction
ok "composer install کامل شد"
# ─── مرحله ۲: APP_KEY ─────────────────────────────────────────────
step "بررسی APP_KEY"
if ! grep -qE '^APP_KEY=base64:' .env 2>/dev/null; then
warn "APP_KEY خالی است → تولید..."
php artisan key:generate --force
ok "APP_KEY تولید شد"
else
ok "APP_KEY از قبل تنظیم شده"
fi
# ─── مرحله ۳: Preflight ──────────────────────────────────────────
step "اجرای ifnex:preflight — fail-fast اگر محیط آماده نباشد"
# در اولین اجرا جدول currencies هنوز ساخته نشده، پس --skip-db می‌زنیم
if ! php artisan ifnex:preflight --skip-db; then
err "preflight ناموفق بود — .env را اصلاح کنید و دوباره اجرا کنید"
exit 1
fi
ok "preflight سبز است"
# ─── مرحله ۴: مایگریشن ───────────────────────────────────────────
step "اجرای migrate --force"
php artisan migrate --force
ok "migrate کامل شد"
# ─── مرحله ۵: Seed های امن Production ────────────────────────────
step "Seed داده‌های مرجع (امن برای Production)"
php artisan db:seed --class=CountriesTableSeeder --force
php artisan db:seed --class=SystemSettingSeeder --force
php artisan db:seed --class=CurrencySeeder --force
php artisan db:seed --class=RoleAndPermissionSeeder --force
ok "seed ها کامل شد"
# ─── مرحله ۵ب: دوباره preflight بدون --skip-db ───────────────────
step "preflight نهایی (شامل بررسی currencies)"
if ! php artisan ifnex:preflight; then
warn "preflight نهایی هشدار داد — ولی ادامه می‌دهیم (ممکن است نرخ ارز هنوز صفر باشد)"
fi
# ─── مرحله ۶: import نرخ ارز اولیه ────────────────────────────────
step "دریافت نرخ ارز اولیه از Exir.io + FreeCurrencyAPI"
php artisan ifnex:import-fx-rates --source=all --auto-approve || warn "دریافت نرخ ناموفق بود (ادامه می‌دهیم — بعداً دستی اجرا کنید)"
# ─── مرحله ۷: storage:link ───────────────────────────────────────
step "ساخت storage symlink"
php artisan storage:link --force || warn "storage:link از قبل موجود است"
# ─── مرحله ۸: Cache ها ────────────────────────────────────────────
step "ساخت cache برای سرعت Production"
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
ok "cache ها ساخته شدند"
# ─── مرحله ۹: دسترسی پوشه‌ها ──────────────────────────────────────
step "تنظیم دسترسی storage و bootstrap/cache"
WEB_USER="${WEB_USER:-www-data}"
chown -R "${WEB_USER}:${WEB_USER}" storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
ok "دسترسی تنظیم شد (owner: ${WEB_USER})"
# ─── مرحله ۱۰: حساب ادمین ───────────────────────────────────────
echo
warn "حساب ادمین Filament هنوز ساخته نشده — دستی اجرا کنید:"
echo " php artisan make:filament-user"
echo " php artisan tinker"
echo " >>> \$u = User::where('email','YOUR_EMAIL')->first();"
echo " >>> \$u->assignRole('super_admin');"
echo
ok "═══════════════════════════════════════════════════"
ok " دیپلوی IFNEX با موفقیت کامل شد ✓"
ok "═══════════════════════════════════════════════════"
echo
echo "گام بعدی:"
echo " ۱. ساخت حساب ادمین (بالا)"
echo " ۲. همگام‌سازی کاربران وردپرس: php artisan ifnex:sync-wp-users ..."
echo " ۳. تنظیم کرون روزانه نرخ ارز (scripts/cron-exir-rates.sh)"
echo " ۴. تست end-to-end از مرورگر (به DEPLOYMENT_HANDOFF.md §۵ مراجعه کنید)"