domain: add domain errors, events, and services module scaffold

This commit is contained in:
2026-05-31 03:16:40 +02:00
parent 3571c94bec
commit aa432e6594
10 changed files with 74 additions and 4 deletions

View File

@@ -6,8 +6,12 @@ pub enum DomainError {
Conflict(String), Conflict(String),
#[error("Unauthorized: {0}")] #[error("Unauthorized: {0}")]
Unauthorized(String), Unauthorized(String),
#[error("Forbidden: {0}")]
Forbidden(String),
#[error("Validation error: {0}")] #[error("Validation error: {0}")]
Validation(String), Validation(String),
#[error("Quota exceeded: {0}")]
QuotaExceeded(String),
#[error("Internal error: {0}")] #[error("Internal error: {0}")]
Internal(String), Internal(String),
} }

View File

@@ -1,7 +1,49 @@
use uuid::Uuid; use crate::value_objects::{DateTimeStamp, SystemId};
#[derive(Debug, Clone)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum DomainEvent { pub enum DomainEvent {
UserRegistered { user_id: Uuid }, AssetIngested {
UserLoggedIn { user_id: Uuid }, asset_id: SystemId,
owner_user_id: SystemId,
timestamp: DateTimeStamp,
},
MetadataUpdated {
asset_id: SystemId,
updated_by: SystemId,
timestamp: DateTimeStamp,
},
AssetDeleted {
asset_id: SystemId,
deleted_by: SystemId,
timestamp: DateTimeStamp,
},
ShareCreated {
scope_id: SystemId,
shareable_id: SystemId,
created_by: SystemId,
timestamp: DateTimeStamp,
},
ShareRevoked {
scope_id: SystemId,
revoked_by: SystemId,
timestamp: DateTimeStamp,
},
SidecarSyncRequested {
asset_id: SystemId,
timestamp: DateTimeStamp,
},
JobEnqueued {
job_id: SystemId,
job_type: String,
timestamp: DateTimeStamp,
},
JobCompleted {
job_id: SystemId,
timestamp: DateTimeStamp,
},
JobFailed {
job_id: SystemId,
error: String,
timestamp: DateTimeStamp,
},
} }

View File

@@ -2,4 +2,5 @@ pub mod entities;
pub mod errors; pub mod errors;
pub mod events; pub mod events;
pub mod ports; pub mod ports;
pub mod services;
pub mod value_objects; pub mod value_objects;

View File

@@ -0,0 +1 @@
// Metadata resolver — will be implemented in Task 9

View File

@@ -0,0 +1,3 @@
pub mod metadata_resolver;
pub mod permission_service;
pub mod quota_checker;

View File

@@ -0,0 +1 @@
// Permission service — will be implemented in Task 5

View File

@@ -0,0 +1 @@
// Quota checker — will be implemented in Task 7

View File

@@ -1 +1,2 @@
mod events;
mod value_objects; mod value_objects;

View File

@@ -0,0 +1,14 @@
use domain::events::DomainEvent;
use domain::value_objects::{DateTimeStamp, SystemId};
#[test]
fn asset_ingested_serde_roundtrip() {
let event = DomainEvent::AssetIngested {
asset_id: SystemId::new(),
owner_user_id: SystemId::new(),
timestamp: DateTimeStamp::now(),
};
let json = serde_json::to_string(&event).unwrap();
let back: DomainEvent = serde_json::from_str(&json).unwrap();
assert!(matches!(back, DomainEvent::AssetIngested { .. }));
}

View File

@@ -14,7 +14,9 @@ impl IntoResponse for AppError {
DomainError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()), DomainError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
DomainError::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()), DomainError::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()),
DomainError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg.clone()), DomainError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg.clone()),
DomainError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
DomainError::Validation(msg) => (StatusCode::UNPROCESSABLE_ENTITY, msg.clone()), DomainError::Validation(msg) => (StatusCode::UNPROCESSABLE_ENTITY, msg.clone()),
DomainError::QuotaExceeded(msg) => (StatusCode::PAYLOAD_TOO_LARGE, msg.clone()),
DomainError::Internal(msg) => { DomainError::Internal(msg) => {
tracing::error!("Internal error: {msg}"); tracing::error!("Internal error: {msg}");
(StatusCode::INTERNAL_SERVER_ERROR, "Internal server error".to_string()) (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error".to_string())