Files
AccountForger-neuerUpload/docs/CLEAN_ARCHITECTURE.md
Claude Project Manager ba0ba3fcec RollBack Punkt 2025-09-13
2025-09-13 22:01:58 +02:00

11 KiB
Originalformat Blame Verlauf

Clean Architecture Design - AccountForger

Status: Vorschlag/Entwurf. Diese Architektur ist im aktuellen Code nur teilweise umgesetzt und dient als Zielbild. Ordner/Dateinamen in Beispielen sind konzeptionell zu verstehen.

Übersicht

Diese Dokumentation beschreibt die saubere Architektur für das AccountForger-System mit Fokus auf das Fingerprint-Management und die Login-Funktionalität mit gespeicherten Fingerprints.

Architektur-Schichten

1. Domain Layer (Innerster Kreis)

Keine Abhängigkeiten nach außen!

domain/
├── entities/
│   ├── account.py              # Account Entity
│   ├── browser_fingerprint.py  # Fingerprint Entity
│   └── browser_session.py      # Session Entity
├── value_objects/
│   ├── fingerprint_id.py       # Eindeutige Fingerprint-ID
│   ├── account_id.py           # Eindeutige Account-ID
│   └── session_data.py         # Session-Daten (Cookies, Storage)
└── repositories/              # Interfaces (Abstrakte Klassen)
    ├── fingerprint_repository.py
    ├── account_repository.py
    └── session_repository.py

2. Application Layer

Orchestriert Use Cases, kennt Domain

application/
├── use_cases/
│   ├── create_account/
│   │   ├── create_account_use_case.py
│   │   ├── create_account_dto.py
│   │   └── create_account_presenter.py
│   ├── login_account/
│   │   ├── login_with_fingerprint_use_case.py
│   │   ├── login_dto.py
│   │   └── login_presenter.py
│   └── manage_fingerprint/
│       ├── generate_fingerprint_use_case.py
│       ├── save_fingerprint_use_case.py
│       └── load_fingerprint_use_case.py
└── services/
    ├── fingerprint_manager.py  # Orchestriert Fingerprint-Operationen
    └── session_manager.py      # Verwaltet Browser-Sessions

3. Infrastructure Layer

Implementiert Interfaces aus Domain

infrastructure/
├── persistence/
│   ├── sqlite/
│   │   ├── sqlite_fingerprint_repository.py
│   │   ├── sqlite_account_repository.py
│   │   └── sqlite_session_repository.py
│   └── migrations/
│       └── fingerprint_schema.sql
├── browser/
│   ├── playwright_adapter.py   # Adapter für Playwright
│   ├── fingerprint_injector.py # Injiziert Fingerprints in Browser
│   └── protection_service.py   # Browser-Schutz
└── external/
    ├── proxy_service.py
    └── email_service.py

4. Presentation Layer

UI und Controller

presentation/
├── controllers/
│   ├── account_controller.py
│   └── fingerprint_controller.py
└── views/
    ├── account_view.py
    └── login_view.py

Fingerprint-System Design

Fingerprint Entity (Kern-Domain)

# domain/entities/browser_fingerprint.py
from dataclasses import dataclass
from typing import Optional
import uuid

@dataclass(frozen=True)  # Immutable!
class FingerprintId:
    value: str
    
    @classmethod
    def generate(cls) -> 'FingerprintId':
        return cls(str(uuid.uuid4()))

@dataclass
class BrowserFingerprint:
    """Immutable Fingerprint Entity - Kern der Domain"""
    id: FingerprintId
    canvas_seed: int
    webgl_vendor: str
    webgl_renderer: str
    audio_context_params: dict
    navigator_properties: dict
    hardware_config: dict
    timezone: str
    fonts: list[str]
    
    def to_dict(self) -> dict:
        """Serialisierung für Persistierung"""
        return {
            'id': self.id.value,
            'canvas_seed': self.canvas_seed,
            # ... weitere Felder
        }
    
    @classmethod
    def from_dict(cls, data: dict) -> 'BrowserFingerprint':
        """Deserialisierung aus Persistierung"""
        return cls(
            id=FingerprintId(data['id']),
            canvas_seed=data['canvas_seed'],
            # ... weitere Felder
        )

Fingerprint-Account-Session Verknüpfung

# domain/entities/account.py
@dataclass
class Account:
    id: AccountId
    username: str
    platform: str
    fingerprint_id: FingerprintId  # Verknüpfung!
    created_at: datetime
    
# domain/entities/browser_session.py
@dataclass
class BrowserSession:
    id: SessionId
    account_id: AccountId
    fingerprint_id: FingerprintId  # Gleicher Fingerprint!
    cookies: str  # Encrypted
    local_storage: str  # Encrypted
    session_storage: str  # Encrypted
    last_used: datetime
    is_valid: bool

Use Case: Login mit gespeichertem Fingerprint

# application/use_cases/login_account/login_with_fingerprint_use_case.py
class LoginWithFingerprintUseCase:
    def __init__(self,
                 account_repo: IAccountRepository,
                 fingerprint_repo: IFingerprintRepository,
                 session_repo: ISessionRepository,
                 browser_service: IBrowserService):
        self.account_repo = account_repo
        self.fingerprint_repo = fingerprint_repo
        self.session_repo = session_repo
        self.browser_service = browser_service
    
    def execute(self, account_id: str) -> LoginResult:
        # 1. Account laden
        account = self.account_repo.find_by_id(AccountId(account_id))
        if not account:
            return LoginResult.failure("Account nicht gefunden")
        
        # 2. Fingerprint laden
        fingerprint = self.fingerprint_repo.find_by_id(account.fingerprint_id)
        if not fingerprint:
            return LoginResult.failure("Fingerprint nicht gefunden")
        
        # 3. Session laden
        session = self.session_repo.find_by_account_id(account.id)
        if not session or not session.is_valid:
            return LoginResult.failure("Keine gültige Session")
        
        # 4. Browser mit Fingerprint starten
        browser = self.browser_service.create_with_fingerprint(fingerprint)
        
        # 5. Session wiederherstellen
        browser.restore_session(session)
        
        # 6. Login verifizieren
        if browser.verify_login(account.platform):
            return LoginResult.success(browser)
        else:
            return LoginResult.failure("Login fehlgeschlagen")

Repository Pattern (Clean!)

# domain/repositories/fingerprint_repository.py
from abc import ABC, abstractmethod

class IFingerprintRepository(ABC):
    @abstractmethod
    def save(self, fingerprint: BrowserFingerprint) -> None:
        pass
    
    @abstractmethod
    def find_by_id(self, id: FingerprintId) -> Optional[BrowserFingerprint]:
        pass
    
    @abstractmethod
    def find_by_account_id(self, account_id: AccountId) -> Optional[BrowserFingerprint]:
        pass

# infrastructure/persistence/sqlite/sqlite_fingerprint_repository.py
class SqliteFingerprintRepository(IFingerprintRepository):
    def save(self, fingerprint: BrowserFingerprint) -> None:
        # SQL Implementation
        query = "INSERT OR REPLACE INTO fingerprints ..."
        # Nur primitive Typen in DB!
        data = fingerprint.to_dict()
        self.db.execute(query, data)
    
    def find_by_id(self, id: FingerprintId) -> Optional[BrowserFingerprint]:
        query = "SELECT * FROM fingerprints WHERE id = ?"
        row = self.db.fetchone(query, [id.value])
        return BrowserFingerprint.from_dict(row) if row else None

Dependency Injection Container

# infrastructure/container.py
class Container:
    def __init__(self):
        # Repositories
        self._fingerprint_repo = SqliteFingerprintRepository()
        self._account_repo = SqliteAccountRepository()
        self._session_repo = SqliteSessionRepository()
        
        # Services
        self._browser_service = PlaywrightBrowserService()
        
        # Use Cases
        self._login_use_case = LoginWithFingerprintUseCase(
            self._account_repo,
            self._fingerprint_repo,
            self._session_repo,
            self._browser_service
        )
    
    @property
    def login_use_case(self) -> LoginWithFingerprintUseCase:
        return self._login_use_case

Datenbank-Schema

-- Fingerprints Tabelle
CREATE TABLE fingerprints (
    id TEXT PRIMARY KEY,
    canvas_seed INTEGER NOT NULL,
    webgl_vendor TEXT NOT NULL,
    webgl_renderer TEXT NOT NULL,
    audio_context_params TEXT NOT NULL, -- JSON
    navigator_properties TEXT NOT NULL,  -- JSON
    hardware_config TEXT NOT NULL,       -- JSON
    timezone TEXT NOT NULL,
    fonts TEXT NOT NULL,                 -- JSON Array
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Accounts Tabelle
CREATE TABLE accounts (
    id TEXT PRIMARY KEY,
    username TEXT NOT NULL,
    platform TEXT NOT NULL,
    fingerprint_id TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (fingerprint_id) REFERENCES fingerprints(id)
);

-- Sessions Tabelle
CREATE TABLE browser_sessions (
    id TEXT PRIMARY KEY,
    account_id TEXT NOT NULL,
    fingerprint_id TEXT NOT NULL,
    cookies TEXT NOT NULL,      -- Encrypted
    local_storage TEXT,         -- Encrypted
    session_storage TEXT,       -- Encrypted
    last_used TIMESTAMP,
    is_valid BOOLEAN DEFAULT 1,
    FOREIGN KEY (account_id) REFERENCES accounts(id),
    FOREIGN KEY (fingerprint_id) REFERENCES fingerprints(id)
);

-- Index für Performance
CREATE INDEX idx_accounts_fingerprint ON accounts(fingerprint_id);
CREATE INDEX idx_sessions_account ON browser_sessions(account_id);

Vorteile dieser Architektur

  1. Testbarkeit: Jede Schicht ist isoliert testbar
  2. Flexibilität: Repositories können ausgetauscht werden (SQLite → PostgreSQL)
  3. Klarheit: Klare Verantwortlichkeiten pro Schicht
  4. Wartbarkeit: Änderungen sind lokal begrenzt
  5. Fingerprint-Konsistenz: Ein Account = Ein Fingerprint = Konsistente Sessions

Login-Flow mit Fingerprint

  1. User wählt Account aus Liste
  2. System lädt Account mit verknüpftem Fingerprint
  3. Browser wird mit exakt diesem Fingerprint gestartet
  4. Gespeicherte Session (Cookies, Storage) wird geladen
  5. Browser navigiert zur Plattform
  6. Session ist wiederhergestellt = User ist eingeloggt

Beispiel-Verwendung

# In der Presentation Layer
container = Container()

# Login mit gespeichertem Fingerprint
result = container.login_use_case.execute(account_id="abc-123")

if result.success:
    browser = result.browser
    # User ist jetzt eingeloggt mit dem gleichen Fingerprint
else:
    print(f"Login fehlgeschlagen: {result.error}")

Diese Architektur stellt sicher, dass:

  • Fingerprints konsistent bleiben
  • Sessions zuverlässig wiederhergestellt werden
  • Der Code wartbar und erweiterbar bleibt
  • Keine zirkulären Abhängigkeiten entstehen