Files
finanz-cockpit/AGENTS.md
T

109 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# finanz-cockpit Agent Instructions
## Setup Commands
```bash
# Install dependencies
uv sync
# Run migrations
alembic upgrade head
# Run all tests
pytest
# Run a single test file
pytest tests/test_model_b4wexport.py -v
```
## Project Structure
- **`src/`**: Application code
- `main.py`: CLI entrypoint for CSV ingestion
- `db.py`: Database connection management (uses global `_engine` pattern)
- `models/`: Pydantic models + SQLAlchemy tables for b4w and comdirect imports
- `ingest/`: Data ingestion logic per source
- **`tests/`**: Tests with fixtures in `conftest.py`
- **`alembic/versions/`**: Database migrations
## Key Patterns & Gotchas
### Database Configuration
```python
from src.db import get_engine, get_session, set_engine
# Development: use sqlite://
os.environ["DATABASE_URL"] = "sqlite://"
# Production/default: sqlite:///finanz.db
engine = get_engine() # reads DATABASE_URL or uses default
with get_session() as session:
session.query(...).all()
```
**Critical**: Tests override engine via `conftest.py`. Never assume global state - always use `get_session()` context manager.
### CSV Format Expectations
- **b4w**: German bank export (CSV) from `/mnt/anbau/Software/Python/finanz-cockpit/scripts/dummy_data/b4w_export_dummy_01.csv`
- **comdirect**: German bank export (CSV) with fields like `Buchungstag`, `Umsatz in EUR`, `Vorgang`
### Testing Workflow
```bash
# Tests automatically run migrations via conftest fixture
pytest tests/ -v --tb=short
# To test without migrations (in-memory SQLite), use DATABASE_URL="sqlite://"
export DATABASE_URL="sqlite://" pytest tests/test_db.py
```
### Environment Variables
- `DATABASE_URL`: Database connection string (default: `sqlite:///finanz.db`)
## Data Models
Two sources with shared patterns:
- **b4w**: `B4wExport`, `Category`, transactional import to `import_b4w` table + `category` table
- **comdirect**: `ComdirectGiro`, `ComdirectCreditCard`, `ComdirectDepot`, import to `comdirect_giro` table
- **unified**: `Transaction`, `TransactionDb` – both ingest pipelines project their staging rows (`import_b4w`, `comdirect_giro`) into one `transactions` table via `src/ingest/transactions.py` (`map_*` mappers + `consolidate_transactions`). Dedup uses a business-key `hash_id` (source + IBAN + value date + amount + text + counterparty) with a UNIQUE constraint and SQLite `INSERT OR IGNORE`, so re-imports are idempotent. Amounts are canonical signed (negative = money out). Depot/credit-card/tagesgeld are not projected yet.
All models inherit from common base in `src/models/_common.py`:
- `_hash()`: SHA256-based deduplication key
- `_parse_date_german()`: Handles "07.09.2026" format and values like "offen", "--"
- `_parse_decimal_german()`: Converts "1,23" to Decimal
## Factory Pattern for Testing
Import from `tests/factories.py`:
```python
from tests.factories import B4wExportFactory, ComdirectGiroFactory
from src.constants import Currency
B4wExportFactory.__faker__ = Faker("de_DE")
ComdirectGiroFactory.__faker__ = Faker("de_DE")
# Use in tests:
item = B4wExportFactory.build( # build() for partial, create() for full
Amt="50.00",
RmtInf="Supermarket",
)
```
## Common Mistakes to Avoid
1. **Assuming global engine state**: Always use `get_session()` context manager
2. **Ignoring German date formats**: Use `_parse_date_german()` for CSV parsing
3. **Forgetting migration setup in tests**: Tests auto-migrate, but integration tests with real db need explicit upgrade
4. **Wrong Faker locale**: Use `Faker("de_DE")` for realistic names/IBANs
## Testing Tips
- Run single test: `pytest tests/test_model_b4wexport.py -v`
- View migrations: `ls alembic/versions/`
- Test data location: `/scripts/dummy_data/`