فروشگاه آنلاین طلا

گالری مظفر — فروشگاه آنلاین طلا با قیمت لحظه‌ای

فروشگاهی که قیمت ثابت ندارد. هر قطعه از نرخ روز بازار حساب می‌شود، و دو نفر نمی‌توانند یک انگشتر تک‌نسخه‌ای را همزمان بخرند.

Next.jsTypeScriptReactSQLite

صفحه‌ی اول گالری مظفر: نوار سیاه قیمت لحظه‌ای طلا در بالا، هدر سفید با نشان نگین، و تصویر یک گردنبند مروارید
نوار بالای صفحه نرخ ۱۸ و ۲۴ عیار را با درصد تغییر و تاریخ شمسی نشان می‌دهد — همان کاری که فروشگاه‌های واقعی طلا می‌کنند.

مشکل چه بود؟

یک فروشگاه معمولی روی هر محصول یک قیمت می‌نویسد و تمام. طلافروشی این‌طور نیست. قیمت طلا هر روز — گاهی هر ساعت — عوض می‌شود. اگر قیمت‌ها دستی نوشته شوند، یا مغازه ضرر می‌کند یا مشتری را از دست می‌دهد.

سه مسئله‌ی دیگر هم هست که در فروشگاه‌های معمولی وجود ندارد:

  • هر قطعه یکی است. یک انگشتر دست‌ساز دومی ندارد. اگر دو نفر همزمان بخرند، چه می‌شود؟
  • خریدار ایرانی جزئیات می‌خواهد. فقط قیمت کافی نیست؛ باید وزن، عیار، اجرت، سود و مالیات را جدا ببیند.
  • قیمت وسط خرید عوض می‌شود. مشتری مبلغی را می‌بیند و بعد کارت به کارت می‌کند.

چی ساختم؟

یک فروشگاه کامل با ۲۱ محصول نمونه در چهار دسته که هر کدام قانون قیمت‌گذاری خودش را دارد: زیورآلات طلا، سکه، شمش، و نقره.

به‌علاوه ورود با پیامک، سبد خرید مهمان، ماشین‌حساب قیمت طلا، مجله، و یک پنل مدیریت که مغازه‌دار بدون برنامه‌نویس می‌تواند محصول اضافه کند و نرخ را عوض کند.

قیمت چطور حساب می‌شود؟

این بخش قلب پروژه است. فرمول رسمی ایرانی این است:

۱. ارزش طلاوزن × نرخ گرم آن عیار
۲. اجرت ساختارزش طلا × درصد اجرت
۳. سود فروشنده(ارزش طلا + اجرت) × درصد سود
۴. مالیات(اجرت + سود) × درصد مالیات
قیمت نهاییجمع چهار مورد بالا

دو نکته که خیلی از منابع فارسی اشتباه می‌نویسند، و من هر دو را تست‌دار کردم: سود روی «طلا + اجرت» حساب می‌شود، نه فقط روی اجرت. و مالیات هرگز روی خود طلا بسته نمی‌شود — طلای خام طبق ماده ۲۶ قانون مالیات بر ارزش افزوده معاف است. بستن مالیات روی کل فاکتور تخلف است.

صفحه‌ی محصول: عکس انگشتر در سمت راست و جدول کامل وزن، عیار، اجرت، سود، مالیات و قیمت نهایی در سمت چپ
صفحه‌ی محصول، ریز به ریز. خریدار ایرانی دقیقاً دنبال همین جدول می‌گردد.

فقط یک عدد از بیرون گرفته می‌شود

قبل از ساختن، دو تا از بهترین فروشگاه‌های طلای ایران را باز کردم و ترافیک شبکه‌شان را خواندم تا ببینم قیمت را از کجا می‌گیرند. نتیجه جالب بود: هیچ‌کدام از مرورگر به هیچ API وصل نمی‌شوند. قیمت از قبل داخل صفحه‌ای است که سرور می‌فرستد.

یکی از آن‌ها هر دو عیار را نشان می‌داد. حساب کردم: ۱۹٬۹۵۰٬۰۰۰ × ۹۹۵ ÷ ۷۵۰ = ۲۶٬۴۶۷٬۰۰۰ — دقیقاً همان عدد ۲۴ عیارشان. یعنی ۲۴ عیار را حساب می‌کنند، نه اینکه بگیرند.

همین کار را کردم: فقط نرخ گرم ۱۸ عیار گرفته می‌شود و ۲۱ عیار، ۲۴ عیار، نرخ خرید از مشتری (۷۴۰) و مثقال از رویش حساب می‌شوند. درخواست کمتر، و عیارها هیچ‌وقت با هم نمی‌خوانند نمی‌شوند.

دو نفر، یک انگشتر

این سخت‌ترین بخش بود. روش غلط این است: موجودی را بخوان، چک کن بزرگ‌تر از صفر است، بعد کم کن. اگر دو نفر دقیقاً همزمان این کار را بکنند، هر دو عدد «۱» را می‌بینند، هر دو از چک رد می‌شوند، و یک انگشتر دو بار فروخته می‌شود.

راه درست این است که شرط و تغییر را در یک دستور بدهی و بگذاری خود پایگاه داده تصمیم بگیرد:

UPDATE products SET stock = stock - 1
WHERE id = ? AND stock >= 1

پایگاه داده تضمین می‌کند فقط یکی برنده شود. بقیه «۰ سطر تغییر کرد» می‌گیرند و پیام «متأسفانه این قطعه فروخته شد» می‌بینند.

برای اینکه فقط حرف نباشد، تستش نوشتم: ۵۰ درخواست همزمان برای یک قطعه فرستادم. نتیجه باید همیشه یکی باشد — و هست: دقیقاً ۱ برنده، ۴۹ بازنده، موجودی صفر. نه دو تا، نه منفی.

اگر ۱۰٬۰۰۰ نفر همزمان بیایند؟

اولین چیزی که می‌شکند، API قیمت طلا است. اگر هر بازدیدکننده یک درخواست بفرستد، سهمیه‌ی روزانه در چند دقیقه تمام می‌شود.

راه‌حل: نرخ ۶۰ ثانیه کش می‌شود. یعنی هر چقدر آدم بیاید، دقیقه‌ای یک بار سراغ منبع می‌رویم — ۱٬۴۴۰ درخواست در روز، ثابت، چه ۱۰ نفر بیایند چه ۱۰۰٬۰۰۰ نفر.

تست بار گرفتم. نتیجه روی همین لپ‌تاپ، با نسخه‌ی نهایی و صفر خطا در ۱٬۶۰۰ درخواست:

صفحهدرخواست در ثانیهp95خطا
صفحه اصلی۸۳۳۱۳ms۰
صفحه محصول۳۴۷۲۹۶ms۰
فروشگاه (۲۱ محصول)۲۸۴۳۴۸ms۰

پنل مدیریت

مغازه‌دار نباید برای عوض کردن قیمت به برنامه‌نویس زنگ بزند. بالای داشبورد یک کادر هست که فقط یک عدد می‌خواهد: نرخ گرم ۱۸ عیار. بقیه‌ی عیارها همان‌جا زنده حساب می‌شوند و با ذخیره، قیمت همه‌ی محصولات با هم عوض می‌شود.

پنل مدیریت: کادر زرد وارد کردن نرخ طلا در بالا و کارت‌های آمار شامل ارزش کل موجودی و وزن کل طلا
داشبورد: ارزش کل موجودی به تومان و وزن کل طلا، با نرخ همان لحظه حساب می‌شوند.

هنگام ساختن محصول هم قیمت را دستی وارد نمی‌کنی. وزن و عیار و اجرت را می‌دهی و نتیجه را کنار فرم زنده می‌بینی — قبل از اینکه ذخیره کنی.

روی موبایل

دو نمای موبایل کنار هم: صفحه‌ی اول با منوی همبرگری، و صفحه‌ی محصول
منوی کشویی در راست‌به‌چپ از سمت راست باز می‌شود، و نوار قیمت به جای شکستن افقی می‌لغزد.

با چه ابزارهایی

چارچوبNext.js ۱۵ با App Router و TypeScript
پایگاه دادهSQLite داخلی خود Node — بدون هیچ وابستگی
فونتوزیرمتن، خودمیزبان
ورودموبایل + کد پیامکی؛ کد و توکن هر دو هش می‌شوند
تست۱۶ تست: موتور قیمت و خرید همزمان

نتیجه

فروشگاهی که قیمتش زنده است، موجودی‌اش قابل اعتماد است، و مغازه‌دار خودش می‌تواند بچرخاندش. مهم‌تر از ظاهرش، چیزهایی است که دیده نمی‌شوند: فرمول درست مالیات، قفلی که دوبار فروختن را غیرممکن می‌کند، و کشی که سایت را زیر فشار نگه می‌دارد.

این پروژه ادامه دارد — مرحله‌ی بعد ثبت سفارش کامل است: رزرو موجودی، آپلود رسید کارت به کارت، تأیید مدیر و فاکتور چاپی.

پروژه‌ای دارید؟

اگر کاری شبیه این لازم دارید، خوشحال می‌شم دربارش حرف بزنیم.