فروشگاه آنلاین طلا
گالری مظفر — فروشگاه آنلاین طلا با قیمت لحظهای
فروشگاهی که قیمت ثابت ندارد. هر قطعه از نرخ روز بازار حساب میشود، و دو نفر نمیتوانند یک انگشتر تکنسخهای را همزمان بخرند.
مشکل چه بود؟
یک فروشگاه معمولی روی هر محصول یک قیمت مینویسد و تمام. طلافروشی اینطور نیست. قیمت طلا هر روز — گاهی هر ساعت — عوض میشود. اگر قیمتها دستی نوشته شوند، یا مغازه ضرر میکند یا مشتری را از دست میدهد.
سه مسئلهی دیگر هم هست که در فروشگاههای معمولی وجود ندارد:
- هر قطعه یکی است. یک انگشتر دستساز دومی ندارد. اگر دو نفر همزمان بخرند، چه میشود؟
- خریدار ایرانی جزئیات میخواهد. فقط قیمت کافی نیست؛ باید وزن، عیار، اجرت، سود و مالیات را جدا ببیند.
- قیمت وسط خرید عوض میشود. مشتری مبلغی را میبیند و بعد کارت به کارت میکند.
چی ساختم؟
یک فروشگاه کامل با ۲۱ محصول نمونه در چهار دسته که هر کدام قانون قیمتگذاری خودش را دارد: زیورآلات طلا، سکه، شمش، و نقره.
بهعلاوه ورود با پیامک، سبد خرید مهمان، ماشینحساب قیمت طلا، مجله، و یک پنل مدیریت که مغازهدار بدون برنامهنویس میتواند محصول اضافه کند و نرخ را عوض کند.
قیمت چطور حساب میشود؟
این بخش قلب پروژه است. فرمول رسمی ایرانی این است:
| ۱. ارزش طلا | وزن × نرخ گرم آن عیار |
|---|---|
| ۲. اجرت ساخت | ارزش طلا × درصد اجرت |
| ۳. سود فروشنده | (ارزش طلا + اجرت) × درصد سود |
| ۴. مالیات | (اجرت + سود) × درصد مالیات |
| قیمت نهایی | جمع چهار مورد بالا |
دو نکته که خیلی از منابع فارسی اشتباه مینویسند، و من هر دو را تستدار کردم: سود روی «طلا + اجرت» حساب میشود، نه فقط روی اجرت. و مالیات هرگز روی خود طلا بسته نمیشود — طلای خام طبق ماده ۲۶ قانون مالیات بر ارزش افزوده معاف است. بستن مالیات روی کل فاکتور تخلف است.
فقط یک عدد از بیرون گرفته میشود
قبل از ساختن، دو تا از بهترین فروشگاههای طلای ایران را باز کردم و ترافیک شبکهشان را خواندم تا ببینم قیمت را از کجا میگیرند. نتیجه جالب بود: هیچکدام از مرورگر به هیچ API وصل نمیشوند. قیمت از قبل داخل صفحهای است که سرور میفرستد.
یکی از آنها هر دو عیار را نشان میداد. حساب کردم:
۱۹٬۹۵۰٬۰۰۰ × ۹۹۵ ÷ ۷۵۰ = ۲۶٬۴۶۷٬۰۰۰ — دقیقاً همان عدد ۲۴ عیارشان.
یعنی ۲۴ عیار را حساب میکنند، نه اینکه بگیرند.
همین کار را کردم: فقط نرخ گرم ۱۸ عیار گرفته میشود و ۲۱ عیار، ۲۴ عیار، نرخ خرید از مشتری (۷۴۰) و مثقال از رویش حساب میشوند. درخواست کمتر، و عیارها هیچوقت با هم نمیخوانند نمیشوند.
دو نفر، یک انگشتر
این سختترین بخش بود. روش غلط این است: موجودی را بخوان، چک کن بزرگتر از صفر است، بعد کم کن. اگر دو نفر دقیقاً همزمان این کار را بکنند، هر دو عدد «۱» را میبینند، هر دو از چک رد میشوند، و یک انگشتر دو بار فروخته میشود.
راه درست این است که شرط و تغییر را در یک دستور بدهی و بگذاری خود پایگاه داده تصمیم بگیرد:
UPDATE products SET stock = stock - 1
WHERE id = ? AND stock >= 1
پایگاه داده تضمین میکند فقط یکی برنده شود. بقیه «۰ سطر تغییر کرد» میگیرند و پیام «متأسفانه این قطعه فروخته شد» میبینند.
برای اینکه فقط حرف نباشد، تستش نوشتم: ۵۰ درخواست همزمان برای یک قطعه فرستادم. نتیجه باید همیشه یکی باشد — و هست: دقیقاً ۱ برنده، ۴۹ بازنده، موجودی صفر. نه دو تا، نه منفی.
اگر ۱۰٬۰۰۰ نفر همزمان بیایند؟
اولین چیزی که میشکند، API قیمت طلا است. اگر هر بازدیدکننده یک درخواست بفرستد، سهمیهی روزانه در چند دقیقه تمام میشود.
راهحل: نرخ ۶۰ ثانیه کش میشود. یعنی هر چقدر آدم بیاید، دقیقهای یک بار سراغ منبع میرویم — ۱٬۴۴۰ درخواست در روز، ثابت، چه ۱۰ نفر بیایند چه ۱۰۰٬۰۰۰ نفر.
تست بار گرفتم. نتیجه روی همین لپتاپ، با نسخهی نهایی و صفر خطا در ۱٬۶۰۰ درخواست:
| صفحه | درخواست در ثانیه | p95 | خطا |
|---|---|---|---|
| صفحه اصلی | ۸۳۳ | ۱۳ms | ۰ |
| صفحه محصول | ۳۴۷ | ۲۹۶ms | ۰ |
| فروشگاه (۲۱ محصول) | ۲۸۴ | ۳۴۸ms | ۰ |
پنل مدیریت
مغازهدار نباید برای عوض کردن قیمت به برنامهنویس زنگ بزند. بالای داشبورد یک کادر هست که فقط یک عدد میخواهد: نرخ گرم ۱۸ عیار. بقیهی عیارها همانجا زنده حساب میشوند و با ذخیره، قیمت همهی محصولات با هم عوض میشود.
هنگام ساختن محصول هم قیمت را دستی وارد نمیکنی. وزن و عیار و اجرت را میدهی و نتیجه را کنار فرم زنده میبینی — قبل از اینکه ذخیره کنی.
روی موبایل
با چه ابزارهایی
| چارچوب | Next.js ۱۵ با App Router و TypeScript |
|---|---|
| پایگاه داده | SQLite داخلی خود Node — بدون هیچ وابستگی |
| فونت | وزیرمتن، خودمیزبان |
| ورود | موبایل + کد پیامکی؛ کد و توکن هر دو هش میشوند |
| تست | ۱۶ تست: موتور قیمت و خرید همزمان |
نتیجه
فروشگاهی که قیمتش زنده است، موجودیاش قابل اعتماد است، و مغازهدار خودش میتواند بچرخاندش. مهمتر از ظاهرش، چیزهایی است که دیده نمیشوند: فرمول درست مالیات، قفلی که دوبار فروختن را غیرممکن میکند، و کشی که سایت را زیر فشار نگه میدارد.
این پروژه ادامه دارد — مرحلهی بعد ثبت سفارش کامل است: رزرو موجودی، آپلود رسید کارت به کارت، تأیید مدیر و فاکتور چاپی.