Skip to content

feat(web): add a payment initiation form to the payments screen - #300

Merged
tiana-code merged 1 commit into
mainfrom
feat/E-08-payment-initiation
Jun 19, 2026
Merged

feat(web): add a payment initiation form to the payments screen#300
tiana-code merged 1 commit into
mainfrom
feat/E-08-payment-initiation

Conversation

@tiana-code

Copy link
Copy Markdown
Owner

E-08 Sandbox UI #299 (289c) - payment initiation form (follow-up to the payments list #289b). Reuses the #297 write-UI pattern.

What

  • api/client.ts: apiPost extended to (path, {body?, headers?}) - sends a JSON body + custom headers, dev-bearer stays authoritative; backward-compatible (the case-actions apiPost(path) call is unchanged).
  • features/payments/useInitiatePayment.ts: useMutation POST /v1/payments with the body + an Idempotency-Key header; onSuccess invalidates the payments query.
  • features/payments/PaymentForm.tsx: amount / currency (select over USD/EUR/GBP) / reference (maxLength 140) inputs; Create disabled until amount > 0 and reference non-blank (mirrors the backend @DecimalMin/@NotBlank/@SiZe).
  • routes/Payments.tsx: a "New payment" toggle, the form, an error alert, and a reset on toggle.
  • 3 vitest tests: POST asserts method + JSON-number amount body + Idempotency-Key header present + list refetch; Create stays disabled until valid; failure surfaces the alert.

Idempotency (money-path)

The Idempotency-Key is generated per user intent at the mutate() call and passed into the mutation, so a retry of the same submit reuses the key and the backend dedupes it - an accidental retry is not a second payment. (code-reviewer MEDIUM, applied.)

Gate chain

  • critic: GO-WITH-CHANGES (reference maxLength 140; apiPost header-merge dev-bearer authoritative; test asserts POST + JSON-number + Idempotency-Key presence + refetch - all applied).
  • security-auditor (opus): PASS - idempotency per-submit, authz server-side (payments:write; UI does not self-authorize), header merge safe, constrained inputs, no secrets, clean-room clean.
  • code-reviewer: 1 MEDIUM (idempotency-key lifetime) applied; header-merge/204/amount-string declined with rationale (auditor-confirmed safe / YAGNI / matches the codebase number convention).
  • evaluator: PASS (0.88).
    Web gates green: lint 0 errors, typecheck, vitest 63 passed (3 new), build.

Closes #299

Let an operator open a payment from the dashboard: a toggled form takes
an amount, a currency from the supported set and a reference, validates
them against the backend constraints client-side, and posts to the
payments API with a per-submit idempotency key so an accidental retry
of the same intent is deduped rather than charged twice. The shared post
helper now carries a JSON body and custom headers while keeping the dev
bearer authoritative. On success the list refetches and the form closes;
failures surface a dismissable alert.

Closes #299
@tiana-code tiana-code added this to the v0.4.0 milestone Jun 19, 2026
@tiana-code
tiana-code merged commit 55e234f into main Jun 19, 2026
10 checks passed
@tiana-code
tiana-code deleted the feat/E-08-payment-initiation branch June 19, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sandbox UI: payment initiation form (POST /v1/payments)

1 participant