Skip to content

πŸ“¦ BRIM Plugin Guide

How to create a new Broker Report Import Manager plugin to support a new broker's CSV/Excel export format.

Base class: BRIMProvider (in backend/app/services/brim_provider.py) Plugin folder: backend/app/services/brim_providers/ Registry: BRIMProviderRegistry


πŸ”„ Flow

The system calls plugin methods in two distinct phases:

graph TD
    subgraph "Phase 1 β€” Detection (file uploaded)"
        D1["File uploaded"] --> D2["can_parse(file_path)<br/><small>Quick header/extension check</small>"]
        D2 -->|true| D3["Plugin listed as<br/>compatible option"]
        D2 -->|false| D4["Skip"]
    end

    subgraph "Phase 2 β€” Parsing (user selects plugin)"
        P1["parse(file_path, broker_id)<br/><small>Full parsing</small>"] --> P2["Returns:<br/>β€’ transactions[]<br/>β€’ warnings[]<br/>β€’ extracted_assets{}"]
        P2 --> P3["User reviews<br/>in preview UI"]
        P3 --> P4["POST /transactions<br/><small>Core handles persist</small>"]
    end

    D3 ~~~ P1

    style D1 fill:#e3f2fd,stroke:#1565c0
    style D2 fill:#e3f2fd,stroke:#1565c0
    style D3 fill:#e3f2fd,stroke:#1565c0
    style P1 fill:#e8f5e9,stroke:#2e7d32
    style P2 fill:#fff3e0,stroke:#e65100
    style P3 fill:#fff3e0,stroke:#e65100
    style P4 fill:#f3e5f5,stroke:#7b1fa2

Phase 1 runs automatically when a file is uploaded β€” every registered plugin is asked if it can parse the file. Compatible plugins are listed for the user.

Phase 2 runs when the user selects a specific plugin β€” the plugin parses the file, the user reviews the results, and confirms the import.

Plugin responsibility: Read the broker-specific file format and convert to standard TXCreateItem DTOs. Core responsibility: File storage, asset matching, duplicate detection, database persistence.


πŸ“‹ ABC Methods

βœ… Required (Abstract)

Method Signature Description
provider_code @property β†’ str Unique identifier (e.g., "directa_csv")
provider_name @property β†’ str Display name (e.g., "Directa CSV")
description @property β†’ str Brief description for the UI
can_parse(file_path) β†’ bool Quick check if this plugin can parse the file (check extension, header row)
parse(file_path, broker_id) β†’ Tuple[List[TXCreateItem], List[str], Dict[int, BRIMExtractedAssetInfo]] Full parsing β€” returns transactions, warnings, and extracted asset info

πŸ”§ Optional (Override)

Method Default Description
supported_extensions ['.csv'] Accepted file extensions
detection_priority 100 Auto-detection priority (higher = checked first). Use 0-49 for generic plugins.
icon_url None Plugin icon URL for the UI
generate_static_url(path) β€” Helper to build /api/v1/uploads/plugin/brim/{path}

πŸ’» Implementation Example

# backend/app/services/brim_providers/my_broker.py

from pathlib import Path
from typing import List, Tuple, Dict
from backend.app.services.brim_provider import BRIMProvider, BRIMExtractedAssetInfo
from backend.app.services.provider_registry import register_provider, BRIMProviderRegistry
from backend.app.schemas.transactions import TXCreateItem

@register_provider(BRIMProviderRegistry)
class MyBrokerProvider(BRIMProvider):

    @property
    def provider_code(self) -> str:
        return "my_broker_csv"

    @property
    def provider_name(self) -> str:
        return "My Broker (CSV)"

    @property
    def description(self) -> str:
        return "Import transactions from My Broker CSV exports"

    def can_parse(self, file_path: Path) -> bool:
        """Quick check: read first lines and look for known header."""
        content = self._read_file_head(file_path, num_lines=5)
        return "Date;Operation;ISIN;Amount" in content

    def parse(
        self, file_path: Path, broker_id: int
    ) -> Tuple[List[TXCreateItem], List[str], Dict[int, BRIMExtractedAssetInfo]]:
        """Parse the CSV and return transactions."""
        transactions = []
        warnings = []
        extracted_assets = {}

        # ... your parsing logic ...

        return transactions, warnings, extracted_assets

πŸ” Auto-Discovery

Place the file in brim_providers/ and restart the app. The BRIMProviderRegistry will automatically discover and register it. The plugin will appear in the ImportPluginSelect dropdown.