# Messaging Service Konzept

## Übersicht

Das Messaging-System ermöglicht es, Nachrichten über verschiedene Kanäle (E-Mail, SMS, WhatsApp, Teams Chat, etc.) an registrierte Benutzer zu senden, basierend auf Subscriptions. Es ist mandantenbasiert und unterstützt mehrere Kanäle pro Subscription.

## Architektur-Überlegungen

### Kernkonzept

Das System besteht aus zwei Hauptkomponenten:

1. **Subscription-Management**: Users können sich für Subscriptions registrieren und ihre bevorzugten Kanäle wählen
2. **Subscription-Funktionen**: Jede Subscription hat eine eigene Funktion (`subSubscriptionXxxx.py`), die komplett flexibel ist und die Nachrichten vorbereitet

### Setup-Architektur

**Wichtig**: Die Datenbank mit den Subscriptions ist die **stabile Basis-Referenz** und die Grundlage des Systems.

Es gibt zwei Seiten, die an die Datenbank andocken:

1. **User-Seite**: Users können sich für Subscriptions registrieren (subscribe)
   - Dies ist unabhängig davon, ob bereits eine Subscription-Funktion existiert
   - Users können sich bereits subscriben, bevor eine Funktion implementiert ist
   
2. **Funktions-Seite**: Subscription-Funktionen können später hinzugefügt werden
   - Eine Subscription-Funktion ist **optional** und kann nachträglich implementiert werden
   - Wenn eine Subscription-Funktion fehlt, wird beim Trigger ein Fehler geloggt, aber das System bleibt stabil
   - Die Datenbank-Struktur ist unabhängig von der Existenz der Funktionen

**Workflow**:
1. Admin erstellt Subscription in der Datenbank (z.B. "SystemErrors")
2. Users können sich sofort für diese Subscription registrieren
3. Später kann die Subscription-Funktion (`subSubscriptionSystemErrors.py`) hinzugefügt werden
4. Erst dann können Trigger die Subscription ausführen

### Trigger-Mechanismus

Subscriptions können über verschiedene Trigger ausgeführt werden:
- **Trigger-Route-Endpunkt**: API-Endpunkt, der eine Subscription triggert
- **Workflow-Action**: Automatischer Workflow, der eine Subscription als Event auslöst
- **Scheduled Job**: Zeitgesteuerte Ausführung
- **Event-basiert**: System-Events (z.B. Audit-Log-Events)

**Wichtig**: Eine Subscription kann über **alle** Trigger-Typen ausgeführt werden. Es gibt keine Einschränkung pro Subscription.

### Subscription-Funktionen

Jede Subscription hat eine eigene Funktion im Format `subSubscriptionXxxx.py` (z.B. `subSubscriptionSystemErrors.py`, `subSubscriptionAuditLogin.py`).

**Naming-Regel**: Die `subscriptionId` muss nur Buchstaben und Unterstriche (`_`) enthalten. Sie wird direkt als Dateiname verwendet:
- `subscriptionId`: "SystemErrors" → Datei: `subSubscriptionSystemErrors.py`
- `subscriptionId`: "audit_login" → Datei: `subSubscriptionAuditLogin.py`

**Validierung**: Bei der Erstellung einer Subscription wird geprüft, dass `subscriptionId` nur Buchstaben und `_` enthält.

Diese Funktionen:
- Erhalten Event-Parameter vom Trigger (als Pydantic Model)
- Erhalten bereits die Registrierungen (werden vor dem Funktionsaufruf geholt)
- Bereiten die Nachrichten vor (können pro Kanal unterschiedlich sein)
- Rufen `sendMessage` für jeden Channel auf
- Haben vollständige Flexibilität bei der Nachrichtenerstellung

**Beispiel-Struktur:**
```python
# modules/services/serviceMessaging/subscriptions/subSubscriptionSystemErrors.py
from typing import List
from modules.datamodels.datamodelMessaging import (
    MessagingEventParameters,
    MessagingSubscriptionExecutionResult,
    MessagingSubscriptionRegistration,
    MessagingChannel
)

def execute(
    eventParameters: MessagingEventParameters,
    registrations: List[MessagingSubscriptionRegistration],
    messagingService
) -> MessagingSubscriptionExecutionResult:
    """
    Subscription-Funktion für System-Errors.
    Erhält eventParameters vom Trigger und registrations bereits geholt.
    """
    # Gruppiere nach Channel
    emailRegistrations = [r for r in registrations if r.channel == MessagingChannel.EMAIL]
    smsRegistrations = [r for r in registrations if r.channel == MessagingChannel.SMS]
    
    # Bereite Nachrichten vor (können pro Channel unterschiedlich sein)
    emailSubject = "System Error Report"
    errors = eventParameters.triggerData.get('errors', [])
    emailMessage = f"System errors detected: {errors}"
    
    smsMessage = f"System Error: {len(errors)} errors detected"
    
    messagesSent = 0
    
    # Versende über sendMessage
    for reg in emailRegistrations:
        sendResult = messagingService.sendMessage(
            subject=emailSubject,
            message=emailMessage,
            registration=reg
        )
        if sendResult.success:
            messagesSent += 1
    
    for reg in smsRegistrations:
        sendResult = messagingService.sendMessage(
            subject="",  # SMS hat kein Subject
            message=smsMessage,
            registration=reg
        )
        if sendResult.success:
            messagesSent += 1
    
    return MessagingSubscriptionExecutionResult(
        success=True,
        messagesSent=messagesSent
    )
```

## Datenmodell

### 1. MessagingChannel (Enum)
```python
class MessagingChannel(str, Enum):
    EMAIL = "email"
    SMS = "sms"
    WHATSAPP = "whatsapp"
    TEAMS_CHAT = "teams_chat"
    # Weitere Kanäle können hier hinzugefügt werden
```

### 2. MessagingSubscription
- `id`: UUID
- `subscriptionId`: String (eindeutiger Identifier, z.B. "SystemErrors", "audit_login")
  - **Validierung**: Nur Buchstaben und `_` erlaubt
- `subscriptionLabel`: String (Anzeigename)
- `mandateId`: String (Mandanten-ID - wird automatisch vom Interface gesetzt)
- `description`: Optional[String]
- `isSystemSubscription`: Boolean (nur Admin kann System-Subscriptions erstellen)
- `enabled`: Boolean
- System-Felder: `creationDate`, `lastModified`, `createdBy`, `modifiedBy`

### 3. MessagingSubscriptionRegistration
- `id`: UUID
- `subscriptionId`: String (Referenz zur Subscription)
- `userId`: String (Referenz zum User)
- `channel`: MessagingChannel
- `channelConfig`: String (z.B. E-Mail-Adresse, Telefonnummer, Teams User ID)
- `enabled`: Boolean (User kann sich temporär deaktivieren)
- System-Felder: `creationDate`, `lastModified`

### 4. MessagingDelivery
- `id`: UUID
- `subscriptionId`: String (Referenz zur Subscription)
- `userId`: String (Referenz zum User)
- `channel`: MessagingChannel
- `status`: Enum (PENDING, SENT, FAILED)
- `errorMessage`: Optional[String]
- `sentAt`: Optional[Float] (Timestamp wenn gesendet)
- System-Felder: `creationDate`

### 5. MessagingEventParameters (Pydantic Model)
- `triggerData`: dict - Event-Daten vom Trigger als Dictionary/JSON

### 6. MessagingSendResult (Pydantic Model)
- `success`: Boolean
- `deliveryId`: Optional[String] (ID des MessagingDelivery Records)
- `errorMessage`: Optional[String]

### 7. MessagingSubscriptionExecutionResult (Pydantic Model)
- `success`: Boolean
- `messagesSent`: Integer
- `errorMessage`: Optional[String]
- `extra="allow"` für zusätzliche Felder

## RBAC-Berechtigungsmodell

### Access Rules für MessagingSubscription
- **Context**: `DATA`
- **Item**: `MessagingSubscription`
- **Permissions**:
  - **Admin**: Alle CRUD-Operationen auf alle Subscriptions
  - **Mandate-Admin**: CRUD auf Subscriptions des eigenen Mandanten (außer System-Subscriptions)
  - **User**: Read auf Subscriptions des eigenen Mandanten, Create/Update/Delete nur auf eigene Registrierungen

### Access Rules für MessagingSubscriptionRegistration
- **Context**: `DATA`
- **Item**: `MessagingSubscriptionRegistration`
- **Permissions**:
  - **User**: CRUD auf eigene Registrierungen
  - **Admin/Mandate-Admin**: Read auf alle Registrierungen des Mandanten

### Access Rules für MessagingDelivery
- **Context**: `DATA`
- **Item**: `MessagingDelivery`
- **Permissions**:
  - **Admin/Mandate-Admin**: Read auf alle Deliveries
  - **User**: Read auf eigene Deliveries

## Service-Architektur

### serviceMessaging/mainServiceMessaging.py

```python
class MessagingService:
    def __init__(self, services):
        self.services = services
        self._messagingInterface = None  # interfaceMessaging
    
    # Core Messaging
    def sendMessage(
        self, 
        subject: str, 
        message: str, 
        registration: MessagingSubscriptionRegistration
    ) -> MessagingSendResult:
        """
        Sendet eine Nachricht über einen Channel an einen User.
        Erstellt MessagingDelivery Record.
        
        Args:
            subject: Subject der Nachricht (für E-Mail, leer für SMS)
            message: Nachrichtentext
            registration: MessagingSubscriptionRegistration mit Channel-Info und userId
        
        Returns:
            MessagingSendResult mit Status und Delivery-ID
        """
        # Erstelle Delivery Record
        delivery = MessagingDelivery(
            subscriptionId=registration.subscriptionId,
            userId=registration.userId,
            channel=registration.channel,
            status=DeliveryStatus.PENDING
        )
        
        # Speichere Delivery Record
        deliveryRecord = self.services.interfaceDbComponent.createDelivery(delivery)
        
        try:
            # Versende über interfaceMessaging
            success = self._getMessagingInterface().send(
                channel=registration.channel,
                recipient=registration.channelConfig,
                subject=subject,
                message=message
            )
            
            if success:
                # Update Delivery Record
                self.services.interfaceDbComponent.updateDelivery(
                    deliveryRecord["id"],
                    {
                        "status": DeliveryStatus.SENT,
                        "sentAt": getUtcTimestamp()
                    }
                )
                return MessagingSendResult(
                    success=True,
                    deliveryId=deliveryRecord["id"]
                )
            else:
                # Update Delivery Record mit Fehler
                self.services.interfaceDbComponent.updateDelivery(
                    deliveryRecord["id"],
                    {
                        "status": DeliveryStatus.FAILED,
                        "errorMessage": "Failed to send message"
                    }
                )
                return MessagingSendResult(
                    success=False,
                    deliveryId=deliveryRecord["id"],
                    errorMessage="Failed to send message"
                )
        except Exception as e:
            logger.error(f"Error sending message: {str(e)}")
            # Update Delivery Record mit Fehler
            self.services.interfaceDbComponent.updateDelivery(
                deliveryRecord["id"],
                {
                    "status": DeliveryStatus.FAILED,
                    "errorMessage": str(e)
                }
            )
            return MessagingSendResult(
                success=False,
                deliveryId=deliveryRecord["id"],
                errorMessage=str(e)
            )
    
    def executeSubscription(
        self, 
        subscriptionId: str, 
        eventParameters: MessagingEventParameters
    ) -> MessagingSubscriptionExecutionResult:
        """
        Führt eine Subscription-Funktion aus.
        
        Args:
            subscriptionId: ID der Subscription
            eventParameters: Parameter vom Trigger (als Pydantic Model)
        
        Returns:
            MessagingSubscriptionExecutionResult
        
        Raises:
            ValueError: Wenn Subscription nicht existiert oder nicht enabled ist
            FileNotFoundError: Wenn Subscription-Funktion nicht gefunden wird
        """
        # Prüfe ob Subscription existiert und enabled ist
        subscription = self.services.interfaceDbComponent.getSubscription(subscriptionId)
        if not subscription:
            raise ValueError(f"Subscription {subscriptionId} not found")
        if not subscription.enabled:
            logger.warning(f"Subscription {subscriptionId} is disabled, skipping execution")
            return MessagingSubscriptionExecutionResult(
                success=False,
                messagesSent=0,
                errorMessage="Subscription is disabled"
            )
        
        # Hole alle aktiven Registrierungen für diese Subscription
        registrations = self._getSubscribers(subscriptionId)
        
        if not registrations:
            logger.info(f"No active registrations for subscription {subscriptionId}")
            return MessagingSubscriptionExecutionResult(
                success=True,
                messagesSent=0
            )
        
        # Lade Subscription-Funktion dynamisch
        subscriptionFunction = self._loadSubscriptionFunction(subscriptionId)
        if not subscriptionFunction:
            errorMsg = f"Subscription function not found for {subscriptionId}"
            logger.error(errorMsg)
            raise FileNotFoundError(errorMsg)
        
        # Führe Funktion aus mit Registrierungen
        try:
            return subscriptionFunction.execute(eventParameters, registrations, self)
        except Exception as e:
            logger.error(f"Error executing subscription {subscriptionId}: {str(e)}", exc_info=True)
            return MessagingSubscriptionExecutionResult(
                success=False,
                messagesSent=0,
                errorMessage=str(e)
            )
    
    # Helper Methods
    def _getSubscribers(
        self, 
        subscriptionId: str, 
        channel: Optional[MessagingChannel] = None
    ) -> List[MessagingSubscriptionRegistration]:
        """Holt alle aktiven Subscriber einer Subscription"""
        return self.services.interfaceDbComponent.getAllRegistrations(
            subscriptionId=subscriptionId,
            filters={"enabled": True} if not channel else {"enabled": True, "channel": channel.value}
        )
    
    def _loadSubscriptionFunction(self, subscriptionId: str) -> Optional[Callable]:
        """
        Lädt die Subscription-Funktion dynamisch.
        
        Returns:
            Callable mit execute-Methode oder None wenn nicht gefunden
        
        Note:
            subscriptionId wird direkt als Dateiname verwendet (z.B. "SystemErrors" -> subSubscriptionSystemErrors.py)
        """
        # Format: subSubscription{subscriptionId}.py
        functionName = f"subSubscription{subscriptionId}"
        moduleName = f"modules.services.serviceMessaging.subscriptions.{functionName}"
        
        try:
            # Dynamisches Import
            import importlib
            subscriptionModule = importlib.import_module(moduleName)
            return subscriptionModule
        except ImportError:
            # Funktion existiert noch nicht - das ist OK
            logger.debug(f"Subscription function {moduleName} not found (this is OK if not yet implemented)")
            return None
    
    def _getMessagingInterface(self):
        """Holt das Messaging-Interface (interfaceMessaging)"""
        if not self._messagingInterface:
            from modules.interfaces.interfaceMessaging import getInterface
            self._messagingInterface = getInterface()
        return self._messagingInterface
```

## Connector-Architektur

### Überblick

Für jeden Channel gibt es einen separaten Connector in `modules/connectors/`:
- `connectorMessagingEmail.py` - Azure Communication Services
- `connectorMessagingSms.py` - Twilio
- `connectorMessagingWhatsapp.py` - WhatsApp API (zukünftig)
- `connectorMessagingTeams.py` - Microsoft Teams API (zukünftig)

### Interface: interfaceMessaging.py

Das Interface `modules/interfaces/interfaceMessaging.py` stellt eine einheitliche Schnittstelle bereit, die alle Connectors nach dem gleichen Schema verwendet:

```python
class MessagingInterface:
    def send(
        self,
        channel: MessagingChannel,
        recipient: str,
        subject: str,
        message: str
    ) -> bool:
        """
        Sendet eine Nachricht über den angegebenen Channel.
        
        Args:
            channel: MessagingChannel Enum
            recipient: Empfänger-Adresse (E-Mail, Telefonnummer, etc.)
            subject: Betreff (für E-Mail, leer für SMS)
            message: Nachrichtentext
        
        Returns:
            bool: True wenn erfolgreich, False bei Fehler
        """
        # Wähle Connector basierend auf Channel
        if channel == MessagingChannel.EMAIL:
            connector = ConnectorMessagingEmail()
        elif channel == MessagingChannel.SMS:
            connector = ConnectorMessagingSms()
        elif channel == MessagingChannel.WHATSAPP:
            connector = ConnectorMessagingWhatsapp()
        elif channel == MessagingChannel.TEAMS_CHAT:
            connector = ConnectorMessagingTeams()
        else:
            logger.error(f"Unknown channel: {channel}")
            return False
        
        # Rufe Connector mit einheitlichem Schema auf
        return connector.send(recipient=recipient, subject=subject, message=message)
```

### Connector-Struktur

Jeder Connector implementiert die gleiche Schnittstelle:

```python
# modules/connectors/connectorMessagingEmail.py
class ConnectorMessagingEmail:
    def __init__(self):
        # Initialisiere Azure Communication Services Client
        pass
    
    def send(self, recipient: str, subject: str, message: str) -> bool:
        """
        Sendet E-Mail über Azure Communication Services.
        
        Args:
            recipient: E-Mail-Adresse
            subject: Betreff
            message: Nachrichtentext (kann HTML enthalten)
        
        Returns:
            bool: True wenn erfolgreich
        """
        # Implementierung hier
        pass
```

```python
# modules/connectors/connectorMessagingSms.py
class ConnectorMessagingSms:
    def __init__(self):
        # Initialisiere Twilio Client
        pass
    
    def send(self, recipient: str, subject: str, message: str) -> bool:
        """
        Sendet SMS über Twilio.
        
        Args:
            recipient: Telefonnummer (mit Ländercode)
            subject: Wird ignoriert (SMS hat kein Subject)
            message: Nachrichtentext
        
        Returns:
            bool: True wenn erfolgreich
        """
        # Implementierung hier
        pass
```

**Vorteile**:
- Einheitliches Schema für alle Channels
- Einfache Erweiterung um neue Channels
- Klare Trennung zwischen Service-Logik und Channel-Implementierung
- Connectors können unabhängig getestet werden

## Interface-Methoden (interfaceDbComponentObjects.py)

```python
# Subscription Management
def getAllSubscriptions(self, pagination: Optional[PaginationParams] = None) -> Union[List[MessagingSubscription], PaginatedResult]
def getSubscription(self, subscriptionId: str) -> Optional[MessagingSubscription]
def getSubscriptionById(self, id: str) -> Optional[MessagingSubscription]  # By UUID
def createSubscription(self, subscriptionData: Dict[str, Any]) -> Dict[str, Any]
def updateSubscription(self, subscriptionId: str, updateData: Dict[str, Any]) -> Dict[str, Any]
def deleteSubscription(self, subscriptionId: str) -> bool

# Registration Management
def getAllRegistrations(self, subscriptionId: Optional[str] = None, userId: Optional[str] = None, 
                       pagination: Optional[PaginationParams] = None) -> Union[List[MessagingSubscriptionRegistration], PaginatedResult]
def getRegistration(self, registrationId: str) -> Optional[MessagingSubscriptionRegistration]
def createRegistration(self, registrationData: Dict[str, Any]) -> Dict[str, Any]
def updateRegistration(self, registrationId: str, updateData: Dict[str, Any]) -> Dict[str, Any]
def deleteRegistration(self, registrationId: str) -> bool
def subscribeUser(self, subscriptionId: str, userId: str, channel: MessagingChannel, channelConfig: str) -> Dict[str, Any]
def unsubscribeUser(self, subscriptionId: str, userId: str, channel: MessagingChannel) -> bool

# Delivery Management
def createDelivery(self, delivery: MessagingDelivery) -> Dict[str, Any]
def updateDelivery(self, deliveryId: str, updateData: Dict[str, Any]) -> Dict[str, Any]
def getDeliveries(self, subscriptionId: Optional[str] = None, userId: Optional[str] = None, 
                 pagination: Optional[PaginationParams] = None) -> Union[List[MessagingDelivery], PaginatedResult]
def getDelivery(self, deliveryId: str) -> Optional[MessagingDelivery]
```

## Route-Struktur (routeMessaging.py)

### Rate Limits
- **Subscription Endpoints**: 60 requests/minute pro Session
- **Registration Endpoints**: 60 requests/minute pro Session
- **Trigger Endpoints**: 60 requests/minute pro `subscriptionId`

### Subscription Endpoints
- `GET /api/messaging/subscriptions` - Liste aller Subscriptions
- `POST /api/messaging/subscriptions` - Neue Subscription erstellen
- `GET /api/messaging/subscriptions/{subscriptionId}` - Subscription abrufen
- `PUT /api/messaging/subscriptions/{subscriptionId}` - Subscription aktualisieren
- `DELETE /api/messaging/subscriptions/{subscriptionId}` - Subscription löschen

### Registration Endpoints
- `GET /api/messaging/subscriptions/{subscriptionId}/registrations` - Registrierungen einer Subscription
- `POST /api/messaging/subscriptions/{subscriptionId}/subscribe` - User zu Subscription hinzufügen
- `DELETE /api/messaging/subscriptions/{subscriptionId}/unsubscribe` - User von Subscription entfernen
- `GET /api/messaging/registrations` - Eigene Registrierungen des Users
- `PUT /api/messaging/registrations/{registrationId}` - Registrierung aktualisieren (z.B. enabled/disabled)
- `DELETE /api/messaging/registrations/{registrationId}` - Registrierung löschen

### Trigger Endpoints
- `POST /api/messaging/trigger/{subscriptionId}` - Trigger-Endpunkt für externe Systeme/Workflows
  - Body: `{"eventParameters": {...}}`
  - Führt `executeSubscription` aus
  - Rate Limit: 60 requests/minute pro `subscriptionId`

### Delivery Endpoints
- `GET /api/messaging/deliveries` - Delivery-Historie
- `GET /api/messaging/deliveries/{deliveryId}` - Delivery abrufen

## Use Cases

### 1. Trigger-Route-Endpunkt
```python
@router.post("/api/messaging/trigger/{subscriptionId}")
@limiter.limit("60/minute", key_func=lambda: f"{request.path_params['subscriptionId']}")
async def trigger_subscription(
    request: Request,
    subscriptionId: str,
    eventParameters: Dict[str, Any] = Body(...),
    currentUser: User = Depends(getCurrentUser)
):
    """Trigger-Endpunkt für externe Systeme"""
    # RBAC-Check: Nur Admin/Mandate-Admin kann triggern
    messagingService = request.app.state.services.messaging
    
    # Konvertiere Dict zu Pydantic Model
    eventParams = MessagingEventParameters(triggerData=eventParameters)
    
    executionResult = messagingService.executeSubscription(subscriptionId, eventParams)
    return executionResult
```

### 2. Workflow-Action
Workflow kann `messaging.executeSubscription` Action aufrufen mit:
- `subscriptionId`: String
- `eventParameters`: Dict (wird zu MessagingEventParameters konvertiert)

### 3. Scheduled Job (System Errors)
```python
def _sendSystemErrorsJob(self):
    """Tägliches Mail an Admin mit Log-Errors"""
    # Sammle Errors aus Log
    errors = self._collectLogErrors()
    if errors:
        messagingService = self.services.messaging
        eventParams = MessagingEventParameters(triggerData={"errors": errors, "timestamp": getUtcTimestamp()})
        messagingService.executeSubscription(
            subscriptionId="SystemErrors",
            eventParameters=eventParams
        )
```

### 4. Audit Log Events
```python
# In audit_logger.py
def logAuditEvent(eventType: str, userId: str, details: Dict):
    # ... existing audit logging ...
    
    # Trigger messaging if subscription exists
    if eventType == "login":
        messagingService = getMessagingService(getAdminUser())
        eventParams = MessagingEventParameters(
            triggerData={
                "eventType": eventType,
                "userId": userId,
                "details": details,
                "timestamp": getUtcTimestamp()
            }
        )
        messagingService.executeSubscription(
            subscriptionId="audit_login",
            eventParameters=eventParams
        )
```

## Error Handling

Fehler werden wie in anderen Modulen behandelt:
- Normale Logger-Ausgabe mit `logger.error()`, `logger.warning()`, `logger.info()`
- Exceptions werden geloggt mit `exc_info=True` für Stack-Traces
- Keine speziellen Error-Handler, Standard-Python-Exception-Handling

## Konfiguration

### Environment Variables
```env
# Email (Azure Communication Services)
MESSAGING_ACS_CONNECTION_STRING=...
MESSAGING_ACS_SENDER_EMAIL=...

# SMS (Twilio)
MESSAGING_TWILIO_ACCOUNT_SID=...
MESSAGING_TWILIO_AUTH_TOKEN=...
MESSAGING_TWILIO_FROM_NUMBER=...

# WhatsApp (zukünftig)
MESSAGING_WHATSAPP_API_KEY=...

# Teams Chat (zukünftig)
MESSAGING_TEAMS_APP_ID=...
MESSAGING_TEAMS_APP_SECRET=...
```

## Implementierungsreihenfolge

1. **Datenmodelle** (`datamodelMessaging.py`) ✅
2. **Connectors** (`connectorMessagingEmail.py`, `connectorMessagingSms.py`)
3. **Interface** (`interfaceMessaging.py`)
4. **Interface-Methoden** (`interfaceDbComponentObjects.py`)
5. **Service-Implementierung** (`serviceMessaging/mainServiceMessaging.py`)
6. **Routes** (`routeMessaging.py`)
7. **Integration** (Service in `__init__.py` registrieren, Routes registrieren)
8. **Subscription-Funktionen** (`serviceMessaging/subscriptions/`)
   - Können nachträglich hinzugefügt werden
   - System funktioniert auch ohne Funktionen (Users können sich subscriben)
9. **Tests** (Unit-Tests für Service, Integration-Tests für Routes)

**Wichtig**: Die Datenbank-Struktur ist die Basis. Subscription-Funktionen sind optional und können später hinzugefügt werden.
