Problem RestatementProblem
Design the web and mobile portal where credit card customers manage their account (asked at Capital One Power Day). Customers log in and:
- see current balance, available credit, minimum payment due and due date,
- view transactions (pending and posted) and download statements,
- make payments from a bank account (one-time or autopay),
- use card controls: lock/unlock card, report lost, set alerts, replace card.
The interviewer will ask why you made each decision, so be ready to justify the choices.
RequirementsRequirements
- Secure login with MFA, and session timeout.
- Accurate account data (from the core card processing system).
- Payments must never be duplicated.
- Card lock takes effect immediately for new authorizations.
- High availability, especially around due dates and statement days.
ArchitectureArchitecture
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
U["Web / Mobile"] --> GW["API Gateway - auth, rate limits, WAF"]
GW --> BFF["Portal BFF"]
BFF --> ACC["Account Service"]
BFF --> TXN["Transactions Service"]
BFF --> PAY["Payments Service"]
BFF --> CARD["Card Controls Service"]
BFF --> STM["Statements Service"]
ACC --> CORE["Core card system (processor)"]
TXN --> TDB[("Transactions store - read replica / search")]
STM --> OS[("Statement PDFs - object storage")]
PAY --> ACH["Bank transfer network (ACH)"]
CARD --> AUTHZ["Authorization system - card status"]
IDP["Identity - login, MFA"] --> GW- Identity: login with password + MFA (push/OTP), device recognition, risk-based step-up (a new device → extra check). Short-lived tokens, and refresh with rotation.
- BFF: one API tailored to the portal screens. It calls domain services in parallel.
- Core card system is the source of truth for balances. The portal reads through the Account Service with a short cache.
Key Features
3.1 Balance and transactions
- Pending transactions (authorizations) and posted transactions (settled) come from different stages, so show both, clearly labeled.
- Transactions are served from a read-optimized store (replicated from core, updated in near real time via events) with search and filters (merchant, date, amount).
- The balance is cached for ~30–60 s, and refreshed right after actions like payments.
3.2 Payments
POST /paymentswith an Idempotency-Key, amount, source bank account (tokenized) and date.- Validate (amount ≤ balance or allowed overpay; bank account verified), save as
scheduled→ send via ACH →processing→postedorreturned. - Show the payment immediately as "pending" so the customer doesn't pay twice, and credit available credit according to bank policy.
- Autopay: a scheduler creates payments on the due date (minimum, statement balance or a fixed amount).
3.3 Card controls
- Lock writes the card status to the authorization system, which checks it on every card swipe, so new purchases are declined within seconds.
- Report lost/stolen: block the card, issue a replacement, and move recurring merchants to the new card if supported.
3.4 Statements
Statements are generated monthly by batch jobs as PDFs in object storage. The portal lists them and gives short-lived download links.
Deep Dive — The balance the customer seesDeep dive
"What do I owe?" has several correct answers at once, and showing the wrong one produces either a support call or a declined card.
One number from the core system
Read the account balance and display it.
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
CORE[("Core banking - posted balance")] --> ONE["Show: balance $1,240"]
ONE --> Q1["A $200 hotel hold is invisible - customer thinks they have more credit"]
ONE --> Q2["A payment made this morning is not reflected - customer pays twice"]
ONE --> Q3["Nothing says what is due, or when"]One number cannot answer the three different questions customers actually have: what have I spent, what can I still spend, and what must I pay by when. Hiding pending holds is the expensive one — the customer plans against credit they do not have and gets declined at the till.
Show posted and pending separately
Display posted transactions and pending authorisations as two labelled lists, with the posted balance.
Much more honest, and it exposes the next problem: customers now add the two lists themselves to work out what they can spend, and they get it wrong. The number that governs whether the next purchase is approved — available credit — is still not shown anywhere.
Show the three numbers the customer actually needs, each labelled
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
P["Posted balance"] --> AV["Available credit = limit - (posted + pending holds)"]
H["Pending holds"] --> AV
L["Credit limit"] --> AV
AV --> UI["Available to spend"]
P --> DUE["Statement balance + minimum due + due date"]
DUE --> UI2["What to pay, and by when"]
ACT["Customer makes a payment"] --> IMM["Show it immediately as pending"]
IMM --> REFRESH["Force-refresh the cached balance after any action"]- Available credit is the number that matters for spending, and it is the one the authorisation engine uses:
limit − (posted + pending holds). Showing it removes the arithmetic from the customer and makes the app agree with the card terminal. - Statement balance, minimum due and due date answer the paying question, and they are a different number from the current balance. Conflating them is how customers accidentally pay the wrong amount.
- Reflect the customer's own actions instantly. A payment must appear as pending the moment it is submitted, even though ACH takes days — otherwise the customer refreshes, sees nothing, and pays again. Caching the balance for 30–60 seconds is fine for passive viewing and must be invalidated immediately after any action they take.
Pending and posted arrive from different stages of the card lifecycle and reconcile later, so the UI should never quietly merge them. Labelling each one is not a cosmetic choice — it is what makes the numbers defensible when a customer calls to ask why they disagree.
Security
- TLS everywhere, WAF, rate limiting on login (credential-stuffing protection), and bot detection.
- Sensitive data minimization: show only the last 4 digits of the card, keep full numbers in a vault, and mask everything in logs.
- Audit log of all account changes (address, payments, card status).
- Alerts to the customer on important changes ("your address was changed").
Availability
- Stateless services behind load balancers across zones.
- Statement and due days bring spikes, so pre-scale and cache heavily for read paths.
- If core banking is slow, show cached balances with an "as of" time, and queue non-urgent actions.
Wrap-UpWrap-up
Put a strong identity layer (MFA, risk-based step-up) and a gateway in front of a portal BFF that aggregates account, transactions, payments, card controls and statements services. Balances come from the core card system with short caching, transactions from a read-optimized replica showing pending vs posted, payments are idempotent and tracked through ACH states, and card locks write directly to the authorization system. Secure everything with masking, an audit log and customer alerts.