Authenticated Wallet Transactions
Build an authenticated Express wallet API with seeded wallets, ledger-backed deposits/withdrawals/transfers, validation, authorization, idempotency, and safe failure handling.
Product context
Our backend is expanding from ticket-only support tooling into a fintech wallet service. Wallet owners need to inspect balances and post money movements safely, while the system maintains an auditable transaction history and prevents access to other users’ wallets.
User story
As an authenticated wallet owner, I want to view my wallet and create deposit, withdrawal, and transfer transactions, so that balances are updated through a ledger without exposing or corrupting another user’s wallet.
Acceptance criteria
- Add the wallet feature surface exactly at:
src/walletStore.js, exportingDEFAULT_WALLETS,createWalletStore(initialWallets),defaultWalletStore, andresetDefaultWalletStore().src/wallets.js, exportingVALID_CURRENCIES,VALID_TRANSACTION_TYPES,applyWalletTransaction(store, params), andcreateWalletRouter(options).- Mount
createWalletRouter()fromsrc/app.jsat/walletswithout breaking existing routes.
- Seed deterministic wallets using integer minor units:
wal_alice_usd, owneralice, currencyUSD, balance10000.wal_bob_usd, ownerbob, currencyUSD, balance2500.wal_alice_eur, owneralice, currencyEUR, balance5000.
- Expose the HTTP contract under
/wallets:GET /wallets/:walletIdreturns200 { wallet }.GET /wallets/:walletId/transactionsreturns200 { items }.POST /wallets/:walletId/transactionsaccepts{ type, amount, currency, destinationWalletId?, idempotencyKey? }and returns201 { transaction, wallet }for new successful deposits, withdrawals, and transfers.- Missing wallets return
404 { error: { code: 'WALLET_NOT_FOUND' } }.
- Require
x-user-idauthentication for every/walletsroute:- Missing authentication returns
401 { error: { code: 'AUTH_REQUIRED' } }. - Authenticated users may only read or transact against wallets they own; otherwise return
403 { error: { code: 'WALLET_FORBIDDEN' } }.
- Missing authentication returns
- Validate transaction input before changing state:
typemust bedeposit,withdrawal, ortransfer.amountmust be a positive safe integer.currencymust be one ofUSD,EUR, orGBP.- Request currency must match the source wallet currency.
- Transfers must include
destinationWalletId. - Return
400 { error: { code } }with stable codes such asINVALID_TRANSACTION_TYPE,INVALID_AMOUNT,INVALID_CURRENCY,CURRENCY_MISMATCH, orMISSING_DESTINATION_WALLET.
- Model wallet history with append-only ledger entries. Each successful transaction should record
id,walletId,type,amount,currency,balanceAfter, andcreatedAt; transfers should create linked debit and credit entries using a shared relationship field such asrelatedTransactionId. createWalletStore(initialWallets)must create isolated in-memory state so separate store instances do not leak mutations.- Support safe transaction failure handling:
- Insufficient funds return
409 { error: { code: 'INSUFFICIENT_FUNDS' } }. - Unknown transfer destinations return
404 { error: { code: 'DESTINATION_WALLET_NOT_FOUND' } }. - Failed transactions must not leave partial balance or ledger changes.
- Insufficient funds return
- Support idempotency on
POST /wallets/:walletId/transactionswhenidempotencyKeyis supplied. Repeating the same key for the same source wallet should return the original transaction with200and must not apply the balance change twice.
Constraints
- Store and accept money amounts as integer minor units only.
- Keep response shapes and error codes stable.
- Preserve the existing app structure and ticket routes.
- Use the existing Node/Jest/Express style in the codebase.
Deliverable
Implement the wallet store, transaction logic, router, and app mounting in src/walletStore.js, src/wallets.js, and src/app.js.
Time box
Plan to spend about 60–90 minutes on the implementation and verification.