feat: event infrastructure — payload, transport, NATS adapter

- EventPublisher now takes &DomainEvent (11 call sites + 3 impls updated)
- EventEnvelope + EventConsumer port in domain
- event-payload: serializable DomainEvent mirror with subject routing
- event-transport: generic Transport/MessageSource traits, publisher/consumer adapters
- adapters-nats: JetStream publish + durable pull consumer
This commit is contained in:
2026-05-31 11:50:16 +02:00
parent dacfc3d453
commit 0e9911ebfc
24 changed files with 1294 additions and 21 deletions

View File

@@ -69,7 +69,7 @@ impl RegisterAssetHandler {
};
self.event_pub
.publish(DomainEvent::AssetIngested {
.publish(&DomainEvent::AssetIngested {
asset_id: asset.asset_id,
owner_user_id: asset.owner_user_id,
timestamp: DateTimeStamp::now(),

View File

@@ -43,7 +43,7 @@ impl UpdateMetadataHandler {
self.metadata_repo.save(&metadata).await?;
self.event_pub
.publish(DomainEvent::MetadataUpdated {
.publish(&DomainEvent::MetadataUpdated {
asset_id: cmd.asset_id,
updated_by: cmd.user_id,
timestamp: DateTimeStamp::now(),

View File

@@ -49,7 +49,7 @@ impl CompleteJobHandler {
self.batch_repo.save(&batch).await?;
}
self.event_pub
.publish(DomainEvent::JobCompleted {
.publish(&DomainEvent::JobCompleted {
job_id: job.job_id,
timestamp: DateTimeStamp::now(),
})

View File

@@ -39,7 +39,7 @@ impl EnqueueJobHandler {
}
self.job_repo.save(&job).await?;
self.event_pub
.publish(DomainEvent::JobEnqueued {
.publish(&DomainEvent::JobEnqueued {
job_id: job.job_id,
job_type: format!("{:?}", cmd.job_type),
timestamp: DateTimeStamp::now(),

View File

@@ -77,7 +77,7 @@ impl ExecutePipelineHandler {
self.job_repo.save(&job).await?;
self.update_batch_on_complete(&job).await?;
self.event_pub
.publish(DomainEvent::JobCompleted {
.publish(&DomainEvent::JobCompleted {
job_id: job.job_id,
timestamp: DateTimeStamp::now(),
})
@@ -89,7 +89,7 @@ impl ExecutePipelineHandler {
self.job_repo.save(&job).await?;
self.update_batch_on_fail(&job).await?;
self.event_pub
.publish(DomainEvent::JobFailed {
.publish(&DomainEvent::JobFailed {
job_id: job.job_id,
error: error_msg,
timestamp: DateTimeStamp::now(),

View File

@@ -49,7 +49,7 @@ impl FailJobHandler {
self.batch_repo.save(&batch).await?;
}
self.event_pub
.publish(DomainEvent::JobFailed {
.publish(&DomainEvent::JobFailed {
job_id: job.job_id,
error: cmd.error,
timestamp: DateTimeStamp::now(),
@@ -57,7 +57,7 @@ impl FailJobHandler {
.await?;
} else if job.status == JobStatus::Queued {
self.event_pub
.publish(DomainEvent::JobEnqueued {
.publish(&DomainEvent::JobEnqueued {
job_id: job.job_id,
job_type: format!("{:?}", job.job_type),
timestamp: DateTimeStamp::now(),

View File

@@ -36,7 +36,7 @@ impl RevokeShareHandler {
self.share_repo.delete_scope(&cmd.scope_id).await?;
self.event_pub
.publish(DomainEvent::ShareRevoked {
.publish(&DomainEvent::ShareRevoked {
scope_id: cmd.scope_id,
revoked_by: cmd.revoked_by,
timestamp: DateTimeStamp::now(),

View File

@@ -51,7 +51,7 @@ impl ShareResourceHandler {
self.share_repo.save_target(&target).await?;
self.event_pub
.publish(DomainEvent::ShareCreated {
.publish(&DomainEvent::ShareCreated {
scope_id: scope.scope_id,
shareable_id: cmd.shareable_id,
created_by: cmd.created_by,

View File

@@ -145,7 +145,7 @@ impl IngestAssetHandler {
self.ledger_repo.record(&entry).await?;
self.event_pub
.publish(DomainEvent::AssetIngested {
.publish(&DomainEvent::AssetIngested {
asset_id: asset.asset_id,
owner_user_id: cmd.uploader_id,
timestamp: DateTimeStamp::now(),

View File

@@ -37,8 +37,8 @@ impl Default for StubEventPublisher {
#[async_trait]
impl EventPublisher for StubEventPublisher {
async fn publish(&self, event: DomainEvent) -> Result<(), DomainError> {
self.events.lock().await.push(event);
async fn publish(&self, event: &DomainEvent) -> Result<(), DomainError> {
self.events.lock().await.push(event.clone());
Ok(())
}
}