trading-system-docs/notes/trading/system-docs/modul-14-notification.md
Red Queen 022c30e537 feat(tolaria): migrate C3H HR wave 1 — 16 safe root↔canonical pairs to schema v1
C3H HUMAN REVIEW WAVE 1: migriert 16 freigegebene HR-A PAIR_MIGRATION_SAFE Paare.
Pro Pair: Root (representation=source) + Canonical (representation=canonical,
derived_from=Root-ID) atomar. Body byte-genau unveraendert. IDs stabil aus
C3 Mapping Preview v2. modul-12/18/19/vps.md NICHT angefasst.
Knowledge schema v1. (Red Queen)
2026-08-25 19:19:02 +00:00

8 KiB
Raw Permalink Blame History

knowledge_schema id type role representation state derived_from _organized
1 object/ea077314-9e29-6c7f-1c17-008fa8e720ae arch module canonical current object/0a0c9ca4-1cf4-aee1-3072-e1c3e8cfd29e true

Modul-14: Notification-Service

Status: FREIGEGEBEN · Container Modul-14-Notification · Image notification:0.1.0

Zweck

Zentrale Benachrichtigungen für Trading- und Systemereignisse. Konsumiert relevante Events aus den RabbitMQ-Exchanges der Module 0510 und liefert kompakte, strukturierte Meldungen — V1 primär über Telegram (TelegramProvider), provider-neutral angelegt.

Restriktionen (Nutzer-Vorgabe):

  • keine KI/ML, keine Trading-Entscheidungen, keine Orders.
  • FAIL-SAFE: Ein Notification-Ausfall darf die Trading-Pipeline NIEMALS blockieren.

Architektur / Datenfluss

RabbitMQ (market.signals/.rankings/.risk/.portfolio/.execution/.journal)
        │  NotificationConsumer (notification.input)
        ▼
Modul-14-Notification ── NotificationService ──> RulesEngine + DedupGuard
        │                                            │  Spam-Schutz
        ├── providers/  NotificationProvider-ABC → Telegram / Fake
        ├── rules/      RulesEngine (Regeln) + DedupGuard (Dedup/Cooldown/Rate-Limit)
        ├── storage/    Persistenz notification_log (PostgreSQL, Modul-01)
        ├── core/       formatter (kompakte Nachricht) + service (Retry/Backoff)
        └── api/main.py REST-API (intern, Port 55014)

Event → RabbitMQ → Modul-14 → notification_log → Provider (Telegram) → Chat

API (Docker-intern, Port 55014, kein öffentliches Port-Mapping)

GET /health                 liveness
GET /health/ready           readiness (postgresql, consumer_ready, provider_configured)
GET /notifications/recent   letzte Notifications
GET /notifications/{id}     einzelne Notification
POST /notifications/test    Test-Sendung (nur konfigurierte Destinationen)

Konsumierte Events & Routing-Keys

Event-Typ Exchange Routing-Key Default-Severity Default aktiv
SIGNAL_DETECTED market.signals strategy.signal.detected INFO (deaktiviert)
SIGNAL_RANKED market.rankings signal.ranked INFO (deaktiviert)
RISK_APPROVED market.risk risk.approved INFO (deaktiviert)
RISK_REJECTED market.risk risk.rejected WARNING (deaktiviert)
TRADE_APPROVED market.portfolio trade.approved INFO
PORTFOLIO_REJECTED market.portfolio portfolio.rejected WARNING
ORDER_SUBMITTED market.execution order.submitted INFO (deaktiviert)
ORDER_FILLED market.execution order.filled INFO
ORDER_REJECTED market.execution order.rejected CRITICAL
ORDER_FAILED market.execution order.failed CRITICAL
TRADE_RECORDED market.journal trade.recorded INFO

Die Regeln sind pro Event-Typ konfigurierbar (aktiv/inaktiv, Severity, Provider, Destination, Cooldown, Rate-Limit). Unbekannte Event-Typen werden sicher ignoriert (kein Crash). V1 sind die rauschigen Events (SIGNAL_, RISK_, ORDER_SUBMITTED) standardmäßig deaktiviert.

Severity-Hierarchie

INFO < WARNING < CRITICAL

Regel-Severity überschreibt den Event-Standard. V1: alle über Telegram.

Spam-Schutz (DedupGuard)

Mehrstufig, thread-sicher (Lock):

  1. Idempotenz — gleiche event_id/source_event_id erzeugt nie eine zweite Notification (DB-unique über source_event_id + event_processed-Check).
  2. Dedup — identische Meldungen (gleicher Text/Event-Typ) in kurzem Fenster werden zusammengefasst.
  3. Cooldown — pro Event-Typ ein Mindestabstand (cooldown_seconds, Default 60s).
  4. Rate-Limit — maximale Notifications pro Minute (rate_limit_per_minute, Default 30).
  5. Burst-Schutz — Ansturm vieler Events wird aufs Limit begrenzt.

Retry / Dead (FAIL-SAFE)

  • Provider nicht erreichbar → RETRY_PENDING mit begrenzten Retries (exponentielles Backoff).
  • max_attempts (Default 5) erreicht → DEAD (keine Endlosschleife).
  • Provider nicht konfiguriert (fehlender Token/Chat-ID) → sofort DEAD mit error_code=NOT_CONFIGURED (keine sinnlosen Retries).
  • Nach Provider-Recovery werden neue Events wieder normal gesendet (Retry betrifft nur die jeweilige Notification).

Eigene Tabelle (Migration)

notification_log: notification_id (PK), source_event_id, event_type, severity, provider, destination, status (SENT/FAILED/RETRY_PENDING/DEAD), attempts, created_at, sent_at, error_code, error_message.

Sicherheit

  • KEINE Secrets in DB/Logs/Doku/Commits. Telegram-Bot-Token/Chat-ID ausschließlich über Environment (Compose TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID), nie hart kodiert.
  • /notifications/test sendet nur an konfigurierte Destinationen.

Tests

  • tests/test_notification.py: 14/14 grün (Event→Notification, Idempotenz, Dedup, Cooldown, Rate-Limit, Telegram-Ausfall blockiert nicht, Retry+Backoff, Max→DEAD, keine Secrets, unbekannter Typ ignoriert, Severity/Regeln, FakeProvider, Reconnect).

E2E-Verifikation (VPS, 20.08.2026) — alle 7 Punkte grün

  1. Fake-Telegram-E2E (Modul-14 auf http://fake-telegram:55000, Test-Token/Chat-ID nur als ENV): echtes TRADE_RECORDED publiziert → Event → RabbitMQ → Modul-14 → notification_log → Fake-Telegram komplett durchlaufen. DB: status=SENT, sent_at gesetzt, attempts=0, genau 1 Zustellung, kein Duplikat. Fake-Telegram RAW: {"chat_id": "E2E_TEST_CHAT_114", "text": "TRADE RECORDED | NVDA | LONG | OPEN"}.
  2. NO_CONFIG-Fix: Container ohne Token → Event → status=DEAD, attempts=1, error_code=NOT_CONFIGURED (sofortiges DEAD, keine 5 sinnlosen Retries).
  3. Fehlerfall-E2E: Fake-Telegram gestoppt → Notification RETRY_PENDING mit Backoff (attempts 2→4, NETWORK_ERROR), Trading-Pipeline unbeeinflusst, Max-Retries (attempts=5) → DEAD. Nach Fake-Telegram-Recovery → neues Event wieder SENT.
  4. RabbitMQ-Reconnect: kontrollierter Restart → Modul-14 reconnectet automatisch (Backoff 4s→8s→16s, „Consumer verbunden"), genau 1 Consumer an notification.input, keine Zombies, keine verlorenen/duplizierten Notifications (nach Reconnect: 1 Zustellung, 0 Duplikate).
  5. Spam-/Sicherheitschecks (praktisch): unbekannter Typ UNKNOWN_EVENT_XYZ → ignoriert; gleiche event_id 2× → nur 1 Notification (Idempotenz); gleicher Event-Typ 2× → Cooldown greift; deaktivierter SIGNAL_DETECTED → keine Notification. Keine Tokens/Chat-IDs in Logs/API/Doku/DB (0 Token-Leaks).
  6. Health/Readiness: /health + /health/ready → 200 (postgresql=true, consumer_ready=true, provider_configured=…). Keine Applikations-Tracebacks im Normalbetrieb (nur erwartete Reconnect-Logs beim Test). Port 55014 nur intern (expose, kein Host-Port).
  7. Forgejo-Doku + Commit-ID (siehe Freigabe unten), temporäre Test-Credentials entfernt, Remote token-/key-frei.

Freigabe

  • 20.08.2026: Modul-14-Notification-Service vom Nutzer FREIGEGEBEN (nach vollständiger E2E-Verifikation der Punkte 17, alle grün).
  • Keine weiteren technischen Änderungen an Modul-14.

Compose / Betrieb

  • Netzwerk trading-modules, DB-Host Modul-01-PostgreSQL, RabbitMQ Modul-02-RabbitMQ.
  • Port 55014 nur intern (expose), restart: unless-stopped, non-root (uid 1001).
  • Token/Chat-ID via ENV (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, TELEGRAM_API_BASE).

Nächste Module

  • Modul-15 ff. — noch Platzhalter (alpine), NICHT gestartet.

Geändert

Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-14-Notification-Service dokumentiert — E2E-verifiziert (Punkte 17 grün),
       API/Events/Severity/Retry-Dead/Spam-Schutz/Fake-E2E dokumentiert, Status FREIGEGEBEN.