feat: redesign routed ZarinPal merchant dashboard
This commit is contained in:
@@ -56,12 +56,12 @@ If an implementation-facing API description later conflicts with an approved sou
|
||||
|
||||
## 4. Actors and session model
|
||||
|
||||
| Actor | Entry | Visible merchant scope | Switching behavior |
|
||||
|---|---|---|---|
|
||||
| Demo merchant user | Assigned username and password | Exactly the merchant bound to the authenticated server session | Log out, then sign in with another seeded merchant account |
|
||||
| Merchant user | Same MVP login adapter | Exactly one merchant | Same as demo user until ZarinPal SSO replaces the adapter |
|
||||
| Judge/operator | Uses separately distributed seeded credentials | No hidden operator or cross-tenant browser privilege | Uses explicit logout/login between demonstrations |
|
||||
| Finance/legal recipient | Receives an authorized CSV outside the dashboard workflow | Only fields in the merchant-owned exported detail view | No dashboard access is implied by receiving a file |
|
||||
| Actor | Entry | Visible merchant scope | Switching behavior |
|
||||
| ----------------------- | --------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| Demo merchant user | Assigned username and password | Exactly the merchant bound to the authenticated server session | Log out, then sign in with another seeded merchant account |
|
||||
| Merchant user | Same MVP login adapter | Exactly one merchant | Same as demo user until ZarinPal SSO replaces the adapter |
|
||||
| Judge/operator | Uses separately distributed seeded credentials | No hidden operator or cross-tenant browser privilege | Uses explicit logout/login between demonstrations |
|
||||
| Finance/legal recipient | Receives an authorized CSV outside the dashboard workflow | Only fields in the merchant-owned exported detail view | No dashboard access is implied by receiving a file |
|
||||
|
||||
The active merchant appears as identity context, not as a selector. The UI must not present a merchant dropdown that suggests the current session can change tenant scope.
|
||||
|
||||
@@ -69,18 +69,18 @@ The active merchant appears as identity context, not as a selector. The UI must
|
||||
|
||||
Technical route names are proposed for planning only; final route contracts remain subject to the approved interface and static-host fallback.
|
||||
|
||||
| Screen | Persian label | Primary task | Entry and exits |
|
||||
|---|---|---|---|
|
||||
| Login | ورود | Establish the demo merchant session | Entry from unauthenticated routes/session expiry; exit to overview |
|
||||
| Overview | پیشخوان | Understand current outcomes and the most important qualifying changes | Default authenticated destination; links to focused analysis/detail |
|
||||
| Payment performance | عملکرد پرداخت | Diagnose success, verification, failure, retry, and timing | From navigation/KPIs/insights; links to three approved detail views |
|
||||
| Unverified-paid detail | پرداختهای تأییدنشده | Reconcile bank-paid sessions awaiting merchant verification | From verification card; CSV eligible |
|
||||
| Failed-session detail | پرداختهای ناموفق | Review observed failure stages without invented causes | From failure card; CSV eligible |
|
||||
| Retried-session detail | پرداختهای تکرارشده | Review attempt history and eventual recovery | From retry card; CSV eligible |
|
||||
| Fees | کارمزد و درآمد | Understand real merchant fee amount and paid fee rate in Rial | From navigation/overview; no attempt-grain fee multiplication |
|
||||
| Peer comparison | مقایسه با همگروهها | Compare approved metrics with eligible same-category merchants | Aggregate-only; never links to peer rows or peer export |
|
||||
| Metric quality | کیفیت داده و شاخصها | Understand definitions, periods, freshness, coverage, suppression, and limitations | From navigation and definition/provenance links |
|
||||
| Account/session | حساب کاربری | Confirm current merchant identity, switch theme, or log out | No roles/profile editing in MVP |
|
||||
| Screen | Persian label | Primary task | Entry and exits |
|
||||
| ---------------------- | -------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| Login | ورود | Establish the demo merchant session | Entry from unauthenticated routes/session expiry; exit to overview |
|
||||
| Overview | پیشخوان | Understand current outcomes and the most important qualifying changes | Default authenticated destination; links to focused analysis/detail |
|
||||
| Payment performance | عملکرد پرداخت | Diagnose success, verification, failure, retry, and timing | From navigation/KPIs/insights; links to three approved detail views |
|
||||
| Unverified-paid detail | پرداختهای تأییدنشده | Reconcile bank-paid sessions awaiting merchant verification | From verification card; CSV eligible |
|
||||
| Failed-session detail | پرداختهای ناموفق | Review observed failure stages without invented causes | From failure card; CSV eligible |
|
||||
| Retried-session detail | پرداختهای تکرارشده | Review attempt history and eventual recovery | From retry card; CSV eligible |
|
||||
| Fees | کارمزد و درآمد | Understand real merchant fee amount and paid fee rate in Rial | From navigation/overview; no attempt-grain fee multiplication |
|
||||
| Peer comparison | مقایسه با همگروهها | Compare approved metrics with eligible same-category merchants | Aggregate-only; never links to peer rows or peer export |
|
||||
| Metric quality | کیفیت داده و شاخصها | Understand definitions, periods, freshness, coverage, suppression, and limitations | From navigation and definition/provenance links |
|
||||
| Account/session | حساب کاربری | Confirm current merchant identity, switch theme, or log out | No roles/profile editing in MVP |
|
||||
|
||||
### 5.1 Navigation hierarchy
|
||||
|
||||
@@ -304,12 +304,12 @@ Example qualifying pattern: «نرخ تکمیل تأیید ۴٫۲ واحد در
|
||||
|
||||
#### Recommended visual forms
|
||||
|
||||
| Question | Primary form | Exact alternative |
|
||||
|---|---|---|
|
||||
| Question | Primary form | Exact alternative |
|
||||
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
||||
| How are final session outcomes distributed? | Direct-labeled stacked bar; `Paid` and `Verified` visually distinct but grouped under bank-paid meaning | Semantic table of count, share, and definition |
|
||||
| Is retry recovery changing? | Period trend line/columns with exact current rate and denominator | Period/value table |
|
||||
| What are p50 and p95 times? | Paired dot/range plot per timing metric; no dual-axis chart | Table with p50, p95, sample, coverage, unit |
|
||||
| Where did failed sessions observably reach? | Ordered horizontal bars for zero-attempt, reached-bank, and other observed stages | Stage/count table with caveat |
|
||||
| Is retry recovery changing? | Period trend line/columns with exact current rate and denominator | Period/value table |
|
||||
| What are p50 and p95 times? | Paired dot/range plot per timing metric; no dual-axis chart | Table with p50, p95, sample, coverage, unit |
|
||||
| Where did failed sessions observably reach? | Ordered horizontal bars for zero-attempt, reached-bank, and other observed stages | Stage/count table with caveat |
|
||||
|
||||
`NoAttempt` means zero normalized attempts, not a failed attempt. `InBank` means an observed gateway stage, not bank rejection. Timing nulls are excluded, never displayed as zero. Reversed is outside the success numerator and appears separately when non-zero.
|
||||
|
||||
@@ -430,24 +430,24 @@ Overall progress is written as a contextual message such as «۲ از ۴ بخش
|
||||
|
||||
### 10.2 Section state matrix
|
||||
|
||||
| Contract/UI state | Visible content | Available actions | Accessibility behavior |
|
||||
|---|---|---|---|
|
||||
| Not requested | Section title and neutral placeholder only when the screen has not initiated that section | Apply valid filters/start access | No live announcement |
|
||||
| Starting | Stable section frame; «در حال آمادهسازی تحلیل…» | Controls that would duplicate start are busy/disabled | One overall polite status; `aria-busy` on affected region |
|
||||
| Queued | Section title, period/unit context, layout-matched skeleton, «در صف محاسبه» | None | Status text remains available; skeleton is hidden from assistive tech |
|
||||
| Calculating | Same stable frame, «در حال محاسبه…»; automatic backend retries remain in this state | None; no manual retry yet | Overall progress announces meaningful transitions, not animation frames |
|
||||
| Ready | Exact KPI/takeaway/chart/table/trace metadata | Definition, approved drill-down/export | Focus does not move; one concise completion announcement when useful |
|
||||
| Ready with no rows | Purpose-specific empty copy and period | Change period; no retry unless backend says failure | Announced as successful empty result, not error |
|
||||
| Ready with unavailable comparison | Current exact metric plus «مبنای مقایسه در دسترس نیست» | Definition/change period | No trend icon, relative change, or insight claim |
|
||||
| Ready with undefined rate | Numerator/denominator evidence and «نرخ قابل محاسبه نیست» | Definition/change period | Never spoken/displayed as zero |
|
||||
| Suppressed | Peer-specific privacy/insufficient-data explanation; no peer values | Definition/change period | Status text explains that merchant data is unaffected |
|
||||
| Failed after exhaustion | Section-local safe error; error/reference id only if approved and non-sensitive | «تلاش دوباره برای این بخش» | Error is associated with section heading; retry receives focus only if user initiated it |
|
||||
| Manual retry active | Ready siblings unchanged; failed section returns to calculating with retry label | Retry disabled until terminal response | Polite status; no repeated countdown announcements |
|
||||
| Rate-limited | Ready content retained; affected action explains wait and honors `Retry-After` | Retry becomes available only when permitted; no loop | Remaining time is not announced every second; announce initial limit and availability |
|
||||
| Connection recovering | Ready content retained; unfinished sections show «در حال بازیابی اتصال…» | Optional explicit reconnect only after automatic strategy stops | One overall polite status; heartbeat events are silent |
|
||||
| Replay expired | Ready content retained; «در حال همگامسازی آخرین وضعیت…» while current run snapshot loads | None during snapshot; safe retry on failure | Announce snapshot recovery outcome once |
|
||||
| Unauthorized/session ended | Merchant data removed from active view and navigation returns to login | «ورود دوباره» | Focus lands on login heading; generic session-ended message |
|
||||
| Forbidden/not found | No other-merchant existence detail; safe boundary message | Return to authorized overview | Page title and error are announced; no leaked identifier |
|
||||
| Contract/UI state | Visible content | Available actions | Accessibility behavior |
|
||||
| --------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Not requested | Section title and neutral placeholder only when the screen has not initiated that section | Apply valid filters/start access | No live announcement |
|
||||
| Starting | Stable section frame; «در حال آمادهسازی تحلیل…» | Controls that would duplicate start are busy/disabled | One overall polite status; `aria-busy` on affected region |
|
||||
| Queued | Section title, period/unit context, layout-matched skeleton, «در صف محاسبه» | None | Status text remains available; skeleton is hidden from assistive tech |
|
||||
| Calculating | Same stable frame, «در حال محاسبه…»; automatic backend retries remain in this state | None; no manual retry yet | Overall progress announces meaningful transitions, not animation frames |
|
||||
| Ready | Exact KPI/takeaway/chart/table/trace metadata | Definition, approved drill-down/export | Focus does not move; one concise completion announcement when useful |
|
||||
| Ready with no rows | Purpose-specific empty copy and period | Change period; no retry unless backend says failure | Announced as successful empty result, not error |
|
||||
| Ready with unavailable comparison | Current exact metric plus «مبنای مقایسه در دسترس نیست» | Definition/change period | No trend icon, relative change, or insight claim |
|
||||
| Ready with undefined rate | Numerator/denominator evidence and «نرخ قابل محاسبه نیست» | Definition/change period | Never spoken/displayed as zero |
|
||||
| Suppressed | Peer-specific privacy/insufficient-data explanation; no peer values | Definition/change period | Status text explains that merchant data is unaffected |
|
||||
| Failed after exhaustion | Section-local safe error; error/reference id only if approved and non-sensitive | «تلاش دوباره برای این بخش» | Error is associated with section heading; retry receives focus only if user initiated it |
|
||||
| Manual retry active | Ready siblings unchanged; failed section returns to calculating with retry label | Retry disabled until terminal response | Polite status; no repeated countdown announcements |
|
||||
| Rate-limited | Ready content retained; affected action explains wait and honors `Retry-After` | Retry becomes available only when permitted; no loop | Remaining time is not announced every second; announce initial limit and availability |
|
||||
| Connection recovering | Ready content retained; unfinished sections show «در حال بازیابی اتصال…» | Optional explicit reconnect only after automatic strategy stops | One overall polite status; heartbeat events are silent |
|
||||
| Replay expired | Ready content retained; «در حال همگامسازی آخرین وضعیت…» while current run snapshot loads | None during snapshot; safe retry on failure | Announce snapshot recovery outcome once |
|
||||
| Unauthorized/session ended | Merchant data removed from active view and navigation returns to login | «ورود دوباره» | Focus lands on login heading; generic session-ended message |
|
||||
| Forbidden/not found | No other-merchant existence detail; safe boundary message | Return to authorized overview | Page title and error are announced; no leaked identifier |
|
||||
|
||||
### 10.3 Stale/freshness language
|
||||
|
||||
@@ -499,17 +499,17 @@ Chart rules:
|
||||
|
||||
### 11.3 Status vocabulary
|
||||
|
||||
| Data meaning | Persian display | Prohibited interpretation |
|
||||
|---|---|---|
|
||||
| `Verified` | تأییدشده | — |
|
||||
| `Paid` | پرداختشده، در انتظار تأیید پذیرنده | ناموفق |
|
||||
| `Failed` | ناموفق | A specific cause unless the source proves it |
|
||||
| `Reversed` | برگشتخورده | Successful/finalized |
|
||||
| `NoAttempt` | بدون تلاش پرداخت | A failed attempt |
|
||||
| `InBank` | رسیده به درگاه بانکی | ردشده توسط بانک |
|
||||
| Undefined rate | نرخ قابل محاسبه نیست | `۰٪` |
|
||||
| No rows | دادهای در این بازه وجود ندارد | System failure |
|
||||
| Peer suppression | داده همگروه کافی نیست | Merchant underperformance |
|
||||
| Data meaning | Persian display | Prohibited interpretation |
|
||||
| ---------------- | ----------------------------------- | -------------------------------------------- |
|
||||
| `Verified` | تأییدشده | — |
|
||||
| `Paid` | پرداختشده، در انتظار تأیید پذیرنده | ناموفق |
|
||||
| `Failed` | ناموفق | A specific cause unless the source proves it |
|
||||
| `Reversed` | برگشتخورده | Successful/finalized |
|
||||
| `NoAttempt` | بدون تلاش پرداخت | A failed attempt |
|
||||
| `InBank` | رسیده به درگاه بانکی | ردشده توسط بانک |
|
||||
| Undefined rate | نرخ قابل محاسبه نیست | `۰٪` |
|
||||
| No rows | دادهای در این بازه وجود ندارد | System failure |
|
||||
| Peer suppression | داده همگروه کافی نیست | Merchant underperformance |
|
||||
|
||||
## 12. Persian RTL content and formatting
|
||||
|
||||
@@ -587,18 +587,18 @@ This is a scope confirmation, not a destructive confirmation. Focus returns to t
|
||||
|
||||
### 14.3 Generation and download states
|
||||
|
||||
| State | UX behavior |
|
||||
|---|---|
|
||||
| Ready to request | Show scope summary; generation action enabled |
|
||||
| Requesting | «در حال ثبت درخواست…»; prevent duplicate request |
|
||||
| Generating | Keep detail table usable; show «فایل در حال آمادهسازی است…» with period/unit; do not imply browser-side row assembly |
|
||||
| Ready | Show «فایل آماده است» plus explicit «دانلود CSV»; download is tied to the authorized artifact/response |
|
||||
| Empty | «برای فیلترهای انتخابشده ردیفی برای خروجی وجود ندارد.»; no blank misleading file unless interface explicitly returns one |
|
||||
| Rate-limited | Preserve table and generation context; honor `Retry-After`; no retry loop |
|
||||
| Failed/recoverable | Safe reason category and «تلاش دوباره» for the same approved scope |
|
||||
| Session ended | Cancel access to artifact, remove ready download action, return to login; re-login does not silently resume old download |
|
||||
| Forbidden/not found | Do not confirm another merchant/artifact exists; return to authorized detail context |
|
||||
| Filters changed | Invalidate the prior preflight scope; require a new explicit generation request for current filters |
|
||||
| State | UX behavior |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Ready to request | Show scope summary; generation action enabled |
|
||||
| Requesting | «در حال ثبت درخواست…»; prevent duplicate request |
|
||||
| Generating | Keep detail table usable; show «فایل در حال آمادهسازی است…» with period/unit; do not imply browser-side row assembly |
|
||||
| Ready | Show «فایل آماده است» plus explicit «دانلود CSV»; download is tied to the authorized artifact/response |
|
||||
| Empty | «برای فیلترهای انتخابشده ردیفی برای خروجی وجود ندارد.»; no blank misleading file unless interface explicitly returns one |
|
||||
| Rate-limited | Preserve table and generation context; honor `Retry-After`; no retry loop |
|
||||
| Failed/recoverable | Safe reason category and «تلاش دوباره» for the same approved scope |
|
||||
| Session ended | Cancel access to artifact, remove ready download action, return to login; re-login does not silently resume old download |
|
||||
| Forbidden/not found | Do not confirm another merchant/artifact exists; return to authorized detail context |
|
||||
| Filters changed | Invalidate the prior preflight scope; require a new explicit generation request for current filters |
|
||||
|
||||
### 14.4 Export content boundary
|
||||
|
||||
@@ -668,18 +668,18 @@ Normative basis: [WCAG 2.2](https://www.w3.org/TR/WCAG22/). The focus-obscuring
|
||||
|
||||
## 16. Responsive behavior matrix
|
||||
|
||||
| Concern | Mobile <768 px | Tablet 768–1023 px | Desktop ≥1024 px |
|
||||
|---|---|---|---|
|
||||
| Navigation | Right drawer; compact header | Right drawer | Fixed right sidebar |
|
||||
| Main gutter | 16 px | 20–24 px | 24–32 px |
|
||||
| KPI layout | One column | One or two by content fit | Four headline cards in one row when space permits |
|
||||
| Filter bar | Disclosure/full-width controls; explicit Apply | Two rows | One quiet row where content fits |
|
||||
| Charts | ≥240 px; exact value first; table toggle | Full width or two-column by fit | 8/4 or full 12-column |
|
||||
| Detail table | Priority row summary + disclosure; optional labeled horizontal table | Priority columns; controlled horizontal scroll | Full semantic table |
|
||||
| Export preflight | Full-screen dialog/sheet respecting safe areas | Modal/inline panel | Modal/inline panel near action |
|
||||
| Insights | Stack after relevant KPI | Stack or companion column | Companion 4-column panel where useful |
|
||||
| Merchant identity | Two-line compact context | Compact context | Full sidebar block |
|
||||
| Theme control | Accessible icon+name in drawer/header | Header/drawer | Utility area |
|
||||
| Concern | Mobile <768 px | Tablet 768–1023 px | Desktop ≥1024 px |
|
||||
| ----------------- | -------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------- |
|
||||
| Navigation | Right drawer; compact header | Right drawer | Fixed right sidebar |
|
||||
| Main gutter | 16 px | 20–24 px | 24–32 px |
|
||||
| KPI layout | One column | One or two by content fit | Four headline cards in one row when space permits |
|
||||
| Filter bar | Disclosure/full-width controls; explicit Apply | Two rows | One quiet row where content fits |
|
||||
| Charts | ≥240 px; exact value first; table toggle | Full width or two-column by fit | 8/4 or full 12-column |
|
||||
| Detail table | Priority row summary + disclosure; optional labeled horizontal table | Priority columns; controlled horizontal scroll | Full semantic table |
|
||||
| Export preflight | Full-screen dialog/sheet respecting safe areas | Modal/inline panel | Modal/inline panel near action |
|
||||
| Insights | Stack after relevant KPI | Stack or companion column | Companion 4-column panel where useful |
|
||||
| Merchant identity | Two-line compact context | Compact context | Full sidebar block |
|
||||
| Theme control | Accessible icon+name in drawer/header | Header/drawer | Utility area |
|
||||
|
||||
Acceptance widths: 360 px, 768 px, 1024 px, and 1440 px; include 320 CSS px reflow/zoom verification.
|
||||
|
||||
@@ -687,21 +687,21 @@ Acceptance widths: 360 px, 768 px, 1024 px, and 1440 px; include 320 CSS px refl
|
||||
|
||||
All strings are complete messages; variable insertion must preserve Persian grammar and bidi isolation.
|
||||
|
||||
| Situation | Approved pattern |
|
||||
|---|---|
|
||||
| Overall progress | «{آماده} از ۴ بخش تحلیل آماده است.» |
|
||||
| Calculating | «این بخش در حال محاسبه است…» |
|
||||
| Recovering SSE | «ارتباط با تحلیل قطع شد؛ در حال بازیابی اتصال…» |
|
||||
| Snapshot fallback | «در حال همگامسازی آخرین وضعیت تحلیل…» |
|
||||
| Section failure | «محاسبه این بخش انجام نشد. میتوانید فقط همین بخش را دوباره اجرا کنید.» |
|
||||
| Rate limited | «درخواستهای زیادی ثبت شده است. پس از {زمان} دوباره تلاش کنید.» |
|
||||
| Baseline unavailable | «مبنای مقایسه برای این بازه در دسترس نیست.» |
|
||||
| Undefined rate | «بهدلیل نبود مخرج معتبر، این نرخ قابل محاسبه نیست.» |
|
||||
| Empty period | «در بازه انتخابشده دادهای برای این شاخص وجود ندارد.» |
|
||||
| Session ended | «نشست شما پایان یافته است. برای ادامه دوباره وارد شوید.» |
|
||||
| Safe forbidden | «به این اطلاعات دسترسی ندارید. به پیشخوان حساب خود برگردید.» |
|
||||
| Export ready | «فایل CSV برای بازه انتخابشده آماده است.» |
|
||||
| Export failed | «ساخت فایل انجام نشد. میتوانید همین درخواست را دوباره ثبت کنید.» |
|
||||
| Situation | Approved pattern |
|
||||
| -------------------- | ----------------------------------------------------------------------- |
|
||||
| Overall progress | «{آماده} از ۴ بخش تحلیل آماده است.» |
|
||||
| Calculating | «این بخش در حال محاسبه است…» |
|
||||
| Recovering SSE | «ارتباط با تحلیل قطع شد؛ در حال بازیابی اتصال…» |
|
||||
| Snapshot fallback | «در حال همگامسازی آخرین وضعیت تحلیل…» |
|
||||
| Section failure | «محاسبه این بخش انجام نشد. میتوانید فقط همین بخش را دوباره اجرا کنید.» |
|
||||
| Rate limited | «درخواستهای زیادی ثبت شده است. پس از {زمان} دوباره تلاش کنید.» |
|
||||
| Baseline unavailable | «مبنای مقایسه برای این بازه در دسترس نیست.» |
|
||||
| Undefined rate | «بهدلیل نبود مخرج معتبر، این نرخ قابل محاسبه نیست.» |
|
||||
| Empty period | «در بازه انتخابشده دادهای برای این شاخص وجود ندارد.» |
|
||||
| Session ended | «نشست شما پایان یافته است. برای ادامه دوباره وارد شوید.» |
|
||||
| Safe forbidden | «به این اطلاعات دسترسی ندارید. به پیشخوان حساب خود برگردید.» |
|
||||
| Export ready | «فایل CSV برای بازه انتخابشده آماده است.» |
|
||||
| Export failed | «ساخت فایل انجام نشد. میتوانید همین درخواست را دوباره ثبت کنید.» |
|
||||
|
||||
Persian digits are applied to rendered variable values. Technical identifiers inside an error/support reference remain Latin and isolated LTR.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user