Files
cannamanage/docs/sprint-10/cannamanage-sprint10-testplan.md
T
Patrick Plate 55110c95af feat(sprint10): Phase 1 — Data model + bank statement parsers (MT940, CAMT.053, CSV)
Implements the Sprint 10 Phase 1 foundation for the Smart Payment Import feature:

Domain layer:
- 3 new enums: BankFormat (MT940, CAMT053, CSV), ImportSessionStatus, MatchStatus
- StaffPermission.FINANCE_IMPORT
- AuditEventType: BANK_IMPORT_STARTED/COMPLETED/FAILED + BANK_PAYMENT_CONFIRMED
- NotificationType.BANK_IMPORT_COMPLETED
- ConsentType.BANK_DATA (DSGVO consent for IBAN storage)
- 3 new entities: BankImportSession, BankTransaction, CsvColumnMapping
- Member: + iban (VARCHAR 34) + ibanConsentDate
- MemberStatus.LEFT (semantic alias for RESIGNED, referenced by Sprint 9 RetentionService)

Persistence:
- V30__bank_import_sessions.sql
- V31__bank_transactions.sql
- V32__csv_column_mappings.sql (also adds iban + iban_consent_date to members)
- 3 Spring Data repositories

Parser infrastructure (cannamanage-service/src/main/java/de/cannamanage/service/bankimport):
- BankStatementParser interface (Strategy pattern, Spring-injected list)
- ParsedTransaction + ParseResult records
- BankStatementParseException (parse errors)
- Mt940Parser: custom state machine, CENTURY_BOUNDARY=70 for YY→YYYY, proprietary
  header tolerance (skips lines before first :20: for StarMoney/WISO/Hibiscus wrappers)
- Camt053Parser: StAX streaming with XXE hardening (IS_SUPPORTING_EXTERNAL_ENTITIES,
  SUPPORT_DTD, IS_REPLACING_ENTITY_REFERENCES all false); supports camt.053.001.02
  and camt.053.001.08 namespaces
- CsvBankParser: Apache Commons CSV with configurable columns per club; German number
  format ("1.234,56"); ISO-8859-1 default encoding
- BankStatementParserService: filename-extension hint + content probe; throws
  UnrecognizedFormatException when no parser claims the file

Build verified via Docker (cannamanage-api:sprint10-phase1).

Sprint 9 fix (incidental, required to compile):
- Added MemberStatus.LEFT (Sprint 9 RetentionService referenced it but the enum
  value was missing)
- MemberListRegistryGenerator: added LEFT to formatStatus() switch (mapped to
  "Ausgetreten", same as RESIGNED)

Sprint 10 docs: analysis, plan, plan-review, testplan.

Co-Authored-By: Lumen <lumen@cannamanage.de>
2026-06-15 17:21:55 +02:00

24 KiB

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 <Amt Ccy="EUR">50.00</Amt> amountCents = 5000
c <CdtDbtInd>CRDT</CdtDbtInd> amountCents positive
d <BookgDt><Dt>2025-06-15</Dt></BookgDt> bookingDate = 2025-06-15

T-08: CAMT.053 parsing — multiple entries

Type: Unit Class: Camt053ParserTest.java Method: testMultipleEntries()

Scenarios:

# Input Expected Result
a 10 <Ntry> 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 <Dbtr><Nm>Max Mustermann</Nm></Dbtr> counterpartyName = "Max Mustermann"
b <DbtrAcct><Id><IBAN>DE12...</IBAN></Id></DbtrAcct> counterpartyIban = "DE12..."
c <Ustrd>M-0042 Beitrag</Ustrd> 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:

// 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)

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 version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
  <BkToCstmrStmt>
    <Stmt>
      <Id>2025-06-15-001</Id>
      <Acct><Id><IBAN>DE20050550007654321</IBAN></Id></Acct>
      <Bal><!-- balances --></Bal>
      <Ntry>
        <Amt Ccy="EUR">50.00</Amt>
        <CdtDbtInd>CRDT</CdtDbtInd>
        <BookgDt><Dt>2025-06-15</Dt></BookgDt>
        <ValDt><Dt>2025-06-15</Dt></ValDt>
        <NtryDtls><TxDtls>
          <RmtInf><Ustrd>M-0042 Mitgliedsbeitrag Juni 2025</Ustrd></RmtInf>
          <RltdPties>
            <Dbtr><Nm>Max Mustermann</Nm></Dbtr>
            <DbtrAcct><Id><IBAN>DE89370400440532013000</IBAN></Id></DbtrAcct>
          </RltdPties>
        </TxDtls></NtryDtls>
      </Ntry>
      <!-- more entries... -->
    </Stmt>
  </BkToCstmrStmt>
</Document>

CSV Test File (sparkasse.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