- Implement robust End User Agreement expiry detection and handling - Add graceful error recovery for failed accounts - Rewrite README.md to focus on user benefits - Add documentation guidelines to AGENTS.md
7.8 KiB
7.8 KiB
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:
- Create Anonymized Test Scripts: Write small, focused scripts that extract only the necessary data structure information
- Use Mock Data: Replace real financial values with placeholder data
- Validate Structure, Not Values: Focus on data structure integrity, not actual financial content
- 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=debugto 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
// ✅ 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<BankTransaction>) {
for tx in transactions {
println!("Real amount: {}", tx.amount); // SECURITY VIOLATION
}
}
Rust Development Best Practices
Error Handling
- Use
thiserrorfor domain-specific error types in core modules - Use
anyhowfor application-level error context and propagation - Never use
panic!in production code - handle errors gracefully - Implement
Fromtraits for error type conversions
// 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
tokioas the async runtime (workspace dependency) - Prefer
async-traitfor trait methods that need to be async - Handle cancellation properly with
select!ortokio::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
mockallfor trait-based testing - Test Fixtures: Store sample JSON responses in
tests/fixtures/
#[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 featuresreqwest: HTTP client with JSON supportserde/serde_json: Serialization/deserializationchrono: Date/time handling with serde supportrust_decimal: Precise decimal arithmetic for financial datatracing/tracing-subscriber: Structured loggingclap: CLI argument parsing with derive macrosanyhow/thiserror: Error handlingasync-trait: Async trait supportwiremock: HTTP mocking for testsmockall: 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
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 fmtfor formatting - Use
cargo clippyfor linting - Ensure documentation for public APIs
4. Commit Standards
- Commit both code and tests together
- Write clear, descriptive commit messages
- Ensure the workspace compiles:
cargo build --workspace
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
Client Libraries
- gocardless-client/: Standalone GoCardless API wrapper
- firefly-client/: Standalone Firefly III API wrapper
- Both use
reqwestfor HTTP communication
Security Considerations
- Never log sensitive data: Use tracing filters to exclude financial information
- Environment variables: Store credentials in
.envfile (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
tokiofor concurrent operations where appropriate
Observability
- Structured Logging: Use
tracingwith 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 for implementation details and complex logic explanations