Implement logic
This commit is contained in:
178
AGENTS.md
Normal file
178
AGENTS.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# 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
|
||||
|
||||
### **ABSOLUTE REQUIREMENT: Financial Data Masking**
|
||||
|
||||
**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
|
||||
|
||||
### **Compliance Protocol for Debugging**
|
||||
|
||||
When debugging financial data issues:
|
||||
|
||||
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
|
||||
|
||||
```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<BankTransaction>) {
|
||||
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
|
||||
|
||||
### 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
|
||||
|
||||
### 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 `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)
|
||||
Reference in New Issue
Block a user