From 4e78fd83349c95711cdee5acc56f248f81ebd25c Mon Sep 17 00:00:00 2001 From: Mikkel Thestrup Date: Mon, 26 Jan 2026 21:27:59 +0100 Subject: feat(domain): add core domain models for calendar application Implement domain-driven design layer with entities, value objects, and repository traits for calendar management system. Domain Entities: - Calendar: manages calendar lifecycle and archival state - Event: handles single occurrence events with cancellation support - RecurringEvent: supports recurring events with exception handling - RecurrenceException: manages modifications to specific occurrences Value Objects: - TimeRange: enforces valid start/end time constraints - EventColor: type-safe color representation - Frequency: recurrence frequency enumeration (daily/weekly/monthly/yearly) - RecurrenceRule: encapsulates recurrence pattern logic - CalendarId & EventId: essentially just a wrapper Repository Traits: - CalendarRepository: calendar persistence interface - EventRepository: event querying and persistence with overlap detection - RecurrenceRepository: recurring event management Key Design Decisions: - Use Uuid for entity IDs (type safety, performance) - Encapsulate business logic within entities - Immutable value objects with validation - Repository pattern for infrastructure abstraction - Clear separation of concerns between domain and persistence layers All entities include timestamp tracking and follow builder pattern for construction with validation at domain boundaries. --- src/domain/repository.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/domain/repository.rs (limited to 'src/domain/repository.rs') diff --git a/src/domain/repository.rs b/src/domain/repository.rs new file mode 100644 index 0000000..00b3974 --- /dev/null +++ b/src/domain/repository.rs @@ -0,0 +1,45 @@ +use async_trait::async_trait; +use super::{ + calendar::Calendar, + event::Event, + recurrence::RecurringEvent, + value_objects::{CalendarId, EventId, TimeRange}, +}; + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum RepositoryError { + #[error("Entity not found")] + NotFound, + + #[error("Database error: {0}")] + DatabaseError(String), + + #[error("Constraint violation: {0}")] + ConstraintViolation(String), +} + +#[async_trait] +pub trait CalendarRepository: Send + Sync { + async fn save(&self, calendar: &Calendar) -> Result<()>; + async fn find_by_id(&self, id: &CalendarId) -> Result>; + async fn find_all_active(&self) -> Result>; + async fn delete(&self, id: &CalendarId) -> Result<()>; +} + +#[async_trait] +pub trait EventRepository: Send + Sync { + async fn save(&self, event: &Event) -> Result<()>; + async fn find_by_id(&self, id: &EventId) -> Result>; + async fn find_by_calendar(&self, calendar_id: &CalendarId) -> Result>; + async fn find_in_range(&self, calendar_id: &CalendarId, range: &TimeRange) -> Result>; + async fn delete(&self, id: &EventId) -> Result<()>; +} + +#[async_trait] +pub trait RecurringEventRepository: Send + Sync { + async fn save(&self, event: &RecurringEvent) -> Result<()>; + async fn find_by_calendar(&self, calendar_id: &CalendarId) -> Result>; + async fn delete(&self, id: &str) -> Result<()>; +} -- cgit v1.2.3-70-g09d2