Files
finanz-cockpit/AGENTS.md
T
mathias2784 6d98939024
Tests / test (push) Successful in 10s
Tests / lint (push) Successful in 10s
Transactions table (#7)
Reviewed-on: #7
Co-authored-by: Mathias <mathias2784@web.de>
2026-10-10 20:47:51 +00:00

3.7 KiB
Raw Blame History

finanz-cockpit Agent Instructions

Setup Commands

# 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

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

# 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:

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/