Dieser Commit ist enthalten in:
Claude Project Manager
2025-08-01 23:50:28 +02:00
Commit 04585e95b6
290 geänderte Dateien mit 64086 neuen und 0 gelöschten Zeilen

342
docs/CLEAN_ARCHITECTURE.md Normale Datei
Datei anzeigen

@ -0,0 +1,342 @@
# Clean Architecture Design - AccountForger
## Ü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)
```python
# 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
```python
# 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
```python
# 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!)
```python
# 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
```python
# 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
```sql
-- 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
```python
# 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