Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • A Ahad Mobile
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • holatech
  • Ahad Mobile
  • Merge requests
  • !117

feat: card withdraw to usd wallet and card tab redesign

  • Review changes

  • Download
  • Patches
  • Plain diff
Merged Khanh Pham requested to merge feat/card-withdraw into develop Oct 12, 2026
  • Overview 0
  • Commits 13
  • Pipelines 1
  • Changes 54

What

  • Card withdraw: moves money from the card account to the user's USD wallet through KeySecure account/transfer Out.
  • Card detail redesign: the screen now has View / Withdraw / Add fund / Setting actions.
  • Card tab redesign: follows Figma. It has Virtual/Physical tabs (Physical shows Coming soon) and Default + Backup card sections.
  • Card history: moved to its own /card-history screen.

Backend

  • New route: POST /card-account/withdraw takes { amount, passcode }.
    • Guarded by passcode and listed in MONEY_ROUTES.
    • Free; minimum 1 USD, at most 2 decimals.
    • Pending swipe holds are excluded from the withdrawable balance.
  • Request time: one DB transaction does three things:
    • debits the card ledger (WITHDRAW_OUT);
    • moves the mirror from normal.CARD_USD to reserve.CARD_USD;
    • writes a CARD_WITHDRAW transaction in PROCESSING and a card_transfers Out outbox row.
  • onApplied: credits the wallet from RESERVE USD and emits the socket event card.withdraw.settled.
  • onFailed: re-credits the card (WITHDRAW_REVERSAL) and reverses the mirror. The reserve.CARD_USD leg may go negative here (allowNegativeCardReserve, which only that account accepts).
  • Provider answers: every Out 3002/3008 and every 3004 is resolved by looking up the transfer/list record status.
    • Success → applied
    • Pending → pending
    • Fail → failed
    • unknown → pending + alert
    • failed lookup → pending
  • No migration: the new enum values go into varchar columns.

Frontend

  • /transfer?direction=out: From is the card, To is the fiat wallet. Max and validation use the spendable balance.
  • Fee now shows 0.00 USD in both directions, replacing a hard-coded 0 PRV.
  • The receipt says "Withdrawal submitted / processing".
  • History shows a Card Withdrawal label.
  • The socket listener for card.withdraw.settled is added, and withdraw is on the passcode-401 rule.

Verification

  • be: card-account, transactions and auth jest pass (295 card-account tests); yarn build is clean.
  • fe: full suite passes (1312 tests), type-check is clean, lint has 0 errors.
  • reconciliation.card-flow.postgres.spec passes 10/10 on a throwaway Postgres, including the withdraw settle and refuse cases.
  • The Opus review gate passed in round 4.
  • Simulator screenshots were taken of the Card tab, Detail card, Card history and Withdraw.
  • Not yet verified: a real withdrawal on staging. The test card balance is 0.

Follow-ups (not in this MR)

  • card-add-fund.tsx and CardStack are now unused.
  • The pre-existing lock inversion in deposit onFailed.
  • There is no hold for a pending Out against concurrent swipes.
  • The FE assumes the card deposit fee is 0.

🤖 Generated with Claude Code

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: feat/card-withdraw