Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
1.3 KiB
Python
54 lines
1.3 KiB
Python
"""Channel provider contracts — all external delivery goes through these adapters."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any, Protocol
|
|
from uuid import UUID
|
|
|
|
|
|
@dataclass
|
|
class SendRequest:
|
|
tenant_id: UUID
|
|
channel: str
|
|
to_address: str
|
|
body: str
|
|
from_address: str | None = None
|
|
subject: str | None = None
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
@dataclass
|
|
class SendResult:
|
|
success: bool
|
|
provider_message_id: str | None = None
|
|
error_code: str | None = None
|
|
error_message: str | None = None
|
|
raw_response: dict[str, Any] | None = None
|
|
latency_ms: int | None = None
|
|
|
|
|
|
@dataclass
|
|
class BalanceResult:
|
|
balance: float | None
|
|
currency: str | None = None
|
|
raw: dict[str, Any] | None = None
|
|
|
|
|
|
@dataclass
|
|
class ProviderHealth:
|
|
healthy: bool
|
|
detail: str | None = None
|
|
|
|
|
|
class ChannelProvider(Protocol):
|
|
"""Protocol every channel adapter must implement."""
|
|
|
|
provider_kind: str
|
|
channel: str
|
|
|
|
async def send(self, request: SendRequest, credentials: dict[str, Any]) -> SendResult: ...
|
|
|
|
async def get_balance(self, credentials: dict[str, Any]) -> BalanceResult: ...
|
|
|
|
async def health_check(self, credentials: dict[str, Any]) -> ProviderHealth: ...
|