Skip to content

Payments module: production-hardening checklist from the origin app (make this piece standalone-shareable) #1

Description

@TiredofSleep

Feedback from the origin app (the production two-location wet cleaner customPOS was generalized from). We just finished a pre-launch hardening pass there: every payment mechanism was consolidated into single tested units, adversarially reviewed by multi-agent workflows, and regression-tested (196-assertion money harness gating every deploy). These are the card-handling lessons that were each learned from a REAL production incident — the payments module should bake every one of them into its core so no operator ever re-learns them. The owner also wants this module packaged so it can be shared standalone with operators who only want the card piece — see "Packaging" at the bottom.

Charge-path invariants (each of these bit us live)

  1. One saved-card charge primitive. Tokenized charges MUST send the card expiry normalized to MMYY digits (String(exp).replace(/\D/g,'') — accept "03/28" and "0328"). In the origin app this rule was hand-copied at 7 call sites and the "non-numeric expiry" decline had to be fixed FIVE separate times before consolidation. The primitive should also own: per-location merchant-account resolution (card's store → customer's home store → station), and clearing an "unverified" flag on any approved charge.
  2. One card-present (reader) scaffold owning the whole lifecycle: double-tap debounce; the STATION's terminal (the reader in front of the customer — never the customer's home location's terminal; books still attribute by order/location separately); a cancel contract that cancels the PHYSICAL terminal (Esc/nav teardown included); and the stale-result rule below.
  3. Late-approval alarm — captured money must never vanish silently. If a terminal approval races past the cashier's Cancel, the charge exists at the processor with nothing recorded. Never silently drop it: log auth+ref in ONE searchable format and show a loud tell-a-manager alarm. The origin app had this alarmed at one screen and silently dropped at three others until the audit caught it.
  4. Refund reachability. Store the processor reference on EVERY card payment row and mirror it into the canonical txn field (never overwriting a check number). The origin app had card payments whose "refunds" were recorded in the books but never sent to the card because the ref was stored under a different field per path. Refunds: original tender only, amount computed from the ticket (never typed — anti-theft), owner/approval-gated.
  5. The "3DS-style" issuer fallback. Some issuers refuse ALL $0 account verifications on typed-in cards. Ladder: $0 verify → $1 auth+void fallback → save-unverified with a visible ⚠ flag where the first real charge becomes the test (decline of that first charge lands in a collections queue, not a void).
  6. Debounce at every interactive entry point — but NOT inside the charge primitive. A batch path (monthly auto-billing charging many customers sequentially) will false-decline its second customer if the debounce lives inside the primitive. Learned by near-miss.
  7. Card fee / surcharge discipline. Surcharge is caller policy; fee rows use an exact method label excluded from paid-total math; recompute due+fee at CLICK time (a background sync can change the balance between render and tap — a stale render-time fee once nearly charged a fee against a $0 due), and always show a confirm step before charging a saved card.
  8. Every decline is LOGGED before it is shown. Three origin-app screens presented declines with no audit entry — a dying card or fraud probing on one customer was invisible. A disputed "you charged me / no we didn't" needs the trail.

PCI / trust posture (matches the module's existing blueprint — keep it loud)

  • The browser never touches a PAN: hosted iframe/tokenizer only; gateway credentials live only on the operator's own server; the downloaded file contains no secrets. This posture is exactly what makes the module shareable — operators can adopt the card piece without inheriting PCI scope.

Packaging request (the owner's ask)

Publish the payments piece as a standalone, operator-shareable module page on the site: the processor-agnostic interface + certified reference adapter + THIS hardening checklist as its test plan. Many shops don't want a new POS — they want card handling that is actually right. A page that says "here is the card module, here are the eight production-learned invariants it enforces, here is the harness that proves them" is the sharpest wedge the project has.

Source: origin-app consolidation pass, 2026-07 (adversarial multi-agent review; findings regression-tested). No proprietary data included.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions