docs: align dashboard payment semantics

This commit is contained in:
2026-08-20 16:54:15 +03:30
parent aff8f82f07
commit 8ba8c2c74f
2 changed files with 11 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
# Design System — ZarinPal Merchant Analytics # Design System — ZarinPal Merchant Analytics
- Status: Draft baseline for approval - Status: Draft baseline for approval
- Version: 0.1.9 - Version: 0.2.0
- Last updated: 2026-08-20 - Last updated: 2026-08-20
- Direction: Persian-first RTL - Direction: Persian-first RTL
@@ -84,7 +84,7 @@ Initial authenticated routes:
1. ورود (login) 1. ورود (login)
2. پیشخوان (overview) 2. پیشخوان (overview)
3. عملکرد پرداخت (success, retries, failures, timing) 3. عملکرد پرداخت (success, retries, failures, timing)
4. کارمزد و درآمد (relative fee/cost analytics, clearly qualified) 4. کارمزد و درآمد (real merchant fee amounts and rates in Rial)
5. مقایسه با هم‌گروه‌ها (anonymized category/cohort benchmark) 5. مقایسه با هم‌گروه‌ها (anonymized category/cohort benchmark)
6. کیفیت داده / درباره شاخص‌ها (definitions, freshness, limitations) 6. کیفیت داده / درباره شاخص‌ها (definitions, freshness, limitations)
7. حساب کاربری / خروج 7. حساب کاربری / خروج
@@ -113,7 +113,8 @@ Navigation labels should describe merchant tasks, not internal database concepts
- Charts have a textual summary and downloadable/visible data table when practical. - Charts have a textual summary and downloadable/visible data table when practical.
- Zero, unavailable, suppressed, and not-yet-calculated are visually and linguistically distinct. - Zero, unavailable, suppressed, and not-yet-calculated are visually and linguistically distinct.
- A ready section appears immediately without layout-shifting or blocking on unfinished siblings. Overall progress remains understandable without relying on animation. - A ready section appears immediately without layout-shifting or blocking on unfinished siblings. Overall progress remains understandable without relying on animation.
- Only source status `Verified` is presented as a confirmed successful payment. `Paid` is a separate operational state and is never merged into success or failure without a later approved metric-definition change. - Source statuses `Paid` and `Verified` both count as successful bank payments because funds were deducted. Keep them visually distinguishable: `Paid` means merchant verification is incomplete and is an actionable gap; `Verified` is finalized.
- Present `fee_amount_rial` as the merchant's real fee, summed once per session. Never multiply it by retry attempts or label it as obfuscated/relative-only in the product.
## Motion ## Motion
@@ -145,12 +146,12 @@ Navigation labels should describe merchant tasks, not internal database concepts
| Version | Date | Decision | | Version | Date | Decision |
|---|---|---| |---|---|---|
| 0.2.0 | 2026-08-20 | Corrected payment lifecycle semantics from CTO guidance: `Paid` and `Verified` are bank-payment successes, `Paid` remains unverified, and session-level fees are real Rial amounts. |
| 0.1.9 | 2026-08-20 | Added rate-limit UX, 15-second SSE heartbeat/recovery, one-hour replay, and failed-section-only manual retry. | | 0.1.9 | 2026-08-20 | Added rate-limit UX, 15-second SSE heartbeat/recovery, one-hour replay, and failed-section-only manual retry. |
| 0.1.8 | 2026-08-20 | Fixed the four parallel section ids, 30-day cache, idempotent start/SSE flow, and section timeout/retry behavior. | | 0.1.8 | 2026-08-20 | Fixed the four parallel section ids, 30-day cache, idempotent start/SSE flow, and section timeout/retry behavior. |
| 0.1.7 | 2026-08-20 | Moved analytics results to high-TTL Redis and defined partial, parallel section delivery through authenticated SSE. | | 0.1.7 | 2026-08-20 | Moved analytics results to high-TTL Redis and defined partial, parallel section delivery through authenticated SSE. |
| 0.1.6 | 2026-08-20 | Replaced time-based analytics freshness with lazy first-access calculation and revision-based merchant/cohort cache states; defined Saturday–Friday weeks. | | 0.1.6 | 2026-08-20 | Replaced time-based analytics freshness with lazy first-access calculation and revision-based merchant/cohort cache states; defined Saturday–Friday weeks. |
| 0.1.5 | 2026-08-20 | Removed holiday/event reporting; limited period controls to daily, weekly, Jalali-month, and Persian-season views. | | 0.1.5 | 2026-08-20 | Removed holiday/event reporting; limited period controls to daily, weekly, Jalali-month, and Persian-season views. |
| 0.1.4 | 2026-08-20 | Kept `Paid` separate from confirmed `Verified` success. |
| 0.1.2 | 2026-08-20 | Added the insufficient-data state and visibility threshold for anonymized peer comparisons. | | 0.1.2 | 2026-08-20 | Added the insufficient-data state and visibility threshold for anonymized peer comparisons. |
| 0.1.1 | 2026-08-20 | Fixed merchant-facing time presentation to the Jalali calendar in `Asia/Tehran`, with explicit UTC API instants. | | 0.1.1 | 2026-08-20 | Fixed merchant-facing time presentation to the Jalali calendar in `Asia/Tehran`, with explicit UTC API instants. |
| 0.1.0 | 2026-08-20 | Established ZarinPal-inspired RTL foundation from supplied public/panel screenshots; fixed SvelteKit/Svelte/TypeScript/Tailwind stack; defined responsive shell, core components, accessibility, chart, and motion rules. | | 0.1.0 | 2026-08-20 | Established ZarinPal-inspired RTL foundation from supplied public/panel screenshots; fixed SvelteKit/Svelte/TypeScript/Tailwind stack; defined responsive shell, core components, accessibility, chart, and motion rules. |

View File

@@ -26,7 +26,7 @@ Give a non-technical merchant a fast, trustworthy Persian RTL view of payment pe
8. Responsive behavior and component contracts follow `DESIGN.md`. 8. Responsive behavior and component contracts follow `DESIGN.md`.
9. Merchant-facing dates use the Jalali calendar in `Asia/Tehran`; API instants remain explicit ISO-8601 UTC and filtering sends unambiguous boundaries. 9. Merchant-facing dates use the Jalali calendar in `Asia/Tehran`; API instants remain explicit ISO-8601 UTC and filtering sends unambiguous boundaries.
10. Approved reporting periods are daily, weekly, Jalali-month, and Persian-season views. Weekly periods run Saturday through Friday in `Asia/Tehran`. Every comparison states its exact period and baseline. 10. Approved reporting periods are daily, weekly, Jalali-month, and Persian-season views. Weekly periods run Saturday through Friday in `Asia/Tehran`. Every comparison states its exact period and baseline.
11. Only source session status `Verified` counts as a confirmed successful payment. `Paid` appears as a separate operational state until an approved metric-catalogue revision defines it otherwise. 11. `Paid` and `Verified` both count as successful bank payments. `Paid` means funds were deducted but merchant verification is incomplete; `Verified` is finalized. Success and paid-volume metrics include both, while verification-health metrics show them separately.
12. The first relevant dashboard access sends an idempotent authenticated `POST` that creates or returns the current analytics run and starts four sections in bounded parallel: overview, payment performance, fees, and peer comparison. 12. The first relevant dashboard access sends an idempotent authenticated `POST` that creates or returns the current analytics run and starts four sections in bounded parallel: overview, payment performance, fees, and peer comparison.
13. The app then opens the run's authenticated `GET` SSE stream and renders each section as soon as its `ready` event arrives. A failed section has its own retry/error state and does not hide successful siblings. 13. The app then opens the run's authenticated `GET` SSE stream and renders each section as soon as its `ready` event arrives. A failed section has its own retry/error state and does not hide successful siblings.
14. Later equivalent requests reuse 30-day Redis entries. PostgreSQL merchant/cohort revision changes select new cache keys and cause only missing sections to be recalculated; cache age alone does not make static data stale. 14. Later equivalent requests reuse 30-day Redis entries. PostgreSQL merchant/cohort revision changes select new cache keys and cause only missing sections to be recalculated; cache age alone does not make static data stale.
@@ -35,6 +35,8 @@ Give a non-technical merchant a fast, trustworthy Persian RTL view of payment pe
17. SSE expects a heartbeat every 15 seconds and supports authorized replay for one hour. After replay expires, the app fetches the current run snapshot before reopening the stream. 17. SSE expects a heartbeat every 15 seconds and supports authorized replay for one hour. After replay expires, the app fetches the current run snapshot before reopening the stream.
18. Manual retry targets only one exhausted failed section. It is disabled while active, never restarts ready siblings, and handles a typed `429` by honoring `Retry-After`. 18. Manual retry targets only one exhausted failed section. It is disabled while active, never restarts ready siblings, and handles a typed `429` by honoring `Retry-After`.
19. Analytics starts, manual retries, and concurrent SSE connections expose accessible rate-limited states without discarding already-ready content or retrying in a tight loop. 19. Analytics starts, manual retries, and concurrent SSE connections expose accessible rate-limited states without discarding already-ready content or retrying in a tight loop.
20. Paid amount and fee totals count each eligible session once. Merchant fees are shown as real Rial amounts/rates; retry attempts cannot multiply a session fee.
21. Retry recovery may finish in either `Paid` or `Verified`. Timing cards show p50, p95, sample size, and non-null coverage.
## Frontend architecture baseline ## Frontend architecture baseline
@@ -52,7 +54,9 @@ Give a non-technical merchant a fast, trustworthy Persian RTL view of payment pe
- Critical flows work at 360 px, 768 px, 1024 px, and a wide desktop viewport in RTL. - Critical flows work at 360 px, 768 px, 1024 px, and a wide desktop viewport in RTL.
- Login, navigation drawer, filters, chart alternatives, and logout are keyboard complete and screen-reader understandable. - Login, navigation drawer, filters, chart alternatives, and logout are keyboard complete and screen-reader understandable.
- Values visibly specify period and unit; missing/suppressed/zero states are distinct. - Values visibly specify period and unit; missing/suppressed/zero states are distinct.
- Confirmed-success views include only `Verified`; `Paid` is separately labeled and testable. - Success views include `Paid` plus `Verified`, verification-completion views separate them, and unverified paid sessions are never styled or described as failures.
- Paid volume and merchant fee values reconcile at session grain; fee totals remain unchanged when a session has additional attempts.
- Retry recovery includes eventual `Paid` or `Verified`, and timing percentiles never treat missing values as zero.
- All core sections begin on first access and become visible independently in completion order without blocking the whole dashboard. - All core sections begin on first access and become visible independently in completion order without blocking the whole dashboard.
- The start request is idempotent and always maps equivalent concurrent starts to the same current run. - The start request is idempotent and always maps equivalent concurrent starts to the same current run.
- A second equivalent access reuses current Redis entries, and concurrent first accesses do not enqueue duplicate equivalent section jobs. - A second equivalent access reuses current Redis entries, and concurrent first accesses do not enqueue duplicate equivalent section jobs.