ID: card-crossref | Legacy Source: CBACT03C.cbl + bridge.py:get_all_crossref() + Flask GET /crossref
This guide covers the Card Cross-Reference module — a read-only view that maps credit card numbers to customer IDs and account IDs. It replaces the COBOL batch program CBACT03C which read cardxref.txt (50-byte fixed-width records) and emitted pipe-delimited XREF03| lines. The new system stores this data in the card_customer_xref relational table.
| Layer | Target Component | Legacy Equivalent |
|---|---|---|
| API Controller | CardsController.cs | Flask GET /crossref |
| Application Query | ListCardCrossRefQuery.cs + ListCardCrossRefQueryHandler.cs | bridge.py:get_all_crossref() |
| Response DTO | CardCrossRefDto.cs | XREF03|card-num|cust-id|acct-id stream lines from CBACT03C |
| Data Access | EF Core: CardCustomerXref table (PostgreSQL) | Sequential read of cardxref.txt (50-byte records, CVACT03Y layout) |
| React Page | CrossRefPage.tsx | templates/crossref.html (Jinja2) |
| React Component | CrossRefTable.tsx | HTML table in crossref.html |
| React Hook | useCardCrossRef.ts (TanStack Query) | Server-side render |
/api/cards/crossref
Returns a paginated list of all card-to-customer-to-account cross-reference entries. Replaces CBACT03C full sequential scan.
| Parameter | Type | Default | Description |
|---|---|---|---|
page | int | 1 | Page number |
pageSize | int | 50 | Results per page |
accountId | long | — | Filter by account ID |
customerId | int | — | Filter by customer ID |
{
"data": [
{
"cardNumber": "4111111111111111",
"customerId": 111111111,
"accountId": 4000000111
}
],
"page": 1,
"pageSize": 50,
"totalCount": 1200,
"totalPages": 24
}
/api/cards/{cardNumber}/crossref
Returns the single cross-reference entry for a specific card number. Returns 404 if not found.
// Response
{
"cardNumber": "4111111111111111",
"customerId": 111111111,
"accountId": 4000000111
}
// CVACT03Y layout → CardCustomerXref table
// Legacy: 50-byte fixed record: XREF-CARD-NUM(16) + XREF-CUST-ID(9) + XREF-ACCT-ID(11) + FILLER(14)
public class CardCustomerXref
{
public string CardNumber { get; set; } // PK, FK → cards.card_number
public int CustomerId { get; set; } // FK → customers.id
public long AccountId { get; set; } // FK → accounts.id
}
public record CardCrossRefDto(
string CardNumber,
int CustomerId,
long AccountId
);
GET /api/cards/crossref?page=1&pageSize=50 must respond in <200ms P95.4000000111 in the filter field, When the filter is applied, Then only rows where accountId = 4000000111 are shown.4111111111111111 exists in the XREF, When GET /api/cards/4111111111111111/crossref is called, Then the response returns the single matching entry.404 Not Found.4111222233334444, When displayed in the table, Then it appears as 4111 **** **** 4444.| Points | Example |
|---|---|
| 1–2 | Change column order. Add card number masking. Add "Copy Account ID" button. |
| 3–5 | Add multi-column filtering (account + customer). Add CSV export of cross-reference data. |
| 8+ | Full card lifecycle management (activate, deactivate cards) requiring write endpoints and domain logic. |
GET /api/cards/crossref: <200ms P95 with default pagination.card_customer_xref.account_id and card_customer_xref.customer_id to support filter queries.