Card Preview
VISA
•••• •••• •••• ••••
CARDHOLDER
YOUR NAME
EXPIRES
MM/YY
Card Details
Card Number
Expiry
CVV
Cardholder Name
Validation Pipeline
1
Raw Input entry
User enters card number, expiry, CVV, and name. Input may contain spaces, dashes, formatting characters.
PAN
Expiry
CVV
Name
2
Sanitization clean
Strip non-digits from PAN, normalize expiry format, trim whitespace from all fields.
Strip /\D/g
Normalize MM/YY
Trim whitespace
3
Field Validation verify
Each field validated independently. Errors accumulate — not fail-fast.
Luhn mod-10
BIN detect
Length check
Month 01-12
Not expired
CVV digits
CVV length
Name valid
4
Cross-Validation correlate
Card type determines CVV length: Amex → 4 digits, others → 3. All errors collected.
CVV ↔ Card Type
Accumulate all
5
Security Layer protect
PAN never stored. Output masked. No network calls. Pure local validation.
🔒
PAN Storage
Never stored
🛡
Output
Masked only
Network
Zero calls
PCI DSS
SAQ A-EP
6
Result Assembly output
Returns { valid, fields, errors[], card }. Masked number + last4 only. Safe to log.
PaymentFormResult
Per-field results
•••• 4242
Sequence Diagram
Client PaymentForm CardValidator Result submitPayment({ card, expiry, cvv, name }) sanitizeCardNumber(raw) "4242424242424242" luhnCheck(digits) true detectCardType(digits) { visa, cvvLen: 3, lengths: [16] } IIN/BIN prefix detection (first 6) validateExpiry("12/28") { valid: true, month: 12, year: 2028 } CROSS-VALIDATION validateCVV("123", cardType.cvvLen=3) { valid: true } Amex → 4 digits Others → 3 digits validateCardholderName("John Doe") { valid: true } RESULT ASSEMBLY maskCardNumber(sanitized) "•••• •••• •••• 4242" { valid, fields, errors, card } PaymentFormResult Client PaymentForm CardValidator Result
Risk Vectors