You are building a small fraud-screening validator that reads transactions from a CSV file and outputs a human-readable report.
Input
1) Transactions CSV
Each row is one transaction with exactly 6 fields:
-
transaction_id
(string)
-
user_id
(string)
-
timestamp
(string; assume ISO-8601 like
2026-01-22T13:45:00Z
)
-
amount
(string that should parse to a decimal number)
-
country
(string, e.g.
US
)
-
payment_method
(string, e.g.
VISA
,
PAYPAL
)
You may assume the first row is a header.
2) Risk configuration
-
min_amount
and
max_amount
define the allowed inclusive range for
amount
.
-
blocked_payment_methods
is a set/list of payment methods that are not allowed.
3) User behavior baseline
For each user_id, you are given a baseline profile with these 3 behavioral features:
-
usual_countries
: a set/list of countries the user commonly transacts in
-
usual_time_buckets
: a set/list of time-of-day buckets the user commonly transacts in (e.g.
NIGHT
,
MORNING
,
AFTERNOON
,
EVENING
)
-
usual_amount_range
: an inclusive range
[low, high]
for typical transaction amounts
You may assume every user_id in the transaction file exists in the baseline.
Tasks (multi-part; later parts build on earlier ones)
Part 1 — Verify transaction data integrity
For each transaction, verify that all 6 fields are non-empty (after trimming whitespace).
Part 2 — High-risk rule validation
In addition to Part 1, mark a transaction as suspicious if either is true:
-
Amount rule:
amount
is outside
[min_amount, max_amount]
(or is not parseable as a number).
-
Payment method rule:
payment_method
is in
blocked_payment_methods
.
Part 3 — User behavior matching
Compute how well the transaction matches the user’s baseline across the 3 behavioral features.
-
Feature extraction / normalization
-
Map
timestamp
into one of the defined
usual_time_buckets
(you must define the bucketing rule, e.g. by hour ranges).
-
Matching
-
country
matches if it is in
usual_countries
.
-
time_bucket
matches if it is in
usual_time_buckets
.
-
amount
matches if it is within
usual_amount_range
.
-
Match ratio
-
match_ratio = matched_features / 3
.
If match_ratio < 0.5, flag the transaction as suspicious due to behavior mismatch.
Part 4 — Smart fraud error reporting
Instead of outputting a vague status like SUSPICIOUS, output specific error codes.
-
Output
at most two
error codes per transaction.
-
Error codes must be chosen by priority (highest first). Use this priority order:
-
MISSING_FIELD
-
AMOUNT_OUT_OF_RANGE
-
BLOCKED_PAYMENT_METHOD
-
BEHAVIOR_MISMATCH
-
If there are
no
errors, output
OK
.
Output
Produce a report with fixed-width / aligned columns for readability.
At minimum, include:
-
transaction_id
-
user_id
-
result
(either
OK
or up to two comma-separated error codes)
Notes / constraints
-
Implement so it can process many rows efficiently (streaming is acceptable).
-
Clearly define your time bucketing in code.
-
Trimming whitespace matters when checking for empty fields.