Files
zarinpal-analytics-frontend/DESIGN.md

165 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design System — ZarinPal Merchant Analytics
- Status: Draft baseline for approval
- Version: 0.1.8
- Last updated: 2026-08-20
- Direction: Persian-first RTL
## Design intent
Match the recognizable product language of ZarinPal without copying inaccessible proprietary assets: calm financial confidence, generous whitespace, crisp white surfaces, strong blue actions, restrained yellow accents, dark ink sections, rounded geometry, and dense data presented in plain language.
The authenticated panel screenshots are the primary behavioral reference: fixed right navigation on desktop, right-side drawer on narrow screens, light gray workspace, white cards, compact outlined controls, blue active states, and direct numerical summaries. The public-site screenshots inform larger radius, dark promotional surfaces, and spacing—but the dashboard prioritizes speed and legibility over marketing spectacle.
## Foundations
### Color tokens
| Token | Value | Use |
|---|---:|---|
| `--color-brand-600` | `#0A33FF` | Primary actions, active navigation, links, selected chart series |
| `--color-brand-700` | `#0828CC` | Hover/pressed brand state |
| `--color-accent-400` | `#FFD400` | Small ZarinPal-like accent, highlights; never body text on white |
| `--color-ink-950` | `#19191A` | Primary text, dark panels |
| `--color-ink-700` | `#3D3D42` | Secondary strong text |
| `--color-ink-500` | `#6B6B73` | Supporting text |
| `--color-canvas` | `#F1F1F3` | Application background |
| `--color-surface` | `#FFFFFF` | Cards, drawer, dialogs |
| `--color-surface-muted` | `#F7F7F8` | Nested panels, table headers |
| `--color-border` | `#E3E3E7` | Dividers and neutral outlines |
| `--color-success-600` | `#248061` | Success states and positive semantic data |
| `--color-warning-600` | `#A86700` | Warnings; paired with text/icon, never color alone |
| `--color-danger-500` | `#FF5C5D` | Errors and destructive actions |
| `--color-info-surface` | `#E7F2FF` | Informational callouts |
All text/background pairs must meet WCAG 2.2 AA contrast. Chart palettes require patterns, labels, or shapes in addition to hue.
### Typography
- Preferred Persian UI family: a legally distributable Yekan-family webfont if supplied/licensed for this project.
- Safe open fallback: `Vazirmatn`, then `Tahoma`, system sans-serif.
- Use tabular numerals for tables/KPIs where supported.
- Body: 14–16 px, line-height 1.7–1.9 for Persian.
- Labels/meta: 12–14 px; never below 12 px.
- Section heading: 20–24 px, weight 700.
- Page heading: 28–32 px desktop, 24–28 px mobile, weight 700–800.
- Avoid ultralight weights and excessive bolding. Keep Persian punctuation and half-spaces correct.
### Spacing, shape, elevation
- Base spacing unit: 4 px; common sequence `4, 8, 12, 16, 24, 32, 48, 64`.
- Control height: 40 px desktop; interactive touch target at least 44×44 px on touch layouts.
- Card radius: 12 px for dense dashboard cards; 16–20 px for feature/empty-state surfaces.
- Button/input radius: 8–10 px; pill radius only for compact statuses and segmented controls.
- Card border is preferred over shadow. Default elevation is subtle (`0 1px 3px rgb(25 25 26 / 0.08)`); overlays may use stronger elevation.
- Content width is bounded for scanning; tables/charts may use the full available dashboard column.
## Layout and responsiveness
### Desktop (≥ 1024 px)
- Fixed right sidebar, approximately 248–272 px wide.
- Top utility bar remains visually quiet.
- Main content uses a centered, fluid container with 24–32 px gutters.
- Overview uses a 12-column grid. Primary analytics get 8 columns; secondary summaries get 4 where useful.
- Do not create large empty regions merely to mimic the reference screenshot; use the density required by real content.
### Tablet (768–1023 px)
- Sidebar becomes an overlay drawer from the right.
- Two-column cards collapse according to content, not arbitrary device labels.
- Tables may scroll horizontally only after priority columns and responsive alternatives are considered.
### Mobile (< 768 px)
- Single-column content, 16 px outer gutter.
- Right-side navigation drawer traps focus, closes with Escape/backdrop, restores focus to its trigger, and locks background scroll.
- KPI pairs stack; charts remain at least 240 px tall and expose an accessible data table/summary.
- Sticky actions must not cover content or browser safe areas.
## Navigation and information architecture
Initial authenticated routes:
1. ورود (login)
2. پیشخوان (overview)
3. عملکرد پرداخت (success, retries, failures, timing)
4. کارمزد و درآمد (relative fee/cost analytics, clearly qualified)
5. مقایسه با هم‌گروه‌ها (anonymized category/cohort benchmark)
6. کیفیت داده / درباره شاخص‌ها (definitions, freshness, limitations)
7. حساب کاربری / خروج
Navigation labels should describe merchant tasks, not internal database concepts. Active location is conveyed by color plus a bar/background and `aria-current`.
## Core component contracts
- **App shell:** sidebar/drawer, utility header, page title, merchant identity, analytics progress/status. First access idempotently starts a run, then opens its authenticated SSE stream; the page reveals overview, payment performance, fees, and peer comparison independently as each becomes ready.
- **Metric card:** label, formatted value/unit, comparison and period, semantic trend, definition link, independent queued/calculating/ready/failed states.
- **Chart card:** title, period/filter controls, concise takeaway, plot, legend, accessible tabular alternative, provenance link, and section-local loading/error behavior.
- **Insight card:** deterministic finding, numeric evidence, suggested merchant action, confidence/limitation; AI-generated copy is visibly labeled later.
- **Data table:** semantic headers, server pagination/sorting, row actions named for screen readers, responsive priority, empty/error states.
- **Filter bar:** URL-backed state, explicit apply/reset behavior, and approved daily, weekly, Jalali-month, and Persian-season periods with unambiguous comparison baselines.
- **Status badge:** text plus icon/shape; color reinforces but never carries meaning alone.
- **Feedback:** inline field errors, page-level error boundary, skeleton only when layout is known, retry action for recoverable failures.
## Data visualization
- Lead with a written takeaway and exact KPI; charts support the conclusion rather than decorate it.
- Default comparisons: current period vs previous equivalent period and merchant vs an eligible anonymized cohort. Peer values appear only when at least 10 other merchants and 1,000 combined peer sessions contribute; otherwise show a clear insufficient-data state.
- Always show unit, timezone/calendar, exact reporting period, comparison baseline, sample size, freshness, and missing-data caveat where material.
- Success/failure colors remain semantic and consistent. Never use a rainbow categorical palette for ordered values.
- Tooltips are keyboard reachable and not the sole location of important values.
- Charts have a textual summary and downloadable/visible data table when practical.
- 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.
- 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.
## Motion
- Functional motion only: drawer/dialog transitions, focus/selection feedback, and short chart/filter state changes.
- Typical duration 120–220 ms; enter may be slightly slower than exit.
- Prefer opacity and transform. Avoid layout-heavy animation and dashboard-wide scroll reveals.
- Honor `prefers-reduced-motion` by removing nonessential movement.
- No third-party scroll-reveal library is planned for the authenticated panel. Reconsider only for a separately scoped marketing surface.
## Persian, direction, and formatting
- Root UI is `lang="fa" dir="rtl"`.
- Technical identifiers, URLs, hashes, and mixed Latin values use isolated LTR spans (`dir="ltr"`) to prevent bidi corruption.
- Use `Intl.NumberFormat`/`Intl.DateTimeFormat`. Display merchant-facing dates in the Jalali calendar and `Asia/Tehran`; API instants remain ISO-8601 UTC. Specifications must still choose Persian vs Latin digits and Rial/Toman terminology before implementation.
- Do not concatenate translated fragments. Write complete Persian strings with correct نیم‌فاصله.
- Authentication errors must not reveal whether a username exists.
## Accessibility and interaction
- WCAG 2.2 AA target.
- Visible `:focus-visible` ring on every interactive element.
- Semantic buttons/links/forms before ARIA; icons have accessible names or are hidden when decorative.
- All functionality is keyboard operable. Dialogs/drawers manage focus correctly.
- Validation is associated with fields and announced; asynchronous updates use restrained live regions.
- Loading indicators expose status text; avoid endless skeletons.
- Destructive or consequential actions require clear confirmation and recovery where possible.
## Current decisions and change log
| Version | Date | Decision |
|---|---|---|
| 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.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.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.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. |
Any material token/component/interaction change increments this version and adds a row describing why it changed. A surprising or difficult-to-reverse change also receives an ADR.
## Open design decisions before approval
1. Licensed Yekan-family assets vs open `Vazirmatn` fallback.
2. Persian or Latin digits for dashboard values.
3. Rial-only vs Toman display and conversion wording.
4. Exact information architecture and MVP metric set after the analytics spec.
5. Whether a dark theme is required; it is not assumed merely because the public site uses dark feature sections.