//! Repository ports (traits) //! //! These traits define the interface for data persistence. //! Implementations live in the infra layer. use async_trait::async_trait; use chrono::DateTime; use chrono::Utc; use uuid::Uuid; use crate::entities::{Channel, GeneratedSchedule, PlaybackRecord, User}; use crate::errors::DomainResult; use crate::value_objects::{ChannelId, UserId}; /// Repository port for User persistence #[async_trait] pub trait UserRepository: Send + Sync { /// Find a user by their internal ID async fn find_by_id(&self, id: Uuid) -> DomainResult>; /// Find a user by their OIDC subject (used for authentication) async fn find_by_subject(&self, subject: &str) -> DomainResult>; /// Find a user by their email async fn find_by_email(&self, email: &str) -> DomainResult>; /// Save a new user or update an existing one async fn save(&self, user: &User) -> DomainResult<()>; /// Delete a user by their ID async fn delete(&self, id: Uuid) -> DomainResult<()>; } /// Repository port for `Channel` persistence. #[async_trait] pub trait ChannelRepository: Send + Sync { async fn find_by_id(&self, id: ChannelId) -> DomainResult>; async fn find_by_owner(&self, owner_id: UserId) -> DomainResult>; /// Insert or update a channel. async fn save(&self, channel: &Channel) -> DomainResult<()>; async fn delete(&self, id: ChannelId) -> DomainResult<()>; } /// Repository port for `GeneratedSchedule` and `PlaybackRecord` persistence. #[async_trait] pub trait ScheduleRepository: Send + Sync { /// Find the schedule whose `[valid_from, valid_until)` window contains `at`. async fn find_active( &self, channel_id: ChannelId, at: DateTime, ) -> DomainResult>; /// Find the most recently generated schedule for a channel. /// Used to derive the next generation number. async fn find_latest( &self, channel_id: ChannelId, ) -> DomainResult>; /// Insert or replace a generated schedule. async fn save(&self, schedule: &GeneratedSchedule) -> DomainResult<()>; /// All playback records for a channel, used by the recycle policy engine. async fn find_playback_history( &self, channel_id: ChannelId, ) -> DomainResult>; async fn save_playback_record(&self, record: &PlaybackRecord) -> DomainResult<()>; }