use std::fmt; use std::str::FromStr; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// Defines a strongly-typed UUID wrapper so ids of different entities can /// never be swapped for one another at compile time. New ids are UUIDv7 so /// they sort by creation time in Postgres indexes. macro_rules! define_id { ($(#[$doc:meta])* $name:ident) => { $(#[$doc])* #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, )] #[serde(transparent)] pub struct $name(Uuid); impl $name { #[allow(clippy::new_without_default)] pub fn new() -> Self { Self(Uuid::now_v7()) } pub fn as_uuid(&self) -> Uuid { self.0 } } impl From for $name { fn from(value: Uuid) -> Self { Self(value) } } impl fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl FromStr for $name { type Err = uuid::Error; fn from_str(s: &str) -> Result { Ok(Self(Uuid::parse_str(s)?)) } } }; } define_id!( /// A tenant workspace (team). WorkspaceId ); define_id!( /// A human member of a workspace. UserId ); define_id!( /// An AI agent ("claw"). AgentId ); define_id!( /// A chat session between humans and one agent. SessionId ); define_id!( /// A single message within a session. MessageId ); define_id!( /// A connected fleet node (a user's local-hardware host running the daemon). NodeId ); define_id!( /// A user-driven workflow composed of one or more mission_phases. /// Unifies research_topics + loops behind a single tier (Slice 1 /// of the missions unification). MissionId ); define_id!( /// A single phase within a mission (research | coding | benchmark | /// security_scan). Ordered via `order_idx` on the row. MissionPhaseId ); define_id!( /// A typed unit of work within a phase — e.g. an INT-XX item, a /// CVE finding, a research outcome iteration. MissionTaskId ); define_id!( /// A file artifact produced by a mission phase — MD, PDF, /// benchmark result, security report, code diff. MissionArtifactId );