سبزشدن پرداخت در Sandbox فقط یک ادعای محدود میسازد: سیستم شما با رفتار شبیهسازیشدهٔ مشخص و نسخهٔ مشخص سازگار بوده است. این نتیجه ثابت نمیکند پول در Production جابهجا میشود، Callback همیشه میرسد، Verify معتبر است، Settlement با Ledger میخواند یا کاربر در زمان اختلال دوباره شارژ نمیشود. Sandbox مفید است، اما کپی دقیق شبکهٔ بانکی، محیط ذاتاً امن یا مجوز انتشار نیست.
این راهنما برای تست درگاه پرداخت اینترنتی (IPG) در یک فروشگاه یا سرویس ایرانی نوشته شده است. بهجای «۷ مزیت بینظیر»، یک Payment Sandbox Contract میسازیم: Money و Identifier، State machine، Idempotency، Redirect/Callback/Verify، Fault، Ledger، Reconciliation، امنیت Artifact و شکاف Sandbox-to-Production. همهٔ دادهها و آزمایشها مصنوعیاند؛ شرایط فنی، حقوقی، قراردادی و عملیاتی هر PSP/Acquirer باید از مرجع جاری همان ارائهدهنده و Owner مجاز سازمان تأیید شود.
خلاصهٔ اجرایی؛ Sandbox یک پله است، نه مقصد
- Contract را نسخهدار کنید: Endpoint، Credential class، Currency unit، Identifier، timeout، retry، callback، verify و error taxonomy.
- پول را Integer نگه دارید: واحد Canonical را از نمایش تومان جدا و تبدیل را صریح کنید.
- Browser return را حقیقت ندانید: نتیجهٔ نهایی از Verify سمتسرور و State معتبر میآید.
- Duplicate را انتظار داشته باشید: Request، Callback و worker میتوانند retry/replay شوند؛ Side effect باید Idempotent باشد.
- Unknown را State واقعی بدانید: Timeout یعنی نتیجه نامعلوم، نه Failure قطعی و نه Success.
- Ledger و Reconciliation را تست کنید: UI سبز بدون تطبیق منبع مستقل کافی نیست.
- Sandbox gap را Promote کنید: Test، Certification/UAT و Production هرکدام Evidence و Authority جدا دارند.
Claim: synthetic checkout flow conforms to Sandbox Contract v7
Environment: disconnected fake PSP
Outcome: PASS | FAIL | INCONCLUSIVE
Promotion: HOLD until provider-specific UAT and reconciliation evidence
NotClaimed: real payment, legal eligibility, settlement, refund time, zero fraud
Sandbox درگاه پرداخت چیست؟
Sandbox محیطی کنترلشده برای ساخت Object و پاسخهای مصنوعی بدون حرکت پول واقعی است. ممکن است PSP رسمی، Acquirer، تیم داخلی یا یک Simulator قرارداد آن را ارائه کند. ارزش آن در کنترل داده، Fault injection و تکرارپذیری است؛ Fidelity آن باید سنجیده شود. واژهٔ Sandbox بهتنهایی Isolation، امنیت، رایگانبودن، Localhost support یا برابری با Production را تضمین نمیکند.
برای نمونهٔ غیرایرانی و صرفاً برای نشاندادن تفاوت محیطها، مستندات رسمی Testing environments در Stripe توضیح میدهد Test mode و Sandbox محدودیت و تنظیمات متفاوت دارند و حتی بعضی تغییرات Test mode میتواند روی Live mode اثر بگذارد. این Citation توصیهٔ استفاده، دسترسپذیری در ایران یا شباهت به PSP داخلی نیست؛ فقط نشان میدهد نام «تست» معادل Isolation مطلق نیست.
پنج لایهٔ محیط را از هم جدا کنید
| لایه | هدف | Fidelity | ادعای مجاز |
|---|---|---|---|
| In-process fake | State/branch سریع و قطعی | فقط Contract انتخابی | منطق داخلی روی Fixture |
| Service simulator | HTTP/schema/timeout/retry | Protocol شبیهسازیشده | Client در برابر Simulator |
| Provider sandbox | Endpoint و Scenarioهای رسمی Test | رفتار مستند Test | Sandbox integration |
| Certification/UAT | Gateهای ارائهدهنده/سازمان | Provider-specific | عبور از Gate مشخص |
| Controlled live probe | Delta محدود و مجاز | Production واقعی با Blast radius | همان Probe و همان بازه |
هر لایه Risk دیگری را میگیرد. Fake برای Faultهای کمیاب عالی است اما رفتار واقعی PSP را ثابت نمیکند. Sandbox رسمی Contract جاری را بهتر میسنجد اما Settlement، محدودیت شبکه، Anti-fraud، Load یا عملیات بانکی را کامل بازنمایی نمیکند. Live probe فقط با مجوز، Runbook، سقف اثر، حساب/ابزار مجاز و Reconciliation انجام میشود؛ این مقاله اجرای آن را تجویز نمیکند.
قبل از Test، Authority و Scope را روشن کنید
- ارائهدهنده، Product/API version و Merchant/Test-account مالک چه کسی است؟
- کدام محیط و Credential مجاز است و چه کسی دسترسی میدهد؟
- آیا Callback public، IP allowlist، mTLS یا signature لازم است؟
- کدام داده ممنوع، حساس یا دارای Retention قراردادی است؟
- چه کسی Residual financial risk و Release را میپذیرد؟
- چه Onboarding/مجوز/قراردادی برای Production لازم است؟
- Escalation و Support receipt کجا ثبت میشود؟
الزامهای ایران، PSP، بانک، شاپرک، مالیات، اینماد، IP و قرارداد ممکن است با مدل پذیرنده و زمان تغییر کنند. آنها را از متن عمومی یا تجربهٔ تیم دیگر استنتاج نکنید. این مقاله راهنمای حقوقی، مالی، انطباق یا جایگزین مستند رسمی ارائهدهنده نیست.
Payment Contract Manifest بسازید
ProviderContract
ProviderId: FAKE-PSP-01
Environment: synthetic-sandbox
ApiVersion: v7-fixture
RetrievedAt: 2026-08-14
CurrencyUnit: IRR
Create/Redirect/Return/Verify/Inquiry/Refund: capability map
AuthAndSignature: fake-only specification
TimeoutRetryErrorRules: versioned
Owner/Expiry/ChangeTrigger: explicit
نمونهکد Blog یا SDK قدیمی Authority نیست. URL، Version، Hash/commit، تاریخ دریافت، قابلیت، Header/field، Error code، timeout، retry، signature، callback و deprecation را ثبت کنید. اگر مستند و پاسخ مشاهدهشده فرق دارند، نتیجه INCONCLUSIVE و Provider question بسازید؛ حدس در کد Production راهحل نیست.
Money Contract؛ ریال و تومان را مخلوط نکنید
Amount را Integer در واحد Canonical قرارداد نگه دارید. Decimal float، جداکنندهٔ نمایشی یا تبدیل ضمنی میتواند اختلاف ۱۰برابری و Round ایجاد کند. برای هر Request، مبلغ Order snapshot، Discount، Tax، Shipping، currency/unit و نسخهٔ Quote باید به Attempt متصل باشد. Callback نباید Amount دلخواه را جایگزین Order کند.
Money
Canonical: 1250000 IRR
DisplayOnly: 125000 تومان
Conversion: 1 toman = 10 IRR (explicit presentation rule)
Storage: integer minor/contract unit
CompareAtVerify: merchant/order/attempt/currency/amount
Forbidden: binary float, unlabeled number, callback overwrite
تست مالی جامعتر شامل Ledger، Settlement، Refund و Reconciliation در راهنمای تست نرمافزار مالی آمده است. این مقاله فقط مرز Sandbox و Promotion یک اتصال IPG را مالک است.
Identifierها را معنایی و یکتا نگه دارید
- OrderId: قصد خرید؛ ممکن است چند Attempt داشته باشد.
- AttemptId: یک تلاش پرداخت سمت Merchant.
- ProviderToken: شناسهٔ ایجادشده برای Redirect/پردازش.
- ProviderTransactionId/Reference: شناسهٔ مرجع گزارششده پس از پردازش.
- Callback/EventId: یک Delivery؛ ممکن است duplicate یا reorder شود.
- LedgerEntryId: اثر مالی داخلی و immutable.
- ReconciliationBatchId: Snapshot تطبیق با منبع مستقل.
یکیکردن Order و Transaction باعث میشود Retry یک خرید تازه بسازد یا دو تلاش legitimate به هم بخورند. Unique constraint باید Scope درست داشته باشد: مثلاً Provider + Merchant + ProviderReference، نه Reference خام در همهٔ زمانها بدون Contract.
State machine را پیش از UI طراحی کنید
CREATED → TOKEN_REQUESTED → REDIRECT_READY → CUSTOMER_RETURNED
↘ EXPIRED | CANCELLED
CUSTOMER_RETURNED → VERIFY_PENDING → VERIFIED
↘ REJECTED | UNKNOWN
VERIFIED → LEDGER_POSTED → RECONCILED
REFUND_REQUESTED → REFUND_PENDING → REFUNDED | REFUND_UNKNOWN
State نام UI نیست. Transition باید Source event، Guard، Authority، timestamp، previous/new state، side effect و idempotency rule داشته باشد. Success نمیتواند از Query string مرورگر به VERIFIED جهش کند. UNKNOWN باید قابل Inquiry/Reconciliation باشد. Terminal بودن هر State وابسته به Contract است و عمومی فرض نمیشود.
Out-of-order و Replay را عمداً تست کنید
راهنمای امنیت REST در OWASP توصیه میکند Workflow state در هر درخواست سمتسرور enforce شود، Token به Stage مناسب bind شود و Transition خارج از ترتیب رد شود. برای IPG یعنی Verify پیش از Create، Refund پیش از Verify، Callback برای Merchant دیگر، Token قدیمی و replay بعد از Terminal state باید Test منفی داشته باشند.
TransitionCheck
Current: VERIFY_PENDING
Event: fake_callback(id=E-42, attempt=A-7)
Guards: provider/merchant/token/amount/signature/time/state
DuplicateKey: provider + event/reference + semantic fingerprint
Effect: at most one state advance and one ledger intent
Invalid: reject + audit; never silently coerce
Redirect و Return URL منبع حقیقت نیستند
Browser در کنترل کاربر و شبکه است: ممکن است Return باز نشود، دوبار Refresh شود، Query تغییر کند، Tab بسته شود یا Back اجرا شود. صفحهٔ Return باید شناسهٔ داخلی را Resolve کند و Status را از Backend بخواند؛ نه اینکه فقط بر اساس پارامتر «success» سفارش را تحویل دهد. پیام UI بهتر است «در حال بررسی» را از «تأیید شد» جدا کند.
Callback/Webhook فقط یک Signal غیرقابلاعتماد است
Contract ارائهدهنده تعیین میکند Callback چگونه Auth/Sign میشود، چند بار retry میشود و آیا ترتیب تضمین است. بهعنوان شاهد اینکه رفتار Providerها متفاوت است، مستندات رسمی Webhook در Stripe Signature verification، Retry و نبود تضمین ترتیب Eventها را توضیح میدهد. این قواعد را به PSP ایرانی تعمیم ندهید؛ از مستند همان Provider استفاده کنید و duplicate/late/reordered را در Simulator خود بسازید.
CallbackEnvelope
RawBodyHash: captured without secret payload retention
Provider/Event/Attempt: bound identifiers
Authenticity: provider-contract-specific
FreshnessAndReplay: timestamp/nonce/event ledger as supported
Ack: independent from business completion
Processing: queued, idempotent, observable
OrderingAssumption: none unless explicitly guaranteed
Verify سمتسرور، Guard نهایی Merchant است
پس از Return یا Callback، Backend باید طبق Contract رسمی Provider عملیات Verify/Inquiry را انجام دهد و Merchant/Terminal، Token/Reference، Attempt، Amount، Currency و State را تطبیق دهد. پاسخ موفق HTTP بهتنهایی Success مالی نیست؛ Schema، code، signature و semantic outcome هم لازماند. Timeout در Verify نتیجه را UNKNOWN نگه میدارد.
VerifyOracle
Transport: expected status/TLS peer
Schema: versioned and strict-enough
Identity: merchant + attempt + provider reference
Money: canonical amount/unit equals frozen order snapshot
State: transition allowed and not already consumed
Outcome: VERIFIED | REJECTED | UNKNOWN
Evidence: redacted receipt + correlation
Idempotency؛ «دقیقاً یک بار» شعار خطرناک است
RFC ۹۱۱۰ دربارهٔ Idempotent Method میگوید Client نباید روش non-idempotent را خودکار retry کند مگر بداند semantics واقعاً idempotent است یا اعمالنشدن درخواست را تشخیص دهد. بیشتر Create/Verifyهای پرداخت POST هستند؛ پس HTTP بهتنهایی Duplicate side effect را حل نمیکند. Idempotency key، fingerprint، scope، retention و concurrent-in-flight policy باید در Contract شما و Provider تعریف شوند.
IdempotencyRecord
Key: random synthetic identifier
Scope: merchant + operation + attempt
Fingerprint: normalized amount/currency/order/operation
FirstResult: stored semantic outcome
SameKeySameFingerprint: replay prior outcome
SameKeyDifferentFingerprint: conflict
ExpiryAndConcurrency: explicit, not infinite/exactly-once claim
Timeout را به Failure قطعی تبدیل نکنید
Timeout ممکن است قبل از رسیدن Request، حین پردازش یا بعد از Commit و قبل از Response رخ دهد. Retry کور میتواند Duplicate بسازد؛ نمایش «ناموفق» میتواند کاربر را به تلاش دوم هدایت کند درحالیکه اولی موفق بوده است. State را UNKNOWN کنید، Inquiry با backoff و سقف اجرا کنید و سپس Reconciliation/Escalation داشته باشید.
الگوی Fault، Recovery و Convergence در راهنمای تست تابآوری سیستم عمیقتر پوشش داده شده است.
Fault catalog را از Contract بسازید، نه مبلغ جادویی
- DNS/TLS/connect/read timeout پیش و پس از fake commit؛
- HTTP 4xx/5xx، malformed body و schema version ناشناخته؛
- Duplicate/late/reordered/missing Callback؛
- Signature missing/invalid، timestamp stale و replay؛
- Amount/currency/merchant/reference mismatch؛
- Concurrent Verify و Refund؛
- Partial worker failure پس از State و پیش از Ledger؛
- Provider reports success، inquiry unknown یا reconciliation mismatch؛
- Clock skew، timezone boundary و expired token؛
- Rate limit، maintenance و degraded provider.
عددهایی مانند «۱۰۰۲ تومان = خطای ناموفق» فقط وقتی معتبرند که مستند نسخهدار Provider آن را تعریف کند. Fixture داخلی باید Namespace و Label واضح داشته باشد تا تصادفاً به Endpoint واقعی ارسال نشود.
Contract test، Simulator و E2E را ترکیب کنید
Schema/semantic contract را سریع و گسترده روی Fake اجرا کنید؛ Client integration را با Simulator؛ تعداد محدودی Scenario را در Provider sandbox؛ و فقط Gap ضروری را در UAT/Live مجاز. راهنمای CDC در برابر E2E کمک میکند E2E پرهزینه را جایگزین همهٔ لایهها نکنید.
Sandbox parity را با Delta manifest بسنجید
| بعد | Sandbox | Production/UAT | Gap action |
|---|---|---|---|
| Endpoint/Credential | Test namespace | Live namespace | config allowlist + secret separation |
| Fraud/limits | ممکن است ساده یا قابلتحریک | پویا/قراردادی | claim limit + monitoring |
| Callback | Delivery pattern تستی | network/retry واقعی | duplicate/late/reorder + live observation |
| Settlement | معمولاً مصنوعی/غایب | گزارش/چرخه واقعی | reconciliation gate |
| Performance | quota و capacity متفاوت | SLO/limits واقعی | contracted load evidence |
| Compliance/operations | ممکن است bypass شود | Onboarding/Support/incident | owner sign-off and runbook |
DeltaId: SBOX-LIVE-07
Dimension: callback retry schedule
SandboxObserved: fake schedule only
ProductionAuthority: provider document/support receipt
Risk: delayed order completion
CompensatingEvidence: inquiry + reconciliation + user status polling
Owner/Expiry: explicit
Test data باید مصنوعی، معتبر و پاکشدنی باشد
از کارت، موبایل، نام، Order یا Merchant واقعی در Fixture عمومی استفاده نکنید. Test token و card number فقط در Environment تعیینشدهٔ Provider معتبرند و نباید با دادهٔ واقعی ترکیب شوند. Data pack باید lineage، validity، lease، namespace، sensitivity، retention و cleanup receipt داشته باشد. راهنمای مدیریت دادهٔ تست الگوی کاملتری میدهد.
Secret و Endpoint را بین محیطها دیوارکشی کنید
- Credential تست و Live جدا، کماختیار و در Secret manager؛
- Endpoint allowlist و Environment assertion در Startup؛
- Live secret در Laptop، Feature branch، Screenshot یا Postman export نباشد؛
- Test worker به Production DNS/network route دسترسی نداشته باشد؛
- Rotation، revoke، access review و break-glass ثبت شوند؛
- نام Environment و Merchant در UI/Log/Evidence واضح باشد؛
- Promotion config با چهارچشم و diff امن انجام شود.
همهٔ Header و Body را Log نکنید
توصیهٔ «ذخیرهٔ کامل Request/Response برای Debug» میتواند Cardholder data، Token، Cookie، Secret یا PII را تکثیر کند. OWASP Logging Cheat Sheet میگوید Access token، Password، کلید، Bank/payment-card data و دادهٔ حساس معمولاً نباید مستقیم Log شوند؛ Event source نیز میتواند missing، forged یا replayed باشد.
PaymentLog
Allowed: run/attempt/correlation ids, state transition, reason class, latency
Masked/Hashed: provider reference only when justified
Excluded: PAN, CVV, PIN, password, token, secret, raw signature, cookie
Integrity: append/audit controls
Access/Retention/Delete: named policy and owner
DebugEscalation: time-bound, approved, minimized
PCI DSS را با Sandbox دور نمیزنید
PCI DSS در PCI SSC برای Entityهایی است که Cardholder/Sensitive Authentication Data را ذخیره، پردازش یا منتقل میکنند یا بر محیط آن اثر دارند. Applicability را Assessor/Owner واجد صلاحیت تعیین میکند، نه این مقاله. FAQ رسمی PCI SSC دربارهٔ SAD نیز یادآور میشود ذخیرهٔ Sensitive Authentication Data پس از Authorization حتی بهصورت رمزشده ممنوع است. Test data و Log design را بر مبنای کمینهسازی بسازید.
Localhost و Tunnel بهطور پیشفرض امن نیستند
Callback عمومی ممکن است Tunnel، Preview environment یا Relay بخواهد؛ اما ساخت URL عمومی تصادفی نسخهٔ امنیت نیست. Authentication/signature، TLS validation، allowlist، least privilege، rate limit، replay protection، no-index، TTL، log redaction، owner و shutdown receipt لازماند. ابزار یا Proxy ناشناخته، credential-sharing و TLS bypass راهحل نیست.
Ledger؛ Payment state با Money movement یکی نیست
State عملیاتی سفارش، State Provider و اثر Ledger را جدا نگه دارید. «Verified» میتواند اجازهٔ ثبت Intent مالی بدهد، اما Ledger entry باید unique، immutable، balanced و traceable باشد. Update موجودی با overwrite یک ستون، Audit و reversal را سخت میکند. Refund یک Transaction تازه و قابلتطبیق است؛ حذف Payment قبلی نیست.
LedgerIntent
Source: verified attempt A-7
BusinessKey: payment-capture:A-7
Debit/Credit: synthetic balanced entries
Amount: 1250000 IRR
DuplicatePolicy: same key → same immutable receipt
Correction: reversal/new entry; no destructive edit
Status: posted ≠ settled ≠ reconciled
Reconciliation؛ Oracle مستقل پس از Verify
تطبیق باید Snapshot داخلی را با منبع مستقل و مجاز Provider/Acquirer مقایسه کند: missing internal، missing external، amount mismatch، duplicate reference، unexpected state، late item و settlement mismatch. نتیجهٔ Sandbox ممکن است Report واقعی نداشته باشد؛ در این صورت Gap را صریح نگه دارید، نه اینکه Verify را Reconciliation بنامید.
ReconciliationRow
AsOf/Cutoff/Timezone: explicit
InternalAttempt/Ledger: ids + amount/unit/state
ExternalReference: authorized source snapshot
MatchClass: MATCH | MISSING_INTERNAL | MISSING_EXTERNAL | AMOUNT | STATE | DUPLICATE
Owner/SLA/Evidence: explicit
NoSilentDelete: correction is auditable
Refund و Reversal را وعدهٔ زمانی ندهید
عبارتی مانند «اگر مبلغ کم شد تا ۷۲ ساعت برمیگردد» فقط با Policy و وضعیت مشخص Provider/بانک معتبر است. UI باید واقعیت قابلاثبات را بگوید: شناسهٔ پیگیری داخلی، State فعلی، زمان آخرین بررسی، اقدام بعدی و کانال Support. Refund requested، accepted، processed، settled و customer-visible یک State نیستند.
UX پرداخت؛ Unknown را صادقانه نمایش دهید
- دکمهٔ Pay از Double submit محافظت کند، اما Recoverable باشد؛
- Back/Refresh/closed-tab باعث ساخت Order تازهٔ خاموش نشود؛
- Processing با Success یا Failure یکی نباشد؛
- Amount و واحد پیش از Redirect و پس از Return قابلفهم باشند؛
- Reference حساس کامل نمایش داده نشود؛
- Retry فقط پس از وضعیت/Policy مجاز ارائه شود؛
- Accessibility، RTL، Bidi، Focus و message announcement تست شوند؛
- Support متن ثابتِ غیرقابلتحقق وعده ندهد.
برای اتصال Checkout به Inventory، Order و Fulfillment از راهنمای تست فروشگاه اینترنتی استفاده کنید.
Observability بدون افشای داده
Metricهای مفید شامل Create/Verify latency distribution، UNKNOWN age، duplicate callback، invalid transition، idempotency conflict، reconciliation mismatch، stale attempt و Support handoff هستند. Trace باید Correlation را از Order تا Attempt/worker/Ledger نشان دهد، اما Payload حساس را حمل نکند. Alert به Owner و Runbook متصل باشد.
آزمایشگاه کاملاً قطعشدهٔ فارسی
آزمایشگاه SYN-IPG-SANDBOX-IR-01 هیچ Endpoint، SDK، Account، Merchant، Bank، PSP، Card، Credential یا پول واقعی ندارد. Fakeها فقط Objectهای حافظهای و Contractهای متنیاند. هدف تمرین State، Fault، Idempotency و Reconciliation است، نه اجرای تراکنش.
LabId: SYN-IPG-SANDBOX-IR-01
Fake: Merchant, Order, Attempt, PSPStub, Callback, Ledger, Reconciliation
Amount: 1250000 IRR / display-only 125000 تومان
Digits: ۱۲۵ / ١٢٥ / 125; Text: ی/ي, ک/ك, ZWNJ, RTL/LTR/Bidi
Time: UTC storage | Asia/Tehran compute | Jalali presentation only
Faults: before/after-fake-commit timeout, duplicate/late/reordered callback
Network=false; Production=false; RealCard=false; RealMoney=false
Validator مستقل چه چیزی را کنترل میکند؟
Validator بدون Dependency ابتدا Checker سطحی را اجرا میکند که «Sandbox دقیقاً Production، بدون ریسک، رایگان، فوری و بازگشت ۷۲ساعته» را پاداش میدهد و بهاشتباه Ready میشود. سپس ۹۳۲ کنترل Group-qualified در Contract، Money، Identifier، State، Callback، Verify، Idempotency، Fault، Security، Ledger، Reconciliation، Promotion و Claim بررسی میشوند.
PAYMENT_SANDBOX_EXACT_PRODUCTION_ZERO_RISK_FREE_INSTANT_72H_REFUND_READY
HOLD-932
NO_REAL_MERCHANT_CUSTOMER_CARD_CREDENTIAL_PSP_BANK_MONEY_TRANSACTION_PRODUCTION_REFUND_SETTLEMENT_OR_RELEASE_DECISION_PASS
READY_FOR_PAYMENT_SANDBOX_PROMOTION_REVIEW-0
خروجی صفر فقط کاملبودن Fixture قراردادی خودش را نشان میدهد؛ نه امنیت/انطباق، درستی Provider، حرکت پول، Settlement، Refund، Reconciliation واقعی، UX، Production readiness یا Release approval.
Evidence Pack هر Run
- Run/commit/build/environment/contract version؛
- Provider/product/api/doc retrieved-at و hash؛
- Order/Attempt synthetic IDs و Money contract؛
- Fault schedule، retry و virtual clock؛
- Transition history و invalid-transition evidence؛
- Callback/Verify semantic receipts با Redaction؛
- Idempotency/concurrency outcomes؛
- Ledger و reconciliation fixture receipts؛
- Sandbox-live Delta و Coverage gap؛
- FAIL/INCONCLUSIVE، Owner، expiry و correction.
برای Reproduction Contract در شکستهای غیرقطعی از راهنمای گزارش باگ قابلبازتولید استفاده کنید.
Promotion Gate از Fake تا Production
| Gate | Evidence | Hard stop | Authority |
|---|---|---|---|
| Contract | version/schema/semantic fixtures | unknown/mismatched contract | integration owner |
| Sandbox | state/fault/idempotency/security | duplicate effect or secret leak | engineering/security |
| UAT/Certification | provider-required receipts | missing eligibility/approval | provider/business owner |
| Operational | monitor/alert/runbook/support/reconcile | no unknown recovery | operations/finance |
| Release | delta/residual risk/rollback | unauthorized acceptance | named release authority |
سند استراتژی و Residual-risk gate در راهنمای استراتژی تست و Context فینتک/انطباق/حجم در راهنمای تست فینتک تکمیل میشوند.
Pilot سیروزهٔ بدون پول واقعی
- هفتهٔ ۱: Contract manifest، Money/ID/State و forbidden-data inventory.
- هفتهٔ ۲: Fake/Simulator با timeout-before/after-commit، duplicate/reorder و invalid transition.
- هفتهٔ ۳: Provider sandbox مجاز، Delta manifest، redacted evidence و reconciliation fixture.
- هفتهٔ ۴: Security/operations/finance review، unknown-recovery drill و HOLD/PROMOTE/ADAPT/STOP.
PilotDecision: PROMOTE_TO_UAT | ADAPT | HOLD | STOP
NoRealMoney: true
NoProductionCredential: true
Required: contract, state, idempotency, fault, log, ledger, reconciliation, delta
Unknowns: visible and owned
PromotionAuthority: separate from test author
Expiry: provider/app/security change or review date
Anti-patternهای تست درگاه پرداخت
- Sandbox را کپی کامل Production میدانیم؛
- Return URL مستقیماً Order را Paid میکند؛
- Timeout مساوی Failed و Retry کور است؛
- OrderId، AttemptId و Provider reference یکیاند؛
- Callback duplicate/order/freshness تست نمیشود؛
- POST بهطور ذاتی Idempotent فرض میشود؛
- مبلغ ریال/تومان بدون واحد و با Float است؛
- عدد یا کارت جادویی بدون مستند Provider ساخته میشود؛
- Request/Response کامل با Secret و Card data Log میشود؛
- Live credential در Local/CI و Test export قرار میگیرد؛
- Tunnel عمومی بدون Auth/TTL ساخته میشود؛
- Verified با Ledger/Settled/Reconciled یکی است؛
- Refund زمان عمومی و تضمینی دارد؛
- Pass Sandbox مجوز، امنیت یا Release را اثبات میکند.
چکلیست Owner پیش از Promotion
- Contract/version/source/expiry و Provider questionها بستهاند؟
- Environment/credential/endpoint hard boundary دارند؟
- Money unit/rounding/order snapshot صریح است؟
- Order/Attempt/Provider/Event/Ledger شناسهٔ جدا دارند؟
- State/transition/guard/unknown/recovery تعریف شدهاند؟
- Return، Callback و Verify Authority جدا دارند؟
- Duplicate/late/reorder/replay/concurrency تست شده؟
- Idempotency scope/fingerprint/expiry/conflict روشن است؟
- Fault پیش/پس از commit و Inquiry پوشش دارد؟
- Log/trace/report Secret و card data ندارند؟
- Test data synthetic و Cleanup رسید دارد؟
- Ledger immutable/balanced و Refund جداست؟
- Reconciliation independent source و mismatch queue دارد؟
- Sandbox-live Delta، عملیات و Support مستندند؟
- Residual risk فقط توسط Authority مجاز پذیرفته میشود؟
منابع رسمی و تاریخ اعتبار
این راهنما در ۲۳ مرداد ۱۴۰۵ / ۲۰۲۶-۰۸-۱۴ با منابع رسمی PCI SSC، OWASP، RFC Editor و دو سند Vendor صرفاً برای نشاندادن Variation محیط و Event delivery بازبینی شده است. PCI DSS در Document Library نسخهٔ جاری ۴.۰.۱ را نشان میدهد؛ Applicability و اجرای کنترل باید با Owner/Assessor واجد صلاحیت و الزامات محلی سنجیده شود. هیچ Citation بینالمللی جای مستند جاری PSP/Acquirer ایرانی، قرارداد پذیرندگی یا نظر حقوقی/مالی/امنیتی سازمان را نمیگیرد.
سوالات متداول تست Sandbox درگاه پرداخت
آیا Sandbox دقیقاً مثل Production رفتار میکند؟
خیر. فقط رفتارهای مستند و مشاهدهشدهٔ محیط Test را شبیهسازی میکند. Fraud، Limit، Network، Callback، Settlement، Performance، عملیات و Onboarding ممکن است متفاوت باشند. Delta manifest، UAT/Certification و Evidence عملیاتی لازماند.
آیا بعد از Callback موفق میتوان سفارش را Paid کرد؟
نه صرفاً بر اساس Browser return یا Payload خام. طبق Contract Provider باید Authenticity، Identifier، Amount/Unit، State و Verify/Inquiry سمتسرور بررسی شوند. Timeout نتیجه را UNKNOWN میکند و Duplicate نباید اثر دوم بسازد.
چگونه خطاهای بانکی را در Sandbox بسازیم؟
فقط از Triggerهای نسخهدار مستند همان Provider یا Simulator تحت کنترل خودتان استفاده کنید. Fault catalog باید timeout پیش/پس از commit، malformed response، mismatch، duplicate/late/reordered callback، replay و concurrency را هم پوشش دهد؛ مبلغ جادویی عمومی وجود ندارد.
آیا میتوان Request و Response کامل را برای Debug ذخیره کرد؟
بهطور پیشفرض نه. Token، Secret، Cookie، PAN، CVV/PIN و PII نباید وارد Log عادی شوند. Event و correlation کمینه، Mask/Hash موجه، access/retention/delete و مسیر Debug زماندار و تأییدشده لازم است.
Pass شدن Sandbox برای انتشار کافی است؟
خیر. Contract، Sandbox، Provider UAT/Certification، امنیت، عملیات، Ledger/Reconciliation، UX، Delta و Residual risk Gateهای جدا هستند. Release را Authority مجاز با Evidence محدود و تاریخدار میپذیرد، نه نویسندهٔ Test.
جمعبندی؛ از شبیهسازی تا ادعای محدود
Sandbox زمانی ارزشمند است که محدودیتش آشکار باشد. Contract را Pin کنید، Money و Identifier را دقیق نگه دارید، State/Unknown/Idempotency را طراحی کنید، Callback را Signal و Verify را Guard بدانید، Faultهای توزیعشده را بسازید و نتیجه را با Ledger و Reconciliation ببندید. سپس Sandbox-to-Production gap را به Gate بعدی تحویل دهید؛ سبزی یک سناریوی ساختگی هرگز مجوز حرکت پول واقعی نیست.

