<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>smbz.ir — مقالات و اخبار فناوری</title>
    <link>https://smbz.ir/</link>
    <description>وب‌سایت شخصی سید محمد بهبهانی‌زاده (SMBZ)؛ توسعه‌دهنده فول‌استک و معمار نرم‌افزار. معرفی پروژه‌ها (۲حساب، عینک‌سازی، پیج‌یار)، مهارت‌ها و مقالات فنی درباره فین‌تک، هوش مصنوعی، سئو و زیرساخت.</description>
    <language>fa-IR</language>
    <lastBuildDate>Fri, 16 Oct 2026 19:22:36 GMT</lastBuildDate>
    <atom:link href="https://smbz.ir/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>تعویق PostgreSQL 19؛ بازبینی کد با هوش مصنوعی بیش از توان توسعه‌دهندگان باگ یافت</title>
      <link>https://smbz.ir/news/postgres-19-delayed-ai-code-review/</link>
      <guid isPermaLink="true">https://smbz.ir/news/postgres-19-delayed-ai-code-review/</guid>
      <pubDate>Fri, 16 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>اخبار</category>
      <category>داده و دیتابیس</category>
      <description>انتشار PostgreSQL 19 به حدود ۱۹ نوامبر عقب افتاد. بازبینی کد با هوش مصنوعی آن‌قدر باگ پیدا کرد که بین ۸ تا ۱۰ قابلیت مهم، از جمله SQL/PGQ، از این نسخه کنار رفت.</description>
      <content:encoded><![CDATA[<p>گروه توسعه جهانی PostgreSQL انتشار نسخه ۱۹ این پایگاه داده متن‌باز را عقب انداخت. این نسخه قرار بود اواخر سپتامبر یا اوایل اکتبر ۲۰۲۶ منتشر شود و حالا انتظار می‌رود حدود ۱۹ نوامبر عرضه شود. به گفته توسعه‌دهندگان اصلی پروژه، علت اصلی تأخیر این است که ابزارهای بازبینی کد مبتنی بر مدل‌های زبانی بزرگ، بیش از ظرفیت تیم برای رفع اشکال، باگ و نقص پیدا کرده‌اند.</p><h2>چه چیزی از نسخه ۱۹ کنار گذاشته شد؟</h2><p>طبق گزارش The Register، بین هشت تا ده قابلیت مهم از PostgreSQL 19 حذف یا به اصطلاح revert شده‌اند و احتمالاً در PostgreSQL 20 عرضه می‌شوند. مهم‌ترینِ آن‌ها پشتیبانی از SQL Property Graph Queries یا SQL/PGQ است. این قابلیت که از سال ۲۰۲۳ بخشی از استاندارد SQL شده، نحوی برای پرس‌وجو روی داده‌های گرافی (گره‌ها و یال‌های میان آن‌ها) فراهم می‌کند. به گفته منابع، با حذف آن ده‌ها commit مرتبط با این قابلیت هم برگردانده شد.</p><p>به گفته یک مقاله فنی در وبلاگ Snowflake، قابلیت‌های دیگری هم از این نسخه کنار رفته‌اند: ادغام و تقسیم پارتیشن با ALTER TABLE MERGE/SPLIT PARTITION، عبارت GROUP BY ALL که در برخی حالت‌ها نتیجه نادرست برمی‌گرداند، تغییر الگوریتم پیش‌فرض فشرده‌سازی TOAST به lz4، خروجی‌های غیرمتنی برای pg_dumpall و ردیابی پرس‌وجوهای تودرتو در pg_stat_statements. همین منبع شمار کل revertها در دوره بتای نسخه ۱۹ را ۵۳ مورد ذکر کرده است. این عدد برای نسخه ۱۸ حدود ۴۴ بود و بیشتر آن‌ها در همان اوایل بتا رخ دادند.</p><ul><li>زمان انتشار تازه: حدود ۱۹ نوامبر ۲۰۲۶</li><li>۸ تا ۱۰ قابلیت مهم به نسخه ۲۰ منتقل شد</li><li>SQL/PGQ و GROUP BY ALL از جمله موارد حذف‌شده‌اند</li></ul><h2>نقش هوش مصنوعی در این تأخیر</h2><p>یکی از commiterهای ارشد PostgreSQL در یادداشتی توضیح داده که بعضی از قابلیت‌های حذف‌شده ایرادهای جدی در معماری داشتند که در دوره بتا نمی‌شد سریع رفعشان کرد. در کنار آن، بازبینی کد با کمک مدل‌های زبانی فهرست بلندی از اشکال‌های کوچک‌تر در حالت‌های مرزی را هم نشان داد. پیش‌تر این نوع اشکال‌ها معمولاً طی سال‌ها پس از انتشار، کم‌کم کشف و وصله می‌شدند.</p><p>استدلال او این است که هرچند رفع هر کدام از این ایرادها شاید فقط چند خط کد بخواهد، هر مورد هزینه ثابتی برای بررسی، آزمایش و تأیید دارد و جمع آن‌ها از وقت تیم بیشتر شد. به گفته او، این ابزارها زمانی که قابلیت‌های بزرگ نسخه ۱۹ نوشته می‌شدند هنوز به این اندازه کارآمد نبودند. در عمل «سطح کیفیت مورد انتظار» پس از نوشته شدن کدها بالا رفت. او تأکید کرده که این برگشت‌ها ربطی به vibe coding یا کدنویسی شتاب‌زده با هوش مصنوعی ندارد و نسخه ۱۹ پس از این بازبینی‌های اضافه، نسخه‌ای بسیار پایدار خواهد بود.</p><h2>چرا برای برنامه‌نویس‌ها مهم است؟</h2><p>PostgreSQL از محبوب‌ترین پایگاه‌های داده میان توسعه‌دهندگان حرفه‌ای است و سرویس‌های مدیریت‌شده بزرگ و بسیاری از سیستم‌های سازگار با آن بر پایه همین پروژه ساخته شده‌اند. پس اگر برای مهاجرت به نسخه ۱۹ یا استفاده از قابلیت‌هایی مثل SQL/PGQ برنامه داشتید، باید زمان‌بندی را بازنگری کنید. وبلاگ Snowflake فعلاً PostgreSQL 18 را هدف امن ارتقا معرفی کرده است.</p><p>با این حال بخشی از قابلیت‌های مورد انتظار همچنان در نسخه ۱۹ می‌مانند. از جمله REPACK CONCURRENTLY برای بازپس‌گیری فضای دیسک بدون قفل‌کردن جدول (برخلاف VACUUM FULL)، autovacuum موازی، ON CONFLICT DO SELECT و پشتیبانی از IGNORE NULLS در توابع پنجره‌ای. البته همان منبع REPACK را هم جزو موارد در معرض خطر حذف دانسته است.</p><p>فراتر از PostgreSQL، این ماجرا نشانه‌ای از یک روند کلی‌تر است: ابزارهای بازبینی و تست مبتنی بر هوش مصنوعی معیار «آماده انتشار بودن» را تغییر می‌دهند. پروژه‌های متن‌باز و تیم‌های نرم‌افزاری احتمالاً باید این ابزارها را زودتر و از همان مرحله نوشتن کد وارد چرخه توسعه کنند، نه در روزهای پایانی پیش از انتشار.</p><pre dir="ltr"><code>-- نمونه ساختگی: بازپس‌گیری فضای جدول بدون قفل طولانی در PostgreSQL 19
REPACK (CONCURRENTLY) example_table;</code></pre><h2>جمع‌بندی</h2><p>تأخیر PostgreSQL 19 نتیجه سخت‌گیری بیشتر در کیفیت است، نه افت آن. ابزارهای بازبینی مبتنی بر هوش مصنوعی ایرادهایی را زودتر آشکار کردند که پیش‌تر سال‌ها بعد از انتشار پیدا می‌شدند. حالا نسخه ۱۹ کوچک‌تر و دیرتر می‌آید و احتمالاً PostgreSQL 20 میزبان قابلیت‌های جامانده خواهد بود.</p><h3>منابع</h3><ol><li><a href="https://www.theregister.com/databases/2026/10/16/postgres-19-delayed-after-ai-reviewers-find-more-bugs-than-humans-can-fix/5303471">The Register - Postgres 19 delayed after AI reviewers find more bugs than humans can fix</a></li><li><a href="https://www.snowflake.com/en/blog/engineering/postgresql-19-release-delay-feature-reverts/">Snowflake Engineering Blog - What Is Happening with PostgreSQL 19?</a></li></ol>]]></content:encoded>
    </item>
    <item>
      <title>کش دولایه با Redis و Nginx برای عبور از ترافیک ناگهانی کمپین‌ها</title>
      <link>https://smbz.ir/blog/redis-nginx-two-layer-cache/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/redis-nginx-two-layer-cache/</guid>
      <pubDate>Fri, 16 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>زیرساخت و لینوکس</category>
      <description>چطور با میکروکش Nginx و کش داده در Redis، یک فروشگاه را در برابر ترافیک ناگهانی کمپین‌ها مقاوم کنیم بدون اینکه قیمت و سبد خرید کاربر اشتباه نمایش داده شود.</description>
      <content:encoded><![CDATA[<p>وقتی یک کمپین تبلیغاتی یا استوری پربازدید منتشر می‌شود، در چند دقیقه چند برابر ترافیک عادی به سایت می‌رسد. اگر هر درخواست به دیتابیس برسد، سرور زودتر از کمپین تمام می‌شود. کش دولایه این فشار را جذب می‌کند.</p><h2>لایه اول: میکروکش Nginx برای صفحات عمومی</h2><p>صفحاتی که برای همه کاربران یکسان‌اند (لیست محصولات، صفحه دسته، مقالات) می‌توانند برای چند ثانیه در Nginx کش شوند. حتی کش یک‌ثانیه‌ای یعنی در اوج ترافیک، فقط یک درخواست در ثانیه به اپلیکیشن می‌رسد. نکته کلیدی: هر درخواستی که کوکی نشست دارد باید از کش عبور کند.</p><pre dir="ltr"><code>proxy_cache_path /var/cache/nginx/micro levels=1:2
                 keys_zone=micro:20m max_size=500m inactive=10m;

map $http_cookie $skip_cache {
  default         0;
  ~*session=      1;   # کاربر لاگین‌شده یا دارای سبد خرید
}

location / {
  proxy_cache            micro;
  proxy_cache_valid      200 5s;
  proxy_cache_use_stale  updating error timeout;
  proxy_cache_lock       on;
  proxy_cache_bypass     $skip_cache;
  proxy_no_cache         $skip_cache;
  proxy_pass             http://127.0.0.1:3000;
}</code></pre><ul><li>proxy_cache_lock جلوی هجوم هم‌زمان درخواست‌ها به اپ را می‌گیرد.</li><li>proxy_cache_use_stale updating یعنی در زمان بروزرسانی، نسخه قبلی سرو شود.</li><li>صفحات سبد خرید، پرداخت و پنل کاربری هرگز کش نمی‌شوند.</li></ul><h2>لایه دوم: کش داده در Redis</h2><p>کوئری‌های سنگین و پرتکرار (درخت دسته‌بندی، تنظیمات سایت، لیست برندها) در Redis با زمان انقضا نگه‌داری می‌شوند. هنگام تغییر داده در پنل مدیریت، کلید مربوط حذف می‌شود تا داده کهنه نمایش داده نشود.</p><pre dir="ltr"><code>async function cached&lt;T&gt;(key: string, ttlSec: number, load: () =&gt; Promise&lt;T&gt;): Promise&lt;T&gt; {
  const hit = await redis.get(key);
  if (hit) return JSON.parse(hit) as T;

  const value = await load();
  await redis.set(key, JSON.stringify(value), 'EX', ttlSec);
  return value;
}

// هنگام ویرایش در پنل:
await redis.del('categories:tree');</code></pre><h2>جمع‌بندی</h2><p>کش خوب یعنی بدانید چه چیزی را نباید کش کنید. قیمت، موجودی لحظه‌ای و هر چیزی که به کاربر وابسته است بیرون از کش می‌ماند؛ بقیه می‌تواند چند ثانیه کهنه باشد و سایت را زنده نگه دارد.</p>]]></content:encoded>
    </item>
    <item>
      <title>سئوی فنی فروشگاه اینترنتی با Next.js: وقتی مشکل کد نیست، بودجه خزش است</title>
      <link>https://smbz.ir/blog/technical-seo-nextjs-ecommerce/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/technical-seo-nextjs-ecommerce/</guid>
      <pubDate>Fri, 16 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>وب، سئو و فرانت‌اند</category>
      <description>تجربه عملی سئوی فنی یک فروشگاه Next.js: رندر سمت سرور، داده ساختاریافته محصول، سایت‌مپ تمیز و مدیریت بودجه خزش گوگل برای صفحات فیلتر و برند.</description>
      <content:encoded><![CDATA[<p>در فروشگاه‌های اینترنتی، بیشتر مشکلات ایندکس نشدن صفحات از کد نیست؛ از این است که گوگل وقت و منابع محدودی برای خزیدن سایت شما دارد و آن را صرف URLهای بی‌ارزش می‌کند. در این یادداشت، چک‌لیستی را مرور می‌کنم که در عمل برای یک فروشگاه Next.js جواب داده است.</p><h2>اول: HTML کامل از سرور</h2><p>ربات گوگل جاوااسکریپت را اجرا می‌کند، اما با تاخیر و در صف جداگانه. اگر عنوان، قیمت و توضیح محصول در HTML اولیه نباشد، ایندکس شدن صفحه هفته‌ها عقب می‌افتد. در Next.js یعنی صفحات محصول و دسته‌بندی باید Server Component یا SSG باشند و متن اصلی بدون اجرای جاوااسکریپت دیده شود. یک تست ساده: صفحه را با curl بگیرید و دنبال نام محصول بگردید.</p><pre dir="ltr"><code>curl -s -A &quot;Googlebot&quot; https://example.com/product/sample \
  | grep -o '&lt;title&gt;[^&lt;]*&lt;/title&gt;'

# اگر عنوان درست برنگشت، صفحه برای ربات خالی است</code></pre><ul><li>متن اصلی، قیمت و موجودی در HTML اولیه باشد.</li><li>تگ canonical روی هر صفحه، به‌خصوص صفحاتی که پارامتر فیلتر دارند.</li><li>لیست‌های طولانی کارت را دوبار نفرستید (یک بار HTML و یک بار داده کلاینت)؛ حجم صفحه مستقیم روی سرعت خزش اثر دارد.</li></ul><h2>داده ساختاریافته محصول</h2><p>Schema.org از نوع Product به گوگل می‌گوید قیمت، واحد پول، موجودی و برند چیست. این داده باید دقیقاً با چیزی که کاربر روی صفحه می‌بیند یکی باشد؛ اختلاف قیمت در JSON-LD و صفحه یکی از دلایل رایج هشدار در Search Console است.</p><pre dir="ltr"><code>const productJsonLd = {
  '@context': 'https://schema.org',
  '@type': 'Product',
  name: product.title,
  image: product.images,
  brand: { '@type': 'Brand', name: product.brand },
  offers: {
    '@type': 'Offer',
    price: product.price,          // همان عددی که روی صفحه است
    priceCurrency: 'IRR',
    availability: product.inStock
      ? 'https://schema.org/InStock'
      : 'https://schema.org/OutOfStock',
  },
};</code></pre><h2>بودجه خزش: URLهای بی‌ارزش را ببندید</h2><p>هر ترکیب فیلتر (رنگ × برند × سایز × مرتب‌سازی) یک URL جدید می‌سازد و گوگل ممکن است هزاران صفحه تکراری را بخزد و به صفحات مهم نرسد. راه‌حل، کم کردن URLهای قابل‌خزش است، نه اضافه کردن صفحه جدید.</p><ul><li>صفحات فیلتر چندگانه را noindex کنید یا canonical را به دسته اصلی بدهید.</li><li>سایت‌مپ فقط شامل URLهای canonical و قابل ایندکس باشد.</li><li>برای برندهای مهم صفحه واقعی با محتوای اختصاصی بسازید، نه پارامتر ?brand=.</li><li>گزارش Crawl Stats در Search Console را هفتگی ببینید.</li></ul><h2>جمع‌بندی</h2><p>سئوی فنی بیشتر از جنس حذف است: حذف URLهای تکراری، حذف حجم اضافه صفحه و حذف وابستگی محتوا به جاوااسکریپت. وقتی این‌ها درست شد، محتوای خوب فرصت دیده شدن پیدا می‌کند.</p>]]></content:encoded>
    </item>
    <item>
      <title>تایپوگرافی فارسی و RTL در رابط‌های مدرن: Vazirmatn، اعداد و Tailwind</title>
      <link>https://smbz.ir/blog/persian-typography-rtl-ui/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/persian-typography-rtl-ui/</guid>
      <pubDate>Thu, 15 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>وب، سئو و فرانت‌اند</category>
      <description>نکات عملی برای ساخت رابط کاربری فارسی خوانا: انتخاب و میزبانی فونت، اعداد فارسی و جدولی، فاصله‌گذاری حروف، و ترکیب درست متن فارسی و انگلیسی در جهت راست‌به‌چپ.</description>
      <content:encoded><![CDATA[<p>بیشتر قالب‌ها و کامپوننت‌های آماده برای انگلیسی طراحی شده‌اند و وقتی فارسی می‌شوند، متن فشرده، اعداد نامرتب و آیکون‌ها برعکس می‌شوند. چند قاعده ساده کیفیت رابط فارسی را چند برابر می‌کند.</p><h2>فونت را خودتان میزبانی کنید</h2><p>وابستگی به CDN خارجی برای فونت یعنی در شرایط اختلال اینترنت، سایت با فونت پیش‌فرض و ظاهری شکسته باز می‌شود. نسخه متغیر (Variable) فونت Vazirmatn همه وزن‌ها را در یک فایل woff2 دارد و با font-display: swap متن هیچ‌وقت نامرئی نمی‌ماند.</p><pre dir="ltr"><code>@font-face {
  font-family: 'Vazirmatn';
  src: url('/fonts/Vazirmatn[wght].woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}</code></pre><h2>letter-spacing منفی، دشمن فارسی</h2><p>کلاس‌هایی مثل tracking-tight که در طراحی انگلیسی رایج‌اند، حروف متصل فارسی را به هم می‌چسبانند یا اتصال‌ها را می‌شکنند. برای متن فارسی فاصله حروف را عادی نگه دارید و به جای آن با وزن و اندازه فونت سلسله‌مراتب بسازید.</p><ul><li>letter-spacing برای فارسی همیشه normal.</li><li>ارتفاع خط متن بدنه فارسی بین ۱.۸ تا ۲؛ بیشتر از انگلیسی.</li><li>برای اعداد در جدول‌ها از font-variant-numeric: tabular-nums استفاده کنید تا ستون‌ها تراز بمانند.</li></ul><h2>ترکیب فارسی و انگلیسی</h2><p>کد، آدرس ایمیل، دامنه و شماره نسخه باید در جهت چپ‌به‌راست نمایش داده شوند، وگرنه نقطه و علامت‌ها جابه‌جا می‌شوند. کافی است این بخش‌ها را در یک المان با dir=&quot;ltr&quot; بگذارید. آیکون‌های جهت‌دار (فلش بازگشت و ادامه) هم در RTL باید قرینه شوند.</p><pre dir="ltr"><code>&lt;p&gt;
  برای ارتباط به
  &lt;span dir=&quot;ltr&quot; class=&quot;font-mono&quot;&gt;hello@example.com&lt;/span&gt;
  ایمیل بزنید.
&lt;/p&gt;</code></pre><h2>جمع‌بندی</h2><p>رابط فارسی خوب از ترجمه رابط انگلیسی به دست نمی‌آید؛ باید از ابتدا با قواعد خط فارسی طراحی شود. فونت محلی، فاصله‌گذاری عادی و جداسازی جهت متن، بیشترین اثر را با کمترین هزینه دارند.</p>]]></content:encoded>
    </item>
    <item>
      <title>کنترل سخت‌افزار ESP32 از راه دور با وب: الگوی Polling ساده و مطمئن</title>
      <link>https://smbz.ir/blog/esp32-remote-control-polling/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/esp32-remote-control-polling/</guid>
      <pubDate>Wed, 14 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>سخت‌افزار و IoT</category>
      <description>معماری ساده برای کنترل یک دستگاه ESP32 (مثل پمپ دوزینگ) از طریق پنل وب، بدون نیاز به IP ثابت یا باز کردن پورت روی مودم؛ با الگوی Polling و وضعیت مطلوب.</description>
      <content:encoded><![CDATA[<p>دستگاهی که پشت مودم خانگی است IP عمومی ندارد و نمی‌شود مستقیم به آن وصل شد. به جای پیچیدگی‌هایی مثل باز کردن پورت، خود دستگاه هر چند ثانیه از سرور می‌پرسد «وضعیت مطلوب چیست؟» و خودش را با آن هماهنگ می‌کند.</p><h2>وضعیت مطلوب به جای فرمان</h2><p>سرور فرمان «روشن کن» نمی‌فرستد؛ وضعیت مطلوب را نگه می‌دارد (مثلاً پمپ ۱ روشن، دبی ۲۰). دستگاه در هر Poll وضعیت واقعی خودش را گزارش می‌دهد و وضعیت مطلوب را می‌گیرد. اگر یک درخواست گم شود، Poll بعدی همه چیز را درست می‌کند؛ هیچ فرمانی دوبار اجرا نمی‌شود.</p><pre dir="ltr"><code>// سرور (Node.js)
app.post('/api/device/sync', auth, (req, res) =&gt; {
  const { deviceId, actual } = req.body;
  devices.set(deviceId, { actual, lastSeen: Date.now() });
  res.json({ desired: desiredState.get(deviceId) ?? {} });
});</code></pre><h2>سمت ESP32</h2><p>حلقه اصلی هر چند ثانیه یک درخواست HTTPS می‌فرستد. اگر شبکه قطع شد، دستگاه آخرین وضعیت امن را حفظ می‌کند و بعد از برگشت اتصال، دوباره همگام می‌شود.</p><pre dir="ltr"><code>void loop() {
  if (millis() - lastSync &gt; SYNC_INTERVAL_MS) {
    lastSync = millis();
    StaticJsonDocument&lt;256&gt; body;
    body[&quot;deviceId&quot;] = DEVICE_ID;
    body[&quot;actual&quot;][&quot;pump1&quot;] = digitalRead(PUMP1_PIN);

    String desired;
    if (postJson(&quot;/api/device/sync&quot;, body, desired)) {
      applyDesiredState(desired);   // فقط تفاوت‌ها را اعمال کن
    }
  }
}</code></pre><ul><li>توکن اختصاصی برای هر دستگاه؛ هیچ endpoint بدون احراز هویت.</li><li>نمایش «آخرین ارتباط» در پنل برای تشخیص آفلاین بودن دستگاه.</li><li>در صورت قطع طولانی، دستگاه به وضعیت امن (مثلاً خاموش) برگردد.</li></ul><h2>جمع‌بندی</h2><p>Polling شاید قدیمی به نظر برسد، اما برای دستگاه‌های پشت NAT ساده‌ترین و مقاوم‌ترین راه است. با الگوی وضعیت مطلوب، گم شدن پیام‌ها دیگر خطرناک نیست.</p>]]></content:encoded>
    </item>
    <item>
      <title>کاردکس کالا و روش FIFO در نرم‌افزار انبارداری: از تئوری تا کوئری</title>
      <link>https://smbz.ir/blog/fifo-inventory-costing/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/fifo-inventory-costing/</guid>
      <pubDate>Mon, 12 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>فین‌تک و حسابداری</category>
      <description>پیاده‌سازی بهای تمام‌شده کالا به روش FIFO در یک نرم‌افزار انبارداری: لایه‌های موجودی، مصرف لایه‌ها هنگام فروش و ثبت سند حسابداری بهای کالای فروش‌رفته.</description>
      <content:encoded><![CDATA[<p>وقتی یک کالا را در زمان‌های مختلف با قیمت‌های متفاوت خریده‌اید، سود واقعی فروش به این بستگی دارد که بهای تمام‌شده را چطور حساب کنید. در روش FIFO (اولین ورودی، اولین خروجی) فرض می‌شود قدیمی‌ترین موجودی زودتر فروخته می‌شود.</p><h2>لایه‌های موجودی</h2><p>هر رسید خرید یک «لایه» با مقدار باقی‌مانده و بهای واحد می‌سازد. موجودی یک کالا جمع مقدار باقی‌مانده همه لایه‌های آن است. این مدل، کاردکس کالا را دقیق و قابل حسابرسی نگه می‌دارد.</p><pre dir="ltr"><code>CREATE TABLE stock_layer (
  id           BIGSERIAL PRIMARY KEY,
  item_id      BIGINT NOT NULL REFERENCES item(id),
  warehouse_id BIGINT NOT NULL REFERENCES warehouse(id),
  received_at  TIMESTAMPTZ NOT NULL,
  qty_in       NUMERIC(18, 3) NOT NULL,
  qty_left     NUMERIC(18, 3) NOT NULL CHECK (qty_left &gt;= 0),
  unit_cost    NUMERIC(20, 2) NOT NULL
);

CREATE INDEX idx_layer_fifo
  ON stock_layer (item_id, warehouse_id, received_at)
  WHERE qty_left &gt; 0;</code></pre><h2>مصرف لایه‌ها هنگام فروش</h2><p>هنگام فروش، از قدیمی‌ترین لایه شروع کرده و مقدار را کم می‌کنیم تا مقدار فروش پوشش داده شود. جمع «مقدار × بهای واحد» لایه‌های مصرف‌شده، بهای کالای فروش‌رفته است. همه این کار باید داخل یک تراکنش و با قفل ردیف‌ها انجام شود تا دو فروش هم‌زمان یک لایه را دوبار مصرف نکنند.</p><pre dir="ltr"><code>async function consumeFifo(tx: Tx, itemId: bigint, whId: bigint, qty: Decimal) {
  const layers = await tx.query(
    `SELECT id, qty_left, unit_cost FROM stock_layer
      WHERE item_id = $1 AND warehouse_id = $2 AND qty_left &gt; 0
      ORDER BY received_at, id
      FOR UPDATE`, [itemId, whId]);

  let remaining = qty;
  let cost = new Decimal(0);
  for (const l of layers.rows) {
    if (remaining.isZero()) break;
    const take = Decimal.min(remaining, l.qty_left);
    await tx.query('UPDATE stock_layer SET qty_left = qty_left - $1 WHERE id = $2',
                   [take.toString(), l.id]);
    cost = cost.plus(take.times(l.unit_cost));
    remaining = remaining.minus(take);
  }
  if (!remaining.isZero()) throw new Error('موجودی کافی نیست');
  return cost; // بهای کالای فروش‌رفته
}</code></pre><ul><li>FOR UPDATE از مصرف هم‌زمان یک لایه جلوگیری می‌کند.</li><li>بهای تمام‌شده با Decimal حساب می‌شود، نه Float.</li><li>سند حسابداری بهای کالای فروش‌رفته در همان تراکنش ثبت شود.</li></ul><h2>جمع‌بندی</h2><p>FIFO وقتی درست پیاده شود، هم کاردکس کالا را قابل اعتماد می‌کند و هم سود واقعی هر فروش را نشان می‌دهد. کلید کار، لایه‌های صریح، تراکنش و قفل ردیف است.</p>]]></content:encoded>
    </item>
    <item>
      <title>چرا در محاسبات مالی و فین‌تک هرگز نباید از Floating Point استفاده کرد؟</title>
      <link>https://smbz.ir/blog/float-vs-decimal-in-fintech/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/float-vs-decimal-in-fintech/</guid>
      <pubDate>Wed, 07 Oct 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>فین‌تک و حسابداری</category>
      <description>بررسی خطاهای پنهان استاندارد IEEE 754 در محاسبات اعشاری نرم‌افزارهای حسابداری و راهکارهای پیاده‌سازی موتور مالی با دقت دلخواه (Arbitrary Precision).</description>
      <content:encoded><![CDATA[<p>در سیستم‌های مالی، حسابداری دوبل و درگاه‌های پرداخت، استفاده از انواع ممیز شناور (Float یا Double) می‌تواند منجر به خطاهای پنهان اعشاری شود. در این مقاله به بررسی علت این رخداد و راهکارهای تضمین تراز صفر مطلق می‌پردازیم.</p><h2>چالش بازنمایی باینری در اعداد اعشاری</h2><p>پردازنده‌ها اعداد اعشاری را بر اساس استاندارد IEEE 754 به صورت باینری ذخیره می‌کنند. برخی اعداد دهدهی ساده مانند ۰.۱ بازنمایی متناهی در مبنای دو ندارند، بنابراین در محاسبات مقادیر بسیار کوچکی اختلاف به وجود می‌آید که در حجم بالای تراکنش‌ها تراز مالی را مخدوش می‌کند.</p><pre dir="ltr"><code>// مثال خطای محاسباتی ممیز شناور:
const result = 0.1 + 0.2; // خروجی: 0.30000000000000004

// راهکار استاندارد با کتابخانه‌های دقت اعشار دلخواه:
import Decimal from 'decimal.js';
const safeResult = new Decimal('0.1').plus('0.2'); // خروجی دقیق: 0.3</code></pre><ul><li>ذخیره مبالغ پولی در دیتابیس با نوع داده‌ای NUMERIC یا DECIMAL به جای FLOAT.</li><li>تبادل مقادیر مالی در APIها در قالب رشته (String) برای جلوگیری از گرد شدن در کلاینت.</li><li>انجام تمام محاسبات سود، زیان و مالیات با کتابخانه‌های Decimal.</li></ul><h2>اعتبارسنجی توازن اسناد مالی دوطرفه (Double-Entry)</h2><p>در یک سیستم حسابداری استاندارد، مجموع ستون بدهکار (Debit) باید دقیقاً با ستون بستانکار (Credit) برابر باشد. پیش از ذخیره سند در دیتابیس، موتور ثبت سند باید توازن مطلق را تایید کند.</p><pre dir="ltr"><code>function isBalanced(entries: { debit: string; credit: string }[]): boolean {
  let diff = new Decimal('0');
  for (const entry of entries) {
    diff = diff.plus(new Decimal(entry.debit)).minus(new Decimal(entry.credit));
  }
  return diff.isZero(); // تراز باید دقیقاً صفر باشد
}</code></pre><h2>جمع‌بندی</h2><p>در توسعه سامانه‌های مالی، دقت ریاضیاتی اولویت اول است. با کنار گذاشتن Float و استفاده از رویکرد رشته‌ای/Decimal، از مغایرت‌های مالی جلوگیری می‌شود.</p>]]></content:encoded>
    </item>
    <item>
      <title>راهنمای تفکیک ترافیک چند دامنه روی پورت ۴۴۳ با Nginx Stream SNI</title>
      <link>https://smbz.ir/blog/nginx-stream-sni-routing/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/nginx-stream-sni-routing/</guid>
      <pubDate>Sat, 19 Sep 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>زیرساخت و لینوکس</category>
      <description>آموزش پیکربندی ماژول Stream در Nginx برای هدایت هوشمند ترافیک TLS به سرویس‌های مختلف داخلی بدون نیاز به باز کردن پورت‌های متعدد.</description>
      <content:encoded><![CDATA[<p>هنگامی که چندین سرویس مستقل (مانند وب‌سایت اصلی، API، پنل مدیریت و ورکرها) روی یک سرور یا زیرساخت قرار دارند، استفاده از قابلیت SNI Preread به شما امکان می‌دهد ترافیک لایه TCP را بر اساس نام دامنه (SNI) مستقیماً به پورت‌ها یا کانتینرهای مختلف هدایت کنید.</p><h2>مفهوم SNI Preread در لایه انتقال (Layer 4)</h2><p>در این معماری، Nginx ابتدا در لایه Stream اطلاعات سرآیند TLS ClientHello را خوانده و بدون اینکه نیاز به بازگشایی یا دستکاری گواهینامه در ورودی اصلی باشد، ترافیک را به سرویس مقصد ارسال می‌کند.</p><ul><li>امکان میزبانی چندین سرویس مستقل روی پورت استاندارد ۴۴۳.</li><li>تفکیک تمیز ترافیک میکروسرویس‌ها بدون درگیر کردن کدهای اپلیکیشن.</li><li>حفظ آی‌پی واقعی کلاینت با فعال‌سازی پروتکل Proxy Protocol.</li></ul><h2>نمونه کانفیگ عمومی Nginx Stream SNI</h2><p>در قطعه کد زیر نمونه‌ای از پیکربندی استاندارد Nginx برای تفکیک دامنه‌های نمونه به پورت‌های لوکال آورده شده است:</p><pre dir="ltr"><code>stream {
  map $ssl_preread_server_name $backend_pool {
    app.example.com      127.0.0.1:8001;
    api.example.com      127.0.0.1:8002;
    panel.example.com    127.0.0.1:8003;
    default              127.0.0.1:8001;
  }

  server {
    listen 443;
    proxy_pass $backend_pool;
    ssl_preread on;
    proxy_protocol on;
  }
}</code></pre><h2>جمع‌بندی</h2><p>معماری SNI Splitter به ساده‌سازی مدیریت فایروال سرورها کمک کرده و اجازه می‌دهد سرویس‌های ایزوله روی پورت استاندارد وب فعالیت کنند.</p>]]></content:encoded>
    </item>
    <item>
      <title>الگوی طراحی ایجنت‌های هوش مصنوعی (LLM Agents) متصل به پایگاه داده</title>
      <link>https://smbz.ir/blog/building-production-llm-agents/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/building-production-llm-agents/</guid>
      <pubDate>Thu, 03 Sep 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>هوش مصنوعی</category>
      <description>چگونه ایجنت‌های پاسخگویی هوشمند را به دیتابیس متصل کنیم تا بدون خطر توهم (Hallucination) به سوالات کاربران پاسخ داده و عملیات تجاری را انجام دهند.</description>
      <content:encoded><![CDATA[<p>استفاده از مدل‌های زبانی بزرگ در نرم‌افزارهای تجاری نیازمند حصار امنیتی (Guardrails) و تفکیک لایه‌های تصمیم‌گیری است تا مدل هرگز اطلاعات ساختگی به مشتری ارائه ندهد.</p><h2>جداسازی استخراج نیت از تولید پاسخ نهایی</h2><p>یک پایپ‌لاین مطمئن نباید مستقیماً پیام کاربر را به پرامپت نهایی تزریق کند. ابتدا در مرحله اول، نیت کاربر (مثلاً استعلام موجودی یا رهگیری سفارش) تشخیص داده شده و پارامترها به فرمت JSON استخراج می‌شوند. سپس داده واقعی از دیتابیس دریافت شده و در مرحله دوم به مدل فرستاده می‌شود.</p><ul><li>استخراج هوشمند موجودیت‌ها (Entities) به شکل JSON ساختاریافته.</li><li>اعتبارسنجی مقادیر با اسکیما پیش از فراخوانی کوئری دیتابیس.</li><li>پاسخگویی به زبان طبیعی بر پایه فکت‌های دریافت شده از سیستم.</li></ul><h2>نمونه الگوی فراخوانی ابزار (Tool Calling)</h2><p>کد نمونه زیر نحوه دریافت وضعیت یک سفارش فرضی از دیتابیس را نشان می‌دهد:</p><pre dir="ltr"><code>async function handleUserQuery(query: string) {
  // ۱. تشخیص نیت و استخراج شناسه
  const intent = await extractIntent(query);
  
  if (intent.type === 'CHECK_ORDER_STATUS') {
    // ۲. دریافت اطلاعات معتبر از پایگاه داده
    const orderData = await db.orders.findById(intent.orderId);
    
    // ۳. تولید پاسخ نهایی به زبان طبیعی با دیتای واقعی
    return await generateResponseWithContext(query, orderData);
  }
}</code></pre><h2>جمع‌بندی</h2><p>ایجنت‌های کاربردی در محیط عملیاتی، بر پایه ساختار داده‌های دقیق و کوئری‌های کنترل‌شده عمل می‌کنند نه بر پایه حدس‌های احتمالی مدل.</p>]]></content:encoded>
    </item>
    <item>
      <title>مدل‌سازی داده‌های ماتریسی چندبعدی در پایگاه‌داده‌های رابطه‌ای</title>
      <link>https://smbz.ir/blog/multi-dimensional-matrix-database-design/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/multi-dimensional-matrix-database-design/</guid>
      <pubDate>Mon, 27 Jul 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>داده و دیتابیس</category>
      <description>راهکارهای بهینه‌سازی جداول پایگاه‌داده برای محصولاتی که دارای چندین بعد پیوسته از مشخصات فنی، رنگ و سایز هستند.</description>
      <content:encoded><![CDATA[<p>بسیاری از سیستم‌های انبارداری و فروشگاهی با اقلامی سر و کار دارند که فراتر از یک شناسه تکی هستند و ویژگی‌های چندبعدی دارند. طراحی درست اسکیما و ایندکس‌ها مانع از کندی کوئری‌ها در تیراژ بالا می‌شود.</p><h2>طراحی اسکیما با شاخص‌های ترکیبی (Composite Indexes)</h2><p>در چنین سیستم‌هایی، ایجاد یک جدول مجزا برای واریانت‌ها با کلید خارجی به محصول اصلی و یک قید یکتایی چندستونی (Composite Unique Constraint) به حفظ یکپارچگی داده‌ها کمک شایانی می‌کند.</p><pre dir="ltr"><code>CREATE TABLE product_variant (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  product_id UUID REFERENCES product(id),
  dimension_x NUMERIC(5, 2) NOT NULL,
  dimension_y NUMERIC(5, 2) NOT NULL,
  stock_quantity INTEGER NOT NULL DEFAULT 0,
  UNIQUE(product_id, dimension_x, dimension_y)
);

CREATE INDEX idx_variant_lookup 
ON product_variant (product_id, dimension_x, dimension_y);</code></pre><h2>جمع‌بندی</h2><p>مدل‌سازی دقیق ابعاد کالا در سطح دیتابیس، فرآیند ثبت فاکتور و کنترل موجودی انبار را سریع و بدون مغایرت نگاه می‌دارد.</p>]]></content:encoded>
    </item>
    <item>
      <title>مدیریت ریسک و اندازه پوزیشن در سیستم‌های معاملات الگوریتمی</title>
      <link>https://smbz.ir/blog/risk-management-quantitative-systems/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/risk-management-quantitative-systems/</guid>
      <pubDate>Thu, 09 Jul 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>معاملات الگوریتمی</category>
      <description>فرمول‌های کاربردی مدیریت سرمایه، پایش نوسان‌پذیری بازار و جلوگیری از افت ارزش سرمایه (Drawdown) در ربات‌های معاملاتی.</description>
      <content:encoded><![CDATA[<p>در بازارهای مالی پویا، حفظ بقا و سرمایه اولیه همواره بر سودآوری اولویت دارد. هر سیستم الگوریتمی باید مجهز به مکانیسم‌های پویا برای کنترل ریسک هر موقعیت معاملاتی باشد.</p><h2>محاسبه اندازه موقعیت بر اساس نوسان و حد ضرر</h2><p>به جای ورود با حجم ثابت، سیستم‌های کمی حجم معامله را بر مبنای درصدی مشخص از کل سرمایه و فاصله تا حد ضرر تعیین می‌کنند تا نوسانات شدید بازار حساب را با بحران مواجه نکند.</p><pre dir="ltr"><code>def calculate_position_size(account_equity, risk_percent, stop_loss_distance, point_value):
    &quot;&quot;&quot;
    محاسبه حجم بهینه ورود بر اساس درصد ریسک مشخص
    &quot;&quot;&quot;
    max_risk_amount = account_equity * (risk_percent / 100.0)
    position_size = max_risk_amount / (stop_loss_distance * point_value)
    return round(position_size, 2)</code></pre><ul><li>محدود کردن ریسک هر معامله به ۱ الی ۲ درصد کل موجودی.</li><li>تنظیم خودکار حد ضرر بر اساس شاخص‌های نوسان‌پذیری میانگین دامنه واقعی (ATR).</li><li>پایش بلادرنگ میزان افت سرمایه روزانه و غیرفعال‌سازی موقت در شرایط بحرانی.</li></ul><h2>جمع‌بندی</h2><p>موفقیت در معاملات خودکار نتیجه ترکیب انضباط آماری، تست‌های تاریخی معتبر و پایبندی به قوانین سفت‌وسخت مدیریت ریسک است.</p>]]></content:encoded>
    </item>
    <item>
      <title>پردازش و بهینه‌سازی خودکار و دسته‌ای تصاویر در وب‌سایت‌های مقیاس‌پذیر</title>
      <link>https://smbz.ir/blog/batch-image-processing-web/</link>
      <guid isPermaLink="true">https://smbz.ir/blog/batch-image-processing-web/</guid>
      <pubDate>Tue, 23 Jun 2026 04:30:00 GMT</pubDate>
      <dc:creator>سید محمد بهبهانی‌زاده</dc:creator>
      <category>مقاله</category>
      <category>وب، سئو و فرانت‌اند</category>
      <description>خط لوله خودکار فشرده‌سازی تصاویر محصولات با فرمت‌های نوین WebP و AVIF، بهبود سرعت بارگذاری و ارتقای امتیاز Core Web Vitals.</description>
      <content:encoded><![CDATA[<p>تصاویر محصولات معمولاً بیش از ۶۰ درصد از حجم صفحات فروشگاه‌ها و پلتفرم‌های اینترنتی را به خود اختصاص می‌دهند. پردازش دستی یا انتشار تصاویر حجیم سرعت تعامل کاربر را کاهش می‌دهد.</p><h2>خط لوله پردازش خودکار با Sharp</h2><p>با استفاده از کتابخانه‌های پردازش باینری تصویر در محیط Node.js مانند Sharp، می‌توان به سادگی تصاویری با رزولوشن بالا را بدون افت وضوح به فرمت‌های سبک تبدیل کرد.</p><pre dir="ltr"><code>import sharp from 'sharp';

async function processProductImage(inputBuffer: Buffer): Promise&lt;Buffer&gt; {
  return await sharp(inputBuffer)
    .resize(1200, 900, { fit: 'inside', withoutEnlargement: true })
    .webp({ quality: 80, effort: 4 })
    .toBuffer();
}</code></pre><ul><li>کاهش حجم تصاویر تا ۷۰٪ با مهاجرت از JPEG به WebP و AVIF.</li><li>حفظ استاندارد ریسپانسیو و بهینه‌سازی سرعت رندر اولیه (LCP).</li><li>اجرای خودکار پردازش در هنگام آپلود فایل بدون نیاز به مداخله انسانی.</li></ul><h2>جمع‌بندی</h2><p>اتوماسیون پردازش مدیا یکی از موثرترین اقدامات برای دستیابی به تجربه کاربری روان و بهینه‌سازی سئو در پلتفرم‌های اینترنتی است.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
