Android POS QA Checklist
Prerequisites
- Local QA smoke passes.
./scripts/local-validation/qa.sh test androidprerequisites are satisfied.- APK is built in WSL and installable from Windows
adb.exe. - Android emulator or device can reach the local QA host/proxy.
- If automatic install is desired, Windows
adb.exeis on PATH orQA_WINDOWS_ADBpoints to it. - Windows emulator/backend battery records emulator name/API level, Windows host IP, WSL distro, local QA proxy URL, terminal mTLS proxy URL, Firebase emulator/auth tenant, APK SHA, and backend report path before PASS.
- Battery run starts from a clean install or records retained app data, seeded org/store/register/terminal IDs, and any physical hardware dependency that is unavailable in the emulator.
- Current device-gate evidence is produced by
./scripts/local-validation/qa.sh test external-gates, the aggregate report.dev-logs/qa/reports/external-gates-20260607T083639Z.md,bazel test //scripts/qa:android_device_inventory_testplus.dev-logs/qa/reports/android-device-adb-inventory-20260607T083639Z.md. The live inventory found Windowsadb.exeat/mnt/c/Users/natha/AppData/Local/Android/Sdk/platform-tools/adb.exe, butadb devices -lwas empty and documented wireless endpoints10.1.10.228:41905,10.1.10.196:5555, and10.1.10.23:5555timed out. Device/local-backend proofs remain blocked until an emulator or physical terminal is connected, authorized, and reachable from the Windows bridge. - Physical hardware checks that require real peripherals are tracked in
../hardware-smoke-runbook.md. Use HW-20 there for LANDI C20Pro cash drawer verification for GitHub #1760.
Manual Local Checks
- Build debug APK with Bazel in WSL.
- Copy/expose APK to a Windows-readable path.
- Record manual emulator/device evidence from the host that owns ADB.
- Install with Windows
adb.exeinto the Windows-hosted emulator. - Verify app can reach local API proxy and terminal mTLS proxy.
- Firebase emulator auth/session starts correctly.
- Terminal onboarding and local cert enrollment work.
- PIN login and shift unlock work.
- Windows emulator/backend battery: run launch, auth, terminal selection, catalog sync, cash sale, receipt capture, refund/void, offline replay, session expiry, app restart, and backend ID reconciliation in one continuous run with timestamps and request IDs.
- Battery negative cases: backend stopped, mTLS proxy stopped, wrong terminal cert, expired/revoked terminal, Firebase token expired, wrong tenant, stale catalog, duplicate payment tap, network toggled offline, and app process killed during pending payment all fail or recover with auditable state.
- Product/catalog sync works, including image URLs and low-stock items.
- Cash sale records server-side.
- Simulated card-present handoff records success, decline, timeout, and failure.
- Void/refund paths update server state.
- Offline queue records failed request and replays after reconnect.
- Offline replay idempotency proof covers both same-terminal replay suppression and cross-org, cross-store, and cross-terminal key-collision attempts; the second boundary must create its own transaction with captured org/store/ terminal IDs.
- Receipt preview/capture works through generic printer adapter.
- Scanner/cash drawer generic adapters expose clear emulator behavior.
- Physical cash drawer behavior is not satisfied by generic adapter or emulator
evidence. Run
HW-20on a LANDI C20Pro with an attached drawer before closing GitHub #1760. - App Check missing/valid local tokens behave as expected when wired.
Terminal Checkout Discount Preview
- Local: start from a seeded terminal identity and run checkout discount preview
through
/v1/checkout/discount-previewwith valid mTLS/demo-terminal attributes. - Local: verify the response preserves the provider discount payload and record the org ID, store ID, terminal ID, preview request ID, coupon code, request timestamp, and backend report path.
- Local: repeat with terminal resolution failure and provider retry/audit failure inputs; verify no provider call occurs before terminal validation and failures are not converted into successful discount previews.
- Staging/device: repeat on approved terminal hardware or emulator-backed staging identity with test coupon data; save the terminal identity, provider correlation ID, response payload, and any retry/audit failure evidence.
Terminal mTLS Identity Denial Contract
- Local: run the terminal mTLS proof bundle and confirm a valid proxy certificate identity resolves to the expected org, store, and terminal before terminal runtime routes execute.
- Local: repeat missing certificate, unverified chain, missing cert hash, invalid base64 cert hash, expired certificate, not-yet-valid certificate, malformed validity headers, revoked certificate, and inactive terminal credential cases; verify each denial stops before terminal mutation, downstream filter execution, principal attachment, organization lookup, or other side effects as appropriate.
- Local: keep the security checklist anchor
security-compliance.md#terminal-mtls-identity-denial-contractsynchronized with the focused automated proof commands and redaction expectations. - Device/staging: repeat the same acceptance and denial matrix through an Android emulator or approved terminal fixture pointed at the real terminal mTLS proxy/load balancer, recording terminal ID, org/store IDs, request IDs, logcat request correlation, backend/security logs, and redacted certificate hash/serial evidence.
EBT Acceptance Product Contract
- Gateway does not currently own or process EBT. Per the Gateway integration
charter, EBT eligibility and EBT sales remain POS-owned: POS owns the
product-level
ebt_eligibleflag, terminal split tender, transaction records, and EBT reporting. - EBT/PIN debit is a Peak POS-tier capability only and requires the separate PIN-capable reader. Peak Terminal and Peak Simple remain out of scope for EBT acceptance, including Tap to Pay-only Simple devices.
- Current implementation status:
terminal-apivalidates a nonblank EBT card token plus terminal EBT config and Peak POS tier eligibility before returning the current placeholder balance contract. Placeholdernullbalances and EBT metadata persistence are not evidence of live EBT acceptance, provider authorization, settlement, or certified device flow. - Do not close EBT acceptance until product, provider, and device owners confirm the tender flow, balance inquiry behavior, eligible-item split, non-EBT residual tender, reversal/refund handling, receipt/report fields, and the approved EBT-capable Peak POS hardware + reader fixtures.
- Payment-data boundary: never record raw EBT PAN, track data, PIN block, PIN, or unredacted card token in docs, screenshots, logs, issues, or test evidence. Evidence must use fixture aliases, redacted token/card references, backend request IDs, and provider/device correlation IDs only.
- Required staging/device evidence for acceptance closure: Peak POS-tier org and terminal config, approved EBT-capable device plus separate reader, provider test account/fixture, eligible and ineligible catalog items, successful balance inquiry, EBT-only sale, split EBT/non-EBT sale, ineligible-item denial, disabled-tier/config denial, persisted POS transaction/report rows, redacted receipt evidence, Android logcat request IDs, backend request IDs, provider/device correlation IDs, tester, timestamp, and environment.
Terminal EBT Balance Token Boundary
- Local: call
/v1/ebt/balancethrough a resolved mTLS/demo-terminal identity with a missing or blankcardTokenand verify terminal-api rejects the request before terminal payment-config lookup, placeholder balance response, or provider/device handoff. - Local: repeat with a nonblank token for enabled and disabled EBT terminal configs, verifying enabled terminals return the current placeholder contract and disabled terminals reject through the EBT-enabled check.
- Staging/device: repeat on approved EBT-capable terminal fixtures, recording terminal ID, store ID, card-token fixture alias, request ID, rejection or balance result, tester, timestamp, screenshots, and provider/device correlation evidence where available.
Terminal Notification Read Scope
- Local: mark a notification read from a terminal identity in the same org and
verify the terminal-api repository uses an atomic
notification_id + org_idmutation rather than an unscoped notification ID update. - Local: attempt to mark a cross-org notification read and verify it is hidden as not found with no repository mutation and no duplicate service call.
- Local: verify list, count, unread count, and mark-all-read are resolved from the mTLS/demo-terminal org before repository calls.
- Device/local-backend proof is not satisfied by controller/service tests alone: capture an Android emulator or physical device run that lists notifications and performs mark-read plus mark-all-read, with matching Android logcat request IDs and backend request IDs for the resolved terminal identity.
- Current status: the 2026-06-07 ADB inventory found the Windows bridge but no connected or reachable emulator/device, so this remains a device-gated proof rather than a backend-test gap.
- Staging/device: repeat read/list/count/mark-all-read from approved terminal identities in two orgs, recording terminal IDs, org IDs, notification IDs, read-state query evidence, tester, timestamp, screenshots, and backend request IDs.
Terminal PIN Store Scope
- Local: authenticate PIN through a resolved mTLS/demo-terminal identity and verify the PIN service receives the resolved terminal object, not a caller-supplied store ID.
- Local: seed a matching PIN in a different store and verify terminal PIN auth searches only the resolved terminal store, does not update the other user Firebase ID, and records the attempt as invalid.
- Local: verify terminal-resolution failure stops before any PIN lookup, password comparison, attempt-clear, or Firebase custom-token work.
- Staging/device: repeat PIN login on approved terminal identities in two stores, recording terminal ID, resolved store ID, attempted cross-store user fixture, auth result, attempt-counter evidence, tester, timestamp, screenshots, and backend request IDs.
Terminal Card Authorization Scope
- Local: record a card authorization for a transaction owned by the resolved terminal store and terminal ID; verify the authorization row is persisted and Gateway sale sync uses the persisted transaction/card-authorization evidence.
- Local: attempt to record a card authorization from a different terminal or store than the persisted transaction; verify the request is forbidden before card-authorization insert, lookup, or Gateway sale sync.
- Local: repeat approved, declined, EBT, nested card-present, and SDK-owned Gateway transaction ID cases with terminal/transaction scope matched.
- Staging/device: repeat card-present authorization with approved terminal identities in two stores, recording terminal IDs, store IDs, transaction IDs, card-authorization IDs, provider/Gateway references, rejection evidence for mismatched scope, tester, timestamp, screenshots, and backend request IDs.
Terminal Refund Finalization Idempotency
- Local: create a terminal card-present refund in
refund_in_processand finalize it with anIdempotency-Key; verify terminal-api records the processor reference, card-authorization receipt evidence, final refunded status, Gateway refund sync, and Gateway refund transaction ID exactly once. - Local: repeat the same refund finalization request with the same idempotency key and verify the cached finalized response is returned without duplicate processor-reference updates, card-authorization inserts, status writes, Gateway refund sync calls, or Gateway refund ID updates.
- Device/local-backend proof is not satisfied by terminal-api service tests alone: capture an Android emulator or physical device run with the first refund finalization request ID, a replay using the same idempotency key, the original finalized response on replay, and backend/Gateway evidence showing no duplicate provider or local side effects.
- Current status: the 2026-06-07 ADB inventory found the Windows bridge but no connected or reachable emulator/device, so this remains a device-gated proof rather than a backend-test gap.
- Staging/device: repeat refund finalization replay from approved terminal hardware or emulator-backed staging identity, recording terminal ID, store ID, refund transaction ID, idempotency key, processor/Gateway references, request IDs, provider evidence, tester, timestamp, screenshots, and backend row counts.
Terminal Transaction Detail Status Void Scope
- Local: fetch transaction detail through a resolved mTLS/demo-terminal identity and verify the terminal-api service receives the resolved terminal store and terminal ID before returning transaction data.
- Local: update status and void a transaction through a resolved terminal identity; verify the service receives terminal scope and uses that scope before local mutation or Gateway void delegation.
- Local: attempt detail, status, and void operations for a transaction owned by a different store or terminal; verify the request is forbidden before detail fallback, status mutation, local void mutation, or Gateway side effects.
- Staging/device: repeat detail, status update, and void checks with approved terminal identities in two stores, recording terminal IDs, store IDs, transaction IDs, rejected cross-scope evidence, tester, timestamp, screenshots, provider/Gateway references, and backend request IDs.
Terminal Offline Idempotency Boundary
- Local: replay the same offline transaction idempotency key through the same resolved org, store, and terminal; verify only one transaction, item set, ledger movement, inventory adjustment, loyalty accrual, KDS write, and kitchen notification side effect occurs.
- Local: reuse the same raw offline idempotency key from a different org, store, or terminal; verify terminal-api creates a distinct transaction and does not return the first terminal's org, store, terminal, or transaction ID.
- Local: record transaction IDs, org IDs, store IDs, terminal IDs, raw idempotency key, replay result, and side-effect counts for both same-terminal replay and cross-boundary collision attempts.
- Staging/device: repeat the same-terminal retry and cross-boundary collision checks through the Android offline queue, local or staging backend, and terminal mTLS proxy, recording request IDs, logcat, screenshots, backend rows, transaction IDs, and provider/Gateway references where applicable.
Source Surface Coverage Inventory
Every item below must have either automated emulator/unit coverage, explicit manual execution evidence, or an open finding explaining why it cannot yet be proved locally.
-
age verification: restricted-item sale allowed/denied flows, override prompts, audit evidence, and failed validation handling. -
appointment operatorandappointments: appointment lookup, create/update attempts, unavailable operator/API failure, empty schedule, and permission denial. -
workflow appointment operator: account-service workflow appointment lookup, service listing, availability, create/reschedule/cancel actions, management API auth/App Check propagation, permission denial, malformed availability filters, and API failure handling. -
account invoice: account invoice lookup, invoice detail refresh, payment status refresh, missing invoice, wrong-account denial, payment-link handoff, and backend request-ID correlation. -
batch,batch detail, andbatch label printing: batch list, detail, close/reopen where supported, label print success, printer unavailable, and malformed batch data. -
cartandupsell: add/remove/update item, quantity changes, discounts, taxes, upsell accepted/declined, empty cart, stale catalog item, and invalid item state. -
cash count,cash drawer,drawer open,mid shift action,shift,shift start, andshift close: open drawer, paid-in/paid-out, no-sale, start shift, close shift, count mismatch, manager override, offline attempt, audit trail capture, and LANDI-only physical drawer proof throughHW-20. -
cash payment,checkout,checkout flow,split payment,keyed card entry,payment,http payment,payment backend,pending request recovery, andpending transactions: cash/card/split success, decline, timeout, retry, duplicate-submit prevention, keyed-entry validation, recovery after process death, and pending transaction resolution. -
cert renewal,certificate,provisioning,terminal discovery,terminal selection, andonboarding token: token validation, enrollment, certificate storage, certificate renewal, mTLS failure, discovery success, duplicate terminal, revoked terminal, and local proxy routing. -
consent capture,sms receipt delivery, andreceipt delivery: opt-in, opt-out, invalid phone/email, SMS capture, email capture, delivery failure, resend, and local notification-capture evidence. -
customerandcustomer display: customer search, create/update, loyalty attach, display connection, display disconnect, basket mirroring, payment status mirroring, and privacy-safe idle screen. -
dashboard,report,report transactions,terminal report transactions,transaction history,transaction detail, andreconciliation: report filters, empty data, populated data, permission denial, reconciliation totals, terminal-backed transaction fetch, API failure, and export/print where present. -
discount,tax config, andtier feature: item/order discount, invalid discount, tax configuration display, feature enabled/disabled, module-gated action denial, and stale permission refresh. -
ebt balance,gift card, andreturn: balance inquiry, gift-card sale or redemption where implemented, partial/full return, failed return, and receipt linkage to original transaction. -
encrypted invoice draft,invoice,invoice create,invoice draft,invoice payment,invoice print,invoice sync,cashier create invoice, andterminal invoice: draft save/load, encrypted local queue, create/send, payment success/failure, print, sync retry, conflict resolution, and terminal API handoff. -
environment,firebase remote config,firebase messaging handler,notification, andnotification list: local/staging environment switch, remote-config default/failure, FCM/local notification receipt, notification list empty/populated/read state, and invalid notification payload. -
expiry alert,lot receiving,stock transfer,product,product catalog,product detail,product form, andproduct sync: catalog load, product detail, create/update validation, image URL display, expiry alert, lot receive, stock transfer success/failure, sync retry, low-stock item, and stale/offline catalog behavior. -
kitchenandkitchen http: local kitchen order send, order status refresh, API failure, empty queue, populated queue, and kitchen service unavailable. -
heartbeat,label printer,landi system,nexgo system,system,scanner, andserial: device heartbeat, printer/scanner/device adapter available/unavailable, serial lookup, payment-terminal adapter detection, hardware capability fallback, and clear emulator behavior when no physical device exists. -
loyaltyandloyalty enrollment: enrollment, lookup, earn/redeem where implemented, invalid phone, duplicate customer, and permission denial. -
main,settings,setup confirmation,user login token, anduser pin: app launch, setup completion, token login, PIN login, lockout, session expiry, settings update, and failed settings persistence. -
root detection: local rooted/emulator classification, blocked sensitive action, warning-only behavior where configured, and staging/device evidence.
Terminal Receipt Transaction Ownership
- Local: request SMS receipt delivery for a transaction whose org, store, or terminal ID does not match the resolved mTLS/demo terminal; verify terminal-api rejects before calling the receipt proxy client.
- Local: repeat the ownership denial for email receipt delivery and hosted receipt-link generation, including cross-store and different-terminal transaction IDs.
- Staging: repeat with approved disposable transactions and record terminal ID, transaction ID, org/store IDs, request ID, response message, tester, timestamp, and redacted command or browser output.
Open Android Route Wiring Gaps
The checked-in endpoint consumer-wiring artifact still contains the stale row below. It is intentionally kept as invalidated QA evidence until the endpoint audit artifact is regenerated or corrected.
GET /api/v1/stores/{}/discounts/active: Endpoint-audit artifact references stale DiscountController route; current merchant-api source has no DiscountController, current OpenAPI has no /discounts/active path, and generated SDKs expose no active-discounts method. Closing evidence must show the endpoint audit artifact was regenerated from current source or the expectation was removed with rationale.
Manual Staging/Device Checks
- Repeat launch and auth on approved physical terminal hardware.
- Verify real Gateway SDK/device activation only with approved test credentials.
- Verify Play Integrity, FCM delivery, hardware printer/scanner/cash drawer, and secure storage on physical device.
- For cash drawer, follow
HW-20: PR #1770 wired LANDI support onmain, and #1760 remains open until the drawer physically opens on a LANDI C20Pro. - Repeat offline replay idempotency on two staging terminals or terminal identities, using distinct org/store/terminal boundaries when available; save the provider/local transaction rows that prove cross-boundary collision isolation.
Expected Evidence
- Bazel build command and APK path.
- Android handoff report path.
- Windows
adb.exeinstall/run command output. - Emulator/device screenshots.
- Backend transaction/receipt IDs.
- Battery artifact fields: emulator/device, API level, APK path/SHA, WSL host address, proxy URLs, org/store/register/terminal IDs, transaction/refund/ receipt IDs, offline queue item ID, request correlation IDs, logcat path, screenshots/video path, tester, and timestamp.
- Offline replay artifact fields: original and replay idempotency key, first and second org/store/register/terminal IDs, transaction IDs returned to both callers, ledger/inventory/KDS/notification side-effect IDs, local backend report path, and scoped collision-isolation result.