7.9 KiB
Capability Map
Status: approved Phase 0 baseline
Implementation authorization: granted by user on 2026-08-20
Product intent
Build a production-shaped, Persian-first merchant analytics panel that turns payment-attempt data into accurate, traceable, numerical, and actionable insights. Each merchant can sign in with a dedicated username and password, see only its own detailed data, and compare itself with anonymized category/cohort aggregates.
The hackathon demo will seed one account per merchant. Where merchant profile fields are absent from the source dataset, clearly synthetic display data may be generated for presentation; synthetic values must never be represented as source facts.
Capabilities and dependency order
| Order | Capability | Responsibility | Depends on | MVP |
|---|---|---|---|---|
| 1 | Data foundation | PostgreSQL model, one-time CSV bootstrap, provenance, validation, quality reporting, synthetic merchant profiles; MVP payment facts are immutable afterward | — | Yes |
| 2 | Identity and access | Replaceable demo credential adapter, sessions, tenant isolation, demo account seeding; future ZarinPal SSO is external | Data foundation | Yes |
| 3 | Analytics engine | Deterministic metrics, cohorts, trends, diagnostic drill-downs, bounded parallel on-demand section jobs, and a 30-day Redis cache namespaced by the sole completed immutable dataset snapshot | Data foundation | Yes |
| 4 | Merchant API | Stable authenticated interfaces and tenant-scoped SSE for partial analytics delivery | Identity and access, analytics engine | Yes |
| 5 | Merchant dashboard | Persian RTL dashboard, responsive navigation, accessible charts/tables and explanations | Merchant API | Yes |
| 6 | AI growth analyst | Deterministic 90-day event-aware forecasts, persisted report snapshots, cost controls, and bounded AvalAI interpretation over sanitized evidence | Analytics engine, merchant API | Yes |
| 7 | Platform operations | Compose, Nginx, manual deployment, phased observability, backup/restore, release and rollback | All deployables | Yes |
Build sequence: data foundation → identity and analytics → API → dashboard → platform operations → AI assistance.
Repository boundaries
zarinpal-analytics-backend: one Go repository containing the modular backend and independently runnable commands where needed (API, importer, migrations, jobs).zarinpal-analytics-frontend: SvelteKit 2, Svelte 5, strict TypeScript, Tailwind CSS v4.zarinpal-analytics-deployment: Compose/Nginx/scripts/configuration and orchestration only; service repositories appear as ignored nested checkouts during deployment.
Dataset facts that constrain the design
- Source grain: one attempt-or-no-attempt session record, uniquely identified by
(session_key, try_seq). Atry_seq = 0/NoAttemptmarker creates no normalized attempt. - Observed volume: 2,213,289 source records, including 263,936 no-attempt markers and 1,949,353 actual attempts; 2,062,839 sessions, 343 merchants, 348 terminals, and 5 categories.
- Observed period: 2026-01-01 through 2026-07-01.
- Nullability is material: response, PSP, issuer/card, verification timing, and settlement fields are incomplete.
- Source
adjusted_feeis the merchant-fee field for this product and is normalized once per session as a real Rial amount; the challenge source name/value was confidentiality-adjusted. - Raw CSV/database state is local operational input, not versioned source.
Cross-cutting invariants
- Tenant isolation is enforced server-side on every merchant-scoped operation.
- Cross-merchant output is aggregate and anonymized; no row-level peer data is exposed. Peer benchmarks use other merchants in the active merchant's category for the same selected period, exclude the active merchant, and require at least 10 peers plus 1,000 combined peer sessions.
- Every displayed metric has a definition, source fields, filters, time window, and drill-down path.
- Dataset imports are repeatable and produce a versioned manifest with checksum, counts, timestamps, and validation results.
- Secrets stay outside Git; examples contain names and safe placeholders only.
- AI growth analysis is feature-flagged, receives only minimized/sanitized aggregates, and cannot become the source of record. Deterministic forecasts and cached reports remain usable when AvalAI is disabled, unavailable, or over budget.
- External calls have timeouts and bounded retries; jobs are idempotent and observable.
- Production changes are reversible and backed by documented health checks and rollback steps.
PaidandVerifiedare both successful bank payments;Paidstill requires merchant verification andVerifiedis finalized. Paid-volume and recovery metrics include both while verification metrics keep them separate.- Merchant fees are real Rial amounts stored/summed once per session; repeated attempt rows never multiply a fee.
- MVP reporting periods are limited to daily, Saturday–Friday weekly, Jalali-month, and Persian-season views with consistent
Asia/Tehranboundaries across database, API, and frontend. - An idempotent start request enqueues overview, payment-performance, fees, and peer-comparison sections for bounded parallel calculation by a separate Go worker; Redis caches each typed section for 30 days under the merchant, completed dataset snapshot, and metric-definition version.
- A separate authenticated SSE request exposes each section as it becomes ready. Redis and the on-demand worker remain private, and Redis is never a source of truth or backup target.
- Each section attempt is limited to 60 seconds and at most two transient retries with exponential backoff/jitter; deterministic errors fail immediately.
- The worker pins pre-1.0 Asynq
v0.26.0, runs at 16 jobs globally and 4/merchant by default, and changes require reviewed dependency/load evidence. - Start, manual-retry, and SSE limits use independent authenticated-user/merchant buckets and return
429withRetry-Afterbefore work is queued. SSE heartbeats run every 15 seconds and authorized run-event replay lasts one hour. - Peer outputs use the median of one independently calculated value per eligible merchant plus a direction-aware merchant performance percentile. Equal merchant weighting is intentional because transaction weighting would let the dataset's largest merchants dominate the benchmark.
- Authentication uses revocable server-side sessions and an opaque host-only
Secure,HttpOnly,SameSite=Laxcookie. Passwords use Argon2id; sessions expire after 12 idle hours or seven absolute days and are revoked on logout/account disablement. Demo credentials are generated once and never stored in Git. - Demo authentication stays replaceable and minimal because ZarinPal SSO will own production identity after acceptance. Failed logins are limited by username and IP without permanent lockout; mutations require CSRF and same-origin checks; each user has at most two active sessions.
- Demo sessions live in PostgreSQL and store only SHA-256 digests of 32-byte random tokens. Activity writes are coalesced to five-minute windows; Redis remains disposable and is not the session source of truth.
- AI growth reports are keyed by authenticated merchant/optional terminal plus data, catalog, analytics, prompt/schema, and model versions. PostgreSQL is authoritative; Redis may coordinate locks, limits, budgets, and hot reads only.
- Merchant page visits reuse the current matching report. At most one explicit merchant-wide refresh is allowed per Tehran calendar day, and budget exhaustion degrades to deterministic partial output instead of hiding analytics.
Required capability specs
Each capability spec must define objective, scope/non-scope, actors, functional requirements, data/API contracts, security and privacy requirements, failure behavior, observability, tests, acceptance criteria, migration/rollback considerations, and unresolved decisions. A capability may enter implementation only after its spec status is marked Approved.