# Architecture Documentation ## Overview Banks2FF implements a **Hexagonal (Ports & Adapters) Architecture** to synchronize bank transactions from GoCardless to Firefly III. This architecture separates business logic from external concerns, making the system testable and maintainable. ## Workspace Structure ``` banks2ff/ ├── banks2ff/ # Main CLI application │ └── src/ │ ├── core/ # Domain logic and models │ ├── adapters/ # External service integrations │ └── main.rs # CLI entry point ├── firefly-client/ # Firefly III API client library ├── gocardless-client/ # GoCardless API client library └── docs/ # Architecture documentation ``` ## Core Components ### 1. Domain Core (`banks2ff/src/core/`) **models.rs**: Defines domain entities - `BankTransaction`: Core transaction model with multi-currency support - `Account`: Bank account representation - Supports `foreign_amount` and `foreign_currency` for international transactions **ports.rs**: Defines abstraction traits - `TransactionSource`: Interface for fetching transactions (implemented by GoCardless adapter) - `TransactionDestination`: Interface for storing transactions (implemented by Firefly adapter) - Traits are mockable for isolated testing **sync.rs**: Synchronization engine - `run_sync()`: Orchestrates the entire sync process - Implements "Healer" strategy for idempotency - Smart date range calculation (Last Transaction Date + 1 to Yesterday) ### 2. Adapters (`banks2ff/src/adapters/`) **gocardless/**: GoCardless integration - `client.rs`: Wrapper for GoCardless client with token management - `mapper.rs`: Converts GoCardless API responses to domain models - `cache.rs`: Caches account mappings to reduce API calls - Correctly handles multi-currency via `currencyExchange` array parsing **firefly/**: Firefly III integration - `client.rs`: Wrapper for Firefly client for transaction storage - Maps domain models to Firefly API format ### 3. API Clients Both clients are hand-crafted using `reqwest`: - Strongly-typed DTOs for compile-time safety - Custom error handling with `thiserror` - Rate limit awareness and graceful degradation ## Synchronization Process The "Healer" strategy ensures idempotency: 1. **Account Discovery**: Fetch active accounts from GoCardless 2. **Account Matching**: Match GoCardless accounts to Firefly asset accounts by IBAN 3. **Date Window**: Calculate sync range (Last Firefly transaction + 1 to Yesterday) 4. **Transaction Processing**: - **Search**: Look for existing transaction using windowed heuristic (date ± 3 days, exact amount) - **Heal**: If found without `external_id`, update with GoCardless transaction ID - **Skip**: If found with matching `external_id`, ignore - **Create**: If not found, create new transaction in Firefly ## Key Features ### Multi-Currency Support - Parses `currencyExchange` array from GoCardless responses - Calculates `foreign_amount = amount * exchange_rate` - Maps to Firefly's `foreign_amount` and `foreign_currency_code` fields ### Rate Limit Management - **Caching**: Stores `AccountId -> IBAN` mappings to reduce requisition calls - **Token Reuse**: Maintains tokens until expiry to minimize auth requests - **Graceful Handling**: Continues sync for other accounts when encountering 429 errors ### Idempotency - GoCardless `transactionId` → Firefly `external_id` mapping - Windowed duplicate detection prevents double-creation - Historical transaction healing for pre-existing data ## Data Flow ``` GoCardless API → GoCardlessAdapter → TransactionSource → SyncEngine → TransactionDestination → FireflyAdapter → Firefly API ``` ## Testing Strategy - **Unit Tests**: Core logic with `mockall` for trait mocking - **Integration Tests**: API clients with `wiremock` for HTTP mocking - **Fixture Testing**: Real JSON responses for adapter mapping validation - **Isolation**: Business logic tested without external dependencies ## Error Handling - **Custom Errors**: `thiserror` for domain-specific error types - **Propagation**: `anyhow` for error context across async boundaries - **Graceful Degradation**: Rate limits and network issues don't crash entire sync - **Structured Logging**: `tracing` for observability and debugging ## Configuration Management - Environment variables loaded via `dotenvy` - Workspace-level dependency management - Feature flags for optional functionality - Secure credential handling (no hardcoded secrets)