Design a transaction authorization system that processes payment transactions and determines whether to approve or reject them based on configurable rules.
The system should support three authorization rules applied in order:
1. Global MCC Blocking Certain merchant category codes (MCCs) are globally blocked. Any transaction with a blocked MCC should be rejected.
2. User-Specific MCC Blocking In addition to the global list, each authorization request may include a user-specific list of blocked MCCs. Reject if the transaction's MCC appears in either the global or user-specific blocked list.
3. Rolling Velocity Limit Track the total transaction amount per user within a rolling time window. If adding the new transaction's amount to the current window total would exceed the velocity limit, reject the transaction.
Important: Rejected transactions are still recorded and count toward the velocity window totals.
Implementation:
Solution(global_blocked_mccs, velocity_limit, window_seconds) — Initialize with a list of globally blocked MCCs, a velocity limit (maximum total amount), and a time window in seconds.authorize(timestamp, user_id, amount, mcc, user_blocked_mccs) — Process a transaction. Return true if approved, false if rejected.The velocity window for a transaction at time t includes all previously recorded transactions (for the same user) with timestamps in the range [t - window_seconds, t] (inclusive on both ends). Transactions with timestamps strictly less than t - window_seconds are considered expired.
Example:
| Step | Timestamp | User | Amount | MCC | Result | Reason | |------|-----------|------|--------|-----|--------|--------| | 1 | 1 | user1 | $1,000 | 5411 | Approved | Window total: $1,000 | | 2 | 2 | user1 | $2,000 | 5411 | Approved | Window total: $3,000 | | 3 | 3 | user1 | $1,500 | 5411 | Approved | Window total: $4,500 | | 4 | 4 | user1 | $600 | 5411 | Rejected | Would be $5,100 > $5,000 limit | | 5 | 3602 | user1 | $500 | 5411 | Approved | t=1 expired; window total $4,100 + $500 = $4,600 |
(velocity_limit=5000, window_seconds=3600, no blocked MCCs)
Note: At step 5, the transaction at t=1 has expired because 1 < 3602 - 3600 = 2. The rejected transaction at step 4 ($600) still counts toward the window total.
Follow-up Questions: