Files
zarinpal-analytics-backend/docs/METRIC-CATALOGUE.md

7.9 KiB
Raw Blame History

Analytics Metric Catalogue

  • Status: Approved specification — implementation authorized 2026-08-20
  • Version: 0.5.0
  • Last updated: 2026-08-22

Every merchant-facing number identifies its grain, formula, source fields, filters, Tehran-local period, unit, missing-data behavior, trace path, and definition version.

Physical source mapping

  • Session-grain metrics read payment_sessions, scoped by merchant_id and the approved half-open created_at period.
  • Attempt-grain diagnostics and timings join payment_attempts.payment_session_id to the already merchant-scoped session set.
  • Money uses payment_sessions.amount_rial and payment_sessions.fee_amount_rial exactly once per session.
  • Terminal filters join the session's terminal_id; peer cohorts join the merchant's category_id and exclude the active merchant.
  • The sole completed import_runs row identifies the immutable MVP dataset snapshot included in cache/result metadata.
  • calendar_dates defines Saturday–Friday weeks, Jalali months, and Persian seasons; it intentionally has no holiday dimension. Growth reports use their own reviewed, versioned event-evidence catalog under ADR 0015.

Bank-paid sessions

  • Canonical id: bank_paid_sessions
  • Grain: distinct payment session
  • Formula: count sessions where session_status IN ('Paid', 'Verified')
  • Meaning: the buyer completed the bank payment and funds were deducted
  • Unit: sessions
  • Time attribution: session created_at in Asia/Tehran
  • Traceability: merchant-scoped session identifiers and attempt histories

Payment success rate

  • Canonical id: payment_success_rate
  • Numerator: bank_paid_sessions
  • Denominator: sessions where session_status IN ('Paid', 'Verified', 'Failed', 'Reversed')
  • Formula: numerator / denominator; undefined when denominator is zero
  • Unknown statuses: excluded from both sides and disclosed as coverage/quality evidence until classified
  • Unit: percentage

Verified sessions

  • Canonical id: verified_sessions
  • Formula: count sessions where session_status = 'Verified'
  • Meaning: bank payment and merchant verification are complete; the payment is finalized
  • Unit: sessions

Unverified paid sessions

  • Canonical id: unverified_paid_sessions
  • Formula: count sessions where session_status = 'Paid'
  • Meaning: bank payment succeeded and funds were deducted, but merchant verification is incomplete
  • Presentation: actionable verification gap; never label as failure
  • Unit: sessions

Verification completion rate

  • Canonical id: verification_completion_rate
  • Formula: verified_sessions / bank_paid_sessions; undefined when no bank-paid sessions exist
  • Unit: percentage

Transaction status analytics

  • total_sessions: count all merchant-scoped sessions in the selected half-open reporting period.
  • bank_success_rate: sessions with status Paid or Verified divided by total_sessions; undefined when the total is zero.
  • failure_rate: sessions with status Failed divided by total_sessions; undefined when the total is zero.
  • Status distribution reports Paid, Verified, Failed, and Reversed separately as count and share of total_sessions.
  • Trend grain is hourly for a day, daily for a week or Jalali month, and Saturday-aligned weekly for a Persian season. Empty buckets are returned as zeroes.

Paid volume

  • Canonical id: bank_paid_amount_rial
  • Formula: sum session amount_rial once where session_status IN ('Paid', 'Verified')
  • Unit: Rial
  • Subsets: verified_amount_rial uses Verified; unverified_paid_amount_rial uses Paid

Retried sessions and eventual payment

  • retried_sessions: count sessions containing more than one payment attempt
  • eventually_paid_after_retry_sessions: count retried sessions whose final session status is Paid or Verified and which contain a lower-try_seq attempt whose status is neither Paid nor Verified
  • retry_recovery_rate: eventually_paid_after_retry_sessions / retried_sessions; undefined when no retried sessions exist
  • Grain/unit: distinct sessions
  • Traceability: ordered merchant-scoped attempt history; never depend on CSV row order

Payment-stage diagnostics

  • no_attempt_sessions: count sessions with zero normalized payment attempts. During challenge bootstrap this corresponds to the source marker try_seq = 0 AND try_status = 'NoAttempt'; the marker itself is not an attempt.
  • reached_bank_sessions: count distinct sessions containing at least one attempt with try_status IN ('InBank', 'Paid', 'Verified', 'Reversed').
  • in_bank_without_result_sessions: count sessions whose latest positive-sequence attempt is InBank and which have no later Paid, Verified, Failed, or Reversed attempt.
  • failed_sessions: count sessions with final session_status = 'Failed'; drill-down may distinguish zero-attempt, reached-bank, and other observable stages without inventing undocumented failure causes.
  • Grain/unit: distinct payment sessions; attempt-stage counts must deduplicate by session when presented as sessions.

Processing time

  • Report median (p50) and p95 separately for init_time_ms and verify_time_ms
  • Include only non-null values for the relevant field
  • Always show contributing sample count and coverage percentage
  • Do not replace missing timing with zero
  • Unit: milliseconds, with human-readable seconds allowed as an additional presentation

Merchant fee

  • Canonical field: fee_amount_rial, sourced from CSV adjusted_fee and stored once per session
  • paid_fee_amount_rial: sum session fee once where session_status IN ('Paid', 'Verified')
  • paid_fee_rate: paid_fee_amount_rial / bank_paid_amount_rial; undefined when paid amount is zero
  • Meaning/presentation: real merchant fee in Rial; do not label it obfuscated or relative-only in the product
  • Retry rule: never sum the repeated source value per attempt

Common behavior

  • Rates are recomputed from summed numerator/denominator components for every selected day, Saturday–Friday week, Jalali month, and Persian season.
  • Zero, undefined, missing, suppressed peer value, and calculation failure remain distinct states.
  • Paid and Verified are both bank-payment successes, but only Verified is finalized.
  • Reversed is not in the success numerator; display it separately when non-zero.
  • NoAttempt is a source session marker, not a failed payment attempt. InBank means the user reached a bank gateway but no later outcome was recorded for that attempt; do not call it a bank rejection.

Peer comparison

  • Cohort: eligible merchants in the active merchant's category for the same selected reporting period; always exclude the active merchant.
  • Availability: return a typed suppressed state unless at least 10 other merchants and 1,000 combined peer payment sessions contribute. Suppression never hides the active merchant's own metrics.
  • Weighting: calculate each eligible peer merchant's metric independently, then use the median of those merchant values. Every merchant contributes one value regardless of payment volume.
  • Rationale: merchant volume is extremely skewed (median 78 attempts, p95 8,915, maximum 1,138,592). A transaction-weighted average would mostly describe the largest merchants, while a merchant-weighted median represents a typical peer and resists extreme values.
  • Output: expose the cohort median and the active merchant's performance percentile; never expose an individual peer's identity, value, or rank.
  • Percentile direction: a higher displayed percentile always means better performance. Use the natural direction for payment success, verification completion, and retry recovery; invert the ranking direction for processing time and paid fee rate, where lower is better.
  • Benchmarked metrics: payment_success_rate, verification_completion_rate, retry_recovery_rate, init_time_ms p50/p95, verify_time_ms p50/p95, and paid_fee_rate.
  • Periods: calculate benchmarks for the same selected day, Saturday–Friday week, Jalali month, or Persian season as the active merchant value. Never compare unlike periods.