Case Study 1: Building an ATM Interface Prototype

Background

First National Bank is modernizing its ATM fleet. Before investing in hardware integration and network connectivity, the development team has been asked to prototype the ATM user interface in COBOL. The prototype will run on a console terminal, simulating the flow that customers experience at a physical ATM.

This is a common approach in financial systems development: prototype the screen flow and business logic on a simple terminal before wiring up the hardware and communication layers. The COBOL business logic will eventually be reused in the production system -- the I/O layer is what changes.

Project Requirements

Functional Requirements

The ATM prototype must support the following user interactions:

  1. Welcome Screen -- Display the bank branding, current date and time, and prompt the customer to insert their card (simulated by pressing Enter).

  2. Card Entry -- Accept a 16-digit card number. Validate it against a stored list of valid cards. Display an error and return to the welcome screen if invalid.

  3. PIN Entry -- Accept a 4-digit PIN. Allow up to 3 attempts. Lock the card after 3 failures. Display masked card number (only last 4 digits visible) for security.

  4. Main Menu -- Display transaction options: Balance Inquiry, Withdrawal, Deposit, Another Transaction, and Exit/Remove Card.

  5. Balance Inquiry -- Display the current account balance in currency-formatted output with the account number and timestamp.

  6. Withdrawal -- Offer quick-amount buttons ($20, $40, $60, $100, $200) and a custom amount option. Validate that the withdrawal does not exceed the available balance. Deduct from the balance and confirm.

  7. Deposit -- Accept a deposit amount. Add to the balance and confirm.

  8. Receipt -- After each transaction, ask if the customer wants a receipt. If yes, display a formatted receipt with date, time, card (masked), account, transaction type, amount, and new balance.

  9. Exit -- Thank the customer, remind them to take their card, and return to the welcome screen.

Non-Functional Requirements

  • All currency amounts must be displayed with dollar signs, commas, and two decimal places.
  • Card numbers must be masked as ****-****-****-XXXX wherever displayed.
  • The PIN must never be displayed on screen (not even in receipts).
  • Each screen should have a consistent visual frame using border characters.
  • The system clock should be used for date and time stamps.

Design Approach

Screen State Machine

The ATM interface follows a state machine pattern, where each screen represents a state and user actions cause transitions between states:

WELCOME --> CARD ENTRY --> PIN ENTRY --> MAIN MENU
                |              |             |
                |              |             +--> BALANCE --> RECEIPT? --> MAIN MENU
                |              |             |
                |              |             +--> WITHDRAW --> RECEIPT? --> MAIN MENU
                |              |             |
                |              |             +--> DEPOSIT --> RECEIPT? --> MAIN MENU
                |              |             |
                |              |             +--> EXIT --> WELCOME
                |              |
                |              +--> LOCKED --> EXIT
                |
                +--> INVALID --> WELCOME

In the COBOL implementation, this state machine is represented by a state variable with 88-level condition names:

       01  WS-ATM-STATE         PIC X(10) VALUE "WELCOME".
           88  STATE-WELCOME    VALUE "WELCOME".
           88  STATE-CARD-ENTRY VALUE "CARD".
           88  STATE-PIN-ENTRY  VALUE "PIN".
           88  STATE-MAIN-MENU  VALUE "MENU".
           88  STATE-BALANCE    VALUE "BALANCE".
           88  STATE-WITHDRAW   VALUE "WITHDRAW".
           88  STATE-DEPOSIT    VALUE "DEPOSIT".
           88  STATE-EXIT       VALUE "EXIT".

The main processing loop uses EVALUATE TRUE to dispatch to the appropriate screen handler:

       PERFORM UNTIL ATM-IS-STOPPED
           EVALUATE TRUE
               WHEN STATE-WELCOME   PERFORM 200-WELCOME-SCREEN
               WHEN STATE-CARD-ENTRY PERFORM 300-CARD-ENTRY-SCREEN
               WHEN STATE-PIN-ENTRY PERFORM 400-PIN-ENTRY-SCREEN
               WHEN STATE-MAIN-MENU PERFORM 500-MAIN-MENU-SCREEN
               *> ... additional states
               WHEN STATE-EXIT      PERFORM 800-EXIT-SCREEN
                                    SET ATM-IS-STOPPED TO TRUE
           END-EVALUATE
       END-PERFORM

Each screen handler is responsible for displaying its screen, accepting input, processing the input, and setting the next state.

Data Architecture

The prototype stores customer data in WORKING-STORAGE variables rather than a database. In a production system, these would be replaced with calls to a database or transaction processing system:

      * Simulated customer record (would be DB2 in production)
       01  WS-CUSTOMER-DATA.
           05  WS-CARD-NUMBER      PIC X(16).
           05  WS-PIN              PIC X(4).
           05  WS-CUSTOMER-NAME    PIC X(25).
           05  WS-ACCOUNT-NUMBER   PIC X(12).
           05  WS-ACCOUNT-BALANCE  PIC S9(9)V99.

Screen Layout Standards

Every screen follows a consistent template:

================================================  <-- Top border
|     FIRST NATIONAL BANK - ATM               |  <-- Title bar
------------------------------------------------  <-- Divider
|                                              |  <-- Content area
|  [Screen-specific content here]              |
|                                              |
------------------------------------------------  <-- Bottom divider
|  [Status or instruction line]                |  <-- Footer
================================================  <-- Bottom border

This is implemented using DISPLAY statements with carefully sized strings:

       01  WS-ATM-BORDER  PIC X(48) VALUE ALL "=".
       01  WS-ATM-DASH    PIC X(48) VALUE ALL "-".

       DISPLAY WS-ATM-BORDER
       DISPLAY "|     FIRST NATIONAL BANK - ATM               |"
       DISPLAY WS-ATM-DASH

The 48-character width was chosen to represent a typical ATM screen width while fitting comfortably in an 80-column terminal.

Key Implementation Details

Card Number Masking

Card numbers should only display the last 4 digits. This is a security requirement in financial systems (similar to PCI DSS compliance):

       STRING "****-****-****-" DELIMITED SIZE
              WS-CARD-NUMBER(13:4) DELIMITED SIZE
              INTO WS-CARD-MASKED
       END-STRING

The reference modification WS-CARD-NUMBER(13:4) extracts 4 characters starting at position 13, which are the last 4 digits of the 16-digit card number.

PIN Validation with Limited Attempts

The PIN entry handler tracks attempts and locks the card after 3 failures:

       01  WS-PIN-ATTEMPTS  PIC 9 VALUE 0.

       ADD 1 TO WS-PIN-ATTEMPTS

       IF WS-PIN-ENTERED = WS-PIN-CORRECT
           MOVE "MENU" TO WS-ATM-STATE
       ELSE
           IF WS-PIN-ATTEMPTS >= 3
               DISPLAY "*** CARD LOCKED ***"
               MOVE "EXIT" TO WS-ATM-STATE
           ELSE
               DISPLAY "Incorrect PIN. Try again."
           END-IF
       END-IF

Withdrawal Validation

Withdrawals must not exceed the available balance:

       IF WS-TXN-AMOUNT > WS-ACCOUNT-BALANCE
           DISPLAY "*** INSUFFICIENT FUNDS ***"
           MOVE "MENU" TO WS-ATM-STATE
       ELSE
           SUBTRACT WS-TXN-AMOUNT FROM WS-ACCOUNT-BALANCE
           DISPLAY "WITHDRAWAL CONFIRMED"
       END-IF

In a production system, additional validations would include daily withdrawal limits, denomination constraints (ATMs only dispense certain bill combinations), and multi-account checks.

Receipt Generation

The receipt is a formatted console display that mimics a paper receipt:

=================================
  FIRST NATIONAL BANK
  ATM RECEIPT
---------------------------------
  Date: 2026-02-10
  Time: 14:30:22
  Card: ****-****-****-0366
  Acct: CHK-00458721
---------------------------------
  Transaction: WITHDRAWAL
  Amount:         $200.00
  Balance:     $15,047.83
---------------------------------
  Ref: TXN-100001
  Thank you for banking with us!
=================================

Each line is formatted using structured DISPLAY statements with edited PICTURE fields for currency amounts.

Testing the Prototype

Test Scenario 1: Successful Transaction Flow

  1. Start the program
  2. Press Enter at the welcome screen
  3. Enter valid card number: 4532015112830366
  4. Enter correct PIN: 1234
  5. Select "1" for Balance Inquiry
  6. Select "Y" for receipt
  7. Select "2" for Withdrawal
  8. Select "D" for $100
  9. Verify balance is reduced by $100
  10. Select "5" to exit

Test Scenario 2: PIN Lockout

  1. Start the program
  2. Enter valid card number
  3. Enter wrong PIN three times
  4. Verify "CARD LOCKED" message appears
  5. Verify program exits

Test Scenario 3: Insufficient Funds

  1. Complete login
  2. Attempt to withdraw more than the balance
  3. Verify "INSUFFICIENT FUNDS" message
  4. Verify balance is unchanged
  5. Verify return to main menu

Test Scenario 4: Deposit and Verify

  1. Complete login
  2. Note the starting balance
  3. Deposit $500
  4. Check balance -- should be starting balance + $500
  5. Withdraw $200
  6. Check balance -- should be starting balance + $300

From Prototype to Production

In a real ATM system, this prototype would evolve in several ways:

  1. I/O Layer: The DISPLAY/ACCEPT statements would be replaced with hardware-specific I/O calls to the ATM device controller, or with BMS maps in a CICS environment.

  2. Data Access: The hardcoded customer data would be replaced with DB2 queries or IMS database calls.

  3. Security: PIN validation would use encrypted comparisons, and the session would implement timeouts.

  4. Transaction Processing: Each transaction would be wrapped in a CICS unit of work with commit/rollback capabilities.

  5. Networking: The ATM would communicate with a central authorization system for real-time balance checks and fraud detection.

However, the fundamental program structure -- the state machine, the validation logic, the formatted output -- would remain largely unchanged. This is why COBOL's console I/O is such a valuable prototyping tool: the business logic you develop at the console level transfers directly to production systems.

Source Code

The complete implementation is available in code/case-study-code.cob. Compile and run it with:

cobc -x case-study-code.cob
./case-study-code

Use the test card number 4532015112830366 and PIN 1234 to access the system.

Discussion Questions

  1. Why does the ATM use a state machine pattern rather than a simple sequential flow? What advantage does this provide for adding new transaction types?

  2. In a production system, why would the PIN never be stored in plain text in WORKING-STORAGE? What security measures would replace the approach used in this prototype?

  3. The receipt shows the card number masked. What other data on the receipt might need to be protected, and how?

  4. How would the program need to change if it supported multiple accounts per card (checking, savings, credit)?

  5. What would be the impact of converting this program from DISPLAY/ACCEPT to CICS BMS maps? Which parts of the code would remain unchanged?