Repository navigation
📡 v2.12.0 — REST API v1 (Sanctum, Mobile-Ready)
📡 v2.12.0 — REST API v1 (Sanctum, Mobile-Ready)
دیجیشاپ — فروشگاه آنلاین تجهیزات شبکه | Digi-Shop — Online network-equipment store
Laravel 12 · PHP 8.2+ · Sanctum 4 · Bootstrap 5 RTL · MIT License
🇬🇧 English
📡 New — REST API v1, authenticated with Sanctum tokens
- The whole store is now available to a mobile app or any external client: 18 endpoints under
/api/v1— auth, catalog, reviews, questions, wishlist and orders — authenticated with Laravel Sanctum personal access tokens (Authorization: Bearer …); the web shop keeps its session flow untouched - Token auth that behaves like a phone:
POST /auth/loginnames the token after yourdevice_name;POST /auth/logoutrevokes only the current device's token — sign out on the phone, stay logged in on the tablet; login errors are deliberately generic so the API never reveals whether an email exists; tokens are stored hashed - The catalog with the same rules as the web:
GET /productsruns the exact same filter request as the storefront — search, category, price ranges typed in Persian digits (۵۰۰٬۰۰۰), in-stock filter and best-selling sort (withSum);GET /products/{slug}fills an entire product screen in one call: gallery, rating summary + 5→1 breakdown, first page of approved reviews with verified-buyer badges (one query, no N+1), answered questions and 4 related products - Orders placed straight from the app:
POST /orderstakesitems: [{slug, quantity}], customer details, payment method and an optionalcoupon_code— everything runs through the new sharedPlaceOrderservice (the web checkout was refactored onto it too): final stock re-validation, row-locked coupon redemption, price snapshots, stock decrement and mail/SMS notifications behave identically on both surfaces; ZarinPal orders answer with apayment_urlfor WebView hand-off, and every response carries raw values (status,total) plus ready-made Persian labels (status_label,total_fa) - The social layer, readable and writable: paginated
GETendpoints for reviews and questions (approved/answered only, verified badges included);POSTendpoints enforce the web rules — one review per user/product, pending moderation on both,throttle:5,1 - Idempotent wishlist:
POST/DELETE /wishlist/{slug}always return the final state — a retry after a flaky connection never errors; product responses carryis_in_wishlistfor logged-in tokens (one query per page) - Guardrails: 60 req/min per token (
throttle:api), 10/min on login/register, standard 422 validation shape,409for stock conflicts with the Persian message, the same[a-z0-9-]+slug constraint as the web - Housekeeping:
laravel/sanctum^4.3 (one migration —personal_access_tokens— applied automatically byshop:install);symfony/mimebumped past CVE-2026-45070 (composer audit clean);fa_price()now uses the Persian thousands separator «٬» —۲٬۰۰۰٬۰۰۰everywhere - 48 new tests across 5 API suites: auth flows, token revocation, filters + Persian-digit parsing, one-call detail shape, verified badges, wishlist idempotency, ownership isolation, direct orders with coupon math, 409 stock conflicts, restock on cancel, email delivery
📊 Numbers
- 264 feature tests (990 assertions) — all green; code style: Pint clean
- One new migration (
personal_access_tokens) —php artisan shop:installor plainmigratehandles it; zero config changes - 18 new API endpoints under
/api/v1; 1 new shared service (PlaceOrder); 7 API resources; 5 new feature-test suites
Quick start (unchanged)
git clone https://github.com/MSS1625/shop-php.git && cd shop-php
composer install
php artisan shop:install # env + key + migrate + seed + link (includes WELCOME10)
php artisan admin:create # interactive admin user
php artisan serve # → http://localhost:8000Seeing it in action
# Log in from your "app" and grab a token:
curl -s -X POST http://localhost:8000/api/v1/auth/login \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"secret","device_name":"Pixel 8"}'
# → {"message":"خوش آمدید!","data":{…},"token":"1|abc…"}
# Browse the catalog — Persian digits work in price filters:
curl -s "http://localhost:8000/api/v1/products?sort=popular&min=۵۰۰٬۰۰۰" \
-H "Accept: application/json"
# Place an order straight from the app, with a coupon:
curl -s -X POST http://localhost:8000/api/v1/orders \
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"items":[{"slug":"network-switch","quantity":1}],
"customer_name":"سارا محمدی","customer_phone":"09123456789",
"customer_address":"تهران، خیابان ولیعصر، پلاک ۱۲",
"payment_method":"cod","coupon_code":"WELCOME10"}'
# → 201 + order with status_label, total_fa and payment_url when online
# Sign out on just this device — the tablet keeps working:
curl -s -X POST http://localhost:8000/api/v1/auth/logout \
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json"🇮🇷 فارسی
📡 جدید — REST API نسخهٔ ۱ با توکن Sanctum
- کل فروشگاه حالا در دسترس اپلیکیشن موبایل یا هر کلاینت بیرونی است: ۱۸ نقطهٔ اتصال زیر
/api/v1— احراز هویت، کاتالوگ، نظرات، پرسشها، علاقهمندیها و سفارشها — با توکن دسترسی شخصی Sanctum (Authorization: Bearer …)؛ جریان سشن وب دستنخورده ماند - توکنی که مثل گوشی رفتار میکند:
POST /auth/loginتوکن را به نامdevice_nameشما ثبت میکند؛POST /auth/logoutفقط توکن همین دستگاه را باطل میکند — از گوشی خارج شوید، تبلت لاگین میماند؛ پیام خطای ورود عمداً کلی است تا API لو ندهد ایمیل وجود دارد یا نه؛ توکنها هششده ذخیره میشوند - کاتالوگ با همان قواعد وب:
GET /productsهمان فیلترهای ویترین را اجرا میکند — جستجو، دسته، بازهٔ قیمت با ارقام فارسی (۵۰۰٬۰۰۰)، فیلتر موجودی و پرفروشترین (withSum)؛GET /products/{slug}کل صفحهٔ محصول را در یک فراخوانی پر میکند: گالری، خلاصهٔ امتیاز + تفکیک ۵→۱، اولین صفحهٔ نظرات تأییدشده با نشان خریدار تأییدشده (یک کوئری، بدون N+1)، پرسشهای پاسخداده و ۴ محصول مشابه - سفارش مستقیم از اپ:
POST /ordersباitems، اطلاعات مشتری، روش پرداخت وcoupon_codeاختیاری — همهچیز از سرویس مشترک جدیدPlaceOrderمیگذرد (فرم خرید وب هم روی آن بازآرایی شد): اعتبارسنجی نهایی موجودی، نقد کردن کوپن با قفل ردیف، اسنپشات قیمت، کاهش انبار و اطلاعرسانی ایمیل/پیامک روی هر دو سطح یکی است؛ سفارش زرینپالpayment_urlبرای WebView برمیگرداند و هر پاسخ هم مقدار خام دارد (status,total) هم برچسب فارسی آماده (status_label,total_fa) - لایهٔ اجتماعی، خواندنی و نوشتنی:
GETهای صفحهبندیشدهٔ نظرات و پرسشها (فقط تأییدشده/پاسخداده، با نشان خریدار)؛POSTها همان قواعد وب را دارند — یک نظر برای هر کاربر/محصول، شروع در انتظار تأیید،throttle:5,1 - علاقهمندی idempotent:
POST/DELETE /wishlist/{slug}همیشه وضعیت نهایی را برمیگردانند — تلاش دوباره بعد از قطع اینترنت خطا نمیدهد؛ پاسخ محصولات برای توکن لاگینشدهis_in_wishlistدارد (یک کوئری برای کل صفحه) - حفاظتها: ۶۰ درخواست در دقیقه برای هر توکن (
throttle:api)، ۱۰ در دقیقه برای ورود/ثبتنام، شکل استاندارد 422 برای اعتبارسنجی،409برای تعارض موجودی با پیام فارسی، همان قید اسلاگ[a-z0-9-]+وب - کارهای جانبی:
laravel/sanctumنسخهٔ ^4.3 (یک مایگریشن —personal_access_tokens— کهshop:installخودش اعمال میکند)؛symfony/mimeاز CVE-2026-45070 عبور داده شد (composer audit پاک)؛fa_price()حالا جداکنندهٔ هزارگان فارسی «٬» میگذارد —۲٬۰۰۰٬۰۰۰همهجا - ۴۸ تست جدید در ۵ مجموعهٔ API: جریانهای احراز هویت، باطلکردن توکن، فیلترها + پارس ارقام فارسی، شکل پاسخ یکفراخوانی، نشانهای خریدار، idempotency علاقهمندی، جداسازی مالکیت، سفارش مستقیم با محاسبهٔ کوپن، تعارض 409، بازگشت موجودی هنگام لغو، ارسال ایمیل
📊 اعداد
- ۲۶۴ تست فیچر (۹۹۰ ادعا) — همه سبز؛ سبک کد: Pint پاک
- یک مهاجرت جدید (
personal_access_tokens) — باphp artisan shop:installیاmigrateساده اعمال میشود؛ بدون تغییر کانفیگ - ۱۸ نقطهٔ اتصال جدید زیر
/api/v1؛ ۱ سرویس مشترک جدید (PlaceOrder)؛ ۷ منبع API؛ ۵ مجموعهٔ تست جدید
راهاندازی سریع (بدون تغییر)
git clone https://github.com/MSS1625/shop-php.git && cd shop-php
composer install
php artisan shop:install # env + کلید + مهاجرت + داده + لینک (شامل WELCOME10)
php artisan admin:create # ساخت مدیر (تعاملی)
php artisan serve # → http://localhost:8000دیدن آن در عمل
# از «اپ» وارد شوید و توکن بگیرید:
curl -s -X POST http://localhost:8000/api/v1/auth/login \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"secret","device_name":"Pixel 8"}'
# → {"message":"خوش آمدید!","data":{…},"token":"1|abc…"}
# کاتالوگ را ببینید — ارقام فارسی در فیلتر قیمت کار میکند:
curl -s "http://localhost:8000/api/v1/products?sort=popular&min=۵۰۰٬۰۰۰" \
-H "Accept: application/json"
# مستقیم از اپ سفارش ثبت کنید، با کد تخفیف:
curl -s -X POST http://localhost:8000/api/v1/orders \
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"items":[{"slug":"network-switch","quantity":1}],
"customer_name":"سارا محمدی","customer_phone":"09123456789",
"customer_address":"تهران، خیابان ولیعصر، پلاک ۱۲",
"payment_method":"cod","coupon_code":"WELCOME10"}'
# → 201 + سفارش با status_label و total_fa و payment_url برای سفارش آنلاین
# فقط از همین دستگاه خارج شوید — تبلت کارش را میکند:
curl -s -X POST http://localhost:8000/api/v1/auth/logout \
-H "Authorization: Bearer $TOKEN" -H "Accept: application/json"