//! Domain events emitted when important state transitions occur. //! //! These are pure data — no I/O, no tokio deps. The transport //! (tokio::sync::broadcast) lives in `api`; domain only owns the schema. use uuid::Uuid; use crate::entities::{Channel, GeneratedSchedule, ScheduledSlot}; /// Events emitted by the application when important state changes occur. /// /// Must be `Clone + Send + 'static` for use as a `broadcast::channel` item. #[derive(Clone)] pub enum DomainEvent { BroadcastTransition { channel_id: Uuid, slot: ScheduledSlot, }, NoSignal { channel_id: Uuid, }, ScheduleGenerated { channel_id: Uuid, schedule: GeneratedSchedule, }, ChannelCreated { channel: Channel, }, ChannelUpdated { channel: Channel, }, ChannelDeleted { channel_id: Uuid, }, } #[cfg(test)] mod tests { use super::*; use uuid::Uuid; fn make_slot() -> crate::entities::ScheduledSlot { use crate::entities::{MediaItem, ScheduledSlot}; use crate::value_objects::{ContentType, MediaItemId}; use chrono::Utc; ScheduledSlot { id: Uuid::new_v4(), start_at: Utc::now(), end_at: Utc::now() + chrono::Duration::minutes(30), item: MediaItem { id: MediaItemId::new("test-item".to_string()), title: "Test Movie".to_string(), content_type: ContentType::Movie, duration_secs: 1800, description: None, genres: vec![], year: None, tags: vec![], series_name: None, season_number: None, episode_number: None, }, source_block_id: Uuid::new_v4(), } } #[test] fn broadcast_transition_carries_slot() { let channel_id = Uuid::new_v4(); let slot = make_slot(); let event = DomainEvent::BroadcastTransition { channel_id, slot: slot.clone() }; match event { DomainEvent::BroadcastTransition { channel_id: cid, slot: s } => { assert_eq!(cid, channel_id); assert_eq!(s.item.title, "Test Movie"); } _ => panic!("wrong variant"), } } #[test] fn no_signal_carries_channel_id() { let channel_id = Uuid::new_v4(); let event = DomainEvent::NoSignal { channel_id }; match event { DomainEvent::NoSignal { channel_id: cid } => assert_eq!(cid, channel_id), _ => panic!("wrong variant"), } } #[test] fn schedule_generated_carries_metadata() { use crate::entities::GeneratedSchedule; use chrono::Utc; let channel_id = Uuid::new_v4(); let schedule = GeneratedSchedule { id: Uuid::new_v4(), channel_id, valid_from: Utc::now(), valid_until: Utc::now() + chrono::Duration::hours(48), generation: 3, slots: vec![], }; let event = DomainEvent::ScheduleGenerated { channel_id, schedule: schedule.clone() }; match event { DomainEvent::ScheduleGenerated { schedule: s, .. } => { assert_eq!(s.generation, 3); assert_eq!(s.slots.len(), 0); } _ => panic!("wrong variant"), } } }