Skip to content

Usage Domain

The usage_domain bounded context tracks all product interactions. Usage decay (declining event frequency) is the strongest leading indicator of churn.

Entities

src.domain.usage.entities

UsageEvent entity – core of the Usage bounded context.

Classes

UsageEvent dataclass

A single product interaction by a customer.

Parameters:

Name Type Description Default
event_id str

UUID primary key.

required
customer_id str

FK to Customer entity.

required
timestamp datetime

UTC datetime of the event.

required
event_type EventType

The type of product action taken.

required
feature_adoption_score FeatureAdoptionScore

Adoption score snapshot at the time of the event.

required
Source code in src/domain/usage/entities.py
@dataclass
class UsageEvent:
    """A single product interaction by a customer.

    Args:
        event_id: UUID primary key.
        customer_id: FK to Customer entity.
        timestamp: UTC datetime of the event.
        event_type: The type of product action taken.
        feature_adoption_score: Adoption score snapshot at the time of the event.
    """

    event_id: str
    customer_id: str
    timestamp: datetime
    event_type: EventType
    feature_adoption_score: FeatureAdoptionScore

    @property
    def is_retention_signal(self) -> bool:
        """True if this event type is a known strong retention indicator.

        Integration connects and API calls indicate deep product embedding,
        which significantly reduces churn probability.
        """
        return self.event_type in {
            EventType.INTEGRATION_CONNECT,
            EventType.API_CALL,
            EventType.MONITORING_RUN,
        }
Attributes
is_retention_signal property
is_retention_signal: bool

True if this event type is a known strong retention indicator.

Integration connects and API calls indicate deep product embedding, which significantly reduces churn probability.

Value Objects

src.domain.usage.value_objects

Value objects for the Usage domain.

Classes

EventType

Bases: StrEnum

Product event types tracked in usage_events.

integration_connect events are strong retention signals. Absence of monitoring_run events is an early churn indicator.

Source code in src/domain/usage/value_objects.py
class EventType(StrEnum):
    """Product event types tracked in usage_events.

    `integration_connect` events are strong retention signals.
    Absence of `monitoring_run` events is an early churn indicator.
    """

    EVIDENCE_UPLOAD = "evidence_upload"
    MONITORING_RUN = "monitoring_run"
    REPORT_VIEW = "report_view"
    USER_INVITE = "user_invite"
    INTEGRATION_CONNECT = "integration_connect"
    API_CALL = "api_call"
FeatureAdoptionScore dataclass

Composite 0–1 score reflecting breadth and depth of feature usage.

Scores below 0.2 combined with declining event frequency are the strongest leading indicators of churn in the first 90 days.

Source code in src/domain/usage/value_objects.py
@dataclass(frozen=True)
class FeatureAdoptionScore:
    """Composite 0–1 score reflecting breadth and depth of feature usage.

    Scores below 0.2 combined with declining event frequency are the
    strongest leading indicators of churn in the first 90 days.
    """

    value: float

    def __post_init__(self) -> None:
        if not (0.0 <= self.value <= 1.0):
            raise ValueError(f"FeatureAdoptionScore must be in [0, 1], got {self.value}")

    @property
    def is_low(self) -> bool:
        """True if adoption is critically low (below 0.2)."""
        return self.value < 0.2

    @property
    def label(self) -> str:
        if self.value < 0.2:
            return "critical"
        if self.value < 0.5:
            return "low"
        if self.value < 0.75:
            return "moderate"
        return "high"
Attributes
is_low property
is_low: bool

True if adoption is critically low (below 0.2).

Repository Interface

src.domain.usage.repository

UsageRepository – abstract port for the Usage domain.

Classes

UsageRepository

Bases: ABC

Port for retrieving usage events.

Source code in src/domain/usage/repository.py
class UsageRepository(ABC):
    """Port for retrieving usage events."""

    @abstractmethod
    def get_events_for_customer(
        self,
        customer_id: str,
        since: datetime | None = None,
    ) -> Sequence[UsageEvent]:
        """Retrieve all usage events for a customer, optionally filtered by date.

        Args:
            customer_id: The customer whose events to fetch.
            since: If provided, return only events after this UTC datetime.
        """
        ...

    @abstractmethod
    def get_event_count_last_n_days(self, customer_id: str, days: int) -> int:
        """Count events in the last N days.

        Used as a feature for churn model: event decay is a leading indicator.
        """
        ...
Functions
get_events_for_customer abstractmethod
get_events_for_customer(customer_id: str, since: datetime | None = None) -> Sequence[UsageEvent]

Retrieve all usage events for a customer, optionally filtered by date.

Parameters:

Name Type Description Default
customer_id str

The customer whose events to fetch.

required
since datetime | None

If provided, return only events after this UTC datetime.

None
Source code in src/domain/usage/repository.py
@abstractmethod
def get_events_for_customer(
    self,
    customer_id: str,
    since: datetime | None = None,
) -> Sequence[UsageEvent]:
    """Retrieve all usage events for a customer, optionally filtered by date.

    Args:
        customer_id: The customer whose events to fetch.
        since: If provided, return only events after this UTC datetime.
    """
    ...
get_event_count_last_n_days abstractmethod
get_event_count_last_n_days(customer_id: str, days: int) -> int

Count events in the last N days.

Used as a feature for churn model: event decay is a leading indicator.

Source code in src/domain/usage/repository.py
@abstractmethod
def get_event_count_last_n_days(self, customer_id: str, days: int) -> int:
    """Count events in the last N days.

    Used as a feature for churn model: event decay is a leading indicator.
    """
    ...