System Design: Account Management with Transfers, Payments, and Cashback
You are to design and implement an in-memory account management service that supports atomic balance updates, delayed cashback, and a leaderboard of top transfer spenders. Assume integer timestamps (e.g., seconds since epoch) and integer amounts in the smallest currency unit (e.g., cents).
Assumptions to make explicit:
-
Amounts must be positive integers; operations with non-positive amounts fail.
-
Timestamps are provided by the caller and should be used to determine due cashback.
-
2% cashback is computed as floor(0.02 × amount) (integer math:
(amount * 2) / 100
).
-
Return Optional.empty() for any failure condition (e.g., missing account, insufficient funds, invalid input), unless otherwise stated.
-
Transfer spending for topSpenders counts only outgoing transfer amounts from the transfer operation and excludes pay and cashback.
Implement the following operations with the specified semantics:
-
createAccount(int timestamp, String accountId)
-
Create a new account with 0 balance.
-
Return false if the account already exists; otherwise true.
-
deposit(int timestamp, String accountId, int amount)
-
Deposit amount into an existing account.
-
Return Optional.of(newBalance) on success.
-
Return Optional.empty() if the account does not exist or amount ≤ 0.
-
transfer(int timestamp, String sourceAccountId, String targetAccountId, int amount)
-
Transfer amount between two distinct existing accounts if the source has sufficient balance.
-
On success, return Optional.of(sourceNewBalance).
-
Return Optional.empty() if any precondition fails (missing accounts, identical accounts, amount ≤ 0, insufficient funds).
-
Increase only the source account's cumulative outgoing transfer total (used for topSpenders).
-
topSpenders(int timestamp, int n)
-
Return a List
<String>
of up to n accountIds with the highest cumulative outgoing transfer totals.
-
If fewer than n accounts exist, return all.
-
Use a deterministic tie-break (e.g., lexicographic accountId ascending).
-
pay(int timestamp, String accountId, int amount)
-
Deduct amount from the account if sufficient funds; return Optional.of(uniquePaymentId) on success.
-
Return Optional.empty() on failure (missing account, amount ≤ 0, insufficient funds).
-
Automatically schedule 2% cashback after 24 hours (86,400 seconds) from the provided timestamp.
-
The cashback credit must not affect topSpenders.
-
getPaymentStatus(int timestamp, String accountId, String paymentId)
-
Return Optional.of("IN_PROGRESS") if the cashback has not yet been applied.
-
Return Optional.of("CASHBACK_RECEIVED") after the cashback is applied.
-
Return Optional.empty() if the account or paymentId is invalid or mismatched.
Additional requirements:
-
Ensure atomicity and correctness under concurrency (e.g., transfers must not lose or double-count funds).
-
Ensure each call first processes any due cashbacks up to the provided timestamp.