forked from Yara724/api
Added documentation
This commit is contained in:
1506
docs/blame-claim-flow-architecture.fa.html
Normal file
1506
docs/blame-claim-flow-architecture.fa.html
Normal file
File diff suppressed because it is too large
Load Diff
1893
docs/blame-claim-flow-architecture.html
Normal file
1893
docs/blame-claim-flow-architecture.html
Normal file
File diff suppressed because it is too large
Load Diff
593
docs/external-integrations-reference.html
Normal file
593
docs/external-integrations-reference.html
Normal file
@@ -0,0 +1,593 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>External Integrations Reference</title>
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, "Segoe UI", system-ui, sans-serif;
|
||||||
|
font-size: 14px; line-height: 1.6;
|
||||||
|
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.05em;
|
||||||
|
color: #57606a; margin-bottom: 8px; margin-top: 14px;
|
||||||
|
}
|
||||||
|
.section-intro {
|
||||||
|
font-size: 13px; color: #57606a;
|
||||||
|
margin-bottom: 14px; line-height: 1.5;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
border: 1px solid #e5e7eb; border-radius: 6px;
|
||||||
|
padding: 16px; background: #f7f8fa; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.card.card-blue { border-left: 4px solid #3b82f6; }
|
||||||
|
.card.card-green { border-left: 4px solid #22c55e; }
|
||||||
|
.card.card-purple { border-left: 4px solid #8b5cf6; }
|
||||||
|
.card.card-orange { border-left: 4px solid #f97316; }
|
||||||
|
.card.card-teal { border-left: 4px solid #14b8a6; }
|
||||||
|
.card.card-indigo { border-left: 4px solid #6366f1; }
|
||||||
|
.card.card-gray { border-left: 4px solid #94a3b8; }
|
||||||
|
.card.card-red { border-left: 4px solid #ef4444; }
|
||||||
|
.card.card-yellow { border-left: 4px solid #eab308; }
|
||||||
|
table {
|
||||||
|
border-collapse: collapse; width: 100%;
|
||||||
|
font-size: 12px; margin-top: 4px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background: #f1f5f9; font-weight: 600;
|
||||||
|
text-align: left; 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; }
|
||||||
|
.method {
|
||||||
|
font-family: monospace; font-size: 11px;
|
||||||
|
font-weight: 700; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.method.get { color: #059669; }
|
||||||
|
.method.post { color: #2563eb; }
|
||||||
|
.method.put { color: #d97706; }
|
||||||
|
.method.patch { color: #7c3aed; }
|
||||||
|
.note { font-size: 11px; color: #57606a; font-style: italic; margin-top: 6px; }
|
||||||
|
.warn { font-size: 11px; color: #9a3412; font-style: italic; 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-left: 18px; }
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
.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.8;
|
||||||
|
}
|
||||||
|
.decision-tree ul { padding-left: 20px; }
|
||||||
|
.decision-tree li { margin-bottom: 2px; }
|
||||||
|
.env-table th:first-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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="max-wrap">
|
||||||
|
<h1>External Integrations Reference</h1>
|
||||||
|
<p class="subtitle">
|
||||||
|
Every outbound integration: what it does, when it fires, how auth works,
|
||||||
|
retry behaviour, fallbacks, and all environment variables. Internal-only
|
||||||
|
services (captcha, offline inquiry seed) are included for completeness.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
<div class="toc">
|
||||||
|
<div class="toc-title">Contents</div>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#inquiry-routing">Inquiry routing decision tree</a></li>
|
||||||
|
<li><a href="#fanavaran">Fanavaran — insurance claims platform</a></li>
|
||||||
|
<li><a href="#sanhub">SandHub — legacy inquiry gateway</a></li>
|
||||||
|
<li><a href="#tejarat">Tejarat inquiry — block-inquiry gateway (V2+)</a></li>
|
||||||
|
<li><a href="#esg">ESG — Parsian-tenant inquiry provider</a></li>
|
||||||
|
<li><a href="#sms">SMS — Kavenegar and Parsian gateways</a></li>
|
||||||
|
<li><a href="#ai">AI service — car damage detection</a></li>
|
||||||
|
<li><a href="#car-pricing">Car pricing service — market value lookup</a></li>
|
||||||
|
<li><a href="#offline-inquiry">Offline inquiry — fallback seed data</a></li>
|
||||||
|
<li><a href="#env-ref">Environment variable reference</a></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="inquiry-routing">1 — Inquiry Routing Decision Tree</h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Every blame file starts with a "run-inquiries" call that fetches the
|
||||||
|
guilty party's insurance policy from an external provider. Which provider
|
||||||
|
is actually called depends on three factors: the tenant (<code>CLIENT_ID</code>),
|
||||||
|
the file type (THIRD_PARTY vs CAR_BODY), and whether live API mode is
|
||||||
|
enabled in system settings. The offline-inquiry seed layer sits in front
|
||||||
|
of all three providers.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-indigo">
|
||||||
|
<h3>Provider selection</h3>
|
||||||
|
<div class="decision-tree">
|
||||||
|
<strong>For every plate-based block inquiry:</strong>
|
||||||
|
<ul>
|
||||||
|
<li>1. Check offline-inquiry seeds (MongoDB) — if a matching seed exists, return it and skip all HTTP.</li>
|
||||||
|
<li>2. If <code>CLIENT_ID=8</code> (Parsian/ESG tenant) → route to <strong>ESG</strong> <code>/inquiry/policyByPlate</code> or <code>/inquiry/policyByChassis</code>.</li>
|
||||||
|
<li>3. Otherwise → route to <strong>Tejarat inquiry</strong> <code>/block-inquiry-tejarat</code> (THIRD_PARTY) or <code>/block-inquiry-tejarat/badane</code> (CAR_BODY).</li>
|
||||||
|
<li>4. If <code>system_settings.externalApis.sandHubUseLiveApi = false</code> (default) → return mock response instead of making HTTP calls.</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<strong>For personal-identity, driving-licence, ownership, and Sheba checks:</strong>
|
||||||
|
<ul>
|
||||||
|
<li>If <code>CLIENT_ID=8</code> → ESG <code>/inquiry/person</code> and <code>/inquiry/sheba</code>.</li>
|
||||||
|
<li>Otherwise → Tejarat/SandHub <code>/personal-inquiry/tejarat-no</code>, <code>/driver-license-check</code>, <code>/ownership</code>, <code>/sheba/sheba-tejaratno</code>.</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<strong>Key difference — birth date format:</strong>
|
||||||
|
SandHub/Tejarat expect a <em>Gregorian</em> birth date (converted internally from Jalali).
|
||||||
|
ESG expects the <em>Jalali</em> date directly.
|
||||||
|
</div>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
SandHub endpoints are only used in legacy code paths. All active V2+ blame flows go through the Tejarat or ESG providers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="fanavaran">2 — Fanavaran <span class="status-badge status-live">live</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Fanavaran (<code>apimanager.iraneit.com</code>) is the national insurance
|
||||||
|
damage-case platform. After the damage expert submits their assessment,
|
||||||
|
the system auto-submits a structured claim to Fanavaran through a
|
||||||
|
four-step protocol. Fanavaran also serves as the lookup source for
|
||||||
|
code-lists (accident types, car components, city codes, etc.) used
|
||||||
|
across the platform.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Authentication lifecycle</h3>
|
||||||
|
<div class="flow-box">
|
||||||
|
<div class="flow-step"><div class="flow-num">1</div><div class="flow-text"><strong>GET AppToken</strong> — <code>POST /EITAuthentication/GetAppToken</code> with <code>appname</code> + <code>secret</code> headers. Returns <code>apptoken</code> header.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">2</div><div class="flow-text"><strong>Login</strong> — <code>POST /EITAuthentication/Login</code> with <code>appToken</code> + <code>userName</code> + <code>password</code> headers. Returns <code>authenticationToken</code> header.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">3</div><div class="flow-text"><strong>Cache</strong> — token is cached in memory <em>and</em> persisted to MongoDB (<code>fanavaran_auth_tokens</code>). Valid until midnight <strong>Asia/Tehran</strong> — the first call after 00:00 fetches a fresh token.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">4</div><div class="flow-text"><strong>All subsequent calls</strong> include four headers: <code>authenticationToken</code>, <code>CorpId</code>, <code>ContractId</code>, <code>Location</code> — tenant-specific, hardcoded per <code>FANAVARAN_CLIENT</code> key.</div></div>
|
||||||
|
</div>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
A config fingerprint (hash of appName + secret + username + password + corpId + contractId + location)
|
||||||
|
forces a fresh login when any credential changes, even before midnight.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Claim submission protocol (4 steps)</h3>
|
||||||
|
<div class="flow-box">
|
||||||
|
<div class="flow-step"><div class="flow-num">1</div><div class="flow-text"><strong>Base claim (GEN.03)</strong> — <code>POST /car/third-party-car-financial-claims</code>. Sends owner, driver, insurance, vehicle, and accident data. Returns a Fanavaran <code>claimId</code> and <code>claimNo</code>. SMS is sent to the owner with both identifiers.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">2</div><div class="flow-text"><strong>Damage cases (GEN.05)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/dmg-cases</code>. One entry per damaged part with component ID, severity, and price. Cap: total ≤ 53 000 000 Toman.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">3</div><div class="flow-text"><strong>Attachments (GEN.07)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/files</code>. Documents, car-capture images, and videos referenced by file ID.</div></div>
|
||||||
|
<div class="flow-step"><div class="flow-num">4</div><div class="flow-text"><strong>Expertise (GEN.08)</strong> — <code>POST /car/third-party-car-financial-claims/{claimId}/expertise</code>. Expert assessment metadata (expert role, date, result). Finalises the submission.</div></div>
|
||||||
|
</div>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
All four steps are recorded in the <code>fanavaran_audit_logs</code> collection with full request/response bodies, HTTP status, duration, and tracking code for debugging.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Lookup endpoints</h3>
|
||||||
|
<p class="note">All under <code>https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/</code>. Results are cached to disk (per client key) and in the <code>lookups</code> MongoDB collection. Parsian tenant reads DB before hitting the API; others go to the API first.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Path</th><th>Used for</th></tr>
|
||||||
|
<tr><td><code>/car/base-info/accident-causes</code></td><td>accidentReason dropdown options (mapped to local IDs)</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/accident-report-type</code></td><td>accidentWay options</td></tr>
|
||||||
|
<tr><td><code>/car/base-info/vehicle-use-types</code></td><td>vehicle usage classification</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/dmg-pay-method</code></td><td>damage payment method</td></tr>
|
||||||
|
<tr><td><code>/car/base-info/driving-licence-types</code></td><td>licence type options</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/accident-culprit-type</code></td><td>guilty-party classification</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/inspection-place</code></td><td>inspection location options</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/drop-amount-status</code></td><td>price-drop status codes</td></tr>
|
||||||
|
<tr><td><code>/car/base-info/car-components</code></td><td>component catalog (maps to outer/inner parts)</td></tr>
|
||||||
|
<tr><td><code>/car/code-list/accident-level</code></td><td>accident severity options</td></tr>
|
||||||
|
<tr><td><code>/common/code-list/insurance-corp</code></td><td>resolve <code>INSURANCE_CORP_ID</code> → Fanavaran corpId</td></tr>
|
||||||
|
<tr><td><code>/common/base-info/cities</code>, <code>/common/base-info/Provinces</code></td><td>city/province pickers</td></tr>
|
||||||
|
<tr><td><code>/car/third-party-car-policies/{policyId}</code></td><td>fetch full policy by ID after inquiry</td></tr>
|
||||||
|
<tr><td><code>/car/vehicles/inquiry-by-vin?vin=…</code></td><td>VIN-based vehicle lookup</td></tr>
|
||||||
|
<tr><td><code>/common/Policies/inquiry-my-policies</code></td><td>list policies for a national code</td></tr>
|
||||||
|
<tr><td><code>/common/customers/{customerId}</code></td><td>fetch customer record by ID</td></tr>
|
||||||
|
<tr><td><code>/common/parties/inquiry-by-unique-identifier</code></td><td>party lookup by national code + birth date</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Error handling & resilience</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Mechanism</th><th>Detail</th></tr>
|
||||||
|
<tr><td>Retry</td><td>3 attempts, 500 ms → 1 000 ms exponential backoff on all HTTP calls.</td></tr>
|
||||||
|
<tr><td>Transient backoff</td><td>When Fanavaran returns the Persian "try again later" message (or tracking-code 500), a tenant-wide 5-minute pause is activated. All calls during this window get <code>503 ServiceUnavailable</code> immediately — no hammering.</td></tr>
|
||||||
|
<tr><td>Token invalidation</td><td>On 401, token is cleared from memory and MongoDB; next call triggers a fresh GetAppToken + Login.</td></tr>
|
||||||
|
<tr><td>Inflight de-dup</td><td>Concurrent login requests for the same tenant are collapsed to a single in-flight Promise.</td></tr>
|
||||||
|
<tr><td>Audit log</td><td>Every step (GET_APP_TOKEN, LOGIN, and all four submission steps) is written to <code>fanavaran_audit_logs</code> with STARTED / SUCCESS / FAILURE status, full headers, body, and duration.</td></tr>
|
||||||
|
<tr><td>Timeout</td><td>20–30 s per HTTP call.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Tenant profiles (<code>FANAVARAN_CLIENT</code>)</h3>
|
||||||
|
<p class="section-intro" style="margin-top:6px; margin-bottom:8px;">Three pre-seeded tenant profiles exist. The active one is chosen by the <code>FANAVARAN_CLIENT</code> env var. Each profile carries its own <code>appName</code>, <code>secret</code>, <code>username</code>, <code>password</code>, <code>CorpId</code>, <code>ContractId</code>, and <code>Location</code> headers, plus payload defaults (AccidentCityId, etc.).</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Key</th><th>Insurance company</th></tr>
|
||||||
|
<tr><td><code>parsian</code></td><td>Parsian Insurance</td></tr>
|
||||||
|
<tr><td><code>tejaratno</code></td><td>Tejaratno Insurance</td></tr>
|
||||||
|
<tr><td><code>moallem</code></td><td>Moallem Insurance</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
<code>INSURANCE_CORP_ID</code> is a display-caption string (e.g. <em>"بیمه پارسیان"</em>) that is resolved against the live Fanavaran <code>insurance-corp</code> list to produce the numeric <code>corpId</code> used in submissions. The resolved ID is cached to disk.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="sanhub">3 — SandHub <span class="status-badge status-partial">legacy</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
SandHub is the original inquiry gateway. It is still present in the
|
||||||
|
codebase but all active blame flows (V2+) have been migrated to the
|
||||||
|
Tejarat inquiry provider. SandHub endpoints remain callable but are
|
||||||
|
only reached through legacy code paths. Its mock mode is controlled
|
||||||
|
by the same <code>sandHubUseLiveApi</code> system setting.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>Auth</h3>
|
||||||
|
<p class="note">
|
||||||
|
<code>POST {SANHUB_BASE_URL}/user/login</code> with username + password JSON body.
|
||||||
|
Token cached in memory for <strong>55 minutes</strong>. On 401, token is cleared and one retry is made.
|
||||||
|
3 attempts with 1 000 ms → 2 000 ms exponential backoff.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>Endpoints</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat</code></td><td>Plate-based insurance policy inquiry (THIRD_PARTY). Body: <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 policy inquiry. Timeout 50 s (longer than standard).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/personal-inquiry/tejarat-no</code></td><td>Personal identity check. Body: <code>nationalCode</code> + <em>Gregorian</em> <code>birthDate</code> (converted from Jalali internally).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/driver-license-check</code></td><td>Driving licence validation. Returns <code>IsSucceed</code> flag.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/ownership</code></td><td>Vehicle ownership check. Returns <code>IsSuccess</code> flag.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/sheba/sheba-tejaratno</code></td><td>Sheba / bank account validation. Returns <code>ReturnValue</code> + <code>HasError</code>.</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
All endpoints support full mock responses when <code>sandHubUseLiveApi=false</code> in system settings (default). Mock data is deterministic and produced locally without any HTTP calls.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="tejarat">4 — Tejarat Inquiry <span class="status-badge status-live">live</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
The active block-inquiry gateway for all non-ESG tenants. Used in every
|
||||||
|
V2+ <code>run-inquiries</code> call where <code>CLIENT_ID ≠ 8</code>.
|
||||||
|
The base URL is configurable; in production it points to the same host
|
||||||
|
as SandHub but uses separate credentials.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>Auth</h3>
|
||||||
|
<p class="note">
|
||||||
|
<code>POST {TEJARAT_INQUIRY_BASE_URL}/user/login</code> with email + password JSON body.
|
||||||
|
Token cached for <strong>55 minutes</strong>. 2 attempts with 500 ms → 1 000 ms backoff.
|
||||||
|
Separate from SandHub credentials — uses <code>TEJARAT_INQUIRY_EMAIL</code> / <code>TEJARAT_INQUIRY_PASSWORD</code>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>Endpoints</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat</code></td><td>THIRD_PARTY plate inquiry. Body: plate fields + <code>nationalCode</code>. Offline seed checked first.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/block-inquiry-tejarat/badane</code></td><td>CAR_BODY plate inquiry. Body: <code>part1–part4</code> (numeric) + <code>nationalCode</code>. Always goes live (no mock for badane path).</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
When <code>sandHubUseLiveApi=false</code>, the THIRD_PARTY path returns a mock response without HTTP. The CAR_BODY path always calls the live API regardless of this flag.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="esg">5 — ESG <span class="status-badge status-live">live (CLIENT_ID=8)</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
ESG is an internal insurance API gateway used exclusively by the Parsian
|
||||||
|
tenant (<code>CLIENT_ID=8</code>). It replaces Tejarat/SandHub for all
|
||||||
|
inquiry types when this tenant is active. It has a different response
|
||||||
|
shape, a dynamic token TTL, and expects birth dates in <strong>Jalali</strong>
|
||||||
|
format (not Gregorian, unlike SandHub/Tejarat).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>Auth</h3>
|
||||||
|
<p class="note">
|
||||||
|
<code>POST {ESG_URL}/auth/login</code> with <code>{ username, password }</code> JSON body.
|
||||||
|
Token TTL is read from the response <code>expiresIn</code> field (default 14 min).
|
||||||
|
2 attempts with 500 ms → 1 000 ms backoff. On 401, token cleared and one retry.
|
||||||
|
Default URL: <code>http://192.168.20.22:8085</code> (internal network).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>Endpoints</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/policyByPlate</code></td><td>Plate-based policy lookup (THIRD_PARTY). Body: <code>nationalCode</code>, <code>plk1–plk4</code>. Response is mapped to the old Tejarat format before being stored.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/policyByChassis</code></td><td>VIN/chassis-based alternative to plate inquiry. Called by <code>run-inquiries-vin</code> endpoints. Uses ESG chassis lookup (not the SandHub path). Body: <code>nationalCode</code>, <code>chassis</code>.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/person</code></td><td>Personal identity check. Body: <code>nationalCode</code>, <code>birthDate</code> (Jalali, NOT Gregorian).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>/inquiry/sheba</code></td><td>Sheba / bank account validation.</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
ESG wraps every response as <code>{ success: boolean, data: … }</code>. A <code>success=false</code> body is translated to a Persian "استعلام در دسترس نیست" (inquiry unavailable) error.
|
||||||
|
The offline-inquiry seed check still runs first, before any ESG HTTP call.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="sms">6 — SMS <span class="status-badge status-live">live</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Two SMS providers are supported: <strong>Kavenegar</strong> (default)
|
||||||
|
and <strong>Parsian SMS Gateway</strong>. The active provider is chosen
|
||||||
|
by the <code>SMS_PROVIDER</code> (or <code>SMS</code>) env var. Both
|
||||||
|
providers implement the same internal gateway interface so the
|
||||||
|
orchestration layer is provider-agnostic.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>Provider selection</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Env var</th><th>Value</th><th>Active provider</th></tr>
|
||||||
|
<tr><td><code>SMS_PROVIDER</code> (or <code>SMS</code>)</td><td><code>kavenegar</code> (default)</td><td>Kavenegar — <code>api.kavenegar.com</code></td></tr>
|
||||||
|
<tr><td><code>SMS_PROVIDER</code> (or <code>SMS</code>)</td><td><code>parsian</code></td><td>Parsian SMS Gateway — <code>PARSIAN_SMS_URL</code></td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>Kavenegar endpoints</h3>
|
||||||
|
<p class="note">Base URL: <code>https://api.kavenegar.com/v1/{SMS_API_KEY}/</code></p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>When used</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>sms/send.json</code></td><td>Plain-text messages (e.g. key-based notification texts stored in <code>sms_texts</code> collection).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>verify/lookup.json</code></td><td>All template-based messages (OTPs, invite links, expert notifications). Params: <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>Parsian SMS Gateway</h3>
|
||||||
|
<p class="note">Base URL from <code>PARSIAN_SMS_URL</code>. Auth: <code>X-PACKAGE-API-KEY</code> header + <code>Authorization: Basic {PARSIAN_BASIC_TOKEN}</code>. Sends as a GET with URL-encoded <code>ReceiverNumbers</code> and <code>Message</code> query params. Template messages are pre-rendered into a plain text body before sending (no verify/lookup equivalent).</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>SMS templates in use</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Template name</th><th>Trigger</th><th>Tokens</th></tr>
|
||||||
|
<tr><td><code>AUTH_SMS_TEMPLATE</code> (env)</td><td>User / actor OTP login, forget-password, party OTPs</td><td><code>token</code> = OTP code</td></tr>
|
||||||
|
<tr><td><code>yara724-invite-link</code></td><td>Second party receives blame invite link via SMS</td><td><code>token</code> = publicId, <code>token2</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-field-expert-link</code></td><td>Field expert sends link to a party</td><td><code>token</code> = file type, <code>token2</code> = expert surname, <code>token3</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-blame-agreement</code></td><td>Notify party that the other side agreed to the expert verdict</td><td><code>token</code> = publicId, <code>token2</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-claim-link</code></td><td>Damaged party notified to open claim flow after blame is complete</td><td><code>token</code> = publicId, <code>token2</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-expert-lock</code></td><td>Expert locks a blame or claim file</td><td><code>token</code> = "تصادف"/"خسارت", <code>token2</code> = publicId, <code>token3</code> = expert surname</td></tr>
|
||||||
|
<tr><td><code>yara-resend-documents</code></td><td>Expert requests document resend</td><td><code>token</code> = file kind, <code>token2</code> = publicId, <code>token3</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-signature</code></td><td>Party notified to sign the expert's damage assessment</td><td><code>token</code> = file kind, <code>token2</code> = publicId, <code>token3</code> = expert surname, <code>token10</code> = link</td></tr>
|
||||||
|
<tr><td><code>yara-fanavaran-claim</code></td><td>Fanavaran submission confirmed — sent to claim owner with Fanavaran claim number and ID</td><td><code>token</code> = publicId, <code>token2</code> = Fanavaran claimId, <code>token3</code> = Fanavaran claimNo</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
All SMS calls are fire-and-forget — they never throw. Failures are logged but do not block the main flow.
|
||||||
|
An <code>sms_send_logs</code> MongoDB collection records every outbound message with its kind (OTP vs TEMPLATE), provider, template name, and success/failure status.
|
||||||
|
Notification text messages (parties-disagree, one-party-signed, etc.) are seeded into the <code>sms_texts</code> collection on startup and editable at runtime.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="ai">7 — AI Service <span class="status-badge status-disabled">disabled (code present)</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
An image-based car damage detection service is integrated in the
|
||||||
|
codebase but its HTTP calls are <strong>fully commented out</strong>.
|
||||||
|
The module initialises on startup, attempts a login (silently swallowed
|
||||||
|
if it fails), and exposes an <code>aiRequestImage</code> method — but
|
||||||
|
the underlying axios calls are disabled. The service does not affect
|
||||||
|
any production flow.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-yellow">
|
||||||
|
<h3>Intended interface (when re-enabled)</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>{AI_URL_V2}/auth/login</code></td><td>Authenticate with username + password. Returns <code>accessToken</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>{AI_URL_V2}/auth/profile</code></td><td>Fetch <code>apiKey.key</code> needed as the <code>gateway-api-key</code> request header.</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>Submit a car part image (multipart). Returns <code>downloadLink</code> with annotated result.</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="warn" style="margin-top:8px;">
|
||||||
|
Status: all three calls are wrapped in commented-out <code>axios.request(…)</code> blocks.
|
||||||
|
<code>CW_URL</code> is not in <code>.env.example</code>. To re-enable, uncomment the login, getApiKey, and aiRequestImage axios calls, and configure <code>AI_URL_V2</code>, <code>AI_USERNAME</code>, <code>AI_PASSWORD</code>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="car-pricing">8 — Car Pricing Service <span class="status-badge status-partial">partially active</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Used only during damage-expert price-drop calculation. When an expert
|
||||||
|
provides per-part severity values the system fetches real-time market
|
||||||
|
prices for the damaged car model, then computes the price-drop using
|
||||||
|
the formula: <strong>carPrice × yearCoefficient × sumOfPartCoefficients ÷ 400</strong>.
|
||||||
|
The service has two data sources (endpoints) that are tried in parallel.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>Endpoints</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Path</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>{CW_URL}price?akharin</code></td><td>Fetch car market prices from the "Akharin" source. Returns array of <code>{ carName, marketPrice }</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>{CW_URL}price?hamrah</code></td><td>Fetch car market prices from the "Hamrah" source. Same response shape.</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
Both endpoints are tried; results are merged and de-duplicated. The best match for
|
||||||
|
the damaged car's name is found using <strong>Levenshtein distance</strong> (fuzzy string match).
|
||||||
|
If both endpoints fail or return empty, the price-drop calculation is skipped (marked incomplete) — it does not block claim submission.
|
||||||
|
</p>
|
||||||
|
<p class="warn" style="margin-top:6px;">
|
||||||
|
<strong><code>CW_URL</code> is not documented in <code>.env.example</code>.</strong>
|
||||||
|
This service will silently produce no price-drop if the variable is unset.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="offline-inquiry">9 — Offline Inquiry <span class="status-badge status-internal">internal / fallback</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
The offline inquiry layer intercepts plate-based inquiry calls before
|
||||||
|
any external HTTP is made. It is primarily used for development and
|
||||||
|
testing (pre-seeded known plates) but also acts as a resilience fallback
|
||||||
|
when live inquiry services are unavailable. It is controlled by a
|
||||||
|
runtime database flag, not an env var.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>How it works</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Aspect</th><th>Detail</th></tr>
|
||||||
|
<tr><td>Storage</td><td>MongoDB collection <code>offline-inquiries</code>. Documents contain <code>clientKey</code>, normalised plate fields, <code>nationalCode</code>, and the pre-built <code>raw</code> + <code>mapped</code> response to return.</td></tr>
|
||||||
|
<tr><td>Master switch</td><td><code>system_settings.offlineInquiry.enabled</code> — defaults to <code>true</code>. Toggle via <code>PATCH /super-admin/system-settings/offline-inquiry</code>.</td></tr>
|
||||||
|
<tr><td>Lookup order</td><td>Normalised plate (digits-only, Arabic→Persian) + national code + Fanavaran client key must all match. If found, returned immediately; no HTTP call is made.</td></tr>
|
||||||
|
<tr><td>Scope</td><td>Only applies to plate-based block-inquiry (THIRD_PARTY). CAR_BODY inquiry (<code>/badane</code>) always hits the live API.</td></tr>
|
||||||
|
<tr><td>Live API flag</td><td><code>system_settings.externalApis.sandHubUseLiveApi</code> — when <code>false</code> (default), even if no offline seed matches, a built-in mock response is returned rather than calling Tejarat/ESG.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="env-ref">10 — Environment Variable Reference</h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
All env vars across all integrations, grouped by service.
|
||||||
|
Variables marked <strong>*</strong> are not present in <code>.env.example</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Fanavaran</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>FANAVARAN_CLIENT</code></td><td>Active tenant profile key: <code>parsian</code> | <code>tejaratno</code> | <code>moallem</code></td></tr>
|
||||||
|
<tr><td><code>INSURANCE_CORP_ID</code></td><td>Display caption of the insurer company (e.g. <em>"بیمه پارسیان"</em>) — resolved to a numeric corpId at startup against the Fanavaran insurance-corp list.</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">Per-tenant credentials (appName, secret, username, password, CorpId, ContractId, Location) are hardcoded in <code>src/core/config/fanavaran-client.config.ts</code> under <code>SEED_FANAVARAN_CLIENT_PROFILES</code>.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>SandHub (legacy)</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>SANHUB_BASE_URL</code></td><td>Base URL for SandHub. Default: <code>http://82.99.202.245:3027</code></td></tr>
|
||||||
|
<tr><td><code>SANHUB_URL_LOGIN</code></td><td>Full login URL (usually base + <code>/user/login</code>)</td></tr>
|
||||||
|
<tr><td><code>SANHUB_USERNAME</code></td><td>SandHub login email</td></tr>
|
||||||
|
<tr><td><code>SANHUB_PASSWORD</code></td><td>SandHub login password</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>Tejarat inquiry</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>TEJARAT_INQUIRY_BASE_URL</code></td><td>Base URL. Default: <code>http://82.99.202.245:3027</code></td></tr>
|
||||||
|
<tr><td><code>TEJARAT_INQUIRY_EMAIL</code></td><td>Login email</td></tr>
|
||||||
|
<tr><td><code>TEJARAT_INQUIRY_PASSWORD</code></td><td>Login password</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>ESG (CLIENT_ID=8 only)</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>CLIENT_ID</code></td><td>Set to <code>8</code> to activate the ESG inquiry provider for the Parsian tenant.</td></tr>
|
||||||
|
<tr><td><code>ESG_URL</code></td><td>ESG base URL. Default: <code>http://192.168.20.22:8085</code> (internal network)</td></tr>
|
||||||
|
<tr><td><code>ESG_USERNAME</code></td><td>ESG login username</td></tr>
|
||||||
|
<tr><td><code>ESG_PASSWORD</code></td><td>ESG login password</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>SMS</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>SMS_PROVIDER</code> (or <code>SMS</code>)</td><td><code>kavenegar</code> (default) or <code>parsian</code></td></tr>
|
||||||
|
<tr><td><code>SMS_API_KEY</code></td><td>Kavenegar API key (required when provider = kavenegar)</td></tr>
|
||||||
|
<tr><td><code>AUTH_SMS_TEMPLATE</code></td><td>Kavenegar template name for OTP messages (e.g. <code>yara-otp</code>)</td></tr>
|
||||||
|
<tr><td><code>PARSIAN_SMS_URL</code></td><td>Parsian SMS Gateway base URL (required when provider = parsian)</td></tr>
|
||||||
|
<tr><td><code>PARSIAN_API_KEY</code></td><td>Parsian SMS <code>X-PACKAGE-API-KEY</code> header value</td></tr>
|
||||||
|
<tr><td><code>PARSIAN_BASIC_TOKEN</code></td><td>Base64-encoded credentials for <code>Authorization: Basic …</code> header</td></tr>
|
||||||
|
<tr><td><code>URL</code></td><td>Frontend base URL — used to build all invite + claim links embedded in SMS messages</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-yellow">
|
||||||
|
<h3>AI service</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>AI_URL_V2</code></td><td>AI gateway base URL. Default: <code>https://ai-gw.ittalie.ir</code> (unused — service is disabled)</td></tr>
|
||||||
|
<tr><td><code>AI_USERNAME</code></td><td>AI service login username (unused)</td></tr>
|
||||||
|
<tr><td><code>AI_PASSWORD</code></td><td>AI service login password (unused)</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>Car pricing service</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>CW_URL</code> *</td><td>Base URL for car market price API (e.g. <code>https://…/</code>). Not in <code>.env.example</code>. Price-drop silently skipped if unset.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>General / app</h3>
|
||||||
|
<table class="env-table">
|
||||||
|
<tr><th>Variable</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>PORT</code></td><td>HTTP port (default 3000). Used by the Fanavaran insurance-corp fallback to call its own local lookup endpoint.</td></tr>
|
||||||
|
<tr><td><code>CAPTCHA_ENABLED</code></td><td><code>true</code> / <code>false</code> — enables/disables login CAPTCHA challenge. Internal, no external service.</td></tr>
|
||||||
|
<tr><td><code>EXP_CAPTCHA_TIME</code></td><td>CAPTCHA challenge TTL in minutes.</td></tr>
|
||||||
|
<tr><td><code>EXP_OTP_TIME</code></td><td>OTP TTL in minutes.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>Made by Sepehr</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
624
docs/panel-roles-reference.fa.html
Normal file
624
docs/panel-roles-reference.fa.html
Normal file
@@ -0,0 +1,624 @@
|
|||||||
|
<!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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Role header strip */
|
||||||
|
.role-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.role-name {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.role-enum {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #3b82d4;
|
||||||
|
background: #f0f7ff;
|
||||||
|
border: 1px solid #bfdbfe;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
direction: ltr;
|
||||||
|
unicode-bidi: embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px; font-weight: 600;
|
||||||
|
padding: 1px 7px; border-radius: 10px;
|
||||||
|
margin-left: 4px; margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
.badge-blue { background: #dbeafe; color: #1d4ed8; }
|
||||||
|
.badge-green { background: #dcfce7; color: #166534; }
|
||||||
|
.badge-purple { background: #ede9fe; color: #5b21b6; }
|
||||||
|
.badge-orange { background: #ffedd5; color: #9a3412; }
|
||||||
|
.badge-teal { background: #ccfbf1; color: #0f766e; }
|
||||||
|
.badge-indigo { background: #e0e7ff; color: #3730a3; }
|
||||||
|
.badge-gray { background: #f1f5f9; color: #475569; border: 1px solid #e2e8f0; }
|
||||||
|
.badge-red { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
|
/* Cards */
|
||||||
|
.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; }
|
||||||
|
|
||||||
|
/* Endpoint tables */
|
||||||
|
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; }
|
||||||
|
.method.delete { color: #dc2626; }
|
||||||
|
.dep { color: #94a3b8; font-style: italic; font-size: 11px; }
|
||||||
|
|
||||||
|
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||||
|
@media (max-width: 860px) { .grid-2 { grid-template-columns: 1fr; } }
|
||||||
|
|
||||||
|
.note {
|
||||||
|
font-size: 11px; color: #57606a; font-style: normal;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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; }
|
||||||
|
|
||||||
|
/* Role overview table */
|
||||||
|
.overview-table { font-size: 12px; margin-bottom: 24px; }
|
||||||
|
.overview-table th { white-space: nowrap; }
|
||||||
|
.overview-table td:last-child { font-weight: 600; white-space: nowrap; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="max-wrap">
|
||||||
|
<h1>مرجع نقشهای پنل</h1>
|
||||||
|
<p class="subtitle">
|
||||||
|
آنچه هر نقش میتواند ببیند و انجام دهد — اندپوینتها، مسئولیتها و
|
||||||
|
مراحل فرآیند. سوپر ادمین در این مستند نیست.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Table of Contents -->
|
||||||
|
<div class="toc">
|
||||||
|
<div class="toc-title">نقشهای پوششدادهشده</div>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#insurer">بیمهگر (COMPANY) — ادمین تنانت شرکت بیمه</a></li>
|
||||||
|
<li><a href="#blame-expert">کارشناس تقصیر (EXPERT) — صف بررسی اختلاف</a></li>
|
||||||
|
<li><a href="#damage-expert">کارشناس خسارت (DAMAGE_EXPERT) — قیمتگذاری خسارت</a></li>
|
||||||
|
<li><a href="#field-expert">کارشناس میدانی (FIELD_EXPERT) — ثبت حضوری در صحنه</a></li>
|
||||||
|
<li><a href="#file-maker">فایلساز (FILE_MAKER) — روایت طرفین در V4/V5</a></li>
|
||||||
|
<li><a href="#file-reviewer">بازبین فایل (FILE_REVIEWER) — ارزیابی خسارت V4/V5</a></li>
|
||||||
|
<li><a href="#registrar">ثبات (REGISTRAR) — ثبت اداری حضوری</a></li>
|
||||||
|
<li><a href="#call-center">مرکز تماس (CALL_CENTER) — ثبت تلفنی V6</a></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Role overview table ────────────────────────────────────── -->
|
||||||
|
<h2>نمای کلی نقشها</h2>
|
||||||
|
<table class="overview-table">
|
||||||
|
<tr>
|
||||||
|
<th>وظیفه اصلی</th>
|
||||||
|
<th>محدوده</th>
|
||||||
|
<th>پنل ورود</th>
|
||||||
|
<th>enum نقش</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>مشاهده تمام فایلها؛ مدیریت شعب و کارشناسان؛ گزارشگیری؛ امتیازدهی به کارشناسان</td>
|
||||||
|
<td>سطح تنانت</td>
|
||||||
|
<td>پورتال بیمهگر</td>
|
||||||
|
<td><code>company</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>قفلکردن پروندههای تقصیر، بررسی اسناد طرفین، صدور رأی یا درخواست ارسال مجدد</td>
|
||||||
|
<td>صف DISAGREEMENT تنانت</td>
|
||||||
|
<td>پنل کارشناس تقصیر</td>
|
||||||
|
<td><code>expert</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>قفلکردن خسارت، قیمتگذاری، اعتبارسنجی فاکتورها، درخواست ارسال مجدد/بازدید</td>
|
||||||
|
<td>صف خسارت تنانت</td>
|
||||||
|
<td>پنل خسارت</td>
|
||||||
|
<td><code>damage_expert</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ثبت حضوری تقصیر + خسارت در V2/V3؛ دسترسی به پنلهای تقصیر/خسارت</td>
|
||||||
|
<td>فایلهای ساختهشده توسط خود</td>
|
||||||
|
<td>پنل کارشناس میدانی</td>
|
||||||
|
<td><code>field_expert</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>روایت طرفین V4/V5 (OTP، استعلام، جزئیات، امضا)؛ تأیید خسارت در V5</td>
|
||||||
|
<td>فایلهای ساختهشده توسط خود</td>
|
||||||
|
<td>پنل فایلساز</td>
|
||||||
|
<td><code>file_maker</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ارزیابی خسارت V4/V5 (فیلدهای تصادف، قطعات، عکسها، امضای مالک)</td>
|
||||||
|
<td>فایلهای تخصیصیافته</td>
|
||||||
|
<td>پنل بازبین فایل</td>
|
||||||
|
<td><code>file_reviewer</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ثبت حضوری اداری تقصیر + خسارت به نمایندگی از طرفین</td>
|
||||||
|
<td>فایلهای ساختهشده توسط خود</td>
|
||||||
|
<td>پنل ثبات</td>
|
||||||
|
<td><code>registrar</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ثبت تلفنی V6: اجرای استعلام، ارسال لینک؛ کاربر بقیه را تکمیل میکند</td>
|
||||||
|
<td>فایلهای ساختهشده توسط خود</td>
|
||||||
|
<td>پنل مرکز تماس</td>
|
||||||
|
<td><code>call_center</code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="insurer">۱ — بیمهگر <span class="role-enum">company</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
به ازای هر تنانت شرکت بیمه یک اکتور <code>company</code> وجود دارد. پورتال بیمهگر
|
||||||
|
لایه مدیریتی است: میتواند همه چیز زیر تنانت خود را ببیند، لیست کارشناسان را مدیریت
|
||||||
|
کند، شعب را اداره کند، تنظیمات رسانهای هر تنانت را پیکربندی کند و گزارشهای آماری
|
||||||
|
استخراج کند. بیمهگر هرگز مستقیماً با مراحل تقصیر/خسارت درگیر نمیشود — فقط نظارهگر
|
||||||
|
و امتیازدهنده است.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>مدیریت فایل — <code>expert-insurer/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files</code></td><td>فهرست تمام فایلهای تقصیر + خسارت تنانت (ادغامشده بر اساس publicId). فیلترپذیر بر اساس وضعیت، نوع فایل، جستجو، مرتبسازی، صفحه.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId</code></td><td>جزئیات کامل یک فایل بر اساس publicId.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId/timeline</code></td><td>تایملاین فعالیت به ترتیب زمانی (تمام رویدادهای تاریخچه: منبع، نوع، اکتور، متادیتا).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId/report</code></td><td>دادههای ساختاریافته گزارش برای تولید PDF (بخشهای مالک، راننده، بیمه، خودرو، تصادف).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>expert-insurer/files/:publicId/rating</code></td><td>امتیازدهی به کارشناسان یک فایل (۱–۵ در هر بُعد: روش تصادف، بهموقعبودن، دقت علت، دقت شناسایی مقصر، امتیاز ربات).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/report/unified-file-statuses</code></td><td>کاتالوگ وضعیت یکپارچه + تعداد به ازای هر وضعیت برای کل پرتفولیوی تنانت. فیلترپذیر بر اساس fileType و بازه تاریخ.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/report/status-counts</code></td><td class="dep">منسوخشده — از unified-file-statuses استفاده کنید.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>مدیریت شعب — <code>expert-insurer/branches</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/branches</code></td><td>فهرست تمام شعب این بیمهگر. پارامترها: جستجو، بازه تاریخ from/to، فیلتر isActive.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/branches</code></td><td>افزودن شعبه جدید (نام، کد، آدرس، شهر، تلفن و غیره).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>expert-insurer/branches/:branchId/status</code></td><td>فعال یا غیرفعال کردن یک شعبه.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>مدیریت لیست کارشناسان — <code>expert-insurer/experts</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/blame</code></td><td>ایجاد حساب کارشناس تقصیر جدید زیر این بیمهگر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/claim</code></td><td>ایجاد حساب کارشناس خسارت جدید زیر این بیمهگر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/file-maker</code></td><td>ایجاد حساب فایلساز جدید زیر این بیمهگر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/file-reviewer</code></td><td>ایجاد حساب بازبین فایل جدید زیر این بیمهگر.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/experts/list</code></td><td>فهرست صفحهبندیشده تمام حسابهای کارشناس در این تنانت.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/experts/top</code></td><td>برترین کارشناسان تقصیر و خسارت رتبهبندیشده بر اساس میانگین امتیاز کلی (حداکثر ۱۰ نفر از هر نوع).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/top-experts</code></td><td>نام مستعار experts/top (سازگاری با فرانتاند).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/:expertId</code></td><td>فایلهای رسیدگیشده توسط یک کارشناس (ردیفهای خلاصه — تقصیر یا خسارت بسته به نوع کارشناس).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<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>expert-insurer/statistics</code></td><td>کارتهای KPI: totalFilesReviewed، averageUserRating، inPersonCount، filesThisMonth، objectionPercentage و غیره. فیلترپذیر بر اساس بازه تاریخ.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/top-files</code></td><td>۱۰ فایل خسارت برتر بر اساس بالاترین امتیاز (ترکیبی از امتیاز بیمهگر + کاربر).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/expert-work-log</code></td><td>لاگ کاری هر کارشناس: totalHandled، currentlyChecking، distinctFilesCheckedInPeriod. فیلترپذیر بر اساس expertKind و بازه تاریخ.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/requests</code></td><td>تعداد خسارت + وضعیت تقصیر + تعداد فایل یکپارچه برای تنانت.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/per-month-requests</code></td><td>همان خلاصه، تفکیکشده بر اساس ۵ ماه تقویمی اخیر.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/checked-requests</code></td><td>همان خلاصه، فیلترشده بر اساس بازه زمانی اختیاری createdAt.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/expert-work-log</code></td><td>لاگ کاری کارشناسان (مجموعههای کارشناس تقصیر و خسارت، نه کارشناسان میدانی).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/expert-work-log/per-month</code></td><td>همان لاگ کاری تفکیکشده بر اساس ماه تقویمی (۵ ماه اخیر).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>تنظیمات تنانت — <code>client-panel/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>client-panel/settings</code></td><td>دریافت محدودیتهای رسانهای هر تنانت (حداکثر بایت ویدیو/تصویر/صوت) و پنجره زمانی تصادف CAR_BODY (روز).</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>client-panel/settings</code></td><td>بهروزرسانی جزئی این تنظیمات. نمیتواند از سقفهای سطح سیستم تجاوز کند.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="blame-expert">۲ — کارشناس تقصیر <span class="role-enum">expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
فایلهای تقصیر در صف DISAGREEMENT را بررسی میکند — پروندههایی که دو طرف درباره
|
||||||
|
مقصر بودن توافق ندارند. پس از بررسی اسناد و اظهارات طرفین، کارشناس پرونده را قفل
|
||||||
|
میکند، سپس یا رأی صادر میکند، درخواست ارسال مجدد اسناد میدهد، یا نتیجه بازدید
|
||||||
|
حضوری را ثبت میکند. تمام اندپوینتها زیر <code>v2/expert-blame/</code> هستند.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>فرآیند</h3>
|
||||||
|
<p class="note">
|
||||||
|
۱ مرور فهرست ← ۲ تخصیص (قفل) پرونده ← ۳ بررسی مدارک طرفین (ویدیو، صدا، اسناد) ←
|
||||||
|
۴الف صدور رأی <em>یا</em> ۴ب درخواست ارسال مجدد اسناد <em>یا</em> ۴پ ثبت بازدید حضوری.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>اندپوینتها — <code>v2/expert-blame/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/</code></td><td>فهرست پروندههای تقصیر در صف DISAGREEMENT (موجود، قفلشده توسط من، یا تصمیمگرفتهشده توسط من). پارامترها: search، sortBy، sortOrder، page، limit، unifiedStatus، fileType.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/:id</code></td><td>جزئیات کامل یک پرونده تقصیر (اظهارات، عکس، صدا، ویدیو طرفین).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>v2/expert-blame/:id/assign</code></td><td>بررسی در دسترس بودن و قفل پرونده برای این کارشناس. بازمیگرداند: <code>assigned</code>، <code>already_assigned_to_you</code>، یا ۴۰۹ در صورتی که شخص دیگری آن را نگه داشته باشد.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/submit/:id</code></td><td>ارسال رأی (accidentWay، accidentReason، accidentType، تصمیم طرف مقصر). پرونده را آزاد میکند و به COMPLETED منتقل میکند.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/resend/:id</code></td><td>درخواست از طرفین برای بارگذاری مجدد اسناد. تقصیر را به WAITING_FOR_RESEND تنظیم میکند. یک درخواست ارسال مجدد در هر چرخه عمر.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/inPerson/:id</code></td><td>ثبت اینکه بازدید حضوری انجام شده و صدور رأی.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/report/unified-file-statuses</code></td><td>کاتالوگ وضعیت + تعداد به ازای هر وضعیت برای پرتفولیوی این کارشناس.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/report/status-counts</code></td><td class="dep">منسوخشده — از unified-file-statuses استفاده کنید.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/lock/:id</code></td><td class="dep">اندپوینت قفل منسوخشده — از POST assign استفاده کنید.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="damage-expert">۳ — کارشناس خسارت <span class="role-enum">damage_expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
فایلهای خسارت را پس از ارسال مدارک خسارت توسط کاربر بررسی میکند. کارشناس
|
||||||
|
هر قطعه آسیبدیده را قیمتگذاری میکند، بهصورت اختیاری کاهش قیمت (استهلاک)
|
||||||
|
محاسبه میکند، و میتواند از کاربر بخواهد مدارک را مجدداً ارسال کند، حضوری مراجعه
|
||||||
|
کند، یا فاکتورهای تعمیرگاه را هنگام نیاز به قیمتگذاری کارگاهی بارگذاری کند.
|
||||||
|
تمام اندپوینتها زیر <code>v2/expert-claim/</code> هستند.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-red">
|
||||||
|
<h3>فرآیند</h3>
|
||||||
|
<p class="note">
|
||||||
|
۱ مرور فهرست ← ۲ تخصیص (قفل) خسارت ← ۳ بررسی عکسها و اسناد خسارت ←
|
||||||
|
۴ ویرایش اختیاری قطعات انتخابشده یا محاسبه کاهش قیمت ←
|
||||||
|
۵الف ارسال پاسخ قیمتگذاریشده <em>یا</em> ۵ب درخواست ارسال مجدد <em>یا</em> ۵پ درخواست بازدید حضوری ←
|
||||||
|
۶ در صورت وجود قطعات فاکتوردار: اعتبارسنجی فاکتورهای تعمیرگاه بارگذاریشده.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-red">
|
||||||
|
<h3>اندپوینتها — <code>v2/expert-claim/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/requests</code></td><td>فهرست خسارتها در صف <code>WAITING_FOR_DAMAGE_EXPERT</code> + صف اعتبارسنجی فاکتور. پارامترها: search، sortBy، page، limit، unifiedStatus، fileType.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/request/:claimRequestId</code></td><td>جزئیات کامل خسارت: قطعات آسیبدیده، تصاویر گرفتهشده، اسناد، priceDrop، داده طرف بلیم، آدرسهای ویدیو.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>v2/expert-claim/assign/:claimRequestId</code></td><td>قفل خسارت برای این کارشناس. بازمیگرداند: <code>assigned</code>، <code>already_assigned_to_you</code>، یا ۴۰۹.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/request/:claimRequestId/price-drop</code></td><td>محتوای کاهش قیمت: برچسبهای شدت، کاتالوگ ضریب، قطعات آسیبدیده + نگاشت، سال پیشنهادی خودرو از استعلام تقصیر.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/request/:claimRequestId/price-drop</code></td><td>محاسبه و ذخیره کاهش قیمت: قیمت خودرو × ضریب سال × مجموع ضرایب ÷ ۴۰۰.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/reply/submit/:claimRequestId</code></td><td>ارسال پاسخ ارزیابی خسارت (لیست قطعات قیمتگذاریشده، داغی، branchId). سقف: کل ≤ ۵۳،۰۰۰،۰۰۰ تومان. بسته به پرچمهای factorNeeded، خسارت را به owner-sign، mixed-factors-pending، یا صف اعتبارسنجی فاکتور منتقل میکند.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/reply/resend/:claimRequestId</code></td><td>درخواست از کاربر برای ارسال مجدد اسناد/عکسها. یک ارسال مجدد در هر چرخه خسارت؛ در صورت تکمیل قبلی ۴۲۲ برمیگرداند.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/:claimRequestId/visit</code></td><td>درخواست از کاربر برای مراجعه حضوری. خسارت را آزاد میکند، وضعیت claimStatus را به NEEDS_REVISION تنظیم میکند.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/validate-factors/:claimRequestId</code></td><td>اعتبارسنجی فاکتورهای تعمیرگاه بارگذاریشده. تأیید یا رد هر خط فاکتور با totalPayment. سقف برای تمام خطوط اعمال میشود (≤ ۵۳،۰۰۰،۰۰۰ تومان). پس از تصمیمگیری درباره تمام خطوط، بهصورت خودکار تکمیل میشود.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/request/:claimRequestId/damaged-parts</code></td><td>ویرایش قطعات آسیبدیده انتخابشده در حالی که خسارت توسط این کارشناس قفل است (EXPERT_REVIEWING).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/outer-parts-catalog</code></td><td>کاتالوگ قطعات بیرونی خودرو فناوران (مشترک با جریان کاربر).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/inner-parts-catalog</code></td><td>JSON ثابت کاتالوگ قطعات داخلی خودرو.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/branches</code></td><td>شعب بیمهگر برای تنانت این کارشناس (برای انتخاب داغی/شعبه در پیلود پاسخ).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/stream/:id/video</code></td><td>پخش ویدیوی خسارت (ویدیوی دور زدن خودرو یا ویدیوی تصادف). پارامتر: <code>query=car-capture|accident</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/report/unified-file-statuses</code></td><td>کاتالوگ وضعیت + تعداد برای پرتفولیوی خسارت این کارشناس.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/report/status-counts</code></td><td class="dep">منسوخشده — از unified-file-statuses استفاده کنید.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/lock/:claimRequestId</code></td><td class="dep">اندپوینت قفل منسوخشده — از POST assign استفاده کنید.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="field-expert">۴ — کارشناس میدانی <span class="role-enum">field_expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
به صحنه تصادف میرود و فرمهای هر دو طرف را حضوری پر میکند (جریان V2 mirror / V3).
|
||||||
|
کارشناس میدانی همچنین دسترسی خواندن به پنلهای expert-blame و expert-claim دارد
|
||||||
|
(محدود به فایلهای خودش). تنها نقشی است که هم <strong>ثبت تقصیر</strong> و هم
|
||||||
|
<strong>ثبت خسارت</strong> را در یک جلسه انجام میدهد.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>ثبت تقصیر — <code>v2/expert-initiated/blame-request-management/</code></h3>
|
||||||
|
<p class="note">آینهای از API تقصیر کاربر. فرانتاند همان صفحات را با تغییر فقط پیشوند مسیر بازاستفاده میکند.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>POST /</code></td><td>ایجاد فایل تقصیر IN_PERSON.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-party-otp/:id</code></td><td>ارسال OTP به یک طرف از طریق شماره تلفن (بدون لینک دعوت).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>verify-party-otp/:id</code></td><td>تأیید OTP یک طرف و اتصال حساب آنها.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>blame-confession/:id</code></td><td>ثبت اعتراف تقصیر طرف.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>car-body-form/:id</code></td><td>[فقط CAR_BODY] فرم نوع تصادف.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiries/:id</code> / <code>run-inquiries-vin/:id</code></td><td>فرم اولیه / استعلام پلاک یا VIN برای طرف فعلی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:id</code></td><td>بارگذاری ویدیوی طرف اول.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-location/:id</code></td><td>افزودن موقعیت GPS برای طرف فعلی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-voice/:id</code></td><td>بارگذاری ضبط صوتی برای طرف فعلی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-description/:id</code></td><td>افزودن توضیحات برای طرف فعلی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-second-party/:phone/:id/</code></td><td>پیشروی به طرف دوم (بدون ارسال لینک SMS).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>sign/:id</code></td><td>بارگذاری امضای طرف (اول سپس دوم، پارامتر partyRole).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:id</code></td><td>ذخیره فیلدهای تصادف و تکمیل فوری تقصیر (بدون صف کارشناس).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>ثبت تقصیر + خسارت V3 — <code>v3/expert-initiated/blame-request-management/</code></h3>
|
||||||
|
<p class="note">ترتیب مراحل بازسازماندهیشده: ابتدا تمام روایت طرفین، سپس ارزیابی خسارت. هم تقصیر هم خسارت در این کنترلر واحد مدیریت میشوند.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>POST /</code> ← <code>send-party-otp</code> ← <code>verify-party-otp</code> ← <code>run-inquiries</code> ← <code>add-detail-*</code> ← <code>sign</code> (×۲)</td><td>مرحله روایت طرفین (مراحل ۱–۸) — اندپوینتهای یکسان با mirror، همان قرارداد.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:id</code></td><td>مرحله ۹: ذخیره فیلدهای تصادف پس از امضای هر دو طرف.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>مرحله ۱۰: دریافت شناسه خسارت ایجادشده بهصورت خودکار.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>مرحله ۱۱: بارگذاری اسناد گواهینامه / کارت خودرو.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code> / <code>select-other-parts/:claimId</code></td><td>مراحل ۱۲–۱۳: انتخاب قطعات آسیبدیده.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>مرحله ۱۴: عکسبرداری از قطعات + زوایا.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>مرحله ۱۵: ویدیوی دور زدن خودرو.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:requestId</code></td><td>مرحله ۱۶: ویدیوی تصادف تقصیر (نهایی) ← WAITING_FOR_EXPERT (THIRD_PARTY) یا COMPLETED (CAR_BODY).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>دسترسی به پنل expert-blame + expert-claim (خواندن + اقدام روی فایلهای خود)</h3>
|
||||||
|
<p class="note">
|
||||||
|
FIELD_EXPERT مسیر <code>v2/expert-blame/</code> را محدود به فایلهای ساختهشده توسط خودش میبیند (نه صف اختلاف).
|
||||||
|
همچنین <code>v2/expert-claim/</code> را برای خسارتهای مرتبط با فایلهای تقصیرش میبیند.
|
||||||
|
اندپوینتهای یکسان با پنلهای کارشناس تقصیر و کارشناس خسارت در بالا.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="file-maker">۵ — فایلساز <span class="role-enum">file_maker</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
اولین اکتور در تقسیم V4/V5. فایلساز روایت طرفین را در محل انجام میدهد:
|
||||||
|
OTPها، استعلامها، موقعیت/توضیحات/صدا و امضاها برای هر دو طرف.
|
||||||
|
همچنین اسناد اولیه خسارت (گواهینامهها، کارتهای خودرو) را بارگذاری میکند. پس از
|
||||||
|
امضای دوم، فایل برای تحویل به بازبین فایل «مهرومومه» میشود. در V5، فایلساز
|
||||||
|
در انتها بازمیگردد تا خسارت تکمیلشده را قبل از ارسال به فناوران تأیید یا رد کند.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>ثبت تقصیر — <code>v4/file-maker/blame-request-management/</code> و <code>v5/…</code></h3>
|
||||||
|
<p class="note">اندپوینتهای V4 و V5 یکسان هستند — فقط پیشوند تغییر میکند. V5 هنگام ایجاد <code>requiresFileMakerApproval=true</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>POST /</code></td><td>ایجاد فایل تقصیر IN_PERSON.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>فهرست تمام فایلهای تقصیر ایجادشده توسط این فایلساز.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files/:requestId</code></td><td>جزئیات کامل یک فایل (طرفین، گردش کار، شناسه خسارت مرتبط).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>دریافت شناسه خسارت ایجادشده بهصورت خودکار پس از استعلام طرف مقصر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-party-otp/:id</code> / <code>verify-party-otp/:id</code></td><td>ارسال + تأیید OTP برای یک طرف در هر بار (ابتدا مقصر، سپس زیاندیده).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>car-body-form/:id</code></td><td>[فقط CAR_BODY] فرم نوع تصادف.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiries/:id</code> / <code>run-inquiries-vin/:id</code></td><td>اجرای استعلام پلاک یا VIN. فراخوانی اول = مقصر (+ خودکار خسارت ایجاد میکند). فراخوانی دوم = زیاندیده (فقط THIRD_PARTY).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-location/:id</code> / <code>add-detail-description/:id</code> / <code>upload-voice/:id</code></td><td>افزودن موقعیت، توضیحات و صدا برای طرف فعلی (پارامتر partyRole، FIRST/SECOND را انتخاب میکند).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>sign/:id</code></td><td>بارگذاری امضای طرف (partyRole=FIRST سپس SECOND). پس از امضای دوم، فایل مهرومومه میشود.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>بارگذاری گواهینامه / کارتهای خودرو روی خسارت ایجادشده بهصورت خودکار.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>capture-requirements/:claimId</code></td><td>الزامات عکسبرداری آگاه از مرحله (فازها: اسناد پیش از عکسبرداری در مقابل قطعات آسیبدیده + شاسی/موتور).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>تأیید خسارت V5 — <code>v5/file-maker/claim-approval/</code></h3>
|
||||||
|
<p class="note">فقط در V5 استفاده میشود. پس از بررسی کارشناس خسارت و امضای مالک، خسارت وارد <code>WAITING_FOR_FILE_MAKER_APPROVAL</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>approve/:claimId</code></td><td>تأیید خسارت تکمیلشده ← ارسال SMS امضای مالک را فعال میکند ← پس از امضای مالک به فناوران ارسال میشود.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>reject/:claimId</code></td><td>رد به بازبین فایل ← خسارت به WAITING_FOR_DAMAGE_EXPERT برمیگردد. محدودیت: حداکثر ۲ رد در هر خسارت؛ تلاش سوم ۴۲۲ با کد <code>FILE_MAKER_REJECTION_LIMIT_EXCEEDED</code> برمیگرداند.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="file-reviewer">۶ — بازبین فایل <span class="role-enum">file_reviewer</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
دومین اکتور در تقسیم V4/V5. بازبین فایل فایلهای مهرومومهشده (پس از اتمام کار
|
||||||
|
فایلساز) را تحویل میگیرد و مرحله کامل ارزیابی خسارت را انجام میدهد: فیلدهای
|
||||||
|
تصادف، دریافت الزامات عکسبرداری، بارگذاری اسناد (شاسی/موتور)، انتخاب قطعات،
|
||||||
|
عکسهای قطعات، ویدیوی دور زدن خودرو، امضای مالک. تقصیر با car-capture به
|
||||||
|
COMPLETED علامتگذاری میشود. بازبین فایل همچنین دسترسی خواندن به پنل expert-claim
|
||||||
|
برای خسارتهایی که بررسی میکند دارد.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>ارزیابی خسارت — <code>v4/file-reviewer/blame-request-management/</code> و <code>v5/…</code></h3>
|
||||||
|
<p class="note">اندپوینتهای V4 و V5 یکسان هستند — فقط پیشوند تغییر میکند.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>فهرست تمام فایلهای تخصیصیافته به این بازبین فایل.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files/:requestId</code></td><td>جزئیات کامل یک فایل (طرفین، گردش کار، فیلدهای کارشناس، شناسه خسارت مرتبط).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>دریافت شناسه خسارت ایجادشده بهصورت خودکار (از استعلام طرف مقصر فایلساز).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:requestId</code></td><td>مرحله ۱ (بازبین): ذخیره فیلدهای تصادف (accidentWay، accidentReason، accidentType).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>capture-requirements/:claimId</code></td><td>الزامات عکسبرداری آگاه از مرحله (فاز اسناد پیش از عکسبرداری در مقابل فاز عکسبرداری قطعات).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>بارگذاری اسناد شاسی / موتور / پلاک فلزی.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code></td><td>انتخاب قطعات آسیبدیده بیرونی (بدنه).</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-other-parts/:claimId</code></td><td>انتخاب سایر قطعات آسیبدیده (غیر بدنه).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>عکسبرداری از قطعات + زوایا برای هر قطعه آسیبدیده انتخابشده.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>ویدیوی دور زدن خودرو (آخرین مرحله عکسبرداری بازبین). خسارت ← <code>WAITING_FOR_DAMAGE_EXPERT</code>، تقصیر ← <code>COMPLETED</code>.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>claim-sign/:claimId</code></td><td>ثبت امضای مالک روی قیمتگذاری کارشناس به نمایندگی از طرف زیاندیده (موافقت + branchId + تصویر امضا).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:requestId</code></td><td class="dep">در V4/V5 بیاثر است — تقصیر از قبل توسط car-capture COMPLETED شده. موفقیت idempotent برمیگرداند.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>دسترسی به پنل expert-claim</h3>
|
||||||
|
<p class="note">
|
||||||
|
FILE_REVIEWER در نقشهای مجاز برای <code>v2/expert-claim/</code> است.
|
||||||
|
میتواند جزئیات خسارت را مشاهده کند و جریان assign/lock را برای خسارتهای
|
||||||
|
مرتبط با فایلهایش اجرا کند. نمیتواند بهطور مستقل درخواست ارسال مجدد
|
||||||
|
کارشناس خسارت را آغاز کند.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="registrar">۷ — ثبات <span class="role-enum">registrar</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
نقش اداری که تقصیر و خسارت حضوری را به نمایندگی از طرفین ثبت میکند.
|
||||||
|
از جریان OTP دستهای استفاده میکند (OTPهای هر دو طرف بهصورت همزمان ارسال و
|
||||||
|
تأیید میشوند) به جای OTP یکبهیک که توسط کارشناسان میدانی استفاده میشود.
|
||||||
|
پس از تقصیر، ثبات آینه API خسارت کاربر را دنبال میکند تا انتخاب قطعات، اسناد
|
||||||
|
و عکسبرداری را پر کند. سپس فایل وارد چرخه عادی بررسی کارشناس خسارت میشود.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>ثبت تقصیر — <code>registrar-initiated-blame/</code></h3>
|
||||||
|
<p class="note">توجه: <code>@ApiExcludeController</code> — مسیرها وجود دارند اما در مستندات Swagger نمایش داده نمیشوند.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/create</code></td><td>ایجاد فایل تقصیر IN_PERSON.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>registrar-initiated-blame/my-files</code></td><td>فهرست تمام فایلهای تقصیر ایجادشده توسط این ثبات.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>registrar-initiated-blame/blame/:requestId</code></td><td>جزئیات کامل یک فایل تقصیر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/send-party-otps/:id</code></td><td>ارسال OTP به هر دو طرف بهصورت همزمان.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/verify-party-otps/:id</code></td><td>تأیید OTPهای هر دو طرف در یک فراخوانی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/complete-blame-data/:id</code></td><td>ارسال تمام دادههای فرم تقصیر هر دو طرف در یک پیلود.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-video/:id</code></td><td>بارگذاری ویدیوی تقصیر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-voice/:id</code></td><td>بارگذاری ضبط صوتی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/add-accident-fields/:id</code></td><td>ذخیره فیلدهای تصادف و تکمیل تقصیر.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-party-signature/:id</code></td><td>بارگذاری امضای یک طرف (partyRole=FIRST/SECOND).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>ثبت خسارت — <code>v2/registrar/claim-request-management/</code></h3>
|
||||||
|
<p class="note">آینهای از API خسارت کاربر. فرانتاند همان صفحات خسارت را با تغییر فقط پیشوند بازاستفاده میکند.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>create-from-blame/:blameId</code></td><td>ایجاد خسارت از یک فایل تقصیر تکمیلشده.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>outer-parts-catalog</code> / <code>car-other-part</code></td><td>کاتالوگ قطعات (قطعات بیرونی بدنه + JSON سایر قطعات).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>branches/:insuranceId</code></td><td>فهرست شعب بیمهگر (برای انتخاب شعبه در مرحله امضای خسارت).</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code></td><td>انتخاب قطعات آسیبدیده بیرونی.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-other-parts/:claimId</code></td><td>انتخاب سایر قطعات آسیبدیده + اطلاعات بانکی.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>بارگذاری اسناد خسارت (گواهینامه، کارت خودرو).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>عکسبرداری از قطعات + زوایا.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>ویدیوی دور زدن خودرو (مرحله نهایی) ← WAITING_FOR_DAMAGE_EXPERT.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="call-center">۸ — مرکز تماس <span class="role-enum">call_center</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
ثبت تقصیر تلفنی V6 را مدیریت میکند. اپراتور دادههای طرف مقصر را از طریق تلفن
|
||||||
|
جمعآوری میکند، استعلام بیمه را اجرا میکند و لینک تقصیر را از طریق SMS ارسال
|
||||||
|
میکند. کاربر سپس بقیه فرم را از طریق جریان استاندارد V2 تکمیل میکند
|
||||||
|
(با رد شدن مرحله فرم اولیه/استعلام). کار اپراتور مرکز تماس پس از send-link
|
||||||
|
پایان مییابد؛ میتواند پیشرفت را از طریق اندپوینتهای خواندن پایش کند.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-indigo">
|
||||||
|
<h3>اندپوینتها — <code>v6/call-center-blame/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>create</code></td><td>ایجاد فایل تقصیر LINK. بدنه: <code>{ type: "THIRD_PARTY" | "CAR_BODY" }</code>.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiry/:requestId</code></td><td>اجرای استعلام بیمه پلاک + کد ملی برای طرف مقصر. نتیجه را روی سند تقصیر ذخیره میکند.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiry-vin/:requestId</code></td><td>VIN/شاسی جایگزین برای run-inquiry. از جستجوی شاسی ESG استفاده میکند.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-link/:requestId</code></td><td>در صورت لزوم کاربر را ثبتنام میکند، بهعنوان طرف اول ذخیره میکند، لینک دعوت تقصیر را از طریق SMS ارسال میکند. بدنه: <code>{ phoneNumber }</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>فهرست تمام فایلهای تقصیر شروعشده توسط این اپراتور.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>blame/:requestId</code></td><td>وضعیت فعلی و مرحله گردش کار یک فایل (برای بررسی اینکه کاربر لینک را باز کرده و پیشرفت کرده است).</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
پس از <code>send-link</code>، کاربر فرم را از طریق
|
||||||
|
<code>v2/blame-request-management/</code> (جریان استاندارد V2) تکمیل میکند.
|
||||||
|
مرحله فرم اولیه / استعلام بهصورت خودکار رد میشود
|
||||||
|
(<code>skipInitialFormStep=true</code>). جریان خسارت پاییندستی همان
|
||||||
|
جریان استاندارد خسارت V2 است.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2>مشترک: احراز هویت اکتورها</h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
تمام اکتورهای پنل (هر نقش به جز <code>user</code>) از طریق همان اندپوینت
|
||||||
|
<code>POST actor/login</code> با کپچا احراز هویت میکنند. بازنشانی رمز عبور از
|
||||||
|
طریق OTP ایمیل است. خواندن و ویرایش پروفایل نیز مشترک است.
|
||||||
|
</p>
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>اندپوینتها — <code>actor/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">متد</th><th>مسیر</th><th>توضیح</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>actor/captcha</code></td><td>صدور یک چالش کپچای ورود جدید (captchaId + تصویر SVG را برمیگرداند).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/login</code></td><td>احراز هویت هر نقش اکتور. بدنه: role، username/email/nationalCode، password، captchaId، captcha. توکنهای JWT دسترسی + رفرش را برمیگرداند.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/forget-password</code></td><td>ارسال OTP بازنشانی رمز عبور به ایمیل.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/forget-password-verify</code></td><td>تأیید OTP و تنظیم رمز عبور جدید.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>actor/profile</code></td><td>دریافت پروفایل اکتور فعلی.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>actor/profile</code></td><td>بهروزرسانی پروفایل اکتور فعلی.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>Made by Sepehr</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
616
docs/panel-roles-reference.html
Normal file
616
docs/panel-roles-reference.html
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Panel Roles Reference</title>
|
||||||
|
<style>
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, "Segoe UI", system-ui, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
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.05em;
|
||||||
|
color: #57606a; margin-bottom: 8px; margin-top: 14px;
|
||||||
|
}
|
||||||
|
.section-intro {
|
||||||
|
font-size: 13px; color: #57606a;
|
||||||
|
margin-bottom: 14px; line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Role header strip */
|
||||||
|
.role-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.role-name {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.role-enum {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #3b82d4;
|
||||||
|
background: #f0f7ff;
|
||||||
|
border: 1px solid #bfdbfe;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px; font-weight: 600;
|
||||||
|
padding: 1px 7px; border-radius: 10px;
|
||||||
|
margin-right: 4px; margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
.badge-blue { background: #dbeafe; color: #1d4ed8; }
|
||||||
|
.badge-green { background: #dcfce7; color: #166534; }
|
||||||
|
.badge-purple { background: #ede9fe; color: #5b21b6; }
|
||||||
|
.badge-orange { background: #ffedd5; color: #9a3412; }
|
||||||
|
.badge-teal { background: #ccfbf1; color: #0f766e; }
|
||||||
|
.badge-indigo { background: #e0e7ff; color: #3730a3; }
|
||||||
|
.badge-gray { background: #f1f5f9; color: #475569; border: 1px solid #e2e8f0; }
|
||||||
|
.badge-red { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
|
/* Cards */
|
||||||
|
.card {
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.card.card-blue { border-left: 4px solid #3b82f6; }
|
||||||
|
.card.card-green { border-left: 4px solid #22c55e; }
|
||||||
|
.card.card-purple { border-left: 4px solid #8b5cf6; }
|
||||||
|
.card.card-orange { border-left: 4px solid #f97316; }
|
||||||
|
.card.card-teal { border-left: 4px solid #14b8a6; }
|
||||||
|
.card.card-indigo { border-left: 4px solid #6366f1; }
|
||||||
|
.card.card-gray { border-left: 4px solid #94a3b8; }
|
||||||
|
|
||||||
|
/* Endpoint tables */
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background: #f1f5f9; font-weight: 600;
|
||||||
|
text-align: left; 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;
|
||||||
|
}
|
||||||
|
.method {
|
||||||
|
font-family: monospace; font-size: 11px;
|
||||||
|
font-weight: 700; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.method.get { color: #059669; }
|
||||||
|
.method.post { color: #2563eb; }
|
||||||
|
.method.put { color: #d97706; }
|
||||||
|
.method.patch { color: #7c3aed; }
|
||||||
|
.method.delete { color: #dc2626; }
|
||||||
|
.dep { color: #94a3b8; font-style: italic; font-size: 11px; }
|
||||||
|
|
||||||
|
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||||
|
@media (max-width: 860px) { .grid-2 { grid-template-columns: 1fr; } }
|
||||||
|
|
||||||
|
.note {
|
||||||
|
font-size: 11px; color: #57606a; font-style: italic;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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-left: 18px; }
|
||||||
|
.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; }
|
||||||
|
|
||||||
|
/* Role overview table */
|
||||||
|
.overview-table { font-size: 12px; margin-bottom: 24px; }
|
||||||
|
.overview-table th { white-space: nowrap; }
|
||||||
|
.overview-table td:first-child { font-weight: 600; white-space: nowrap; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="max-wrap">
|
||||||
|
<h1>Panel Roles Reference</h1>
|
||||||
|
<p class="subtitle">
|
||||||
|
What every actor role can see and do — endpoints, responsibilities, and
|
||||||
|
process steps. Super-admin excluded.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Table of Contents -->
|
||||||
|
<div class="toc">
|
||||||
|
<div class="toc-title">Roles covered</div>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#insurer">Insurer (COMPANY) — the insurance-company tenant admin</a></li>
|
||||||
|
<li><a href="#blame-expert">Blame Expert (EXPERT) — disagreement review queue</a></li>
|
||||||
|
<li><a href="#damage-expert">Damage Expert (DAMAGE_EXPERT) — claim pricing</a></li>
|
||||||
|
<li><a href="#field-expert">Field Expert (FIELD_EXPERT) — on-scene in-person filing</a></li>
|
||||||
|
<li><a href="#file-maker">File Maker (FILE_MAKER) — V4/V5 party narrative</a></li>
|
||||||
|
<li><a href="#file-reviewer">File Reviewer (FILE_REVIEWER) — V4/V5 damage assessment</a></li>
|
||||||
|
<li><a href="#registrar">Registrar (REGISTRAR) — office-based filing</a></li>
|
||||||
|
<li><a href="#call-center">Call Center (CALL_CENTER) — V6 phone-initiated filing</a></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Role overview table ────────────────────────────────────── -->
|
||||||
|
<h2>Role Overview</h2>
|
||||||
|
<table class="overview-table">
|
||||||
|
<tr>
|
||||||
|
<th>Role enum</th>
|
||||||
|
<th>Login panel</th>
|
||||||
|
<th>Scope</th>
|
||||||
|
<th>Primary job</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>company</code></td>
|
||||||
|
<td>Insurer portal</td>
|
||||||
|
<td>Tenant-wide</td>
|
||||||
|
<td>View all files; manage branches, experts; run reports; rate experts</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>expert</code></td>
|
||||||
|
<td>Blame expert panel</td>
|
||||||
|
<td>Tenant DISAGREEMENT queue</td>
|
||||||
|
<td>Lock blame cases, review party submissions, submit verdict or request resend</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>damage_expert</code></td>
|
||||||
|
<td>Claim/damage panel</td>
|
||||||
|
<td>Tenant claim queue</td>
|
||||||
|
<td>Lock claims, price damage, validate repair factors, request resend/visit</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>field_expert</code></td>
|
||||||
|
<td>Field expert panel</td>
|
||||||
|
<td>Own created files</td>
|
||||||
|
<td>V2/V3 in-person blame + claim filing; also sees blame/claim review panels</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>file_maker</code></td>
|
||||||
|
<td>FileMaker panel</td>
|
||||||
|
<td>Own created files</td>
|
||||||
|
<td>V4/V5 party narrative (OTPs, inquiries, details, signatures); V5 claim approval</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>file_reviewer</code></td>
|
||||||
|
<td>FileReviewer panel</td>
|
||||||
|
<td>Assigned files</td>
|
||||||
|
<td>V4/V5 damage assessment (accident fields, parts, captures, owner sign)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>registrar</code></td>
|
||||||
|
<td>Registrar panel</td>
|
||||||
|
<td>Own created files</td>
|
||||||
|
<td>Office-based in-person blame + claim filing on behalf of parties</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>call_center</code></td>
|
||||||
|
<td>Call-center panel</td>
|
||||||
|
<td>Own created files</td>
|
||||||
|
<td>V6 phone-initiated blame: run inquiry, send link; user completes the rest</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="insurer">1 — Insurer <span class="role-enum">company</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
One <code>company</code> actor per insurance-company tenant. The insurer portal is the
|
||||||
|
management layer: it can see everything under its tenant, manage the expert roster,
|
||||||
|
manage branches, configure per-tenant media settings, and pull statistical reports.
|
||||||
|
The insurer never touches blame/claim steps directly — it only observes and rates.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>File management — <code>expert-insurer/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files</code></td><td>List all blame + claim files for the tenant (merged by publicId). Filterable by status, file type, search, sort, page.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId</code></td><td>Full detail for one file by publicId.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId/timeline</code></td><td>Chronological activity timeline (all history events: source, type, actor, metadata).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/files/:publicId/report</code></td><td>Structured report data for PDF generation (owner, driver, insurance, vehicle, accident sections).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>expert-insurer/files/:publicId/rating</code></td><td>Rate the experts on a file (1–5 per dimension: collision method, timeliness, cause accuracy, guilty-ID accuracy, bot rating).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/report/unified-file-statuses</code></td><td>Unified status catalog + per-status counts for the whole tenant portfolio. Filterable by fileType and date range.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/report/status-counts</code></td><td class="dep">Deprecated — prefer unified-file-statuses.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Branch management — <code>expert-insurer/branches</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/branches</code></td><td>List all branches for this insurer. Query: search, from/to date, isActive filter.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/branches</code></td><td>Add a new branch (name, code, address, city, phone, etc.).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>expert-insurer/branches/:branchId/status</code></td><td>Activate or deactivate a branch.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Expert roster management — <code>expert-insurer/experts</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/blame</code></td><td>Create a new blame-expert account under this insurer.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/claim</code></td><td>Create a new damage-expert (claim) account under this insurer.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/file-maker</code></td><td>Create a new FileMaker account under this insurer.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>expert-insurer/experts/file-reviewer</code></td><td>Create a new FileReviewer account under this insurer.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/experts/list</code></td><td>Paginated list of all expert accounts on this tenant.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/experts/top</code></td><td>Top blame vs claim experts ranked by overall average rating (up to 10 each).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/top-experts</code></td><td>Alias for experts/top (frontend compat).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/:expertId</code></td><td>Files handled by one expert (slim summary rows — blame or claim depending on expert type).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Statistics & reports</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/statistics</code></td><td>KPI cards: totalFilesReviewed, averageUserRating, inPersonCount, filesThisMonth, objectionPercentage, etc. Filterable by date range.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/top-files</code></td><td>Top 10 highest-rated claim files (combined insurer + user score).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>expert-insurer/expert-work-log</code></td><td>Per-expert work log: totalHandled, currentlyChecking, distinctFilesCheckedInPeriod. Filterable by expertKind and date range.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/requests</code></td><td>Claim + blame status bucket counts + unified file count for the tenant.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/per-month-requests</code></td><td>Same summary, broken down by the last 5 calendar months.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/checked-requests</code></td><td>Same summary filtered by optional createdAt date range.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/expert-work-log</code></td><td>Expert work log (blame + damage expert collections, not field experts).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>reports/report/insurer/expert-work-log/per-month</code></td><td>Same work log per calendar month (last 5).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-blue">
|
||||||
|
<h3>Tenant settings — <code>client-panel/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>client-panel/settings</code></td><td>Get per-tenant media limits (video/image/voice maxBytes) and CAR_BODY accident window (days).</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>client-panel/settings</code></td><td>Update those settings (partial). Cannot exceed system-level route ceilings.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="blame-expert">2 — Blame Expert <span class="role-enum">expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Reviews blame files in the DISAGREEMENT queue — cases where the two parties do not
|
||||||
|
agree on who is at fault. After reviewing submitted documents and party statements
|
||||||
|
the expert locks the case, then either submits a verdict, asks the parties to resend
|
||||||
|
documents, or records an in-person visit outcome. All endpoints are under
|
||||||
|
<code>v2/expert-blame/</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>Process</h3>
|
||||||
|
<p class="note">
|
||||||
|
1 Browse list → 2 Assign (lock) the case → 3 Review party evidence (videos, voices, documents) →
|
||||||
|
4a Submit verdict <em>or</em> 4b Request document resend <em>or</em> 4c Record in-person visit.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-orange">
|
||||||
|
<h3>Endpoints — <code>v2/expert-blame/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/</code></td><td>List blame cases in the DISAGREEMENT queue (available, locked by me, or decided by me). Query: search, sortBy, sortOrder, page, limit, unifiedStatus, fileType.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/:id</code></td><td>Full detail for one blame case (party statements, photos, voices, videos).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>v2/expert-blame/:id/assign</code></td><td>Check availability and lock the case to this expert. Returns <code>assigned</code>, <code>already_assigned_to_you</code>, or 409 if someone else holds it.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/submit/:id</code></td><td>Submit verdict (accidentWay, accidentReason, accidentType, guilty party decision). Unlocks the case and moves it to COMPLETED.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/resend/:id</code></td><td>Request parties to re-upload documents. Sets blame to WAITING_FOR_RESEND. One resend request per lifecycle.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/reply/inPerson/:id</code></td><td>Record that an in-person visit was made and submit verdict.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/report/unified-file-statuses</code></td><td>Status catalog + per-status counts for this expert's portfolio.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-blame/report/status-counts</code></td><td class="dep">Deprecated — prefer unified-file-statuses.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-blame/lock/:id</code></td><td class="dep">Deprecated lock endpoint — use POST assign.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="damage-expert">3 — Damage Expert <span class="role-enum">damage_expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Reviews claim files after the user has submitted their damage evidence. The expert
|
||||||
|
prices each damaged part, optionally calculates a price-drop (depreciation), and
|
||||||
|
can ask the user to resend documents, come in person, or upload repair factor invoices
|
||||||
|
when workshop pricing is needed. All endpoints are under <code>v2/expert-claim/</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-red">
|
||||||
|
<h3>Process</h3>
|
||||||
|
<p class="note">
|
||||||
|
1 Browse list → 2 Assign (lock) the claim → 3 Review damage photos and documents →
|
||||||
|
4 Optionally edit selected parts or calculate price-drop →
|
||||||
|
5a Submit priced reply <em>or</em> 5b Request resend <em>or</em> 5c Request in-person visit →
|
||||||
|
6 If factor parts present: validate uploaded factor invoices.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-red">
|
||||||
|
<h3>Endpoints — <code>v2/expert-claim/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/requests</code></td><td>List claims in <code>WAITING_FOR_DAMAGE_EXPERT</code> queue + factor-validation queue. Query: search, sortBy, page, limit, unifiedStatus, fileType.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/request/:claimRequestId</code></td><td>Full claim detail: damaged parts, captured images, documents, priceDrop, blameCase party data, video URLs.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>v2/expert-claim/assign/:claimRequestId</code></td><td>Lock claim to this expert. Returns <code>assigned</code>, <code>already_assigned_to_you</code>, or 409.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/request/:claimRequestId/price-drop</code></td><td>Price-drop context: severity labels, coefficient catalog, damaged parts + mapping, suggested car year from blame inquiry.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/request/:claimRequestId/price-drop</code></td><td>Calculate and persist price-drop: carPrice × yearCoeff × sumOfCoeffs ÷ 400.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/reply/submit/:claimRequestId</code></td><td>Submit damage assessment reply (priced parts list, daghi, branchId). Cap: total ≤ 53 000 000 Toman. Depending on factorNeeded flags moves claim to owner-sign, mixed-factors-pending, or factor-validation queue.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/reply/resend/:claimRequestId</code></td><td>Request user to resend documents/photos. One resend per claim lifecycle; returns 422 if already fulfilled.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/:claimRequestId/visit</code></td><td>Ask user to come in person. Unlocks claim, sets claimStatus to NEEDS_REVISION.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/validate-factors/:claimRequestId</code></td><td>Validate uploaded repair factor invoices. Approve or reject each factor line with totalPayment. Cap applies across all lines (≤ 53 000 000 Toman). Auto-completes when all lines are decided.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>v2/expert-claim/request/:claimRequestId/damaged-parts</code></td><td>Edit selected damaged parts while the claim is locked by this expert (EXPERT_REVIEWING).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/outer-parts-catalog</code></td><td>Fanavaran outer car-components catalog (shared with user flow).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/inner-parts-catalog</code></td><td>Static inner car-parts catalog JSON.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/branches</code></td><td>Insurer branches for this expert's tenant (for daghi/branch selection in reply payload).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/stream/:id/video</code></td><td>Stream claim video (car-capture walk-around or accident video). Query: <code>query=car-capture|accident</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/report/unified-file-statuses</code></td><td>Status catalog + counts for this expert's claim portfolio.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>v2/expert-claim/report/status-counts</code></td><td class="dep">Deprecated — prefer unified-file-statuses.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>v2/expert-claim/lock/:claimRequestId</code></td><td class="dep">Deprecated lock endpoint — use POST assign.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="field-expert">4 — Field Expert <span class="role-enum">field_expert</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Goes to the accident scene and fills both parties' forms in-person (V2 mirror / V3 flows).
|
||||||
|
The field expert also has read access to the expert-blame and expert-claim panels
|
||||||
|
(scoped to their own files). They are the only role that spans both
|
||||||
|
<strong>blame filing</strong> and <strong>claim filing</strong> in the same session.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>Blame filing — <code>v2/expert-initiated/blame-request-management/</code></h3>
|
||||||
|
<p class="note">Mirror of the user blame API. Frontend reuses same pages by swapping prefix only.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>POST /</code></td><td>Create IN_PERSON blame file.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-party-otp/:id</code></td><td>Send OTP to one party by phone number (no invite link).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>verify-party-otp/:id</code></td><td>Verify one party's OTP and bind their account.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>blame-confession/:id</code></td><td>Record party's blame confession.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>car-body-form/:id</code></td><td>[CAR_BODY only] Accident type form.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiries/:id</code> / <code>run-inquiries-vin/:id</code></td><td>Initial form / plate or VIN inquiry for current party.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:id</code></td><td>Upload first-party video.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-location/:id</code></td><td>Add GPS location for current party.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-voice/:id</code></td><td>Upload voice recording for current party.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-description/:id</code></td><td>Add description for current party.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-second-party/:phone/:id/</code></td><td>Advance to second party (no SMS link sent).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>sign/:id</code></td><td>Upload party signature (FIRST then SECOND, partyRole param).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:id</code></td><td>Save accident fields and complete blame immediately (no expert queue).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>V3 blame + claim filing — <code>v3/expert-initiated/blame-request-management/</code></h3>
|
||||||
|
<p class="note">Reorganised step order: all party narrative first, then damage assessment. Blame and claim both handled in this single controller.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>POST /</code> → <code>send-party-otp</code> → <code>verify-party-otp</code> → <code>run-inquiries</code> → <code>add-detail-*</code> → <code>sign</code> (×2)</td><td>Party narrative phase (steps 1–8) — identical endpoints to mirror, same contract.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:id</code></td><td>Step 9: save accident fields after both parties have signed.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>Step 10: get auto-created claim ID.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>Step 11: upload licence / car card documents.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code> / <code>select-other-parts/:claimId</code></td><td>Steps 12–13: select damaged parts.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>Step 14: capture part photos + angles.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>Step 15: walk-around video.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:requestId</code></td><td>Step 16: blame accident video (final) → WAITING_FOR_EXPERT (THIRD_PARTY) or COMPLETED (CAR_BODY).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-green">
|
||||||
|
<h3>Expert-blame + expert-claim panel (read + action on own files)</h3>
|
||||||
|
<p class="note">
|
||||||
|
FIELD_EXPERT sees <code>v2/expert-blame/</code> scoped to their own created files (not the disagreement queue).
|
||||||
|
They also see <code>v2/expert-claim/</code> for claims linked to their blame files.
|
||||||
|
Same endpoints as blame-expert and damage-expert panels above.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="file-maker">5 — File Maker <span class="role-enum">file_maker</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
The first actor in the V4/V5 split. FileMaker handles the party narrative on-site:
|
||||||
|
OTPs, inquiries, location/description/voice, and signatures for both parties.
|
||||||
|
They also upload the initial claim documents (licences, car cards). After the second
|
||||||
|
signature the file is "sealed" for FileReviewer pickup. In V5, FileMaker comes
|
||||||
|
back at the end to approve or reject the completed claim before fanavaran submission.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>Blame filing — <code>v4/file-maker/blame-request-management/</code> and <code>v5/…</code></h3>
|
||||||
|
<p class="note">V4 and V5 endpoints are identical — only the prefix changes. V5 sets <code>requiresFileMakerApproval=true</code> at creation.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>POST /</code></td><td>Create IN_PERSON blame file.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>List all blame files created by this FileMaker.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files/:requestId</code></td><td>Full detail for one file (parties, workflow, linked claim ID).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>Get the auto-created claim ID after guilty-party run-inquiries.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-party-otp/:id</code> / <code>verify-party-otp/:id</code></td><td>Send + verify OTP for one party at a time (guilty first, then damaged).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>car-body-form/:id</code></td><td>[CAR_BODY only] Accident type form.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiries/:id</code> / <code>run-inquiries-vin/:id</code></td><td>Run plate or VIN inquiry. First call = guilty (+ auto-creates claim). Second call = damaged (THIRD_PARTY only).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>add-detail-location/:id</code> / <code>add-detail-description/:id</code> / <code>upload-voice/:id</code></td><td>Add location, description, and voice for current party (partyRole param selects FIRST/SECOND).</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>sign/:id</code></td><td>Upload party signature (partyRole=FIRST then SECOND). After second signature, file is sealed.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>Upload licences / car cards against the auto-created claim.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>capture-requirements/:claimId</code></td><td>Step-aware capture requirements (phases: pre-capture docs vs damaged parts + chassis/engine).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-purple">
|
||||||
|
<h3>V5 claim approval — <code>v5/file-maker/claim-approval/</code></h3>
|
||||||
|
<p class="note">Used only in V5. After damage expert review and owner sign, claim enters <code>WAITING_FOR_FILE_MAKER_APPROVAL</code>.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>approve/:claimId</code></td><td>Approve the completed claim → triggers owner sign SMS → fanavaran submission after owner signs.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>reject/:claimId</code></td><td>Reject back to FileReviewer → claim returns to WAITING_FOR_DAMAGE_EXPERT. Limit: max 2 rejections per claim; 3rd attempt returns 422 <code>FILE_MAKER_REJECTION_LIMIT_EXCEEDED</code>.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="file-reviewer">6 — File Reviewer <span class="role-enum">file_reviewer</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
The second actor in the V4/V5 split. FileReviewer picks up sealed files (after
|
||||||
|
FileMaker is done) and performs the full damage assessment pass: accident fields,
|
||||||
|
capture requirements lookup, document upload (chassis/engine), part selection,
|
||||||
|
part photos, walk-around video, owner signature. The blame is marked COMPLETED
|
||||||
|
by car-capture. FileReviewer also has read access to the expert-claim panel for
|
||||||
|
claims they are reviewing.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>Damage assessment — <code>v4/file-reviewer/blame-request-management/</code> and <code>v5/…</code></h3>
|
||||||
|
<p class="note">V4 and V5 endpoints are identical — only the prefix changes.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>List all files assigned to this FileReviewer.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files/:requestId</code></td><td>Full detail for one file (parties, workflow, expert fields, linked claim ID).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>claim-id/:requestId</code></td><td>Get the auto-created claim ID (from FileMaker's guilty-party inquiry).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>accident-fields/:requestId</code></td><td>Step 1 (FileReviewer): save accident fields (accidentWay, accidentReason, accidentType).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>capture-requirements/:claimId</code></td><td>Step-aware capture requirements (pre-capture docs phase vs capture-parts phase).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>Upload chassis / engine / metal-plate documents.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code></td><td>Select outer (body) damaged parts.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-other-parts/:claimId</code></td><td>Select other (non-body) damaged parts.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>Capture part photos + angles for each selected damaged part.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>Walk-around video (final FileReviewer capture step). Claim → <code>WAITING_FOR_DAMAGE_EXPERT</code>, blame → <code>COMPLETED</code>.</td></tr>
|
||||||
|
<tr><td><span class="method put">PUT</span></td><td><code>claim-sign/:claimId</code></td><td>Submit owner signature on expert pricing on behalf of the damaged party (agree + branchId + signature image).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-video/:requestId</code></td><td class="dep">No-op in V4/V5 — blame already COMPLETED by car-capture. Returns idempotent success.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-teal">
|
||||||
|
<h3>Expert-claim panel access</h3>
|
||||||
|
<p class="note">
|
||||||
|
FILE_REVIEWER is in the allowed roles for <code>v2/expert-claim/</code>.
|
||||||
|
They can view claim details and run the assign/lock flow for claims associated
|
||||||
|
with their files. They cannot initiate a damage-expert resend independently.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="registrar">7 — Registrar <span class="role-enum">registrar</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Office-based role that files in-person blame and claim on behalf of parties.
|
||||||
|
Uses a bulk-OTP flow (both parties' OTPs sent and verified in one call each)
|
||||||
|
rather than the one-at-a-time OTP used by field experts. After blame, the
|
||||||
|
registrar mirrors the user claim API to fill part selection, documents, and
|
||||||
|
captures. The file then enters the normal damage-expert review lifecycle.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>Blame filing — <code>registrar-initiated-blame/</code></h3>
|
||||||
|
<p class="note">Note: <code>@ApiExcludeController</code> — routes exist but not surfaced in Swagger docs.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/create</code></td><td>Create IN_PERSON blame file.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>registrar-initiated-blame/my-files</code></td><td>List all blame files created by this registrar.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>registrar-initiated-blame/blame/:requestId</code></td><td>Full detail for one blame file.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/send-party-otps/:id</code></td><td>Send OTPs to both parties simultaneously.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/verify-party-otps/:id</code></td><td>Verify both parties' OTPs in one call.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/complete-blame-data/:id</code></td><td>Submit all blame form data for both parties in one payload.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-video/:id</code></td><td>Upload blame video.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-voice/:id</code></td><td>Upload voice recording.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/add-accident-fields/:id</code></td><td>Save accident fields and complete blame.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>registrar-initiated-blame/upload-party-signature/:id</code></td><td>Upload a party's signature (partyRole=FIRST/SECOND).</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>Claim filing — <code>v2/registrar/claim-request-management/</code></h3>
|
||||||
|
<p class="note">Mirror of the user claim API. Frontend reuses same claim pages by swapping prefix only.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>create-from-blame/:blameId</code></td><td>Create claim from a completed blame file.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>outer-parts-catalog</code> / <code>car-other-part</code></td><td>Parts catalogs (outer body parts + other parts JSON).</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>branches/:insuranceId</code></td><td>Insurer branch list (for branch selection in claim sign step).</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-outer-parts/:claimId</code></td><td>Select outer damaged parts.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>select-other-parts/:claimId</code></td><td>Select other damaged parts + bank info.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>upload-document/:claimId</code></td><td>Upload claim documents (licences, car card).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>capture-part/:claimId</code></td><td>Capture part photos + angles.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>car-capture/:claimId</code></td><td>Walk-around video (final step) → WAITING_FOR_DAMAGE_EXPERT.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2 id="call-center">8 — Call Center <span class="role-enum">call_center</span></h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
Handles V6 phone-initiated blame filing. The agent collects the guilty party's
|
||||||
|
data over the phone, runs the insurance inquiry, and sends the blame link via
|
||||||
|
SMS. The user then completes the rest of the form through the standard V2 flow
|
||||||
|
(with the initial-form/inquiry step skipped). The call-center agent's job ends
|
||||||
|
after send-link; they can monitor progress via the read endpoints.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card card-indigo">
|
||||||
|
<h3>Endpoints — <code>v6/call-center-blame/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>create</code></td><td>Create a LINK blame file. Body: <code>{ type: "THIRD_PARTY" | "CAR_BODY" }</code>.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiry/:requestId</code></td><td>Run plate + national-code insurance inquiry for the guilty party. Stores result on blame document.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>run-inquiry-vin/:requestId</code></td><td>VIN/chassis alternative to run-inquiry. Uses ESG chassis lookup.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>send-link/:requestId</code></td><td>Register user if needed, store as first party, send blame invite link via SMS. Body: <code>{ phoneNumber }</code>.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>my-files</code></td><td>List all blame files started by this agent.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>blame/:requestId</code></td><td>Current status and workflow step for one file (to check if user has opened the link and progressed).</td></tr>
|
||||||
|
</table>
|
||||||
|
<p class="note" style="margin-top:8px;">
|
||||||
|
After <code>send-link</code> the user completes the form via
|
||||||
|
<code>v2/blame-request-management/</code> (standard V2 flow).
|
||||||
|
The initial-form / inquiry step is automatically skipped
|
||||||
|
(<code>skipInitialFormStep=true</code>). Downstream claim flow is the
|
||||||
|
standard V2 claim flow.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<h2>Shared: Actor Authentication</h2>
|
||||||
|
<p class="section-intro">
|
||||||
|
All panel actors (every role except <code>user</code>) authenticate through the same
|
||||||
|
<code>POST actor/login</code> endpoint with captcha. Password reset is via email OTP.
|
||||||
|
Profile reads and edits are also shared.
|
||||||
|
</p>
|
||||||
|
<div class="card card-gray">
|
||||||
|
<h3>Endpoints — <code>actor/</code></h3>
|
||||||
|
<table>
|
||||||
|
<tr><th style="width:70px">Method</th><th>Route</th><th>What it does</th></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>actor/captcha</code></td><td>Issue a new login captcha challenge (returns captchaId + SVG image).</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/login</code></td><td>Authenticate any actor role. Body: role, username/email/nationalCode, password, captchaId, captcha. Returns JWT access + refresh tokens.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/forget-password</code></td><td>Send password-reset OTP to email.</td></tr>
|
||||||
|
<tr><td><span class="method post">POST</span></td><td><code>actor/forget-password-verify</code></td><td>Verify OTP and set new password.</td></tr>
|
||||||
|
<tr><td><span class="method get">GET</span></td><td><code>actor/profile</code></td><td>Get current actor's profile.</td></tr>
|
||||||
|
<tr><td><span class="method patch">PATCH</span></td><td><code>actor/profile</code></td><td>Update current actor's profile.</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>Made by Sepehr</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user