//! `OutboxWriter` — minimal trait the orchestrator-core sync-HTTP path //! uses to enqueue rows into the universal trigger outbox. The //! manager-core `PostgresOutboxRepo` implements this in addition to //! its richer `OutboxRepo` surface; defining it here lets //! orchestrator-core depend on the trait without pulling in //! manager-core (which would invert the dependency arrow). use async_trait::async_trait; use serde::{Deserialize, Serialize}; use thiserror::Error; use uuid::Uuid; use crate::{AdminUserId, AppId, ExecutionId, ScriptId}; /// What the orchestrator hands to the outbox when it ingests an HTTP /// request. Carries enough for the dispatcher to reconstruct the /// `ExecRequest` end-to-end. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NewHttpOutbox { pub app_id: AppId, /// `routes.id` of the matched route. Discriminated against /// `triggers.id` by `source_kind = 'http'` on the outbox row. pub route_id: Uuid, /// Pre-resolved script so the dispatcher doesn't re-look it up. pub script_id: ScriptId, /// `Some(inbox_id)` for sync HTTP (the orchestrator awaits a /// channel keyed on this id). `None` for `dispatch_mode = async` /// — dispatcher fires-and-forgets, no reply path. pub reply_to: Option, /// Serialized `HttpDispatchPayload` (defined below) — everything /// the dispatcher needs to reconstruct an `ExecRequest`. pub payload: serde_json::Value, /// The principal that ingressed the HTTP request (Some when /// authenticated, None for public). Forensic only; the script /// executes as the route's app principal model, not this. pub origin_principal: Option, /// `0` for direct HTTP ingress; the dispatcher will increment /// for any further fan-out triggered by the script. pub trigger_depth: u32, pub root_execution_id: Option, } /// The shape the orchestrator serializes into `NewHttpOutbox.payload` /// (the JSONB column). Mirrored on the dispatcher side so it can /// rebuild an `ExecRequest`. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HttpDispatchPayload { pub script_name: String, pub path: String, pub method: String, pub headers: std::collections::BTreeMap, pub body: serde_json::Value, pub params: std::collections::BTreeMap, pub query: std::collections::BTreeMap, pub rest: String, pub timeout_seconds: u32, } #[async_trait] pub trait OutboxWriter: Send + Sync { /// Insert a sync- or async-HTTP outbox row. Returns the row's id /// — the orchestrator stores it locally for forensics and to /// correlate `abandoned_executions` rows when the dispatcher's /// inbox delivery fails. async fn enqueue_http(&self, row: NewHttpOutbox) -> Result; } #[derive(Debug, Error)] pub enum OutboxWriterError { #[error("outbox write failed: {0}")] Backend(String), }