use chrono::{DateTime, Utc};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ActorName {
pub name: String,
pub org: Option<String>,
pub node: Option<String>,
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct EventContext {
pub org_id: Option<String>,
pub plan_id: Option<i64>,
pub task_id: Option<i64>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DomainEvent {
pub actor: ActorName,
pub kind: EventKind,
pub timestamp: DateTime<Utc>,
pub context: EventContext,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum EventKind {
PlanCreated {
plan_id: i64,
name: String,
},
TaskAssigned {
task_id: i64,
agent: String,
org: String,
},
TaskCompleted {
task_id: i64,
},
PlanCompleted {
plan_id: i64,
name: String,
},
WaveCompleted {
wave_id: i64,
plan_id: i64,
},
MessageSent {
from: String,
to: String,
preview: String,
},
DelegationStarted {
from_org: String,
to_org: String,
task: String,
},
DelegationCompleted {
delegation_id: String,
plan_id: i64,
peer_name: String,
},
AgentOnline {
name: String,
org: String,
node: String,
},
AgentOffline {
name: String,
reason: String,
},
HealthDegraded {
module: String,
reason: String,
},
BudgetAlert {
org: String,
spent: f64,
limit: f64,
},
ExtensionLoaded {
id: String,
version: String,
},
FilesClaimed {
task_id: i64,
agent: String,
file_paths: Vec<String>,
},
FilesReleased {
task_id: i64,
file_paths: Vec<String>,
},
OrgAsked {
org_id: String,
question: String,
intent: String,
escalated: bool,
latency_ms: u64,
},
}
#[derive(Debug, Clone)]
pub struct EventFilter {
pub kind_prefix: Option<String>,
pub org: Option<String>,
pub actor: Option<String>,
}
pub trait DomainEventSink: Send + Sync {
fn emit(&self, event: DomainEvent);
}
pub fn make_event(actor_name: &str, kind: EventKind, context: EventContext) -> DomainEvent {
DomainEvent {
actor: ActorName {
name: actor_name.to_string(),
org: None,
node: None,
},
kind,
timestamp: Utc::now(),
context,
}
}