# راهنمای ایجنت — پروژهٔ IFNEX Logistics > **تاریخ:** ۲۰۲۶-۱۰-۰۴ > **نسخه:** ۱.۳ > **تهیه‌کننده:** VernaSoft Group — Kazem Alghasi --- ## ۱. خلاصهٔ پروژه سیستم مدیریت لجستیک بین‌المللی با معماری Headless: **Laravel 11** به‌عنوان بک‌اند، **WordPress** به‌عنوان فرانت‌اند و **Filament 3.3** به‌عنوان پنل مدیریت. این سیستم جایگزین فرآیندهای دستی مبتنی بر اکسل شده و از Multi-Package، فاکتور گمرکی، کیف پول دیجیتال، درگاه پرداخت Zarinpal، تولید PDF با بارکد، فلوی تأیید سفارش، تعهدنامه، SMS کاوه‌نگار، سیستم اعتبار چندارزی و رهگیری پیشرفته پشتیبانی می‌کند. ### وضعیت فعلی فازهای ۰، ۱، ۲، ۳ و ۳.۵ تکمیل شده‌اند. فاز ۳.۶ (اصلاحات جلسهٔ کارفرما) حدود ۹۵٪ انجام شده است: - [x] فلوی کامل سفارش (ثبت ← تأیید ← تعهدنامه ← پرداخت) — تست End-to-End - [x] بازطراحی داشبورد و Login پنل Filament (هویت بصری navy + amber) - [x] بازطراحی PDFهای AWB، Invoice و Label (dompdf، چیدمان جدولی) - [x] صفحهٔ «وضعیت مالی مشتری» در پنل ادمین (۴ KPI + بدهی‌های ارزی + سفارش‌ها و تراکنش‌ها) - [x] سیستم اعتبار چندارزی کامل (درخواست ۹) — بدهی به همان ارز، تسویه با نرخ روز - [x] ویجت هشدار بدهی‌های ارزی تسویه‌نشده + badge روی منو - [x] Rate Limiting روی همهٔ APIها (۶ لایه throttle: auth / sms / public / customer / wallet / staff) - [x] چک‌لیست خودکار کارمند پس از تأیید سفارش (درخواست ۵) - [x] نمایش بدهی ارزی در پورتال مشتری وردپرس - [x] استایل‌دهی صفحهٔ پروفایل مشتری در وردپرس - [x] پاک‌سازی کد (حذف فایل‌های تستی، تأیید تمیزی `opcache_reset` / `dd` / `dump`) چندزبانه (i18n) همچنان به زمان دیپلوی موکول است. --- ## ۲. تکنولوژی‌ها و نسخه‌ها | لایه | تکنولوژی | نسخه / توضیح | |------|-----------|--------------| | Backend | Laravel | 11.x | | زبان | PHP | ^8.2 (۸.۳ نیز پشتیبانی می‌شود) | | پنل مدیریت | Filament | 3.3.x | | فرانت‌اند | WordPress | 7.x + قالب سفارشی IFNEX | | احراز هویت | Laravel Sanctum + Bridge Auth | بدون رمز عبور (کلید API مشترک) | | پرداخت | Zarinpal + Mock Gateway (تست) | کلید sandbox برای تست لوکال | | PDF و بارکد | Dompdf + picqer/php-barcode-generator | AWB، Invoice، Label، فاکتور واردات | | پیامک | Kavenegar | تأیید موبایل + اعلان وضعیت سفارش | | اکسل | maatwebsite/excel | Import / Export نرخ‌ها و داده‌های تاریخی | | تاریخ و زمان | morilog/jalali + Carbon | تاریخ شمسی در نمایش، میلادی در DB | | دیتابیس | MySQL | 8.0+ (تست‌ها با SQLite) | | صف | Redis (ترجیحی) / Database | برای پردازش‌های سنگین | | سرور | HestiaCP + Nginx + PHP-FPM | تولید (api.ifnex.vernahost.ir) | --- ## ۳. ساختار دایرکتوری ```text IFNEX-Logistics/ ├── 01_Documents/ # مستندات فنی │ ├── IFNEX_File_Map.md # نقشهٔ ۱۰۰+ فایل پروژه │ ├── IFNEX_Roadmap.md # نقشهٔ راه فازی │ ├── IFNEX_Phase0_Checklist.md # چک‌لیست تکمیل فازها │ ├── IFNEX_ADR.md # تصمیمات معماری (ADR-001 تا 009) │ ├── EXCEL_ANALYSIS.md # تحلیل داده‌های تاریخی │ ├── IFNEX_I18N_Strategy.md # استراتژی چندزبانه │ └── IFNEX_Commercial_Model.md # مدل تجاری │ ├── 03_WordPress/ # فرانت‌اند وردپرس │ └── wp-content/ │ ├── themes/ifnex/ # قالب سفارشی │ └── plugins/ifnex-bridge/ # پلاگین ارتباط با لاراول │ ├── includes/ # api-client، user-bridge، shortcodes، tracking-form │ └── assets/ # CSS و JS فرم سفارش │ ├── 04_Laravel/ # بک‌اند لاراول (هستهٔ اصلی) │ ├── app/ │ │ ├── Enums/ # ShipmentStatus، ShipmentDirection، ShipmentType، PaymentGateway، TransactionStatus │ │ ├── Filament/ # ۱۷ Resource + Pages + Widgets │ │ ├── Http/ │ │ │ ├── Controllers/Api/ # Track، Pricing، Auth، Bridge، Customer، Wallet، Payment، Staff، CommitmentForm │ │ │ └── Middleware/ # ApiKeyMiddleware │ │ ├── Models/ # ۲۶ مدل Eloquent │ │ ├── Notifications/ # DB notifications + SMS │ │ ├── Observers/ # ShipmentObserver │ │ ├── Services/ # PriceCalculator، Pdf، Tracking، OrderPayment، Wallet، Zarinpal، KavenegarSms │ │ ├── Traits/ # Auditable │ │ ├── Imports/ # OldShipments، ShippingRates │ │ └── Exports/ # ShippingRatesTemplateExport │ ├── database/migrations/ # ۵۲ migration │ ├── resources/views/pdfs/ # awb، invoice، label، import-invoice │ └── routes/api.php # ۴۰+ endpoint │ ├── AGENT.md # همین سند ├── CLIENT_DELIVERY.md # چک‌لیست وضعیت تحویل مشتری (منبع اصلی) ├── DEPLOYMENT.md # راهنمای استقرار روی سرور ├── DEPLOYMENT_HANDOFF.md # تحویل استقرار به تیم IT کارفرما └── README.md # معرفی کلی پروژه ``` --- ## ۴. مفاهیم کلیدی بیزینس ### ۴.۱ مرسوله (Shipment) | مورد | مقدار | |------|-------| | انواع (`Type`) | `DOC_NORMAL`، `DOC_ECONOMY`، `PARCEL` | | جهت (`Direction`) | `export` (صادرات) و `import` (واردات) | | وضعیت (`Status`) | `pending_approval` ← `approved` ← `processed` ← `picked_up` ← `in_transit` ← `out_for_delivery` ← `delivered` / `failed` / `returned` / `cancelled` (به‌همراه `pending_payment` legacy و `archived`) | هر مرسوله دارای چند بسته (`packages`)، اقلام گمرکی (`items` — فقط برای PARCEL)، تاریخچهٔ تغییرات وضعیت (`statusHistories`)، شرکت‌های حمل (`carrierMappings`)، رویدادهای رهگیری (`trackingEvents`) و تعهدنامه‌ها (`commitmentForms`) است. ### ۴.۲ بسته (Package) - هر مرسوله می‌تواند چندین بسته داشته باشد (جدول `shipment_packages`). - وزن حجمی = `(Length × Width × Height) / 5000` (استاندارد IATA). - وزن قابل پرداخت = `max(وزن واقعی، وزن حجمی)`. ### ۴.۳ فاکتور گمرکی (Invoice) - فقط برای مرسوله‌های نوع `PARCEL` صادر می‌شود. - حداکثر ۹ قلم کالا (شرح، HS Code، تعداد، قیمت واحد، مجموع به USD). - مجموع کل فاکتور در `shipments.invoice_total_usd` ذخیره می‌شود. - **فاکتور واردات (Import Invoice):** فیلدهای brand_fee، report_fee، customs_clearance_cost، order_registration_fee و… به‌همراه قالب PDF مطابق شیت ENG Invoice. ### ۴.۴ کیف پول (Wallet) - هر کاربر یک کیف پول دارد. - تراکنش‌ها (`WalletTransaction`) با نوع `deposit`، `order_payment`، `refund`، `withdrawal` به‌صورت polymorphic به Payment یا سفارش متصل هستند. - پرداخت از کیف پول یا درگاه Zarinpal (با Mock برای تست)، به‌همراه freeze / unfreeze و activity log کامل. ### ۴.۵ احراز هویت Bridge - کاربران وردپرس بدون نیاز به رمز عبور از طریق `POST /api/v1/bridge/login` با ارسال `bridge_api_key` و `wp_user_id` وارد لاراول می‌شوند. - پاسخ شامل توکن Sanctum (معتبر ۳۰ روز) و اطلاعات کاربر است. - کلید `IFNEX_BRIDGE_API_KEY` باید در هر دو طرف (`.env` لاراول و تنظیمات پلاگین وردپرس) یکسان باشد. - توکن در usermeta کاربر وردپرس (`ifnex_laravel_token`) ذخیره می‌شود و روی ۴۰۱ خودکار باطل و تجدید می‌شود. - کلید `IFNEX_API_KEY` کلید عمومی بخش رهگیری است و `ApiKeyMiddleware` آن را با `!==` مقایسه می‌کند؛ اگر خالی بماند، درخواست با توکن خالی از guard عبور می‌کند. - ⚠️ `BridgeAuthController` فقط مقدار `change-this-secret-key` را رد می‌کند. این مقدار عمداً غیرکارکردی است تا جایگزینی‌اش فراموش نشود — **هر مقدار دیگری، حتی مواردی که شبیه placeholder باشند، یک کلید معتبر محسوب می‌شود.** - 🔐 هرگز کلید واقعی را در این فایل، در `DEPLOYMENT.md` یا در `04_Laravel/README.md` ننویس. مقادیری که قبلاً در این مخزن ثبت شده‌اند را **لو‌رفته فرض کن و چرخش بده.** ### ۴.۶ رهگیری (Tracking) - کاربر با شمارهٔ AWB جستجو می‌کند. - سیستم رویدادهای رهگیری را از جدول `shipment_tracking_events` با فیلد `source` (manual، api، import، system، customer) نمایش می‌دهد. - ایمپورت گروهی وضعیت ترکینگ با CSV از پنل (صفحهٔ BulkTrackingImport) انجام می‌شود. ### ۴.۷ قیمت‌گذاری (Pricing) - بر اساس ۴ زون مجزا (Export/Import × Parcel/Doc) و ۳ نوع سرویس. - فرمول: قیمت پایه (AED) × ضریب سود × نرخ تبدیل به ریال + هزینه‌های جانبی (Packing، Domestic Pickup، …) + مالیات بر ارزش افزوده (۹٪). - محموله‌های بالای ۳۰ کیلوگرم مشمول نرخ ویژه (Spot Rate) هستند و محاسبهٔ آنلاین ندارند. ### ۴.۸ فلوی تأیید سفارش (Approval Flow) - مشتری بعد از ثبت سفارش **مستقیم به درگاه نمی‌رود**؛ سفارش با وضعیت `pending_approval` ثبت می‌شود. - کارمند یا مدیر از پنل فیلمنت (اکشن تأیید در `ShipmentResource`) یا از API (`/staff/orders/{id}/approve|reject`) تأیید می‌کند. - فقط پس از `approved`، گزینه‌های پرداخت (کیف پول / درگاه) در وردپرس باز می‌شود. پرداخت موفق سفارش را `processed` می‌کند (`PaymentController` در callback با `is_order_payment` در metadata). - سفارش‌های `approved` پرداخت‌نشده روی مانده حساب کاربر (`account_balance` در پروفایل) اثر می‌گذارند. ### ۴.۹ تعهدنامه و اسناد سفارش (Commitment Forms) - مدیر فرم‌های تعهدنامه را در فیلمنت (`CommitmentFormResource`) با direction (export / import / both) آپلود می‌کند. - مشتری در جزئیات سفارش وردپرس لیست تعهدنامه‌ها را می‌بیند ← دانلود / چاپ / امضا ← آپلود فایل امضاشده (`POST /orders/{shipment}/commitment-forms/{form}/upload`) که در جدول `shipment_commitment_forms` ثبت می‌شود. - دانلود AWB، Invoice و Label نیز از همین بخش (`/orders/{shipment}/pdf/*`) انجام می‌شود. - ✅ چک مالکیت اعمال شده: `ShipmentPolicy` + بررسی `user_id` در کنترلرهای PDF و تعهدنامه (کامیت `8cf4075`). - دانلود قالب تعهدنامه از route محافظت‌شده با auth (جایگزین asset عمومی) و دانلود ادمین از دیسک secure از طریق روت‌های `admin.commitment-forms.*` انجام می‌شود. ### ۴.۱۰ اعلان‌ها و SMS کاوه‌نگار - تنظیمات از `SystemSetting` خوانده می‌شود (`kavenegar_api_key` به‌همراه سوییچ هر نوع پیام، مانند `kavenegar_send_shipment_approved`). - نوتیفیکیشن‌ها: `ShipmentApprovedSms`، `ShipmentRejectedSms`، `PaymentSuccessSms`، `TrackingUpdatedSms` به‌همراه کانال `SmsChannel`. - تریگر اصلی: `ShipmentObserver` (روی تغییر وضعیت Shipment) و `PaymentController` (پرداخت موفق). تأیید موبایل: `MobileVerificationController`. - در `.env` لوکال کلید کاوه‌نگار خالی است؛ تا وقتی تنظیم نشود SMS ارسال نمی‌شود (فقط DB notification). ### ۴.۱۱ اعتبار مشتری (Credit) — چندارزی - سیستم کامل با `CustomerCreditService` (متدهای `grantCredit()`، `settle()`، `getCustomerDebtsByCurrency()`) و جدول‌های `customer_credits` و `credit_settlements` پیاده‌سازی شده است. - بدهی به همان ارز ثبت می‌شود و تسویه با نرخ روز انجام می‌گیرد. race condition در `settle()` با `lockForUpdate()` و بررسی مجدد مانده اصلاح شد. - فقط `super_admin` مجاز به اعطای اعتبار است (Policy). ### ۴.۱۲ Audit Log - trait `App\Traits\Auditable` روی مدل‌های اصلی (User، Shipment، Wallet و…) اعمال شده و در `AuditLogResource` قابل مشاهده است. - `ShipmentStatusHistory` دارای ستون‌های `from_status` / `to_status` / `reason` به‌همراه نام کاربر تغییردهنده است. --- ## ۵. دستورات روزمره ```bash # نصب وابستگی‌ها composer install # تنظیم محیط cp .env.example .env php artisan key:generate # دیتابیس (ابتدا باید ایجاد شود) php artisan migrate --force php artisan db:seed --force # اجرای سرور توسعه php artisan serve # اجرای صف (پردازش‌های سنگین) php artisan queue:work # تست‌ها php artisan test # پاک‌سازی و بازسازی کش php artisan optimize:clear php artisan config:cache php artisan route:cache php artisan view:cache php artisan filament:clear-cached-components # ایمپورت / اکسپورت نرخ‌ها php artisan ifnex:import:rates {path} php artisan ifnex:import:shipments {path} php artisan ifnex:import:tracking {path} # به‌روزرسانی نرخ ارز (کرون) php artisan ifnex:update-rates --source=ecb # تولید API Token برای ادمین php artisan ifnex:token ``` --- ## ۶. متغیرهای محیطی کلیدی (`.env`) ```dotenv APP_ENV=local APP_DEBUG=true APP_URL=http://localhost:8000 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=ifnex_db DB_USERNAME=root DB_PASSWORD= # IFNEX اختصاصی — پیش از استقرار با رشتهٔ تصادفی جایگزین کن # مقدار change-this-secret-key عمداً غیرکارکردی است تا جایگزینی فراموش نشود IFNEX_API_KEY=change-this-secret-key IFNEX_BRIDGE_API_KEY=change-this-secret-key # باید عیناً با وردپرس یکی باشد IFNEX_TRACKING_RATE_LIMIT=60 # CORS (فقط دامنه‌های مجاز وردپرس) CORS_ALLOWED_ORIGINS=http://localhost,http://127.0.0.1 # Zarinpal (برای تست از Mock استفاده کن) ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing # اگر fake باشد، MockGateway فعال می‌شود ZARINPAL_SANDBOX=true ZARINPAL_CALLBACK_URL=http://localhost:8000/api/v1/payment/callback ZARINPAL_FRONTEND_FAILURE_URL=http://localhost/IFNEX-Logistics/03_WordPress/wallet # نکته: ZARINPAL_FRONTEND_SUCCESS_URL در کد خوانده نمی‌شود؛ ریدایرکت موفق # از frontend_callback ارسالی وردپرس تعیین می‌شود. # Kavenegar SMS (خالی = فقط DB notification) KAVENEGAR_API_KEY= KAVENEGAR_SENDER=10008566 # Wallet WALLET_MIN_DEPOSIT=10000 WALLET_MAX_DEPOSIT=500000000 WALLET_AUTO_CREATE=true ``` --- ## ۷. خط قرمزها (ممنوعیت‌های مطلق) | ❌ هرگز | ✅ همیشه | |---------|----------| | برگرداندن کشورها به ۲ زون | ۴ زون مجزا (Export/Import × Parcel/Doc) | | استفاده از ۲ نوع سرویس | ۳ نوع (`DOC_NORMAL`، `DOC_ECONOMY`، `PARCEL`) | | ذخیرهٔ تاریخ شمسی در DB | ذخیرهٔ timestamp میلادی + تبدیل در نمایش | | `CORS *` در Production | CORS محدود به دامنهٔ وردپرس | | کامیت `.env` در Git | قرار دادن `.env` در `.gitignore` | | `APP_DEBUG=true` در Production | `APP_DEBUG=false` | | PDF فارسی (AWB / Invoice / Label) | همیشه انگلیسی (برای حمل بین‌المللی) | | کپی از DHL | طراحی منحصر به فرد IFNEX | | استفاده از `wire:click` برای دانلود | استفاده از `` با روت مستقیم | | `getFormActions()` در Custom Pages | استفاده از `wire:click` در Blade | | هدایت AJAX به `redirect()` | استفاده از `payment_url` در response JSON | | متدهای نوتیفیکیشن بیرون از کلاس | داخل کلاس `IFNEX_User_Bridge` | | روت staff/admin بدون چک نقش | چک نقش یا مالکیت در middleware یا ابتدای کنترلر | | هدایت مستقیم سفارش به درگاه پس از ثبت | فلوی `pending_approval` ← `approved` ← پرداخت | --- ## ۸. نکات ویژه برای ایجنت ### اصول کلی - هنگام تولید کد جدید، حتماً از Enum‌ها به‌جای رشته‌های سخت‌کدشده استفاده کن. - برای هر مدل جدید، migration، مدل و در صورت نیاز کنترلر یا Resource فیلمنت بساز. - هنگام استفاده از هر Model در فایل جدید، حتماً `use App\Models\...` را import کن. (باگ اخیر نبودِ import برای `SystemSetting` در `PaymentController` / `ShipmentObserver` / `TrackingService`، فلوی تأیید و پرداخت را می‌شکست — کامیت `2737e26`). - مدیریت تاریخ همیشه با Carbon انجام می‌شود و ذخیره به‌صورت `Y-m-d H:i:s` در DB است. - برای کوئری‌های سنگین از `chunk()` یا `cursor()` استفاده کن تا حافظه مصرف نشود. ### خطاهای رایج - نبودِ فیلد `deleted_at` در کوئری‌ها (در صورت استفاده از SoftDeletes). - فراموشی `fillable` یا `casts` در مدل‌ها. - فراموشی `$with` برای بارگذاری روابط در Resourceها. - استفاده از `redirect()` در کنترلرهای API (باید JSON برگردانند). ### قواعد حوزهٔ کار - برای تغییر وضعیت مرسوله، حتماً تاریخچه را به‌روز کن (`ShipmentStatusHistory` با `from_status` / `to_status` / `reason`). - در فرم سفارش مشتری، مرحلهٔ Invoice فقط برای نوع PARCEL نمایش داده می‌شود. - تولید PDF با بارکد به‌صورت base64 embed انجام می‌شود. - Bridge Auth نیازی به رمز عبور ندارد و فقط از `IFNEX_BRIDGE_API_KEY` استفاده می‌کند. - تست لوکال پرداخت: از `ZARINPAL_MERCHANT_ID=fake-merchant-id-for-testing` برای فعال‌سازی Mock Gateway استفاده کن. ### هشدارهای تاریخی - **مارک‌آپ شورت‌کدهای وردپرس:** باز و بسته بودن `div`ها را متوازن نگه دار. باگ «مرحلهٔ ۲ فرم سفارش لود نمی‌شود» ریشه‌اش یک `div` بسته‌نشده در `shortcodes.php` بود که مراحل را داخل هم nest می‌کرد. هک‌های MutationObserver و setInterval هیچ‌کدام مشکل را حل نکردند و حذف شدند. - **هک‌های موقت دیباگ:** `opcache_reset()` و `header()` در بالای فایل‌های پلاگین و cache-buster با `time()` فقط برای کار لوکال هستند و باید پیش از دیپلوی حذف شوند. --- ## ۹. کارهای باقی‌مانده (فاز ۳.۶) | # | کار | وضعیت | |---|-----|--------| | ۱ | تست انتهای فلوی سفارش: آپلود تعهدنامه ← تأیید کارمند ← پرداخت کیف پول یا درگاه | ✅ انجام شد (۲۰۲۶-۱۰-۰۴) | | ۲ | امنیت: چک نقش `/staff/*`، چک مالکیت PDF و تعهدنامه، محدودسازی discount-codes، rate limiting | ✅ انجام شد (۲۰۲۶-۱۰-۰۴) | | ۳ | بازطراحی سیستم اعتبار چندارزی + نمایش در پورتال مشتری + ویجت هشدار داشبورد | ✅ انجام شد (۲۰۲۶-۱۰-۰۴) | | ۴ | چک‌لیست خودکار کارمند پس از تأیید سفارش | ✅ انجام شد (`instantiateChecklist()` در `approve()`) | | ۵ | سند پیشنهادی سیستم مالی (درخواست ۱۳ کارفرما) | ⏳ موکول به آینده | | ۶ | پاک‌سازی: فایل‌های تستی، cache-busterها، `!important`ها | ✅ انجام شد (۲۰۲۶-۱۰-۰۴) | | ۷ | نمایش وزن واقعی و حجمی در خلاصهٔ قیمت وردپرس | ✅ در API موجود است (`weight` + `volumetric_weight` در پاسخ) | | ۸ | چندزبانه (i18n) | ⏳ موکول به زمان دیپلوی | **وضعیت کلی فاز ۳.۶:** حدود ۹۵٪ تکمیل. تنها موارد باقی‌مانده: i18n (زمان دیپلوی) و سند پیشنهادی مالی (آینده). --- ## ۱۰. مستندات مرجع | فایل | محتوا | |------|-------| | `01_Documents/EXCEL_ANALYSIS.md` | تحلیل کامل فایل‌های اکسل (۳۹۵۰ رکورد، فرمول‌ها، زون‌ها) | | `01_Documents/IFNEX_Phase0_Checklist.md` | چک‌لیست کامل فازها (۰ تا ۳.۵) | | `01_Documents/IFNEX_Roadmap.md` | نقشهٔ راه فازی (تا فاز ۳.۶) | | `01_Documents/IFNEX_File_Map.md` | نقشهٔ ۱۰۰+ فایل پروژه | | `01_Documents/IFNEX_I18N_Strategy.md` | استراتژی چندزبانه (برای زمان دیپلوی) | | `01_Documents/IFNEX_Commercial_Model.md` | مدل تجاری و پلن‌های فروش | | `01_Documents/DESIGN_SYSTEM.md` | رنگ‌ها، تایپوگرافی، فاصله‌گذاری | | `DEPLOYMENT.md` | راهنمای کامل استقرار روی سرور | | `DEPLOYMENT_HANDOFF.md` | تحویل استقرار به تیم IT کارفرما | | `04_Laravel/README.md` | راهنمای بک‌اند | | `CLIENT_DELIVERY.md` | چک‌لیست وضعیت تحویل مشتری (منبع اصلی وضعیت تحویل) |