Production controls
What the production console must have (PCI DSS v4.0.1, from the NotebookLM review) and where this deployment stands.
Service Infrastructure
- Environment
- β¦
- Readiness
- β¦
- Schema version
- β¦
- Public URL
- β¦
- Channel envelope
- β¦
- Admin users
- β¦
- Started
- β¦
Security & Governance (Annex A)
- Orders
- Channels send a signed, encrypted envelope; the amount is never taken from the browser (C-01)
- Payment pages
- Provider-hosted only; zero card data touched here (C-09, C-15)
- Callbacks
- Signature + replay checks, then out-of-band verify (C-03, C-04)
- Idempotency
- Database-enforced unique key per order attempt (C-02)
- Audit trail
- Append-only, SHA-256 hash-chained (C-11)
- Routing
- Strict limits & automated circuit breakers (C-16, W-15)
Encryption & TLS Security (C-13)
| Layer | Target | State | Evidence |
|---|
Payment Gateway Providers
| Provider | Status | Detail |
|---|
Transactions
| Created | Order | Amount | Provider | Status |
|---|
Transaction Detail
Configured Provider Limits
Payment methods are only offered if the order amount falls strictly within configured minimum and maximum limits (C-16).
| Provider | Method | Currency | Min | Max | Enabled | Updated |
|---|
Set / Update Limit
Exchange rates (FX policy)
Orders are always paid to Lao Airlines in the order currency. A payer may pay in another currency at a provider's own rate: the checkout asks every eligible provider that quotes rates, and this policy chooses which quote is used. Verification then checks both the order amount and what the payer was charged. Rates are set by each provider (sandbox providers: dashboard β Exchange rates).
Provider Connection Settings
Enter each provider's merchant credentials. Values are sealed with AES-256-GCM in this environment's database (β) and override the environment variables. Secrets are write-only: leave a secret blank to keep the current value. Use sandbox credentials in the Dev Sandbox and live credentials only in Real. Every change is written to the audit trail (field names only).
Reconciliation Exceptions
| Opened | Kind | Payment | Status | Assignee | Detail | Actions |
|---|
Exception SLA and escalation (W-14)
Who owns each kind of exception and how fast they must act. A new exception is announced on the notification channels; one still open past its SLA is escalated once. Lao Airlines decides these values (decision Q6); a kind without a row is announced but not escalated.
| Kind | Owner | Respond within (minutes) | Escalate to |
|---|
Payments by Status
Provider Health & Circuit Breakers (W-15)
| Provider | Offered | Circuit | Fails | Latency | Last probe |
|---|
Channel Webhook Outbox (C-05 / W-08)
| Created | Payment | Target | Status | Attempts | Next / done | Last error |
|---|
Abuse & Rate-Limiting Controls (C-12)
| Time | Rule | Subject |
|---|
Propose a Refund (Maker)
Enforces maker-checker authorization (C-08). Another admin must review and approve before submission to provider.
Batch Refund (W-12)
One merchant order id per line. A refund is proposed for the remaining balance of each order's paid attempt.
| Created | Order | Amount | Of paid | Kind | Status | Maker β Checker | Reason |
|---|
Daily operations report
One UTC day: payments, money verified per provider, refunds, exceptions and discrepancies opened, settlement reports and channel webhooks (C-06). Reconciliation also runs in the other direction: a verified payment missing from its provider's reports for 72 h becomes a discrepancy and an exception.
Upload & Reconcile Settlement Statement
Automated 2-way and 3-way matching of bank clearing CSV records against local transactions and webhook outbox.
provider_ref and amount (or amount_minor); optional merchant_order_id, fee, settled_at. Reports from LAOSPAY_SIM and QRWALLET_SIM are fetched automatically.Reconciliation Statistics & Integrity
Overview of matched settlements, fee totals, and open discrepancies.
- Total Batches
- 0
- Matched Records
- 0
- Open Discrepancies
- 0
- Reconciliation Status
- Active
Settlement Batches
| Batch ID | Provider | Filename | Total Records | Matched | Discrepancies | Amount | Status | Uploaded By | Reconciled At |
|---|
Reconciliation Discrepancies
| ID | Batch ID | Kind | Description | Payment ID | Status | Resolved By | Note | Actions |
|---|
Finance report
Per day (UTC), channel, provider and currency: payments verified and their gross, refunds confirmed, provider fees from matched settlement records, and the net. At most 92 days.
| Date | Channel | Provider | Currency | Payments | Gross | Refunds | Fees | Net |
|---|
Log New Dispute / Chargeback
Record formal retrieval requests or chargeback notices received from payment card schemes or acquirers.
Dispute Defense & Representment Rules
Chargeback lifecycle standards and Maker-Checker defense workflow.
- Retrieval Request: Initial issuer inquiry before formal chargeback debit.
- Chargeback (First Presentment): Cardholder funds debited; representment evidence required within deadline.
- Liability Shift: 3D Secure authenticated transactions shift fraud liability to the card issuer.
- Maker-Checker Decision: Case closure (WON / LOST / ACCEPTED) requires secondary supervisor sign-off.
Disputes & Chargebacks Ledger
| Created | Order ID | Provider | Amount | Reason | Stage | 3DS Shift | Due Date | Status | Maker β Checker | Actions |
|---|
Circuit Breaker Resilience Policies
Automated fault isolation and failover criteria.
- Failure Threshold
- 5 consecutive provider failures (timeouts, unreachable, provider errors); a business decline is a healthy answer
- Cooldown Period
- 60 seconds open, then a passing TLS probe moves it to HALF_OPEN
- Half-Open
- Offered again; one successful call CLOSES it, one failure re-opens it
- Operator
- Trip OPEN suppresses the provider until Reset; probes and successful calls do not restore it
- Failover
- An open provider is not offered at checkout; a provider that fails to start a payment returns the order's other eligible options for the payer to choose (502
provider_unavailable)
Live Provider Circuit Breaker Telemetry
LAOSPAY_SIM Β· QRWALLET_SIM Sandbox providers
Two independent sandbox payment providers in the 2C2P style. Each is its own gateway
with its own base URL, database, merchants, credentials, hosted page, notifications, refunds, settlement reports,
chargebacks and test mode: LAOSPAY_SIM (/sim: card, QR, wallet) and QRWALLET_SIM (/qrsim:
QR and wallet only). The Portal reaches them only over HTTPS, exactly like 2C2P, so every Annex A control can be tested,
including routing between providers and failover (C-16, W-15, W-16). They do not replace a real provider's sandbox.
Providers
Connect each provider like 2C2P: create a merchant in that provider's own dashboard, enter its base URL, merchant ID and secret key under Provider config, then enable methods under Provider limits.
| Provider | Merchant | Channels | Provider config | Enabled limits | Adapter | Test mode |
|---|
Recent LAOSPAY_SIM transactions
| Created | Provider | Invoice (provider ref) | Channel | Amount | Status | Portal payment |
|---|
Reset sandbox data
Deletes all test data so testing starts again from opened accounts: the Portal's orders, payments, refunds, disputes, settlements and webhooks; both providers' payers, balances and transactions; SIMBANK's customers, accounts, links and transfers. Configuration stays (channels, provider config and limits, FX policy and rates, merchants and keys, bank API clients), and each audit trail records the reset. Bookings stay in Sabre.
SIMBANK Sandbox bank
The bank payers link to LAOSPAY_SIM and QRWALLET_SIM. Customers open accounts in internet banking,
the teller records deposits and withdrawals, and the providers debit and credit linked accounts over the bank's API.
Declines to test: insufficient_funds, over_payment_limit, over_daily_limit and
debits_blocked (docs/SIMBANK_API.md).
Latest API transfers
| When | Provider | Account | Amount | Result |
|---|
Linked accounts
| Provider | Customer | Limits | Status |
|---|
| Created | Payment | Merchant order | Provider | Amount | Status |
|---|
Witnessed UAT rounds
Annex A section 9: every item is demonstrated to Lao Airlines in a test environment and recorded in a signed test report. Open a round with its scope and witnesses, run the scenarios (UAT tests tab) while they watch, record what each witness saw, then close the round: the printable report keeps a fixed SHA-256 and has the signature blocks.
| Round | Scope | Witnesses | Status |
|---|
Incident response
Open an incident from a playbook (PCI DSS 12.10.1). Each step is ticked with who and when; notes build the timeline; quick actions contain it. Opening one notifies the people on duty.
| Opened | Incident | Severity | Status | Steps |
|---|
Approvals
Configuration changes (channels, provider settings and limits, circuit breakers, FX policy, MFA resets, key register) wait here for a second administrator when dual control is on (PCI DSS 6.5.4, 3.6.6). The maker cannot approve their own change; an approved change runs as its maker made it and every record it writes names both maker and checker. Refunds and dispute decisions have their own maker-checker in their tabs. Pending changes expire after 24 hours.
| Proposed | Change | Request (secrets masked) | Maker | Status |
|---|
Operator MFA (PCI DSS 8.4)
Every admin user and whether they sign in with an authenticator code. Turn your own on or off with π MFA at the top. Reset removes another operator's authenticator (a lost phone) and signs them out; they set it up again at their next sign-in.
| Operator | Role | MFA |
|---|
Notifications
Security alerts (high and medium), new exceptions, SLA escalations and incidents are sent to the people on duty. Channels are set in the deployment's settings (NOTIFY_WEBHOOK_URL for Slack/Teams/Google Chat, NOTIFY_TELEGRAM_*, NOTIFY_SMTP_* and NOTIFY_EMAIL_*); secrets stay in the Secret.
| Sent | Channel | Subject | Result |
|---|
Clock (C-11, PCI DSS 10.6)
Audit times are evidence only if the clock is right. The server compares its clock with an NTP server daily; over one second off, or no answer, raises an alert.
Security alerts
Raised for repeated failed sign-ins, an MFA lockout, a credential change (high outside 07:00β19:00 MondayβFriday, Vientiane), a payment-page CSP violation, card data found, a broken audit chain, a missing or expiring provider AOC and a key past rotation (PCI DSS 10.4.1.1, 10.7). Each is also an [ALERT] log line.
| Raised | Severity | Alert | Subject | Detail |
|---|
Payment page tamper detection
Browsers report every script or resource the payment pages' Content-Security-Policy blocked (PCI DSS 6.4.3, 11.6.1). Anything here means something tried to load on a payment page that the page does not allow.
| Page | Directive | Blocked | Count | First | Last |
|---|
Service providers (PCI DSS 12.8)
Each payment provider's PCI DSS attestation of compliance (AOC): level, expiry, the document, and which requirements it covers for this service. Enter what the provider's current AOC says; an AOC missing, expiring within 30 days or expired raises an alert.
| Provider | PCI level | AOC valid until | AOC document | Responsibility | State |
|---|
Key custodians and rotation (PCI DSS 3.6, 3.7)
Every key and credential this deployment holds, from its configuration. Record who holds it (custodian and a different deputy) and when it was last rotated; keys are rotated at least every 365 days, and an overdue one raises an alert.
| Key | Custodian | Deputy | Last rotated | State |
|---|
Immutable Audit Log (C-11)
| # | Timestamp | Actor | Action | Entity | State Changes (Before/After) |
|---|
Retention and archives (C-11)
Audit rows are kept for the retention period. Older rows can be archived to a file (JSON lines, with its SHA-256 and the chain's hashes in the register), stored outside the Portal, and then purged: only past the retention, oldest first, with the file's SHA-256 as proof and a second administrator's approval. The remaining chain verifies from the last purged hash.
| Archive | Rows | SHA-256 | Created | Purged |
|---|
API Playground
Build a request with the wizard, send it to this environment's API and inspect the response.
-
1. Choose what to callSets method + path. π = admin token required.
-
2. Pick an order / paymentLoad recent payments, or paste an order id.
-
3. Fill headersIdempotency-Key is needed for POST /payments (C-02); Authorization for π paths.
-
4. Build the bodyChoose an eligible provider/method returned by payment-options.
-
5. Review & sendCheck the builder below, then send.
HTTP Headers
Use the wizard or fill the builder, then press Send.
Response Headers
Automated Scenario Suites & UAT Runner
End-to-end tests against the real handlers, a registered test channel and the provider sandboxes. No mocks: scenarios that write create test orders on the chosen channel.
Scenario Test Matrix
| Scenario | Covers | Needs | Last Result & Step Assertions | Action |
|---|
UAT Evidence Run History
| Time | Scenario | Outcome | Summary | Actor | Channel |
|---|
Transaction Flow Lab & Lifecycle Tracer
Run one order through the real flow step by step: routing decision, attempt, provider session, callback, verification and the channel webhook.
Live Transaction Timeline
- Select or create a payment to view timeline events.
Register a channel
A channel is a shop, app or system that sends customers here to pay. It signs every order with its secret
and encrypts it with the portal's public key (docs/CHANNEL_API.md). Channel developers: developer docs and code samples.
Portal public keys
Channels encrypt with the first key. Also published at GET /api/v1/channel/keys.
Channels
| Name | Channel ID | Return origins | Webhook | State |
|---|
Channel dashboard users Open channel dashboard β
The channel's own staff see their orders, webhooks and refunds in a separate dashboard (/channel.html); the only change they can make is to send a failed (DEAD) webhook again.
Each person gets an access key, shown once, and sets up an authenticator app at first sign-in. Reset access if a phone or key is lost.
/channel.html. Reset access if it is lost.
| Name | Authenticator | Last sign-in | Added | State |
|---|
Envelope tester Dev Sandbox only
Builds an envelope exactly as a channel server does, with the channel's real secret and the portal's key, then runs every check the portal runs. Nothing is recorded until you open the checkout.
How a channel builds the envelope (Node.js)
const crypto = require("crypto");
// key = { kid, public_key_pem } from GET /api/v1/channel/keys; secret = your channel secret
function envelope(order, key, secret) {
const k = crypto.randomBytes(32), iv = crypto.randomBytes(12);
const header = Buffer.concat([Buffer.from([1, key.kid.length]), Buffer.from(key.kid)]);
const wrapped = crypto.publicEncrypt({ key: key.public_key_pem, oaepHash: "sha256",
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }, k);
const c = crypto.createCipheriv("aes-256-gcm", k, iv); c.setAAD(header);
const ct = Buffer.concat([c.update(JSON.stringify(order)), c.final(), c.getAuthTag()]);
const payload = Buffer.concat([header, wrapped, iv, ct]).toString("base64url");
const hashValue = crypto.createHmac("sha256", secret).update(payload).digest("hex");
return { payload, hashValue }; // POST channel, payload, hashValue to /pay
}
System Telemetry & Architecture Status
Background Job Triggers
Manually trigger background scheduled workers on demand for immediate testing and verification.
Production view: the workers run on their schedule only; manual triggers are a testing tool.
Active Runtime Configuration
Live Process Log Stream
Outbound HTTP Wiretap & Packet Inspector Calls to provider gateways and channel webhooks
| Timestamp | Outbound Call | Status | Latency (ms) |
|---|
Annex A Compliance Status
What the statuses mean
Action Tracker & Responsible Stakeholders
Every remaining step across all controls, workflows, and tests, merged and grouped by owner.
| ID | Requirement Item | Priority | Status | Progress | Waiting on |
|---|