# Sprint 10 Test Plan — Smart Payment Import **Date:** 2026-06-15 **Author:** Patrick Plate / Lumen (Architect) **Status:** Draft v1 **Basis:** cannamanage-sprint10-plan.md **Sprint Goal:** Bank statement import with auto-matching for member payment reconciliation --- ## Test Overview | ID | Description | Type | Class/Component | Status | |----|------------|------|-----------------|--------| | T-01 | MT940 parsing — standard Sparkasse file | Unit | Mt940ParserTest | ⬜ | | T-02 | MT940 parsing — multi-line Verwendungszweck | Unit | Mt940ParserTest | ⬜ | | T-03 | MT940 parsing — debit/credit identification | Unit | Mt940ParserTest | ⬜ | | T-04 | MT940 parsing — German amount format (comma decimal) | Unit | Mt940ParserTest | ⬜ | | T-05 | MT940 parsing — multi-statement file (multiple accounts) | Unit | Mt940ParserTest | ⬜ | | T-06 | MT940 parsing — malformed input (graceful error) | Unit | Mt940ParserTest | ⬜ | | T-07 | CAMT.053 parsing — standard XML file | Unit | Camt053ParserTest | ⬜ | | T-08 | CAMT.053 parsing — multiple entries extraction | Unit | Camt053ParserTest | ⬜ | | T-09 | CAMT.053 parsing — namespace v2 and v8 support | Unit | Camt053ParserTest | ⬜ | | T-10 | CAMT.053 parsing — counterparty IBAN + name extraction | Unit | Camt053ParserTest | ⬜ | | T-11 | CAMT.053 parsing — invalid XML (error handling) | Unit | Camt053ParserTest | ⬜ | | T-12 | CSV parsing — semicolon delimiter, ISO-8859-1 | Unit | CsvBankParserTest | ⬜ | | T-13 | CSV parsing — German number format (1.234,56) | Unit | CsvBankParserTest | ⬜ | | T-14 | CSV parsing — configurable column mapping | Unit | CsvBankParserTest | ⬜ | | T-15 | CSV parsing — skip header rows | Unit | CsvBankParserTest | ⬜ | | T-16 | CSV parsing — UTF-8 encoding variant | Unit | CsvBankParserTest | ⬜ | | T-17 | CSV parsing — empty/malformed rows skipped | Unit | CsvBankParserTest | ⬜ | | T-18 | Format detection — MT940 by content signature | Unit | BankStatementParserServiceTest | ⬜ | | T-19 | Format detection — CAMT.053 by XML namespace | Unit | BankStatementParserServiceTest | ⬜ | | T-20 | Format detection — CSV by file extension | Unit | BankStatementParserServiceTest | ⬜ | | T-21 | Format detection — unrecognized format throws exception | Unit | BankStatementParserServiceTest | ⬜ | | T-22 | Matching — exact amount match scores 100 | Unit | PaymentMatchingServiceTest | ⬜ | | T-23 | Matching — amount within 5% scores 80 | Unit | PaymentMatchingServiceTest | ⬜ | | T-24 | Matching — member number in Verwendungszweck (M-0042) | Unit | PaymentMatchingServiceTest | ⬜ | | T-25 | Matching — full member name in reference text | Unit | PaymentMatchingServiceTest | ⬜ | | T-26 | Matching — last name only (partial name match) | Unit | PaymentMatchingServiceTest | ⬜ | | T-27 | Matching — IBAN exact match | Unit | PaymentMatchingServiceTest | ⬜ | | T-28 | Matching — confidence ≥90% → MATCHED status | Unit | PaymentMatchingServiceTest | ⬜ | | T-29 | Matching — confidence 60-89% → SUGGESTED status | Unit | PaymentMatchingServiceTest | ⬜ | | T-30 | Matching — confidence <60% → UNMATCHED status | Unit | PaymentMatchingServiceTest | ⬜ | | T-31 | Matching — conflict: multiple members match → SUGGESTED | Unit | PaymentMatchingServiceTest | ⬜ | | T-32 | Matching — negative amount (debit) skipped from matching | Unit | PaymentMatchingServiceTest | ⬜ | | T-33 | Matching — no active fee assignment → no match | Unit | PaymentMatchingServiceTest | ⬜ | | T-34 | Import service — upload and parse creates session | Integration | BankImportServiceTest | ⬜ | | T-35 | Import service — run matching updates transactions | Integration | BankImportServiceTest | ⬜ | | T-36 | Import service — confirm match creates Payment + LedgerEntry | Integration | BankImportServiceTest | ⬜ | | T-37 | Import service — bulk confirm all matched | Integration | BankImportServiceTest | ⬜ | | T-38 | Import service — skip transaction sets status | Integration | BankImportServiceTest | ⬜ | | T-39 | Import service — manual assign with explicit member | Integration | BankImportServiceTest | ⬜ | | T-40 | Import service — categorize as expense creates LedgerEntry | Integration | BankImportServiceTest | ⬜ | | T-41 | Import service — complete session updates status | Integration | BankImportServiceTest | ⬜ | | T-42 | Tier enforcement — Starter: CSV only | Unit | TierLimitServiceTest | ⬜ | | T-43 | Tier enforcement — Starter: max 1 import/month | Unit | TierLimitServiceTest | ⬜ | | T-44 | Tier enforcement — Pro: all formats allowed | Unit | TierLimitServiceTest | ⬜ | | T-45 | Tier enforcement — Pro: max 3 CSV templates | Unit | TierLimitServiceTest | ⬜ | | T-46 | Tier enforcement — Enterprise: auto-confirm enabled | Unit | TierLimitServiceTest | ⬜ | | T-47 | IBAN validation — valid German IBAN (DE) | Unit | IbanValidatorTest | ⬜ | | T-48 | IBAN validation — invalid checksum rejected | Unit | IbanValidatorTest | ⬜ | | T-49 | IBAN validation — wrong length rejected | Unit | IbanValidatorTest | ⬜ | | T-50 | IBAN validation — international IBAN formats | Unit | IbanValidatorTest | ⬜ | | T-51 | REST API — upload file returns session | Integration | BankImportControllerTest | ⬜ | | T-52 | REST API — upload exceeds 10MB → 413 error | Integration | BankImportControllerTest | ⬜ | | T-53 | REST API — unauthorized user → 403 | Integration | BankImportControllerTest | ⬜ | | T-54 | REST API — confirm match endpoint | Integration | BankImportControllerTest | ⬜ | | T-55 | REST API — list sessions paginated | Integration | BankImportControllerTest | ⬜ | | T-56 | REST API — CSV mapping CRUD | Integration | BankImportControllerTest | ⬜ | | T-57 | REST API — tenant isolation (club A cannot see club B sessions) | Integration | BankImportControllerTest | ⬜ | | T-58 | Member IBAN — store with consent verification | Integration | MemberControllerTest | ⬜ | | T-59 | Member IBAN — reject without consent | Integration | MemberControllerTest | ⬜ | | T-60 | Flyway migration — V30 applies cleanly | Integration | FlywayMigrationTest | ⬜ | | T-61 | Flyway migration — V31 applies cleanly | Integration | FlywayMigrationTest | ⬜ | | T-62 | Flyway migration — V32 applies cleanly | Integration | FlywayMigrationTest | ⬜ | | T-63 | End-to-end — MT940 upload → match → confirm → payment created | E2E | BankImportE2ETest | ⬜ | | T-64 | End-to-end — CSV with custom mapping → successful import | E2E | BankImportE2ETest | ⬜ | | T-65 | End-to-end — mixed matches (auto + manual + skip) | E2E | BankImportE2ETest | ⬜ | | T-66 | Frontend — upload wizard renders all 4 steps | E2E | Playwright | ⬜ | | T-67 | Frontend — CSV column mapping interaction | E2E | Playwright | ⬜ | | T-68 | Frontend — match review table filtering | E2E | Playwright | ⬜ | | T-69 | Frontend — bulk confirm action | E2E | Playwright | ⬜ | | T-70 | Frontend — import history table | E2E | Playwright | ⬜ | Status: ⬜ Pending | ✅ Passed | ❌ Failed | ⏭️ Skipped --- ## Test Cases — Detailed ### T-01: MT940 parsing — standard Sparkasse file **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/Mt940ParserTest.java` **Method:** `testParseSparkasseFile()` **Preconditions:** - MT940 test fixture file in `src/test/resources/fixtures/mt940/sparkasse-standard.sta` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | Standard Sparkasse MT940 with 5 transactions | ParseResult with 5 transactions, correct amounts/dates | | b | Opening balance `:60F:C260601EUR1234,56` | openingBalanceCents = 123456 | | c | Credit transaction `:61:2506150615CR50,00` | amountCents = 5000, bookingDate = 2025-06-15 | | d | Account IBAN from `:25:` field | accountIban extracted correctly | **Postconditions:** - All transactions have non-null bookingDate and amountCents --- ### T-02: MT940 parsing — multi-line Verwendungszweck **Type:** Unit **Class:** `Mt940ParserTest.java` **Method:** `testMultiLineReference()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | `:86:` spanning 3 lines with `SVWZ+` | referenceText contains full concatenated text | | b | `:86:` with `EREF+`, `KREF+`, `MREF+` sub-fields | Sub-fields parsed, SVWZ extracted as reference | | c | `:86:` with `DEBT+DE89370400440532013000` | counterpartyIban = "DE89370400440532013000" | --- ### T-03: MT940 parsing — debit/credit identification **Type:** Unit **Class:** `Mt940ParserTest.java` **Method:** `testDebitCreditIdentification()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | `:61:` with `CR` indicator | amountCents > 0 (positive/incoming) | | b | `:61:` with `D` indicator | amountCents < 0 (negative/outgoing) | | c | `:61:` with `RC` (reversal credit) | amountCents > 0 | | d | `:61:` with `RD` (reversal debit) | amountCents < 0 | --- ### T-04: MT940 parsing — German amount format **Type:** Unit **Class:** `Mt940ParserTest.java` **Method:** `testGermanAmountParsing()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | `50,00` | 5000 cents | | b | `1234,56` | 123456 cents | | c | `0,01` | 1 cent | | d | `99999,99` | 9999999 cents | --- ### T-05: MT940 parsing — multi-statement file **Type:** Unit **Class:** `Mt940ParserTest.java` **Method:** `testMultiStatementFile()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | File with 2 statements (2 different accounts) | Parse both, return transactions from all | | b | Filter by specific account IBAN | Only matching account's transactions returned | --- ### T-06: MT940 parsing — malformed input **Type:** Unit **Class:** `Mt940ParserTest.java` **Method:** `testMalformedInput()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | Empty file | ParseResult with empty list + warning | | b | Missing `:60F:` (no opening balance) | Parse continues, openingBalanceCents = null | | c | Corrupted amount field | Transaction skipped, warning added | | d | Binary file (not text) | Exception or empty result with error warning | --- ### T-07: CAMT.053 parsing — standard XML file **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/Camt053ParserTest.java` **Method:** `testParseStandardCamt053()` **Preconditions:** - CAMT.053 test fixture in `src/test/resources/fixtures/camt053/standard.xml` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | Standard CAMT.053 with 3 entries | ParseResult with 3 transactions | | b | `50.00` | amountCents = 5000 | | c | `CRDT` | amountCents positive | | d | `
2025-06-15
` | bookingDate = 2025-06-15 | --- ### T-08: CAMT.053 parsing — multiple entries **Type:** Unit **Class:** `Camt053ParserTest.java` **Method:** `testMultipleEntries()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | 10 `` elements | 10 ParsedTransaction objects | | b | Mix of CRDT and DBIT | Correct positive/negative amounts | --- ### T-09: CAMT.053 parsing — namespace versions **Type:** Unit **Class:** `Camt053ParserTest.java` **Method:** `testNamespaceVersions()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | Namespace `camt.053.001.02` | Parsed successfully | | b | Namespace `camt.053.001.08` | Parsed successfully | | c | Unknown namespace `camt.054.001.02` | canParse returns false or warning | --- ### T-10: CAMT.053 parsing — counterparty extraction **Type:** Unit **Class:** `Camt053ParserTest.java` **Method:** `testCounterpartyExtraction()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | `Max Mustermann` | counterpartyName = "Max Mustermann" | | b | `DE12...` | counterpartyIban = "DE12..." | | c | `M-0042 Beitrag` | referenceText = "M-0042 Beitrag" | --- ### T-11: CAMT.053 parsing — invalid XML **Type:** Unit **Class:** `Camt053ParserTest.java` **Method:** `testInvalidXml()` **Scenarios:** | # | Input | Expected Result | |---|-------|----------------| | a | Malformed XML (unclosed tag) | Exception with descriptive message | | b | Valid XML but wrong schema (not CAMT) | Empty result or format detection rejects | --- ### T-12 through T-17: CSV parsing tests **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/CsvBankParserTest.java` Test fixtures: - `src/test/resources/fixtures/csv/sparkasse.csv` (semicolon, ISO-8859-1, dd.MM.yyyy) - `src/test/resources/fixtures/csv/ing-diba.csv` (semicolon, ISO-8859-1, different columns) - `src/test/resources/fixtures/csv/commerzbank.csv` (semicolon, UTF-8) - `src/test/resources/fixtures/csv/malformed.csv` (bad rows) Key scenarios: - Semicolon delimiter parsing - German number format: `"1.234,56"` → 123456 cents - Configurable column positions via CsvColumnMapping - Header row skipping (1 or 2 rows) - UTF-8 encoding support - Empty/malformed rows produce warnings, don't abort --- ### T-22 through T-33: Matching algorithm tests **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/PaymentMatchingServiceTest.java` **Test data setup:** ```java // Members: // - Member "M-0042" (Max Mustermann, IBAN DE89370400440532013000, fee 50€/month) // - Member "M-0043" (Anna Schmidt, no IBAN, fee 75€/quarter) // - Member "M-0044" (Peter Müller, IBAN DE12345678901234567890, fee 50€/month) ``` **Key test scenarios:** | Test | Transaction | Expected Match | Confidence | Rationale | |------|-------------|---------------|------------|-----------| | T-22 | 50.00€, ref "M-0042 Beitrag" | M-0042 | ≥95% | Exact amount + member number | | T-23 | 51.00€, ref "M-0042 Beitrag" | M-0042 | ~85% | Amount within 5% + member number | | T-24 | 50.00€, ref "M-0042 Juni" | M-0042 | ≥90% | Exact amount + member number | | T-25 | 50.00€, ref "Max Mustermann Beitrag" | M-0042 | ≥80% | Amount + full name | | T-26 | 50.00€, ref "Mustermann Mitgliedsbeitrag" | M-0042 | ~75% | Amount + last name | | T-27 | 50.00€, ref "Überweisung", IBAN DE89... | M-0042 | ≥85% | Amount + IBAN | | T-28 | 50.00€, ref "M-0042", IBAN DE89... | M-0042 | ≥95% (MATCHED) | All criteria hit | | T-29 | 50.00€, ref "Beitrag", no IBAN | M-0042 or M-0044 | 60-89% (SUGGESTED) | Amount matches two members | | T-30 | 123.45€, ref "random text" | None | <60% (UNMATCHED) | No criteria match | | T-31 | 50.00€, ref "Beitrag", no IBAN match | Conflict | SUGGESTED | Two 50€ members, can't distinguish | | T-32 | -50.00€ (debit) | Skipped | N/A | Negative = outgoing, not a payment | | T-33 | 50.00€ from member with no fee assignment | None | <60% | No expected payment to match against | --- ### T-34 through T-41: Import service integration tests **Type:** Integration (Spring Boot Test with H2) **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/BankImportServiceTest.java` **Setup:** `@SpringBootTest` with `@Transactional`, test fixtures loaded via Flyway | Test | Scenario | Verification | |------|----------|-------------| | T-34 | Upload MT940 file | Session created, status=PENDING, transactions persisted | | T-35 | Run matching on session | Transactions updated with matchStatus + confidence | | T-36 | Confirm a MATCHED transaction | Payment entity created, LedgerEntry(INCOME) created, tx status=CONFIRMED | | T-37 | Bulk confirm 5 MATCHED transactions | 5 Payments created, session.confirmedCount = 5 | | T-38 | Skip a transaction | tx status=SKIPPED, skipReason set | | T-39 | Manual assign to different member | Payment created with specified memberId | | T-40 | Categorize debit as RENT expense | LedgerEntry(EXPENSE, RENT) created | | T-41 | Complete session | status=COMPLETED, completedAt set | **Postconditions for T-36:** - `Payment` exists with correct memberId, amountCents, paymentMethod=BANK_TRANSFER - `LedgerEntry` exists with transactionType=INCOME, relatedPaymentId set - `BankTransaction.matchedPaymentId` set to new Payment ID - Audit event BANK_PAYMENT_CONFIRMED logged --- ### T-42 through T-46: Tier enforcement tests **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/TierLimitServiceTest.java` | Test | Tier | Action | Expected | |------|------|--------|----------| | T-42 | STARTER | Import MT940 | TierLimitExceededException | | T-43 | STARTER | 2nd import in same month | TierLimitExceededException | | T-44 | PRO | Import MT940 | Allowed | | T-45 | PRO | Create 4th CSV mapping | TierLimitExceededException | | T-46 | ENTERPRISE | Check autoConfirmAllowed | returns true | --- ### T-47 through T-50: IBAN validation tests **Type:** Unit **Class:** `cannamanage-service/src/test/java/de/cannamanage/service/bankimport/IbanValidatorTest.java` | Test | Input | Expected | |------|-------|----------| | T-47 | `DE89370400440532013000` | valid = true | | T-48 | `DE00370400440532013000` (bad checksum) | valid = false | | T-49 | `DE893704004` (too short) | valid = false | | T-50 | `GB29NWBK60161331926819` (UK IBAN) | valid = true | --- ### T-51 through T-57: REST API integration tests **Type:** Integration (MockMvc) **Class:** `cannamanage-api/src/test/java/de/cannamanage/api/controller/BankImportControllerTest.java` | Test | Request | Expected Response | |------|---------|------------------| | T-51 | POST /api/finance/import/upload (multipart) | 201, session JSON with transaction count | | T-52 | POST /api/finance/import/upload (15MB file) | 413 Payload Too Large | | T-53 | POST /api/finance/import/upload (no FINANCE_IMPORT permission) | 403 Forbidden | | T-54 | POST /api/finance/import/transactions/{id}/confirm | 200, updated transaction JSON | | T-55 | GET /api/finance/import/sessions?page=0&size=10 | 200, paginated session list | | T-56 | POST + GET + PUT + DELETE /api/finance/import/csv-mappings | Full CRUD cycle | | T-57 | GET /api/finance/import/sessions (as different club) | 200, empty list (tenant isolation) | --- ### T-58 through T-59: Member IBAN consent tests **Type:** Integration **Class:** `cannamanage-api/src/test/java/de/cannamanage/api/controller/MemberControllerTest.java` | Test | Precondition | Request | Expected | |------|-------------|---------|----------| | T-58 | BANK_DATA consent granted | PATCH /api/members/{id}/iban | 200, IBAN stored | | T-59 | No BANK_DATA consent | PATCH /api/members/{id}/iban | 400, "Consent required" | --- ### T-60 through T-62: Flyway migration tests **Type:** Integration **Class:** `cannamanage-api/src/test/java/de/cannamanage/api/FlywayMigrationTest.java` Verify all migrations V30-V32 apply cleanly on a fresh H2 database without errors. --- ### T-63 through T-65: End-to-end backend tests **Type:** E2E (Spring Boot integration with full context) **Class:** `cannamanage-api/src/test/java/de/cannamanage/api/BankImportE2ETest.java` | Test | Flow | Verification | |------|------|-------------| | T-63 | Upload MT940 → detect → parse → match → confirm all → complete | Payments + LedgerEntries created, session COMPLETED | | T-64 | Upload CSV → create mapping → parse with mapping → match → confirm | Custom mapping applied, correct column extraction | | T-65 | Upload → match (3 auto, 2 suggested, 1 unmatched) → confirm 3 → assign 2 → skip 1 → complete | All statuses correct, counts accurate | --- ### T-66 through T-70: Frontend E2E tests (Playwright) **Type:** E2E (Playwright) **File:** `cannamanage-frontend/e2e/bank-import.spec.ts` | Test | Scenario | Verification | |------|----------|-------------| | T-66 | Navigate to /finance/import, verify 4-step wizard structure | Steps visible, upload zone rendered | | T-67 | Upload CSV → column mapping dropdowns → assign columns → proceed | Mapping applied, preview table shown | | T-68 | Match review table → filter by status → verify correct rows | Filter tabs work, row counts match | | T-69 | Click "Alle bestätigen" → success toast → counts update | Confirmed count increases, green rows disappear | | T-70 | Navigate to import history → past sessions listed | Table with filename, date, status columns | --- ## Test Data (Fixtures) ### MT940 Test File (`sparkasse-standard.sta`) ``` :20:STARTUMSE :25:20050550/7654321 :28C:00000/001 :60F:C260601EUR1234,56 :61:2506150615CR50,00NMSCNONREF :86:SVWZ+M-0042 Mitgliedsbeitrag Juni 2025 EREF+NOTPROVIDED DEBT+DE89370400440532013000 :61:2506150615CR75,00NMSCNONREF :86:SVWZ+Anna Schmidt Quartalsbeitrag DEBT+DE55500105175898765432 :61:2506150615DR120,00NMSCNONREF :86:SVWZ+Miete Vereinsraum Juni CRED+DE44100800000123456789 :61:2506150615CR50,00NMSCNONREF :86:SVWZ+Beitrag DEBT+DE12345678901234567890 :61:2506150615CR25,00NMSCNONREF :86:SVWZ+Spende Vereinsfest DEBT+DE99876543210987654321 :62F:C260615EUR1239,56 ``` ### CAMT.053 Test File (`standard.xml`) ```xml 2025-06-15-001 DE20050550007654321 50.00 CRDT
2025-06-15
2025-06-15
M-0042 Mitgliedsbeitrag Juni 2025 Max Mustermann DE89370400440532013000
``` ### CSV Test File (`sparkasse.csv`) ```csv "Auftragskonto";"Buchungstag";"Valutadatum";"Buchungstext";"Verwendungszweck";"Beguenstigter/Zahlungspflichtiger";"Kontonummer";"BLZ";"Betrag";"Waehrung" "DE20050550007654321";"15.06.2025";"15.06.2025";"GUTSCHR";"M-0042 Mitgliedsbeitrag Juni 2025";"Max Mustermann";"DE89370400440532013000";"37040044";"50,00";"EUR" "DE20050550007654321";"15.06.2025";"15.06.2025";"GUTSCHR";"Anna Schmidt Quartalsbeitrag";"Anna Schmidt";"DE55500105175898765432";"50010517";"75,00";"EUR" ``` --- ## Test Coverage Matrix | Component | Unit | Integration | E2E | Total | |-----------|------|-------------|-----|-------| | Mt940Parser | 6 | 0 | 1 | 7 | | Camt053Parser | 5 | 0 | 0 | 5 | | CsvBankParser | 6 | 0 | 1 | 7 | | BankStatementParserService | 4 | 0 | 0 | 4 | | PaymentMatchingService | 12 | 0 | 0 | 12 | | BankImportService | 0 | 8 | 3 | 11 | | TierLimitService | 5 | 0 | 0 | 5 | | IbanValidator | 4 | 0 | 0 | 4 | | BankImportController | 0 | 7 | 0 | 7 | | MemberController (IBAN) | 0 | 2 | 0 | 2 | | Flyway Migrations | 0 | 3 | 0 | 3 | | Frontend (Playwright) | 0 | 0 | 5 | 5 | | **Total** | **42** | **20** | **10** | **70** | --- ## Traceability Matrix | Requirement | Plan Step | Test Case(s) | |-------------|-----------|-------------| | MT940 format parsing | Phase 2, Step 2.2 | T-01 through T-06 | | CAMT.053 format parsing | Phase 2, Step 2.3 | T-07 through T-11 | | CSV format parsing with configurable columns | Phase 2, Step 2.4 | T-12 through T-17 | | Auto-format detection | Phase 2, Step 2.5 | T-18 through T-21 | | Weighted matching algorithm | Phase 3, Step 3.1 | T-22 through T-33 | | Import session lifecycle | Phase 3, Step 3.2 | T-34 through T-41 | | Tier-based restrictions | Phase 3, Step 3.3 | T-42 through T-46 | | IBAN validation + consent | Phase 4, Step 4.4 | T-47 through T-50, T-58, T-59 | | REST API endpoints | Phase 4, Step 4.1 | T-51 through T-57 | | Database migrations | Phase 1, Step 1.1 | T-60 through T-62 | | Full import flow | All phases | T-63 through T-65 | | Frontend wizard UX | Phase 5 | T-66 through T-70 | | Tenant isolation | Phase 4, Step 4.3 | T-57 | | GDPR consent for IBAN | Phase 1, Step 1.2 (ConsentType) | T-58, T-59 | | File size limit (10MB) | Phase 4, Step 4.3 | T-52 | | Permission enforcement | Phase 4, Step 4.3 | T-53 |