Added FA version of integrations documents

This commit is contained in:
SepehrYahyaee
2026-08-18 11:24:06 +03:30
parent bfbcfcab37
commit f09f5b79f0

View File

@@ -0,0 +1,596 @@
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8" />
<title>مرجع یکپارچه‌سازی‌های خارجی</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: "Vazirmatn", "Tahoma", "Segoe UI", system-ui, sans-serif;
font-size: 14px; line-height: 1.8;
background: #ffffff; color: #1f2328; padding: 24px;
}
h1 { font-size: 20px; font-weight: 700; margin-bottom: 4px; }
.subtitle { font-size: 13px; color: #57606a; margin-bottom: 28px; }
h2 {
font-size: 15px; font-weight: 700;
margin-bottom: 10px; margin-top: 32px;
border-bottom: 1px solid #e5e7eb; padding-bottom: 6px;
}
h3 {
font-size: 12px; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.03em;
color: #57606a; margin-bottom: 8px; margin-top: 14px;
}
.section-intro {
font-size: 13px; color: #57606a;
margin-bottom: 14px; line-height: 1.7;
}
.card {
border: 1px solid #e5e7eb; border-radius: 6px;
padding: 16px; background: #f7f8fa; margin-bottom: 16px;
}
.card.card-blue { border-right: 4px solid #3b82f6; }
.card.card-green { border-right: 4px solid #22c55e; }
.card.card-purple { border-right: 4px solid #8b5cf6; }
.card.card-orange { border-right: 4px solid #f97316; }
.card.card-teal { border-right: 4px solid #14b8a6; }
.card.card-indigo { border-right: 4px solid #6366f1; }
.card.card-gray { border-right: 4px solid #94a3b8; }
.card.card-red { border-right: 4px solid #ef4444; }
.card.card-yellow { border-right: 4px solid #eab308; }
table {
border-collapse: collapse; width: 100%;
font-size: 12px; margin-top: 4px; direction: rtl;
}
th {
background: #f1f5f9; font-weight: 600;
text-align: right; padding: 5px 8px; border: 1px solid #e5e7eb;
}
td { padding: 4px 8px; border: 1px solid #e5e7eb; vertical-align: top; }
tr:nth-child(even) td { background: #ffffff; }
code {
font-family: monospace; font-size: 11px; color: #3b82d4;
direction: ltr; unicode-bidi: embed;
}
.method {
font-family: monospace; font-size: 11px;
font-weight: 700; white-space: nowrap;
direction: ltr; unicode-bidi: embed;
}
.method.get { color: #059669; }
.method.post { color: #2563eb; }
.method.put { color: #d97706; }
.method.patch { color: #7c3aed; }
.note { font-size: 11px; color: #57606a; font-style: normal; margin-top: 6px; }
.warn { font-size: 11px; color: #9a3412; font-style: normal; margin-top: 6px; }
.status-badge {
display: inline-block; font-size: 11px; font-weight: 600;
padding: 1px 7px; border-radius: 10px;
}
.status-live { background: #dcfce7; color: #166534; }
.status-partial { background: #ffedd5; color: #9a3412; }
.status-disabled { background: #fee2e2; color: #991b1b; }
.status-internal { background: #f1f5f9; color: #475569; border: 1px solid #e2e8f0; }
.toc {
background: #f7f8fa; border: 1px solid #e5e7eb;
border-radius: 6px; padding: 14px 18px; margin-bottom: 28px;
}
.toc-title { font-size: 13px; font-weight: 700; margin-bottom: 8px; }
.toc ol { padding-right: 18px; padding-left: 0; }
.toc li { font-size: 13px; margin-bottom: 3px; }
.toc a { color: #3b82d4; text-decoration: none; }
.toc a:hover { text-decoration: underline; }
footer {
text-align: center; font-size: 12px; color: #57606a;
border-top: 1px solid #e5e7eb; margin-top: 40px; padding-top: 12px;
}
.max-wrap { max-width: 760px; margin: 0 auto; }
.flow-box {
background: #ffffff; border: 1px solid #e5e7eb; border-radius: 4px;
padding: 10px 14px; font-size: 12px; margin-top: 8px;
}
.flow-step {
display: flex; gap: 10px; align-items: flex-start; margin-bottom: 6px;
direction: rtl;
}
.flow-num {
flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%;
background: #3b82d4; color: #fff; font-size: 11px; font-weight: 700;
display: flex; align-items: center; justify-content: center;
}
.flow-text { flex: 1; padding-top: 2px; }
.decision-tree {
font-size: 12px; background: #ffffff;
border: 1px solid #e5e7eb; border-radius: 4px; padding: 12px 16px;
margin-top: 8px; line-height: 1.9;
}
.decision-tree ul { padding-right: 20px; padding-left: 0; }
.decision-tree li { margin-bottom: 2px; }
.env-table th:last-child { width: 220px; }
pre {
font-family: monospace; font-size: 11px;
background: #f1f5f9; border: 1px solid #e5e7eb;
border-radius: 4px; padding: 10px 12px;
white-space: pre-wrap; word-break: break-all;
margin-top: 6px; color: #1f2328;
direction: ltr; unicode-bidi: embed;
}
</style>
</head>
<body>
<div class="max-wrap">
<h1>مرجع یکپارچه‌سازی‌های خارجی</h1>
<p class="subtitle">
تمام یکپارچه‌سازی‌های خروجی: کاربرد، زمان فعال‌شدن، نحوه احراز هویت،
رفتار retry، fallbackها و تمام متغیرهای محیطی. سرویس‌های داخلی
(کپچا، داده‌های پرس‌وجوی آفلاین) برای کامل‌بودن گنجانده شده‌اند.
</p>
<!-- TOC -->
<div class="toc">
<div class="toc-title">فهرست</div>
<ol>
<li><a href="#inquiry-routing">درخت تصمیم مسیریابی پرس‌وجو</a></li>
<li><a href="#fanavaran">فناوران — پلتفرم خسارت بیمه</a></li>
<li><a href="#sanhub">SandHub — درگاه پرس‌وجوی قدیمی</a></li>
<li><a href="#tejarat">پرس‌وجوی تجارت — درگاه block-inquiry (V2+)</a></li>
<li><a href="#esg">ESG — ارائه‌دهنده پرس‌وجوی تنانت پارسیان</a></li>
<li><a href="#sms">پیامک — درگاه‌های کاوه‌نگار و پارسیان</a></li>
<li><a href="#ai">سرویس هوش مصنوعی — تشخیص خسارت خودرو</a></li>
<li><a href="#car-pricing">سرویس قیمت خودرو — جستجوی ارزش بازار</a></li>
<li><a href="#offline-inquiry">پرس‌وجوی آفلاین — داده‌های fallback</a></li>
<li><a href="#env-ref">مرجع متغیرهای محیطی</a></li>
</ol>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="inquiry-routing">۱ — درخت تصمیم مسیریابی پرس‌وجو</h2>
<p class="section-intro">
هر فایل تقصیر با فراخوانی "run-inquiries" آغاز می‌شود که بیمه‌نامه طرف مقصر
را از یک ارائه‌دهنده خارجی دریافت می‌کند. اینکه کدام ارائه‌دهنده واقعاً فراخوانی
می‌شود به سه عامل بستگی دارد: تنانت (<code>CLIENT_ID</code>)، نوع فایل
(THIRD_PARTY در مقابل CAR_BODY) و اینکه آیا حالت API زنده در تنظیمات سیستم
فعال است یا خیر. لایه داده‌های پرس‌وجوی آفلاین در جلوی هر سه ارائه‌دهنده قرار دارد.
</p>
<div class="card card-indigo">
<h3>انتخاب ارائه‌دهنده</h3>
<div class="decision-tree">
<strong>برای هر پرس‌وجوی مبتنی بر پلاک:</strong>
<ul>
<li>۱. بررسی داده‌های آفلاین (MongoDB) — اگر داده مطابق یافت شد، آن را برگردانده و تمام HTTP را رد کن.</li>
<li>۲. اگر <code>CLIENT_ID=8</code> (تنانت پارسیان/ESG) → مسیریابی به <strong>ESG</strong> <code>/inquiry/policyByPlate</code> یا <code>/inquiry/policyByChassis</code>.</li>
<li>۳. در غیر این صورت → مسیریابی به <strong>پرس‌وجوی تجارت</strong> <code>/block-inquiry-tejarat</code> (THIRD_PARTY) یا <code>/block-inquiry-tejarat/badane</code> (CAR_BODY).</li>
<li>۴. اگر <code>system_settings.externalApis.sandHubUseLiveApi = false</code> (پیش‌فرض) → پاسخ mock برگردانده شود به جای انجام فراخوانی‌های HTTP.</li>
</ul>
<br>
<strong>برای بررسی‌های هویت شخصی، گواهینامه، مالکیت و شبا:</strong>
<ul>
<li>اگر <code>CLIENT_ID=8</code> → ESG <code>/inquiry/person</code> و <code>/inquiry/sheba</code>.</li>
<li>در غیر این صورت → تجارت/SandHub <code>/personal-inquiry/tejarat-no</code>، <code>/driver-license-check</code>، <code>/ownership</code>، <code>/sheba/sheba-tejaratno</code>.</li>
</ul>
<br>
<strong>تفاوت کلیدی — فرمت تاریخ تولد:</strong>
SandHub/تجارت تاریخ تولد <em>میلادی</em> انتظار دارند (داخلی از جلالی تبدیل می‌شود).
ESG مستقیماً تاریخ <em>جلالی</em> انتظار دارد.
</div>
<p class="note" style="margin-top:8px;">
اندپوینت‌های SandHub فقط در مسیرهای قدیمی کد استفاده می‌شوند. تمام جریان‌های فعال تقصیر V2+ از طریق ارائه‌دهندگان تجارت یا ESG می‌روند.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="fanavaran">۲ — فناوران <span class="status-badge status-live">فعال</span></h2>
<p class="section-intro">
فناوران (<code>apimanager.iraneit.com</code>) پلتفرم ملی پرونده خسارت بیمه است.
پس از اینکه کارشناس خسارت ارزیابی خود را ارسال می‌کند، سیستم به‌صورت خودکار
یک خسارت ساختاریافته را از طریق یک پروتکل چهار مرحله‌ای به فناوران ارسال می‌کند.
فناوران همچنین به‌عنوان منبع جستجوی code-listها (انواع تصادف، اجزای خودرو،
کدهای شهر و غیره) در سراسر پلتفرم عمل می‌کند.
</p>
<div class="card card-blue">
<h3>چرخه حیات احراز هویت</h3>
<div class="flow-box">
<div class="flow-step"><div class="flow-num">۱</div><div class="flow-text"><strong>GET AppToken</strong> — <code>POST /EITAuthentication/GetAppToken</code> با هدرهای <code>appname</code> + <code>secret</code>. هدر <code>apptoken</code> را برمی‌گرداند.</div></div>
<div class="flow-step"><div class="flow-num">۲</div><div class="flow-text"><strong>Login</strong> — <code>POST /EITAuthentication/Login</code> با هدرهای <code>appToken</code> + <code>userName</code> + <code>password</code>. هدر <code>authenticationToken</code> را برمی‌گرداند.</div></div>
<div class="flow-step"><div class="flow-num">۳</div><div class="flow-text"><strong>Cache</strong> — توکن در حافظه <em>و</em> پایدار در MongoDB (<code>fanavaran_auth_tokens</code>) ذخیره می‌شود. تا نیمه‌شب <strong>Asia/Tehran</strong> معتبر است — اولین فراخوانی پس از ۰۰:۰۰ یک توکن تازه دریافت می‌کند.</div></div>
<div class="flow-step"><div class="flow-num">۴</div><div class="flow-text"><strong>تمام فراخوانی‌های بعدی</strong> چهار هدر شامل می‌شوند: <code>authenticationToken</code>، <code>CorpId</code>، <code>ContractId</code>، <code>Location</code> — مختص تنانت، hardcoded به ازای هر کلید <code>FANAVARAN_CLIENT</code>.</div></div>
</div>
<p class="note" style="margin-top:8px;">
یک اثر انگشت پیکربندی (هش appName + secret + username + password + corpId + contractId + location)
یک ورود تازه را زمانی که هر مدرکی تغییر کند، حتی قبل از نیمه‌شب، مجبور می‌کند.
</p>
</div>
<div class="card card-blue">
<h3>پروتکل ارسال خسارت (۴ مرحله)</h3>
<div class="flow-box">
<div class="flow-step"><div class="flow-num">۱</div><div class="flow-text"><strong>خسارت پایه (GEN.03)</strong> — <code>POST /car/third-party-car-financial-claims</code>. داده‌های مالک، راننده، بیمه، وسیله نقلیه و تصادف را ارسال می‌کند. یک <code>claimId</code> و <code>claimNo</code> فناوران برمی‌گرداند. پیامک با هر دو شناسه برای مالک ارسال می‌شود.</div></div>
<div class="flow-step"><div class="flow-num">۲</div><div class="flow-text"><strong>موارد خسارت (GEN.05)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/dmg-cases</code>. یک ورودی به ازای هر قطعه آسیب‌دیده با شناسه کامپوننت، شدت و قیمت. سقف: کل ≤ ۵۳،۰۰۰،۰۰۰ تومان.</div></div>
<div class="flow-step"><div class="flow-num">۳</div><div class="flow-text"><strong>پیوست‌ها (GEN.07)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/files</code>. اسناد، تصاویر car-capture و ویدیوها که با شناسه فایل ارجاع داده شده‌اند.</div></div>
<div class="flow-step"><div class="flow-num">۴</div><div class="flow-text"><strong>کارشناسی (GEN.08)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/expertise</code>. متادیتای ارزیابی کارشناس (نقش کارشناس، تاریخ، نتیجه). ارسال را نهایی می‌کند.</div></div>
</div>
<p class="note" style="margin-top:8px;">
هر چهار مرحله در مجموعه <code>fanavaran_audit_logs</code> با بدنه کامل درخواست/پاسخ، وضعیت HTTP، مدت زمان و کد ردیابی برای اشکال‌زدایی ثبت می‌شوند.
</p>
</div>
<div class="card card-blue">
<h3>اندپوینت‌های Lookup</h3>
<p class="note">همه زیر <code>https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/</code>. نتایج روی دیسک (به ازای کلید مشتری) و در مجموعه MongoDB <code>lookups</code> کش می‌شوند. تنانت پارسیان قبل از درخواست API از DB می‌خواند؛ دیگران ابتدا به API می‌روند.</p>
<table>
<tr><th>کاربرد</th><th>مسیر</th></tr>
<tr><td>گزینه‌های dropdown برای accidentReason (نگاشت شده به شناسه‌های محلی)</td><td><code>/car/base-info/accident-causes</code></td></tr>
<tr><td>گزینه‌های accidentWay</td><td><code>/car/code-list/accident-report-type</code></td></tr>
<tr><td>طبقه‌بندی استفاده از وسیله نقلیه</td><td><code>/car/base-info/vehicle-use-types</code></td></tr>
<tr><td>روش پرداخت خسارت</td><td><code>/car/code-list/dmg-pay-method</code></td></tr>
<tr><td>گزینه‌های نوع گواهینامه</td><td><code>/car/base-info/driving-licence-types</code></td></tr>
<tr><td>طبقه‌بندی طرف مقصر</td><td><code>/car/code-list/accident-culprit-type</code></td></tr>
<tr><td>گزینه‌های محل بازرسی</td><td><code>/car/code-list/inspection-place</code></td></tr>
<tr><td>کدهای وضعیت کاهش قیمت</td><td><code>/car/code-list/drop-amount-status</code></td></tr>
<tr><td>کاتالوگ کامپوننت (نگاشت به قطعات بیرونی/داخلی)</td><td><code>/car/base-info/car-components</code></td></tr>
<tr><td>گزینه‌های شدت تصادف</td><td><code>/car/code-list/accident-level</code></td></tr>
<tr><td>تطبیق <code>INSURANCE_CORP_ID</code> ← corpId فناوران</td><td><code>/common/code-list/insurance-corp</code></td></tr>
<tr><td>انتخابگرهای شهر/استان</td><td><code>/common/base-info/cities</code>، <code>/common/base-info/Provinces</code></td></tr>
<tr><td>دریافت بیمه‌نامه کامل بر اساس شناسه پس از استعلام</td><td><code>/car/third-party-car-policies/{policyId}</code></td></tr>
<tr><td>جستجوی وسیله نقلیه بر اساس VIN</td><td><code>/car/vehicles/inquiry-by-vin?vin=…</code></td></tr>
<tr><td>فهرست بیمه‌نامه‌ها برای یک کد ملی</td><td><code>/common/Policies/inquiry-my-policies</code></td></tr>
<tr><td>دریافت رکورد مشتری بر اساس شناسه</td><td><code>/common/customers/{customerId}</code></td></tr>
<tr><td>جستجوی طرف بر اساس کد ملی + تاریخ تولد</td><td><code>/common/parties/inquiry-by-unique-identifier</code></td></tr>
</table>
</div>
<div class="card card-blue">
<h3>مدیریت خطا و انعطاف‌پذیری</h3>
<table>
<tr><th>توضیح</th><th>مکانیزم</th></tr>
<tr><td>۳ تلاش، ۵۰۰ ms ← ۱۰۰۰ ms backoff نمایی در تمام فراخوانی‌های HTTP.</td><td>Retry</td></tr>
<tr><td>وقتی فناوران پیام فارسی "دوباره تلاش کنید" (یا tracking-code 500) برمی‌گرداند، یک مکث ۵ دقیقه‌ای در سطح تنانت فعال می‌شود. تمام فراخوانی‌ها در این پنجره بلافاصله <code>503 ServiceUnavailable</code> دریافت می‌کنند — بدون فشار.</td><td>Backoff گذرا</td></tr>
<tr><td>در ۴۰۱، توکن از حافظه و MongoDB پاک می‌شود؛ فراخوانی بعدی GetAppToken + Login تازه را فعال می‌کند.</td><td>ابطال توکن</td></tr>
<tr><td>درخواست‌های همزمان ورود برای همان تنانت به یک Promise در حال پرواز جمع می‌شوند.</td><td>حذف تکراری Inflight</td></tr>
<tr><td>هر مرحله (GET_APP_TOKEN، LOGIN و هر چهار مرحله ارسال) در <code>fanavaran_audit_logs</code> با وضعیت STARTED / SUCCESS / FAILURE، هدرهای کامل، بدنه و مدت زمان نوشته می‌شود.</td><td>لاگ Audit</td></tr>
<tr><td>۲۰–۳۰ ثانیه به ازای هر فراخوانی HTTP.</td><td>Timeout</td></tr>
</table>
</div>
<div class="card card-blue">
<h3>پروفایل‌های تنانت (<code>FANAVARAN_CLIENT</code>)</h3>
<p class="section-intro" style="margin-top:6px; margin-bottom:8px;">سه پروفایل تنانت از پیش تعیین‌شده وجود دارد. پروفایل فعال توسط متغیر محیطی <code>FANAVARAN_CLIENT</code> انتخاب می‌شود. هر پروفایل <code>appName</code>، <code>secret</code>، <code>username</code>، <code>password</code>، <code>CorpId</code>، <code>ContractId</code> و <code>Location</code> هدرهای خود را به علاوه پیش‌فرض‌های payload (AccidentCityId و غیره) دارد.</p>
<table>
<tr><th>شرکت بیمه</th><th>کلید</th></tr>
<tr><td>بیمه پارسیان</td><td><code>parsian</code></td></tr>
<tr><td>بیمه تجارت نو</td><td><code>tejaratno</code></td></tr>
<tr><td>بیمه معلم</td><td><code>moallem</code></td></tr>
</table>
<p class="note" style="margin-top:8px;">
<code>INSURANCE_CORP_ID</code> یک رشته عنوان نمایشی است (مثلاً <em>"بیمه پارسیان"</em>) که در برابر فهرست زنده فناوران <code>insurance-corp</code> تطبیق داده می‌شود تا <code>corpId</code> عددی مورد استفاده در ارسال‌ها را تولید کند. شناسه تطبیق‌یافته روی دیسک کش می‌شود.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="sanhub">۳ — SandHub <span class="status-badge status-partial">قدیمی</span></h2>
<p class="section-intro">
SandHub درگاه پرس‌وجوی اصلی است. هنوز در کدبیس حضور دارد اما تمام جریان‌های
فعال تقصیر (V2+) به ارائه‌دهنده پرس‌وجوی تجارت منتقل شده‌اند. اندپوینت‌های
SandHub قابل فراخوانی هستند اما فقط از طریق مسیرهای قدیمی کد قابل دسترسی هستند.
حالت mock آن توسط همان تنظیم سیستم <code>sandHubUseLiveApi</code> کنترل می‌شود.
</p>
<div class="card card-gray">
<h3>احراز هویت</h3>
<p class="note">
<code>POST {SANHUB_BASE_URL}/user/login</code> با بدنه JSON نام کاربری + رمز عبور.
توکن در حافظه برای <strong>۵۵ دقیقه</strong> کش می‌شود. در ۴۰۱، توکن پاک می‌شود و یک تلاش مجدد انجام می‌شود.
۳ تلاش با ۱۰۰۰ ms ← ۲۰۰۰ ms backoff نمایی.
</p>
</div>
<div class="card card-gray">
<h3>اندپوینت‌ها</h3>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat</code></td><td>پرس‌وجوی بیمه‌نامه مبتنی بر پلاک (THIRD_PARTY). بدنه: <code>leftTwoDigits</code>، <code>serialLetter</code>، <code>threeDigits</code>، <code>rightTwoDigits</code>، <code>nationalCode</code>.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat/badane</code></td><td>پرس‌وجوی بیمه‌نامه CAR_BODY. Timeout ۵۰ ثانیه (طولانی‌تر از استاندارد).</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/personal-inquiry/tejarat-no</code></td><td>بررسی هویت شخصی. بدنه: <code>nationalCode</code> + <code>birthDate</code> <em>میلادی</em> (داخلی از جلالی تبدیل می‌شود).</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/driver-license-check</code></td><td>اعتبارسنجی گواهینامه. پرچم <code>IsSucceed</code> را برمی‌گرداند.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/ownership</code></td><td>بررسی مالکیت وسیله نقلیه. پرچم <code>IsSuccess</code> را برمی‌گرداند.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/sheba/sheba-tejaratno</code></td><td>اعتبارسنجی شبا / حساب بانکی. <code>ReturnValue</code> + <code>HasError</code> را برمی‌گرداند.</td></tr>
</table>
<p class="note" style="margin-top:8px;">
تمام اندپوینت‌ها پاسخ‌های mock کامل را زمانی که <code>sandHubUseLiveApi=false</code> در تنظیمات سیستم (پیش‌فرض) پشتیبانی می‌کنند. داده‌های mock قطعی هستند و به‌صورت محلی بدون هیچ فراخوانی HTTP تولید می‌شوند.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="tejarat">۴ — پرس‌وجوی تجارت <span class="status-badge status-live">فعال</span></h2>
<p class="section-intro">
درگاه فعال block-inquiry برای تمام تنانت‌های غیر ESG. در هر فراخوانی V2+
<code>run-inquiries</code> که <code>CLIENT_ID ≠ 8</code> استفاده می‌شود.
URL پایه قابل پیکربندی است؛ در تولید به همان هاست SandHub اشاره می‌کند اما از
اعتبارنامه‌های جداگانه استفاده می‌کند.
</p>
<div class="card card-teal">
<h3>احراز هویت</h3>
<p class="note">
<code>POST {TEJARAT_INQUIRY_BASE_URL}/user/login</code> با بدنه JSON ایمیل + رمز عبور.
توکن برای <strong>۵۵ دقیقه</strong> کش می‌شود. ۲ تلاش با ۵۰۰ ms ← ۱۰۰۰ ms backoff.
جدا از اعتبارنامه‌های SandHub — از <code>TEJARAT_INQUIRY_EMAIL</code> / <code>TEJARAT_INQUIRY_PASSWORD</code> استفاده می‌کند.
</p>
</div>
<div class="card card-teal">
<h3>اندپوینت‌ها</h3>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat</code></td><td>پرس‌وجوی پلاک THIRD_PARTY. بدنه: فیلدهای پلاک + <code>nationalCode</code>. ابتدا داده آفلاین بررسی می‌شود.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat/badane</code></td><td>پرس‌وجوی پلاک CAR_BODY. بدنه: <code>part1–part4</code> (عددی) + <code>nationalCode</code>. همیشه زنده می‌شود (mock برای مسیر badane وجود ندارد).</td></tr>
</table>
<p class="note" style="margin-top:8px;">
وقتی <code>sandHubUseLiveApi=false</code>، مسیر THIRD_PARTY یک پاسخ mock بدون HTTP برمی‌گرداند. مسیر CAR_BODY همیشه API زنده را صرف‌نظر از این پرچم فراخوانی می‌کند.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="esg">۵ — ESG <span class="status-badge status-live">فعال (CLIENT_ID=8)</span></h2>
<p class="section-intro">
ESG یک درگاه API بیمه داخلی است که منحصراً توسط تنانت پارسیان
(<code>CLIENT_ID=8</code>) استفاده می‌شود. برای تمام انواع پرس‌وجو زمانی که
این تنانت فعال است، جایگزین تجارت/SandHub می‌شود. شکل پاسخ متفاوتی دارد،
TTL توکن پویا دارد و تاریخ تولد را در فرمت <strong>جلالی</strong> انتظار دارد
(نه میلادی، برخلاف SandHub/تجارت).
</p>
<div class="card card-purple">
<h3>احراز هویت</h3>
<p class="note">
<code>POST {ESG_URL}/auth/login</code> با بدنه JSON <code>{ username, password }</code>.
TTL توکن از فیلد <code>expiresIn</code> پاسخ خوانده می‌شود (پیش‌فرض ۱۴ دقیقه).
۲ تلاش با ۵۰۰ ms ← ۱۰۰۰ ms backoff. در ۴۰۱، توکن پاک و یک تلاش مجدد.
URL پیش‌فرض: <code>http://192.168.20.22:8085</code> (شبکه داخلی).
</p>
</div>
<div class="card card-purple">
<h3>اندپوینت‌ها</h3>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/policyByPlate</code></td><td>جستجوی بیمه‌نامه مبتنی بر پلاک (THIRD_PARTY). بدنه: <code>nationalCode</code>، <code>plk1–plk4</code>. پاسخ قبل از ذخیره به فرمت قدیمی تجارت نگاشت می‌شود.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/policyByChassis</code></td><td>جایگزین مبتنی بر VIN/شاسی برای پرس‌وجوی پلاک. توسط اندپوینت‌های <code>run-inquiries-vin</code> فراخوانی می‌شود. از جستجوی شاسی ESG استفاده می‌کند (نه مسیر SandHub). بدنه: <code>nationalCode</code>، <code>chassis</code>.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/person</code></td><td>بررسی هویت شخصی. بدنه: <code>nationalCode</code>، <code>birthDate</code> (جلالی، نه میلادی).</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/sheba</code></td><td>اعتبارسنجی شبا / حساب بانکی.</td></tr>
</table>
<p class="note" style="margin-top:8px;">
ESG هر پاسخ را به صورت <code>{ success: boolean, data: … }</code> می‌پیچد. یک بدنه <code>success=false</code> به یک خطای فارسی "استعلام در دسترس نیست" ترجمه می‌شود.
بررسی داده آفلاین-پرس‌وجو هنوز ابتدا اجرا می‌شود، قبل از هر فراخوانی HTTP ESG.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="sms">۶ — پیامک <span class="status-badge status-live">فعال</span></h2>
<p class="section-intro">
دو ارائه‌دهنده پیامک پشتیبانی می‌شوند: <strong>کاوه‌نگار</strong> (پیش‌فرض)
و <strong>درگاه پیامک پارسیان</strong>. ارائه‌دهنده فعال توسط متغیر محیطی
<code>SMS_PROVIDER</code> (یا <code>SMS</code>) انتخاب می‌شود. هر دو ارائه‌دهنده
رابط درگاه داخلی یکسانی را پیاده‌سازی می‌کنند بنابراین لایه ارکستراسیون
مستقل از ارائه‌دهنده است.
</p>
<div class="card card-green">
<h3>انتخاب ارائه‌دهنده</h3>
<table>
<tr><th>ارائه‌دهنده فعال</th><th>مقدار</th><th>متغیر محیطی</th></tr>
<tr><td>کاوه‌نگار — <code>api.kavenegar.com</code></td><td><code>kavenegar</code> (پیش‌فرض)</td><td><code>SMS_PROVIDER</code> (یا <code>SMS</code>)</td></tr>
<tr><td>درگاه پیامک پارسیان — <code>PARSIAN_SMS_URL</code></td><td><code>parsian</code></td><td><code>SMS_PROVIDER</code> (یا <code>SMS</code>)</td></tr>
</table>
</div>
<div class="card card-green">
<h3>اندپوینت‌های کاوه‌نگار</h3>
<p class="note">URL پایه: <code>https://api.kavenegar.com/v1/{SMS_API_KEY}/</code></p>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>زمان استفاده</th></tr>
<tr><td><span class="method post">POST</span></td><td><code>sms/send.json</code></td><td>پیام‌های متن ساده (مثلاً متن‌های اطلاع‌رسانی مبتنی بر کلید ذخیره‌شده در مجموعه <code>sms_texts</code>).</td></tr>
<tr><td><span class="method get">GET</span></td><td><code>verify/lookup.json</code></td><td>تمام پیام‌های مبتنی بر قالب (OTPها، لینک‌های دعوت، اطلاع‌رسانی کارشناس). پارامترها: <code>receptor</code>، <code>token</code>[، <code>token2</code>، <code>token3</code>، <code>token10</code>]، <code>template</code>.</td></tr>
</table>
</div>
<div class="card card-green">
<h3>درگاه پیامک پارسیان</h3>
<p class="note">URL پایه از <code>PARSIAN_SMS_URL</code>. احراز هویت: هدر <code>X-PACKAGE-API-KEY</code> + <code>Authorization: Basic {PARSIAN_BASIC_TOKEN}</code>. به‌صورت GET با پارامترهای URL-encoded <code>ReceiverNumbers</code> و <code>Message</code> ارسال می‌کند. پیام‌های قالب قبل از ارسال به یک بدنه متن ساده پیش‌رندر می‌شوند (معادل verify/lookup ندارد).</p>
</div>
<div class="card card-green">
<h3>قالب‌های پیامک در حال استفاده</h3>
<table>
<tr><th>توکن‌ها</th><th>ماشه</th><th>نام قالب</th></tr>
<tr><td><code>token</code> = کد OTP</td><td>ورود OTP کاربر / اکتور، فراموشی رمز، OTPهای طرف</td><td><code>AUTH_SMS_TEMPLATE</code> (محیطی)</td></tr>
<tr><td><code>token</code> = publicId، <code>token2</code> = لینک</td><td>طرف دوم لینک دعوت تقصیر را از طریق پیامک دریافت می‌کند</td><td><code>yara724-invite-link</code></td></tr>
<tr><td><code>token</code> = نوع فایل، <code>token2</code> = نام خانوادگی کارشناس، <code>token3</code> = لینک</td><td>کارشناس میدانی لینک را برای یک طرف ارسال می‌کند</td><td><code>yara-field-expert-link</code></td></tr>
<tr><td><code>token</code> = publicId، <code>token2</code> = لینک</td><td>اطلاع به طرف که طرف دیگر با رأی کارشناس موافقت کرده است</td><td><code>yara-blame-agreement</code></td></tr>
<tr><td><code>token</code> = publicId، <code>token2</code> = لینک</td><td>طرف زیان‌دیده مطلع می‌شود که جریان خسارت را پس از تکمیل تقصیر باز کند</td><td><code>yara-claim-link</code></td></tr>
<tr><td><code>token</code> = "تصادف"/"خسارت"، <code>token2</code> = publicId، <code>token3</code> = نام خانوادگی کارشناس</td><td>کارشناس یک فایل تقصیر یا خسارت را قفل می‌کند</td><td><code>yara-expert-lock</code></td></tr>
<tr><td><code>token</code> = نوع فایل، <code>token2</code> = publicId، <code>token3</code> = لینک</td><td>کارشناس درخواست ارسال مجدد اسناد می‌دهد</td><td><code>yara-resend-documents</code></td></tr>
<tr><td><code>token</code> = نوع فایل، <code>token2</code> = publicId، <code>token3</code> = نام خانوادگی کارشناس، <code>token10</code> = لینک</td><td>طرف مطلع می‌شود که ارزیابی خسارت کارشناس را امضا کند</td><td><code>yara-signature</code></td></tr>
<tr><td><code>token</code> = publicId، <code>token2</code> = claimId فناوران، <code>token3</code> = claimNo فناوران</td><td>ارسال فناوران تأیید شد — با شماره و شناسه خسارت فناوران برای مالک خسارت ارسال می‌شود</td><td><code>yara-fanavaran-claim</code></td></tr>
</table>
<p class="note" style="margin-top:8px;">
تمام فراخوانی‌های پیامک fire-and-forget هستند — هرگز throw نمی‌کنند. شکست‌ها log می‌شوند اما جریان اصلی را مسدود نمی‌کنند.
یک مجموعه MongoDB <code>sms_send_logs</code> هر پیام خروجی را با نوع آن (OTP در مقابل TEMPLATE)، ارائه‌دهنده، نام قالب و وضعیت موفقیت/شکست ثبت می‌کند.
پیام‌های متنی اطلاع‌رسانی (اختلاف طرفین، امضای یک طرف و غیره) در راه‌اندازی در مجموعه <code>sms_texts</code> seed می‌شوند و در زمان اجرا قابل ویرایش هستند.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="ai">۷ — سرویس هوش مصنوعی <span class="status-badge status-disabled">غیرفعال (کد موجود)</span></h2>
<p class="section-intro">
یک سرویس تشخیص خسارت خودرو مبتنی بر تصویر در کدبیس یکپارچه‌سازی شده است اما
فراخوانی‌های HTTP آن <strong>کاملاً comment شده‌اند</strong>. ماژول در راه‌اندازی
مقداردهی اولیه می‌شود، تلاش برای ورود می‌کند (در صورت شکست به صورت خاموش
بلعیده می‌شود)، و یک متد <code>aiRequestImage</code> را expose می‌کند — اما
فراخوانی‌های axios زیرین غیرفعال هستند. سرویس هیچ جریان تولیدی را تحت تأثیر
قرار نمی‌دهد.
</p>
<div class="card card-yellow">
<h3>رابط مورد نظر (زمانی که دوباره فعال شود)</h3>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
<tr><td><span class="method post">POST</span></td><td><code>{AI_URL_V2}/auth/login</code></td><td>احراز هویت با نام کاربری + رمز عبور. <code>accessToken</code> را برمی‌گرداند.</td></tr>
<tr><td><span class="method get">GET</span></td><td><code>{AI_URL_V2}/auth/profile</code></td><td>دریافت <code>apiKey.key</code> مورد نیاز به‌عنوان هدر درخواست <code>gateway-api-key</code>.</td></tr>
<tr><td><span class="method post">POST</span></td><td><code>{AI_URL_V2}/services/car-damage/detector?version=ai-v7</code></td><td>ارسال تصویر قطعه خودرو (multipart). <code>downloadLink</code> با نتیجه حاشیه‌نویسی‌شده را برمی‌گرداند.</td></tr>
</table>
<p class="warn" style="margin-top:8px;">
وضعیت: هر سه فراخوانی در بلوک‌های <code>axios.request(…)</code> comment-شده پیچیده شده‌اند.
<code>CW_URL</code> در <code>.env.example</code> نیست. برای فعال‌سازی مجدد، فراخوانی‌های axios login، getApiKey و aiRequestImage را uncomment کنید و <code>AI_URL_V2</code>، <code>AI_USERNAME</code>، <code>AI_PASSWORD</code> را پیکربندی کنید.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="car-pricing">۸ — سرویس قیمت خودرو <span class="status-badge status-partial">نیمه‌فعال</span></h2>
<p class="section-intro">
فقط در طول محاسبه کاهش قیمت کارشناس-خسارت استفاده می‌شود. وقتی یک کارشناس
مقادیر شدت برای هر قطعه ارائه می‌دهد، سیستم قیمت‌های بازار بلادرنگ برای مدل
خودروی آسیب‌دیده را دریافت می‌کند، سپس کاهش قیمت را با استفاده از فرمول
محاسبه می‌کند: <strong>قیمت خودرو × ضریب سال × مجموع ضرایب قطعات ÷ ۴۰۰</strong>.
سرویس دو منبع داده (اندپوینت) دارد که به‌صورت موازی امتحان می‌شوند.
</p>
<div class="card card-orange">
<h3>اندپوینت‌ها</h3>
<table>
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
<tr><td><span class="method get">GET</span></td><td><code>{CW_URL}price?akharin</code></td><td>دریافت قیمت‌های بازار خودرو از منبع "آخرین". آرایه <code>{ carName, marketPrice }</code> را برمی‌گرداند.</td></tr>
<tr><td><span class="method get">GET</span></td><td><code>{CW_URL}price?hamrah</code></td><td>دریافت قیمت‌های بازار خودرو از منبع "همراه". همان شکل پاسخ.</td></tr>
</table>
<p class="note" style="margin-top:8px;">
هر دو اندپوینت امتحان می‌شوند؛ نتایج ادغام و حذف تکراری می‌شوند. بهترین تطابق برای
نام خودروی آسیب‌دیده با استفاده از <strong>فاصله Levenshtein</strong> (تطابق رشته فازی) پیدا می‌شود.
اگر هر دو اندپوینت شکست بخورند یا خالی برگردانند، محاسبه کاهش قیمت رد می‌شود (ناقص علامت‌گذاری می‌شود) — ارسال خسارت را مسدود نمی‌کند.
</p>
<p class="warn" style="margin-top:6px;">
<strong><code>CW_URL</code> در <code>.env.example</code> مستندسازی نشده است.</strong>
این سرویس در صورت تنظیم نشدن متغیر، به‌صورت خاموش هیچ کاهش قیمتی تولید نخواهد کرد.
</p>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="offline-inquiry">۹ — پرس‌وجوی آفلاین <span class="status-badge status-internal">داخلی / fallback</span></h2>
<p class="section-intro">
لایه پرس‌وجوی آفلاین فراخوانی‌های پرس‌وجوی مبتنی بر پلاک را قبل از اینکه هر
HTTP خارجی انجام شود رهگیری می‌کند. عمدتاً برای توسعه و تست (پلاک‌های شناخته‌شده
از پیش seed شده) استفاده می‌شود اما همچنین به‌عنوان fallback انعطاف‌پذیری
زمانی که سرویس‌های پرس‌وجوی زنده در دسترس نیستند عمل می‌کند. توسط یک پرچم
پایگاه‌داده زمان اجرا کنترل می‌شود، نه یک متغیر محیطی.
</p>
<div class="card card-gray">
<h3>نحوه کار</h3>
<table>
<tr><th>جزئیات</th><th>جنبه</th></tr>
<tr><td>مجموعه MongoDB <code>offline-inquiries</code>. اسناد شامل <code>clientKey</code>، فیلدهای نرمال‌شده پلاک، <code>nationalCode</code> و پاسخ از پیش ساخته‌شده <code>raw</code> + <code>mapped</code> برای برگرداندن هستند.</td><td>ذخیره‌سازی</td></tr>
<tr><td><code>system_settings.offlineInquiry.enabled</code> — پیش‌فرض <code>true</code>. تغییر از طریق <code>PATCH /super-admin/system-settings/offline-inquiry</code>.</td><td>سوئیچ اصلی</td></tr>
<tr><td>پلاک نرمال‌شده (فقط ارقام، عربی→فارسی) + کد ملی + کلید مشتری فناوران باید همه مطابقت داشته باشند. اگر پیدا شد، بلافاصله برگردانده می‌شود؛ هیچ فراخوانی HTTP انجام نمی‌شود.</td><td>ترتیب جستجو</td></tr>
<tr><td>فقط برای پرس‌وجوی block مبتنی بر پلاک (THIRD_PARTY) اعمال می‌شود. پرس‌وجوی CAR_BODY (<code>/badane</code>) همیشه API زنده را می‌زند.</td><td>محدوده</td></tr>
<tr><td><code>system_settings.externalApis.sandHubUseLiveApi</code> — وقتی <code>false</code> (پیش‌فرض)، حتی اگر هیچ داده آفلاینی مطابقت نداشته باشد، یک پاسخ mock داخلی برگردانده می‌شود به جای فراخوانی تجارت/ESG.</td><td>پرچم API زنده</td></tr>
</table>
</div>
<!-- ═══════════════════════════════════════════════════════════ -->
<h2 id="env-ref">۱۰ — مرجع متغیرهای محیطی</h2>
<p class="section-intro">
تمام متغیرهای محیطی در سراسر تمام یکپارچه‌سازی‌ها، گروه‌بندی‌شده بر اساس سرویس.
متغیرهای علامت‌گذاری‌شده با <strong>*</strong> در <code>.env.example</code> وجود ندارند.
</p>
<div class="card card-blue">
<h3>فناوران</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>کلید پروفایل تنانت فعال: <code>parsian</code> | <code>tejaratno</code> | <code>moallem</code></td><td><code>FANAVARAN_CLIENT</code></td></tr>
<tr><td>عنوان نمایشی شرکت بیمه‌گر (مثلاً <em>"بیمه پارسیان"</em>) — در راه‌اندازی در برابر فهرست insurance-corp فناوران به یک corpId عددی تطبیق داده می‌شود.</td><td><code>INSURANCE_CORP_ID</code></td></tr>
</table>
<p class="note" style="margin-top:8px;">اعتبارنامه‌های هر تنانت (appName، secret، username، password، CorpId، ContractId، Location) در <code>src/core/config/fanavaran-client.config.ts</code> زیر <code>SEED_FANAVARAN_CLIENT_PROFILES</code> hardcoded شده‌اند.</p>
</div>
<div class="card card-gray">
<h3>SandHub (قدیمی)</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>URL پایه برای SandHub. پیش‌فرض: <code>http://82.99.202.245:3027</code></td><td><code>SANHUB_BASE_URL</code></td></tr>
<tr><td>URL کامل ورود (معمولاً base + <code>/user/login</code>)</td><td><code>SANHUB_URL_LOGIN</code></td></tr>
<tr><td>ایمیل ورود SandHub</td><td><code>SANHUB_USERNAME</code></td></tr>
<tr><td>رمز عبور ورود SandHub</td><td><code>SANHUB_PASSWORD</code></td></tr>
</table>
</div>
<div class="card card-teal">
<h3>پرس‌وجوی تجارت</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>URL پایه. پیش‌فرض: <code>http://82.99.202.245:3027</code></td><td><code>TEJARAT_INQUIRY_BASE_URL</code></td></tr>
<tr><td>ایمیل ورود</td><td><code>TEJARAT_INQUIRY_EMAIL</code></td></tr>
<tr><td>رمز عبور ورود</td><td><code>TEJARAT_INQUIRY_PASSWORD</code></td></tr>
</table>
</div>
<div class="card card-purple">
<h3>ESG (فقط CLIENT_ID=8)</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>به <code>8</code> تنظیم کنید تا ارائه‌دهنده پرس‌وجوی ESG برای تنانت پارسیان فعال شود.</td><td><code>CLIENT_ID</code></td></tr>
<tr><td>URL پایه ESG. پیش‌فرض: <code>http://192.168.20.22:8085</code> (شبکه داخلی)</td><td><code>ESG_URL</code></td></tr>
<tr><td>نام کاربری ورود ESG</td><td><code>ESG_USERNAME</code></td></tr>
<tr><td>رمز عبور ورود ESG</td><td><code>ESG_PASSWORD</code></td></tr>
</table>
</div>
<div class="card card-green">
<h3>پیامک</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td><code>kavenegar</code> (پیش‌فرض) یا <code>parsian</code></td><td><code>SMS_PROVIDER</code> (یا <code>SMS</code>)</td></tr>
<tr><td>کلید API کاوه‌نگار (الزامی وقتی provider = kavenegar)</td><td><code>SMS_API_KEY</code></td></tr>
<tr><td>نام قالب کاوه‌نگار برای پیام‌های OTP (مثلاً <code>yara-otp</code>)</td><td><code>AUTH_SMS_TEMPLATE</code></td></tr>
<tr><td>URL پایه درگاه پیامک پارسیان (الزامی وقتی provider = parsian)</td><td><code>PARSIAN_SMS_URL</code></td></tr>
<tr><td>مقدار هدر پیامک پارسیان <code>X-PACKAGE-API-KEY</code></td><td><code>PARSIAN_API_KEY</code></td></tr>
<tr><td>اعتبارنامه‌های رمزگذاری‌شده Base64 برای هدر <code>Authorization: Basic …</code></td><td><code>PARSIAN_BASIC_TOKEN</code></td></tr>
<tr><td>URL پایه فرانت‌اند — برای ساخت تمام لینک‌های دعوت + خسارت تعبیه‌شده در پیام‌های پیامک استفاده می‌شود</td><td><code>URL</code></td></tr>
</table>
</div>
<div class="card card-yellow">
<h3>سرویس هوش مصنوعی</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>URL پایه درگاه هوش مصنوعی. پیش‌فرض: <code>https://ai-gw.ittalie.ir</code> (استفاده نشده — سرویس غیرفعال است)</td><td><code>AI_URL_V2</code></td></tr>
<tr><td>نام کاربری ورود سرویس هوش مصنوعی (استفاده نشده)</td><td><code>AI_USERNAME</code></td></tr>
<tr><td>رمز عبور ورود سرویس هوش مصنوعی (استفاده نشده)</td><td><code>AI_PASSWORD</code></td></tr>
</table>
</div>
<div class="card card-orange">
<h3>سرویس قیمت خودرو</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>URL پایه برای API قیمت بازار خودرو (مثلاً <code>https://…/</code>). در <code>.env.example</code> نیست. کاهش قیمت به‌صورت خاموش رد می‌شود اگر تنظیم نشده باشد.</td><td><code>CW_URL</code> *</td></tr>
</table>
</div>
<div class="card card-gray">
<h3>عمومی / برنامه</h3>
<table class="env-table">
<tr><th>شرح</th><th>متغیر</th></tr>
<tr><td>پورت HTTP (پیش‌فرض ۳۰۰۰). توسط fallback insurance-corp فناوران برای فراخوانی اندپوینت جستجوی محلی خودش استفاده می‌شود.</td><td><code>PORT</code></td></tr>
<tr><td><code>true</code> / <code>false</code> — چالش کپچای ورود را فعال/غیرفعال می‌کند. داخلی، بدون سرویس خارجی.</td><td><code>CAPTCHA_ENABLED</code></td></tr>
<tr><td>TTL چالش کپچا به دقیقه.</td><td><code>EXP_CAPTCHA_TIME</code></td></tr>
<tr><td>TTL کد یکبار مصرف به دقیقه.</td><td><code>EXP_OTP_TIME</code></td></tr>
</table>
</div>
<footer>Made by Sepehr</footer>
</div>
</body>
</html>