|
| 1 | +from dataclasses import asdict, dataclass, field, replace |
| 2 | +from typing import Any |
| 3 | +from uuid import uuid4 |
| 4 | + |
| 5 | +from app.domain.enums.common import Environment |
| 6 | + |
| 7 | + |
| 8 | +@dataclass |
| 9 | +class EventMetadata: |
| 10 | + """Domain event metadata for auditing and tracing.""" |
| 11 | + |
| 12 | + service_name: str |
| 13 | + service_version: str |
| 14 | + correlation_id: str = field(default_factory=lambda: str(uuid4())) |
| 15 | + user_id: str | None = None |
| 16 | + ip_address: str | None = None |
| 17 | + user_agent: str | None = None |
| 18 | + environment: Environment = Environment.PRODUCTION |
| 19 | + |
| 20 | + def to_dict(self, exclude_none: bool = True) -> dict[str, Any]: |
| 21 | + result = asdict(self) |
| 22 | + if isinstance(result.get("environment"), Environment): |
| 23 | + result["environment"] = result["environment"].value |
| 24 | + if exclude_none: |
| 25 | + return {k: v for k, v in result.items() if v is not None} |
| 26 | + return result |
| 27 | + |
| 28 | + @classmethod |
| 29 | + def from_dict(cls, data: dict[str, Any]) -> "EventMetadata": |
| 30 | + env = data.get("environment", Environment.PRODUCTION) |
| 31 | + if isinstance(env, str): |
| 32 | + env = Environment(env) |
| 33 | + return cls( |
| 34 | + service_name=data.get("service_name", "unknown"), |
| 35 | + service_version=data.get("service_version", "1.0"), |
| 36 | + correlation_id=data.get("correlation_id", str(uuid4())), |
| 37 | + user_id=data.get("user_id"), |
| 38 | + ip_address=data.get("ip_address"), |
| 39 | + user_agent=data.get("user_agent"), |
| 40 | + environment=env, |
| 41 | + ) |
| 42 | + |
| 43 | + def with_correlation(self, correlation_id: str) -> "EventMetadata": |
| 44 | + return replace(self, correlation_id=correlation_id) |
| 45 | + |
| 46 | + def with_user(self, user_id: str) -> "EventMetadata": |
| 47 | + return replace(self, user_id=user_id) |
0 commit comments