# Bank File SFTP Architecture

## Overview

The `bankfileInformationSFTP` service manages uploading and downloading of bank payment files to/from external SFTP servers. It supports three bank distributors -- Danske Bank, BGC, and Nordea -- each with their own file signing/encryption mechanism.

The service is driven by three cron scripts and configured entirely through the `setting` database table.

---

## Cron Scripts (Entry Points)

| Script | Purpose |
|---|---|
| `sites/cronscripts/bank_file_export.php` | Upload outgoing files to the bank SFTP |
| `sites/cronscripts/bank_file_download.php` | Download incoming files from the bank SFTP |
| `sites/cronscripts/bank_file_import.php` | Parse downloaded files and register payments |

---

## Service Configuration

All settings are stored in the `setting` table under the group path `payment/payment/bankfileInformationSFTP`, scoped per organization.

| Setting key | Type | Default | Description |
|---|---|---|---|
| `isActive` | boolean | `0` | Enable/disable the service |
| `bankFileDistributor` | select | `` | `1`=Danske Bank, `2`=BGC, `3`=Nordea |
| **Incoming (download)** | | | |
| `incomingSftpServerAddress` | string | `` | SFTP hostname for downloading files from bank |
| `incomingSftpServerPort` | string | `22` | SFTP port for incoming connection |
| `incomingSftpServerUsername` | string | `` | Login username for incoming SFTP |
| `incomingSftpServerPassword` | string | `` | Password (unused if SSH key auth is enabled) |
| `incomingSftpServerDownloadFolder` | string | `` | Remote folder to list/download from (e.g. `inbox/ETC/`) |
| **Outgoing (upload)** | | | |
| `outgoingSftpServerAddress` | string | `` | SFTP hostname for uploading files to bank |
| `outgoingSftpServerPort` | string | `22` | SFTP port for outgoing connection |
| `outgoingSftpServerUsername` | string | `` | Login username for outgoing SFTP |
| `outgoingSftpServerPassword` | string | `` | Password (unused if SSH key auth is enabled) |
| `outgoingSftpServerUploadFolder` | string | `` | Remote folder to upload to (e.g. `outbox/`) |
| **Authentication** | | | |
| `useExternalKeyConnection` | boolean | `0` | If `1`: use SSH key from secrets store instead of password |
| `testSftpServerUsername` | string | `` | Username override used in dev/test environment |

### Authentication

- **Password auth** (`useExternalKeyConnection = 0`): uses username + password settings above.
- **SSH key auth** (`useExternalKeyConnection = 1`): loads RSA key from the secrets store by distributor:
  - Danske Bank -> `danskebank_sftp_key`
  - Nordea -> `nordea_sftp_key`
  - Other/BGC -> `sftp_key`
- **Dev environment**: both address fields are overridden with `GConf('BANK_FILE_BGC_TEST_SFTP_SERVER_ADDRESS')` and both usernames use `testSftpServerUsername`.

---

## File Status Lifecycle

```
REGISTERED (1)
   |
   v
READY_TO_BE_HANDLED (2)
   |
   v
IN_PROCESS (3)
   |
   v
FINISHED (4)   or   ERROR_IN_PROCESSING (5)
```

---

## Upload Flow (Outgoing)

```
bank_file_export.php
  -> Exporter::uploadBankFiles()
  -> Read setting: isActive, bankFileDistributor
  -> Query: bank_file WHERE direction=OUTGOING AND status=READY_TO_BE_HANDLED (2)
  -> For each file:
      1. Set status = IN_PROCESS (3)
      2. Load file parts -> read content from filesystem
      3. Sign/encrypt by distributor (see Signing section below)
      4. Write signed content to /tmp/bfpart-out-{partId}
      5. SFTP upload to /{outgoingSftpServerUploadFolder}/{filename}
      6. Success -> status = FINISHED (4)
         Failure -> status = ERROR_IN_PROCESSING (5) + send failure email
      7. Delete /tmp file
```

## Download Flow (Incoming)

```
bank_file_download.php
  -> Importer::importBankFiles()
  -> Read setting: isActive
  -> SFTP connect to incomingSftpServerAddress:incomingSftpServerPort
  -> List files in incomingSftpServerDownloadFolder
  -> For each remote file:
      1. Check if already imported (by filename in bank_file_part)
      2. Download to /tmp/{filename}
      3. Create bank_file record (status = REGISTERED = 1)
      4. Create bank_file_part record
      5. Store file content to filesystem
      6. Set status = READY_TO_BE_HANDLED (2)
      7. Delete file from remote SFTP
      8. Delete /tmp file

bank_file_import.php (separate process)
  -> Picks up files with status = READY_TO_BE_HANDLED (2)
  -> For Nordea: parse SecureEnvelope (validate XML signature, base64 decode, optional gzip decompress)
  -> Parse file format (CAMT053, consent, payment, etc.)
  -> Register payments/consents to payment system
  -> Set status = FINISHED (4)
```

---

## File Signing / Encryption by Distributor

| Distributor | Class | Method |
|---|---|---|
| Danske Bank | `Models/Bank/File/OpenPGPClient.php` | GPG sign + encrypt (RSA, private/public key pair + passphrase) |
| Nordea (outgoing) | `Models/Bank/File/SecureEnvelope.php` | Wraps file in XML `ApplicationRequest`, RSA/SHA1 digital signature, base64-encoded content |
| Nordea (incoming) | `Models/Bank/File/SecureEnvelopeParser.php` | Validates XML signature, base64 decode, optional gzip decompress (files > 1 MB) |
| BGC | `Models/Bank/File/HmacSigner.php` | Adds TK00 header + TK99 HMAC SHA256 footer; normalizes Swedish characters to 7-bit ASCII |

---

## File Storage

Files are stored on the **local filesystem** -- the database holds only metadata and a path.

| Direction | Path pattern |
|---|---|
| Outgoing | `{BANK_FILE_OUTGOING_SAVE_PATH}/{organizationId}/{YYYYMMDD}/BF{partId}` |
| Incoming | `{BANK_FILE_INCOMING_SAVE_PATH}/{organizationId}/{YYYYMMDD}/BF{partId}` |

Temporary files during processing are written to `/tmp/` and cleaned up after each transfer.

---

## Key Database Tables

| Table | Purpose |
|---|---|
| `bank_file` | One record per file transfer (direction, status, category, org) |
| `bank_file_part` | File content metadata + filesystem path |
| `bank_file_key` | Cryptographic keys per distributor, with validity dates |
| `bank_file_category` | 32 file type categories (CAMT053, payment, consent, etc.) |
| `bank_file_status` | Status enum |
| `bank_file_distributor` | Danske Bank / BGC / Nordea |
| `setting` | Service configuration (`bankfileInformationSFTP` group) |

---

## Key Source Files

| File | Role |
|---|---|
| `Models/Bank/File/SFTP/Exporter.php` | Upload orchestration |
| `Models/Bank/File/SFTP/Importer.php` | Download orchestration |
| `Models/Bank/File/SFTP/SFTPCreator.php` | SFTP connection factory (reads all connection settings) |
| `Models/Bank/File/SecureEnvelope.php` | Nordea outgoing XML signing |
| `Models/Bank/File/SecureEnvelopeParser.php` | Nordea incoming XML validation |
| `Models/Bank/File/OpenPGPClient.php` | Danske Bank GPG signing |
| `Models/Bank/File/HmacSigner.php` | BGC HMAC tamper protection |
| `Models/Bank/File/DbObject.php` | Bank file domain model |
| `Models/Bank/File/Part/DbObject.php` | File part + filesystem I/O |
| `Models/Bank/File/Key/DbObject.php` | Cryptographic key management |
| `Models/Bank/File/Repository.php` | Queries by direction, status, distributor |
| `database/migrations/GAS-21372/001_new_settings.sql` | Setting definitions |

---

## Notes for Porting to Another Technology (e.g. Azure Blazor)

| Gasell component | Azure/.NET equivalent |
|---|---|
| Cron scripts | Azure Functions with Timer trigger or Azure Logic Apps |
| `phpseclib\Net\SFTP` | SSH.NET library |
| OpenPGP signing | BouncyCastle for .NET |
| RSA/XML digital signature | `System.Security.Cryptography.Xml` |
| HMAC SHA256 | `System.Security.Cryptography.HMACSHA256` |
| Filesystem file storage | Azure Blob Storage |
| `setting` table config | Azure App Configuration or Key Vault |
| Secrets store (SSH keys) | Azure Key Vault |
| Status machine | Same pattern -- track state transitions in DB |
| Duplicate detection | Check filename in file parts table before downloading |
