# Banks2FF Development Guide ## Project Purpose Banks2FF is a Rust CLI tool that synchronizes bank transactions from GoCardless Bank Account Data API to Firefly III personal finance manager. It implements a hexagonal architecture for clean separation of concerns and comprehensive testing. ## 🚨 CRITICAL: Financial Data Security ### **Financial Data Masking Requirements** **FOR LLM/AI INTERACTIONS ONLY**: When interacting with coding agents, LLMs, or AI assistants: - **NEVER** expose, log, or display raw financial information including: - Transaction amounts - Account balances - IBANs or account numbers - Transaction descriptions - Personal identifiers - API keys or tokens **FOR DEBUG LOGGING**: When using `RUST_LOG=debug`: - **STRUCTURED LOGGING** shows HTTP requests, responses, and errors - **NO SENSITIVE DATA** is logged (financial amounts, personal info, tokens) - **REQUEST TRACING** includes method, URL, status codes, and error details ### **Compliance Protocol for AI Agent Debugging** When debugging financial data issues with AI agents: 1. **Create Anonymized Test Scripts**: Write small, focused scripts that extract only the necessary data structure information 2. **Use Mock Data**: Replace real financial values with placeholder data 3. **Validate Structure, Not Values**: Focus on data structure integrity, not actual financial content 4. **Sanitize All Outputs**: Ensure any debugging output masks sensitive information ### **Debug Logging** The application uses structured logging with the `tracing` crate: - **Normal operation**: Uses INFO level logging for key operations - **Debug mode**: Set `RUST_LOG=debug` to see detailed HTTP request/response logging - **No sensitive data**: Financial amounts and personal information are never logged - **Request tracing**: HTTP method, URL, status codes, and error responses are logged ```rust // ✅ GOOD: Structure validation with mock data fn validate_transaction_structure() { let mock_tx = BankTransaction { amount: Decimal::new(12345, 2), // Mock amount currency: "EUR".to_string(), // ... other fields with mock data }; // Validate structure only } // ❌ BAD: Exposing real financial data fn debug_real_transactions(transactions: Vec) { for tx in transactions { println!("Real amount: {}", tx.amount); // SECURITY VIOLATION } } ``` ## Rust Development Best Practices ### Error Handling - **Use `thiserror`** for domain-specific error types in core modules - **Use `anyhow`** for application-level error context and propagation - **Never use `panic!`** in production code - handle errors gracefully - **Implement `From` traits** for error type conversions ```rust // Core domain errors #[derive(Error, Debug)] pub enum SyncError { #[error("Failed to fetch transactions from source: {0}")] SourceError(#[from] anyhow::Error), #[error("Failed to store transaction: {0}")] DestinationError(#[from] anyhow::Error), } ``` ### Async Programming - **Use `tokio`** as the async runtime (workspace dependency) - **Prefer `async-trait`** for trait methods that need to be async - **Handle cancellation** properly with `select!` or `tokio::time::timeout` - **Use `?` operator** for error propagation in async functions ### Testing Strategy - **Unit Tests**: Test pure functions and business logic in isolation - **Integration Tests**: Test adapter implementations with `wiremock` - **Mock External Dependencies**: Use `mockall` for trait-based testing - **Test Fixtures**: Store sample JSON responses in `tests/fixtures/` ```rust #[cfg(test)] mod tests { use super::*; use mockall::predicate::*; #[tokio::test] async fn test_sync_with_mock_source() { let mut mock_source = MockTransactionSource::new(); // Setup mock expectations // Test core logic } } ``` ### Code Organization - **Workspace Dependencies**: Define common dependencies in root `Cargo.toml` - **Feature Flags**: Use features for optional functionality - **Module Structure**: Keep modules focused and single-responsibility - **Public API**: Minimize public surface area; prefer internal modules ### Dependencies and Patterns **Key Workspace Dependencies:** - `tokio`: Async runtime with full features - `reqwest`: HTTP client with JSON support - `serde`/`serde_json`: Serialization/deserialization - `chrono`: Date/time handling with serde support - `rust_decimal`: Precise decimal arithmetic for financial data - `tracing`/`tracing-subscriber`: Structured logging - `clap`: CLI argument parsing with derive macros - `anyhow`/`thiserror`: Error handling - `async-trait`: Async trait support - `wiremock`: HTTP mocking for tests - `mockall`: Runtime mocking for tests ## Development Workflow ### 1. Code Development - Write code in appropriate modules following the hexagonal architecture - Keep core business logic separate from external integrations - Use workspace dependencies consistently - When working from a spec, update the spec with the current status as soon as you finish something - **MANDATORY**: After making ANY code change, complete the Post-Change Verification Checklist (see Code Quality section below) ### 2. Testing - Write tests alongside code in `#[cfg(test)]` modules - Test both happy path and error conditions - Use mock objects for external dependencies - Ensure all tests pass: `cargo test --workspace` ### 3. Code Quality - Follow Rust idioms and conventions - Use `cargo fmt` for formatting - Use `cargo clippy` for linting - Ensure documentation for public APIs - **MANDATORY: ALWAYS format and lint after making ANY change, and fix ALL linting errors and warnings** - When a change is end-user visible, update the README.md. Use the README.md documentation guidelines - Always clean up unused code. No todo's or unused code is allowed after a change. Remove unused variables, functions, imports, etc. Do NOT hide unused code with underscores - delete it! #### Post-Change Verification Checklist (MANDATORY) After making ANY code change, you MUST run these commands and fix any issues: 1. **Format code**: `cargo fmt --all` 2. **Run linter**: `cargo clippy --all-targets --all-features -- -D warnings` 3. **Run tests**: `cargo test --workspace` 4. **Build project**: `cargo build --workspace` 5. **Clean up unused code**: Remove any unused variables, functions, imports, etc. **FAILURE TO COMPLETE THIS CHECKLIST WILL RESULT IN CODE REJECTION** ### 4. Commit Standards - *Always* ensure the workspace compiles: `cargo build --workspace` - Commit both code and tests together - Write clear, descriptive commit messages, focusing on user benefits over technical details. Use prose over bullet points ### Version Control - **Use JJ (Jujutsu)** as the primary tool for all source control operations due to its concurrency and conflict-free design. Use a specialized agent if available - **Git fallback**: Only for complex operations unsupported by JJ (e.g., interactive rebasing) ## Project Structure Guidelines ### Core Module (`banks2ff/src/core/`) - **models.rs**: Domain entities (BankTransaction, Account) - **ports.rs**: Trait definitions (TransactionSource, TransactionDestination) - **sync.rs**: Business logic orchestration ### Adapters Module (`banks2ff/src/adapters/`) - **gocardless/**: GoCardless API integration - **firefly/**: Firefly III API integration - Each adapter implements the appropriate port trait ### Commands Module (`banks2ff/src/commands/`) - **sync.rs**: Sync command handler - **accounts/**: Account management commands - **mod.rs**: Account command dispatch - **link.rs**: Account linking logic and LinkCommands dispatch - **list.rs**: Account listing handler - **status.rs**: Account status handler - **transactions/**: Transaction management commands - **mod.rs**: Transaction command dispatch - **list.rs**: Transaction listing handler - **cache.rs**: Cache status handler - **clear.rs**: Cache clearing handler - **list.rs**: Source/destination listing handler ### Client Libraries - **gocardless-client/**: Standalone GoCardless API wrapper - **firefly-client/**: Standalone Firefly III API wrapper - Both use `reqwest` for HTTP communication ## Security Considerations - **Never log sensitive data**: Use tracing filters to exclude financial information - **Environment variables**: Store credentials in `.env` file (never in code) - **Input validation**: Validate all external data before processing - **Error messages**: Don't expose sensitive information in error messages ## Performance Considerations - **Caching**: Use caching to reduce API calls (see GoCardlessAdapter) - **Rate Limiting**: Handle 429 responses gracefully - **Batch Processing**: Process transactions in reasonable batches - **Async Concurrency**: Use `tokio` for concurrent operations where appropriate ## Observability - **Structured Logging**: Use `tracing` with spans for operations - **Error Context**: Provide context in error messages for debugging - **Metrics**: Consider adding metrics for sync operations - **Log Levels**: Use appropriate log levels (debug, info, warn, error) ## Documentation Guidelines ### README.md - **Keep High-Level**: Focus on user benefits and key features, not technical implementation details - **User-Centric**: Describe what the tool does and why users would want it - **Skip Implementation Details**: Avoid technical jargon, architecture specifics, or internal implementation that users don't need to know - **Feature Descriptions**: Use concise, benefit-focused language (e.g., "Robust Error Handling" rather than "Implements EUA expiry detection with multiple requisition fallback") ### Technical Documentation - **docs/architecture.md**: Detailed technical specifications, implementation details, and developer-focused content - **specs/**: Implementation planning, API specifications, and historical context - **Code Comments**: Use sparingly for implementation details. *Do* explain complex logic