// @generated
// This file is @generated by prost-build.
// ─── Messages ───────────────────────────────────────────────────────────────

/// Request to submit a user action on a delivered message.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SubmitActionRequest {
    /// ID of the delivery the user is acting on.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub delivery_id: ::prost::alloc::string::String,
    /// ID of the action being performed (matches MessageAction.id).
    /// Constraints: Max length 100 characters.
    #[prost(string, tag="2")]
    pub action_id: ::prost::alloc::string::String,
    /// Optional action-specific payload (e.g. poll response data). Empty for ACK.
    /// Constraints: Max size 10000 bytes.
    #[prost(bytes="vec", tag="3")]
    pub payload: ::prost::alloc::vec::Vec<u8>,
}
/// Response after submitting an action.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SubmitActionResponse {
    /// Whether the action was successfully recorded and forwarded to the workflow.
    #[prost(bool, tag="1")]
    pub success: bool,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A single channel dispatch event for the audit trail. Append-only; the
/// receiver enforces idempotency on terminal states via a partial unique index
/// on (campaign_id, recipient_user_id, channel, step_kind).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ChannelEvent {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub campaign_id: ::prost::alloc::string::String,
    #[prost(string, tag="3")]
    pub recipient_user_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="4")]
    pub channel: i32,
    #[prost(enumeration="ChannelStepKind", tag="5")]
    pub step_kind: i32,
    #[prost(enumeration="ChannelEventStatus", tag="6")]
    pub status: i32,
    /// Set only when status = SKIPPED. UNSPECIFIED in all other cases.
    #[prost(enumeration="ChannelSkipReason", tag="7")]
    pub skip_reason: i32,
    /// Provider's identifier for this dispatch. Empty for SKIPPED events.
    #[prost(string, tag="8")]
    pub provider_message_id: ::prost::alloc::string::String,
    /// Cost in micros (1/1000000 of a USD). Zero for absorbed channels.
    /// Negative is invalid.
    #[prost(int64, tag="9")]
    pub cost_micros: i64,
    /// Free-form provider error payload on FAILED. JSON-encoded; opaque to
    /// the platform.
    #[prost(string, tag="10")]
    pub metadata_json: ::prost::alloc::string::String,
    #[prost(message, optional, tag="11")]
    pub occurred_at: ::core::option::Option<::prost_types::Timestamp>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RecordChannelEventRequest {
    #[prost(message, optional, tag="1")]
    pub event: ::core::option::Option<ChannelEvent>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RecordChannelEventResponse {
    /// True if the row was inserted. False if rejected as a duplicate of an
    /// existing terminal-state row.
    #[prost(bool, tag="1")]
    pub accepted: bool,
    /// "duplicate" when accepted=false and the partial unique index rejected
    /// the insert. Empty when accepted=true.
    #[prost(string, tag="2")]
    pub reason: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RecordChannelEventBatchRequest {
    #[prost(message, repeated, tag="1")]
    pub events: ::prost::alloc::vec::Vec<ChannelEvent>,
}
/// Per-event result inside a batch. Order matches the request's events list.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RecordChannelEventBatchResult {
    #[prost(bool, tag="1")]
    pub accepted: bool,
    #[prost(string, tag="2")]
    pub reason: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RecordChannelEventBatchResponse {
    #[prost(message, repeated, tag="1")]
    pub results: ::prost::alloc::vec::Vec<RecordChannelEventBatchResult>,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Third-party notification channel for reminder + escalation dispatch.
///
/// Push is intentionally NOT in this enum. Push is the primary channel; it
/// always fires alongside any third-party channels. The third-party channels
/// here are additive. Channels carry only a deeplink notification — message
/// content stays in the platform.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ChannelName {
    Unspecified = 0,
    Email = 1,
    Webhook = 2,
    Telegram = 3,
    Slack = 4,
    Sms = 5,
    Whatsapp = 6,
    MicrosoftTeams = 7,
    Line = 8,
}
impl ChannelName {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CHANNEL_NAME_UNSPECIFIED",
            Self::Email => "CHANNEL_NAME_EMAIL",
            Self::Webhook => "CHANNEL_NAME_WEBHOOK",
            Self::Telegram => "CHANNEL_NAME_TELEGRAM",
            Self::Slack => "CHANNEL_NAME_SLACK",
            Self::Sms => "CHANNEL_NAME_SMS",
            Self::Whatsapp => "CHANNEL_NAME_WHATSAPP",
            Self::MicrosoftTeams => "CHANNEL_NAME_MICROSOFT_TEAMS",
            Self::Line => "CHANNEL_NAME_LINE",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CHANNEL_NAME_UNSPECIFIED" => Some(Self::Unspecified),
            "CHANNEL_NAME_EMAIL" => Some(Self::Email),
            "CHANNEL_NAME_WEBHOOK" => Some(Self::Webhook),
            "CHANNEL_NAME_TELEGRAM" => Some(Self::Telegram),
            "CHANNEL_NAME_SLACK" => Some(Self::Slack),
            "CHANNEL_NAME_SMS" => Some(Self::Sms),
            "CHANNEL_NAME_WHATSAPP" => Some(Self::Whatsapp),
            "CHANNEL_NAME_MICROSOFT_TEAMS" => Some(Self::MicrosoftTeams),
            "CHANNEL_NAME_LINE" => Some(Self::Line),
            _ => None,
        }
    }
}
/// Workflow step kind that triggered the channel dispatch. Different step
/// kinds for the same (campaign, recipient, channel) tuple are treated as
/// distinct dispatch events for idempotency purposes.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ChannelStepKind {
    Unspecified = 0,
    Reminder = 1,
    Escalation = 2,
}
impl ChannelStepKind {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CHANNEL_STEP_KIND_UNSPECIFIED",
            Self::Reminder => "CHANNEL_STEP_KIND_REMINDER",
            Self::Escalation => "CHANNEL_STEP_KIND_ESCALATION",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CHANNEL_STEP_KIND_UNSPECIFIED" => Some(Self::Unspecified),
            "CHANNEL_STEP_KIND_REMINDER" => Some(Self::Reminder),
            "CHANNEL_STEP_KIND_ESCALATION" => Some(Self::Escalation),
            _ => None,
        }
    }
}
/// Status of a channel dispatch attempt. The table is append-only — each state
/// transition (e.g. SENT → DELIVERED via provider webhook) is its own row keyed
/// off provider_message_id, not an UPDATE.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ChannelEventStatus {
    Unspecified = 0,
    Sent = 1,
    Delivered = 2,
    Opened = 3,
    Clicked = 4,
    Bounced = 5,
    Failed = 6,
    Skipped = 7,
}
impl ChannelEventStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CHANNEL_EVENT_STATUS_UNSPECIFIED",
            Self::Sent => "CHANNEL_EVENT_STATUS_SENT",
            Self::Delivered => "CHANNEL_EVENT_STATUS_DELIVERED",
            Self::Opened => "CHANNEL_EVENT_STATUS_OPENED",
            Self::Clicked => "CHANNEL_EVENT_STATUS_CLICKED",
            Self::Bounced => "CHANNEL_EVENT_STATUS_BOUNCED",
            Self::Failed => "CHANNEL_EVENT_STATUS_FAILED",
            Self::Skipped => "CHANNEL_EVENT_STATUS_SKIPPED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CHANNEL_EVENT_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "CHANNEL_EVENT_STATUS_SENT" => Some(Self::Sent),
            "CHANNEL_EVENT_STATUS_DELIVERED" => Some(Self::Delivered),
            "CHANNEL_EVENT_STATUS_OPENED" => Some(Self::Opened),
            "CHANNEL_EVENT_STATUS_CLICKED" => Some(Self::Clicked),
            "CHANNEL_EVENT_STATUS_BOUNCED" => Some(Self::Bounced),
            "CHANNEL_EVENT_STATUS_FAILED" => Some(Self::Failed),
            "CHANNEL_EVENT_STATUS_SKIPPED" => Some(Self::Skipped),
            _ => None,
        }
    }
}
/// Reason a dispatch was SKIPPED rather than attempted. Set when status is
/// CHANNEL_EVENT_STATUS_SKIPPED; UNSPECIFIED otherwise.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ChannelSkipReason {
    Unspecified = 0,
    OptedOut = 1,
    RegionBlocked = 2,
    CostCapExceeded = 3,
    NoIdentifier = 4,
}
impl ChannelSkipReason {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CHANNEL_SKIP_REASON_UNSPECIFIED",
            Self::OptedOut => "CHANNEL_SKIP_REASON_OPTED_OUT",
            Self::RegionBlocked => "CHANNEL_SKIP_REASON_REGION_BLOCKED",
            Self::CostCapExceeded => "CHANNEL_SKIP_REASON_COST_CAP_EXCEEDED",
            Self::NoIdentifier => "CHANNEL_SKIP_REASON_NO_IDENTIFIER",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CHANNEL_SKIP_REASON_UNSPECIFIED" => Some(Self::Unspecified),
            "CHANNEL_SKIP_REASON_OPTED_OUT" => Some(Self::OptedOut),
            "CHANNEL_SKIP_REASON_REGION_BLOCKED" => Some(Self::RegionBlocked),
            "CHANNEL_SKIP_REASON_COST_CAP_EXCEEDED" => Some(Self::CostCapExceeded),
            "CHANNEL_SKIP_REASON_NO_IDENTIFIER" => Some(Self::NoIdentifier),
            _ => None,
        }
    }
}
/// A named role within an organization with a set of permissions.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Role {
    /// Unique identifier for the role.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// URL-safe slug (unique within the organization, e.g. "admin", "manager").
    #[prost(string, tag="2")]
    pub slug: ::prost::alloc::string::String,
    /// Human-readable display name.
    #[prost(string, tag="3")]
    pub name: ::prost::alloc::string::String,
    /// Whether this role was seeded by the system on organization creation.
    #[prost(bool, tag="4")]
    pub is_default: bool,
    /// Permissions granted to users with this role.
    #[prost(enumeration="Permission", repeated, tag="5")]
    pub permissions: ::prost::alloc::vec::Vec<i32>,
    /// Whether this role is system-managed and immutable (e.g. super_admin).
    #[prost(bool, tag="6")]
    pub is_system: bool,
}
// ─── Pagination ─────────────────────────────────────────────────────────────

/// Cursor-based pagination parameters for list requests.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Pagination {
    /// Maximum number of items to return per page.
    #[prost(int32, tag="1")]
    pub page_size: i32,
    /// Opaque token from a previous response to fetch the next page.
    #[prost(string, tag="2")]
    pub page_token: ::prost::alloc::string::String,
}
/// Pagination metadata returned alongside list responses.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct PaginationMeta {
    /// Token to pass in the next request to get the following page. Empty if no more pages.
    #[prost(string, tag="1")]
    pub next_page_token: ::prost::alloc::string::String,
    /// Total number of items matching the query (across all pages).
    #[prost(int32, tag="2")]
    pub total_count: i32,
}
// ─── Message & Action Model ─────────────────────────────────────────────────

/// An action button attached to a message that a recipient can interact with.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct MessageAction {
    /// Unique identifier for this action within the message.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// The type of action (e.g. ACK).
    #[prost(enumeration="ActionType", tag="2")]
    pub r#type: i32,
    /// Display label shown to the recipient (e.g. "Got it").
    /// Constraints: Max length 50 characters.
    #[prost(string, tag="3")]
    pub label: ::prost::alloc::string::String,
}
/// Canonical message type used across rendering, inbox, and delivery.
/// Represents the fully rendered content delivered to a recipient.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Message {
    /// SHA-256 hash of the rendered content, used as a content-addressable ID.
    #[prost(string, tag="1")]
    pub content_id: ::prost::alloc::string::String,
    /// ID of the campaign this message belongs to.
    #[prost(string, tag="2")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Display name of the sender (e.g. organization or campaign name).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="3")]
    pub sender_name: ::prost::alloc::string::String,
    /// Short one-line summary shown in notification banners.
    /// Constraints: Max length 500 characters.
    #[prost(string, tag="4")]
    pub summary: ::prost::alloc::string::String,
    /// Preview text shown in inbox list views.
    /// Constraints: Max length 500 characters.
    #[prost(string, tag="5")]
    pub preview: ::prost::alloc::string::String,
    /// Full message body content.
    /// Constraints: Max length 100000 characters.
    #[prost(string, tag="6")]
    pub body: ::prost::alloc::string::String,
    /// Whether this message requires immediate attention from the recipient.
    #[prost(bool, tag="7")]
    pub critical: bool,
    /// Actions available to the recipient (e.g. acknowledge button).
    #[prost(message, repeated, tag="8")]
    pub actions: ::prost::alloc::vec::Vec<MessageAction>,
    /// Timestamp when the message was created.
    #[prost(message, optional, tag="9")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// User-facing title of the message (resolved from campaign or template).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="10")]
    pub title: ::prost::alloc::string::String,
}
// ─── Workflow Definition Model ──────────────────────────────────────────────

/// A data-driven workflow represented as a directed acyclic graph (DAG) of steps.
/// Defines the automation logic for a campaign's lifecycle.
/// Backend MUST validate the graph is a DAG (no cycles) before execution.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WorkflowDefinition {
    /// Ordered list of steps in the workflow DAG.
    /// Constraints: Max 100 steps. Backend MUST validate the graph is a DAG (no cycles).
    #[prost(message, repeated, tag="1")]
    pub steps: ::prost::alloc::vec::Vec<WorkflowStep>,
}
/// A single step in a workflow DAG with typed configuration and transitions.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WorkflowStep {
    /// Unique identifier for this step within the workflow.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// The type of operation this step performs.
    #[prost(enumeration="StepType", tag="2")]
    pub r#type: i32,
    /// Map of outcome labels to the next step ID (e.g. "completed" -> "step_3").
    /// Constraints: Max 10 transitions per step.
    #[prost(map="string, string", tag="7")]
    pub transitions: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    /// Step-specific configuration — exactly one must be set, matching the type.
    #[prost(oneof="workflow_step::Config", tags="3, 4, 5, 6, 8")]
    pub config: ::core::option::Option<workflow_step::Config>,
}
/// Nested message and enum types in `WorkflowStep`.
pub mod workflow_step {
    /// Step-specific configuration — exactly one must be set, matching the type.
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Config {
        /// Configuration for SEND_NOTIFICATION steps.
        #[prost(message, tag="3")]
        SendNotification(super::SendNotificationConfig),
        /// Configuration for DEADLINE_CHECK steps.
        #[prost(message, tag="4")]
        DeadlineCheck(super::DeadlineCheckConfig),
        /// Configuration for SEND_REMINDER steps.
        #[prost(message, tag="5")]
        SendReminder(super::SendReminderConfig),
        /// Configuration for CALL_WEBHOOK steps.
        #[prost(message, tag="6")]
        CallWebhook(super::CallWebhookConfig),
        /// Configuration for STEP_TYPE_ESCALATE steps.
        #[prost(message, tag="8")]
        EscalateConfig(super::EscalateConfig),
    }
}
/// Configuration for a step that sends the initial push notification.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SendNotificationConfig {
    /// Notification delivery type (e.g. "push").
    /// Constraints: Accepted values: "push". Max length 50 characters.
    #[prost(string, tag="1")]
    pub r#type: ::prost::alloc::string::String,
    /// ID of the template to use for this step's notification.
    /// Empty falls back to campaign-level template_id.
    /// Constraints: Max length 36 characters (UUID).
    #[prost(string, tag="2")]
    pub template_id: ::prost::alloc::string::String,
    /// Pinned template version for this step.
    /// 0 falls back to campaign-level template_version.
    #[prost(int32, tag="3")]
    pub template_version: i32,
    /// Display label for the action button (e.g. "Acknowledge", "Got it").
    /// Constraints: Max length 50 characters.
    #[prost(string, tag="4")]
    pub action_label: ::prost::alloc::string::String,
    /// Action type for this step's message button.
    #[prost(enumeration="ActionType", tag="5")]
    pub action_type: i32,
    /// Values for custom-sourced template variables specific to this step.
    /// Constraints: Max 100 entries. Key max length 100 characters, value max length 10000 characters.
    #[prost(map="string, string", tag="6")]
    pub custom_variables: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// Configuration for a deadline-based timer step that sleeps for a configured
/// delay before proceeding. Acknowledgments happen independently at the delivery
/// level and are evaluated by subsequent steps (e.g. SEND_REMINDER).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeadlineCheckConfig {
    /// Duration string for the deadline delay (e.g. "120h", "72h").
    /// Constraints: Valid range 1m to 8760h (1 year).
    #[prost(string, tag="1")]
    pub delay: ::prost::alloc::string::String,
}
/// Configuration for a step that sends a one-time reminder to non-responsive recipients.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SendReminderConfig {
    /// Reminder delivery type (e.g. "push").
    /// Constraints: Accepted values: "push". Max length 50 characters.
    #[prost(string, tag="1")]
    pub r#type: ::prost::alloc::string::String,
    /// Additional third-party channels to dispatch the reminder through
    /// alongside the primary push notification. Empty = push-only behaviour
    /// (the platform's historical default; no surprise for existing
    /// workflows). Each entry produces an independent dispatch attempt
    /// recorded in `channel_events`; per-org configuration in
    /// pidgr-integrations decides which channels are eligible at runtime.
    #[prost(enumeration="ChannelName", repeated, tag="4")]
    pub third_party_channels: ::prost::alloc::vec::Vec<i32>,
    /// Third parties to loop in when this reminder fires. Each resolved
    /// target receives a passive inbox delivery (no action button) plus a
    /// fan-out via the same `third_party_channels` list as the employee
    /// reminder. The delivery auto-dismisses when the original recipient
    /// acknowledges the campaign.
    ///
    /// Each entry reuses the existing `EscalationTarget` shape
    /// (USER / GROUP / MANAGER / ROLE). When `type` is MANAGER, `target_id`
    /// is empty and is resolved at runtime from the original recipient's
    /// `manager_id`. Self-targets (resolved user_id == original recipient)
    /// are dropped at dispatch time.
    /// Constraints: Max 5 entries.
    #[prost(message, repeated, tag="5")]
    pub notify_targets: ::prost::alloc::vec::Vec<EscalationTarget>,
}
/// Configuration for a step that calls an external webhook.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CallWebhookConfig {
    /// Human-readable name for this webhook (for logging/display).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// URL to POST campaign context to.
    /// Constraints: Max length 2048 characters.
    /// Security: HTTPS required in production. Backend MUST reject private,
    /// loopback, and link-local addresses to prevent SSRF attacks.
    #[prost(string, tag="2")]
    pub url: ::prost::alloc::string::String,
    /// Additional HTTP headers to include in the webhook request.
    /// Constraints: Max 20 entries. Key max length 200 characters, value max length 2000 characters.
    #[prost(map="string, string", tag="3")]
    pub headers: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// A target for escalation — who should be notified when escalation fires.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct EscalationTarget {
    /// Type of target.
    #[prost(enumeration="EscalationTargetType", tag="1")]
    pub r#type: i32,
    /// ID of the target (user_id, group_id, or role_id).
    /// Empty for MANAGER type (resolved at runtime from recipient's manager_id).
    #[prost(string, tag="2")]
    pub target_id: ::prost::alloc::string::String,
}
/// Configuration for an escalation step in the workflow DAG.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EscalateConfig {
    /// Condition that triggers escalation.
    #[prost(enumeration="EscalationCondition", tag="1")]
    pub condition: i32,
    /// Targets to notify when escalation fires.
    #[prost(message, repeated, tag="2")]
    pub targets: ::prost::alloc::vec::Vec<EscalationTarget>,
    /// Number of times to repeat this escalation before moving to the next step.
    /// Constraints: Max 5.
    #[prost(int32, tag="3")]
    pub repeat_count: i32,
    /// Minutes between repeat attempts.
    #[prost(int32, tag="4")]
    pub repeat_interval_minutes: i32,
    /// Behavior mode for this escalation. UNSPECIFIED is normalized to DELIVER.
    #[prost(enumeration="EscalateMode", tag="5")]
    pub mode: i32,
    /// Additional third-party channels to dispatch the escalation through
    /// alongside the primary push / delivery side effect. Empty = no
    /// third-party fan-out (existing behaviour). Each entry produces an
    /// independent dispatch attempt recorded in `channel_events`. ALERT_ONLY
    /// and DELIVER modes both support third-party fan-out — the channel
    /// adapters render the alert content from the campaign + a
    /// mode-aware copy variant.
    #[prost(enumeration="ChannelName", repeated, tag="6")]
    pub third_party_channels: ::prost::alloc::vec::Vec<i32>,
}
// ─── Status Enums ───────────────────────────────────────────────────────────

/// Lifecycle status of a campaign.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum CampaignStatus {
    /// Default value; not a valid status.
    Unspecified = 0,
    /// Campaign has been created but not yet started.
    Created = 1,
    /// Campaign is actively delivering messages and processing actions.
    Running = 2,
    /// All recipients have been processed; campaign is finished.
    Completed = 3,
    /// Campaign terminated due to an unrecoverable error.
    Failed = 4,
    /// Campaign was manually cancelled before completion.
    Cancelled = 5,
}
impl CampaignStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CAMPAIGN_STATUS_UNSPECIFIED",
            Self::Created => "CAMPAIGN_STATUS_CREATED",
            Self::Running => "CAMPAIGN_STATUS_RUNNING",
            Self::Completed => "CAMPAIGN_STATUS_COMPLETED",
            Self::Failed => "CAMPAIGN_STATUS_FAILED",
            Self::Cancelled => "CAMPAIGN_STATUS_CANCELLED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CAMPAIGN_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "CAMPAIGN_STATUS_CREATED" => Some(Self::Created),
            "CAMPAIGN_STATUS_RUNNING" => Some(Self::Running),
            "CAMPAIGN_STATUS_COMPLETED" => Some(Self::Completed),
            "CAMPAIGN_STATUS_FAILED" => Some(Self::Failed),
            "CAMPAIGN_STATUS_CANCELLED" => Some(Self::Cancelled),
            _ => None,
        }
    }
}
/// Delivery status for a single message sent to a recipient.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum DeliveryStatus {
    /// Default value; not a valid status.
    Unspecified = 0,
    /// Message is queued but has not been sent yet.
    Pending = 1,
    /// Push notification was sent to the delivery provider.
    Sent = 2,
    /// Message was confirmed delivered to the device.
    Delivered = 3,
    /// Recipient completed the required action (e.g. acknowledged).
    Acknowledged = 4,
    /// Recipient did not act before the deadline.
    Missed = 5,
    /// Recipient has no registered device; delivery was skipped.
    NoDevice = 6,
    /// Delivery failed due to a provider or system error.
    Failed = 7,
}
impl DeliveryStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "DELIVERY_STATUS_UNSPECIFIED",
            Self::Pending => "DELIVERY_STATUS_PENDING",
            Self::Sent => "DELIVERY_STATUS_SENT",
            Self::Delivered => "DELIVERY_STATUS_DELIVERED",
            Self::Acknowledged => "DELIVERY_STATUS_ACKNOWLEDGED",
            Self::Missed => "DELIVERY_STATUS_MISSED",
            Self::NoDevice => "DELIVERY_STATUS_NO_DEVICE",
            Self::Failed => "DELIVERY_STATUS_FAILED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "DELIVERY_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "DELIVERY_STATUS_PENDING" => Some(Self::Pending),
            "DELIVERY_STATUS_SENT" => Some(Self::Sent),
            "DELIVERY_STATUS_DELIVERED" => Some(Self::Delivered),
            "DELIVERY_STATUS_ACKNOWLEDGED" => Some(Self::Acknowledged),
            "DELIVERY_STATUS_MISSED" => Some(Self::Missed),
            "DELIVERY_STATUS_NO_DEVICE" => Some(Self::NoDevice),
            "DELIVERY_STATUS_FAILED" => Some(Self::Failed),
            _ => None,
        }
    }
}
/// Mobile platform for device registration.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Platform {
    /// Default value; not a valid platform.
    Unspecified = 0,
    /// Apple iOS.
    Ios = 1,
    /// Google Android.
    Android = 2,
}
impl Platform {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "PLATFORM_UNSPECIFIED",
            Self::Ios => "PLATFORM_IOS",
            Self::Android => "PLATFORM_ANDROID",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "PLATFORM_UNSPECIFIED" => Some(Self::Unspecified),
            "PLATFORM_IOS" => Some(Self::Ios),
            "PLATFORM_ANDROID" => Some(Self::Android),
            _ => None,
        }
    }
}
/// Granular permission for authorization checks.
/// Stored in the database as enum names (e.g. "PERMISSION_ORG_READ").
/// New values MUST be appended with the next sequential number; existing values
/// MUST NOT be renumbered or removed (enforced by buf breaking).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Permission {
    /// Default value; not a valid permission.
    Unspecified = 0,
    /// View organization settings.
    OrgRead = 1,
    /// Modify organization settings.
    OrgWrite = 2,
    /// View organization members.
    MembersRead = 3,
    /// Invite new users to the organization.
    MembersInvite = 4,
    /// Change user roles, deactivate users.
    MembersManage = 5,
    /// View campaigns and deliveries.
    CampaignsRead = 6,
    /// Create and edit campaigns.
    CampaignsWrite = 7,
    /// Start campaign execution.
    CampaignsStart = 8,
    /// View templates.
    TemplatesRead = 9,
    /// Create and edit templates.
    TemplatesWrite = 10,
    /// View inbox messages and deliveries.
    InboxRead = 11,
    /// Submit actions on deliveries.
    InboxAct = 12,
    /// View all groups in the organization.
    GroupsAllRead = 13,
    /// Create, edit, delete groups the caller created, manage own group membership.
    GroupsWrite = 14,
    /// Create, edit, delete any group in the organization, manage any group membership.
    GroupsAllWrite = 15,
    /// View all teams (organizational units) in the organization.
    TeamsAllRead = 16,
    /// Create, edit, delete teams the caller created, manage own team membership.
    TeamsWrite = 17,
    /// Create, edit, delete any team in the organization, manage any team membership.
    TeamsAllWrite = 18,
    /// View privacy requests (exports, deletions) for the organization.
    PrivacyRead = 19,
    /// Schedule deletions, export user data, restrict processing.
    PrivacyWrite = 20,
    /// View audit trail events for the organization.
    AuditRead = 21,
    /// Review and approve template translations.
    TemplatesReview = 22,
    /// Cross-organization read access for platform-level support operations.
    /// Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformSupport = 23,
    /// Manage platform access codes (generation, listing, revocation).
    /// Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformAccessCodes = 24,
    /// Provision and manage organizations at the platform level.
    /// Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformProvision = 25,
    /// Take abuse-response actions against organizations (suspend, revoke, quota overrides).
    /// Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformAbuseResponse = 26,
    /// Write subprocessor and compliance records at the platform level.
    /// Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformComplianceWrite = 27,
    /// Create synthetic (flagged) data on any org: seed resources and simulate
    /// campaign outcomes. Assignable only to roles within an ORG_TYPE_STAFF organization.
    PlatformSynthetic = 28,
}
impl Permission {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "PERMISSION_UNSPECIFIED",
            Self::OrgRead => "PERMISSION_ORG_READ",
            Self::OrgWrite => "PERMISSION_ORG_WRITE",
            Self::MembersRead => "PERMISSION_MEMBERS_READ",
            Self::MembersInvite => "PERMISSION_MEMBERS_INVITE",
            Self::MembersManage => "PERMISSION_MEMBERS_MANAGE",
            Self::CampaignsRead => "PERMISSION_CAMPAIGNS_READ",
            Self::CampaignsWrite => "PERMISSION_CAMPAIGNS_WRITE",
            Self::CampaignsStart => "PERMISSION_CAMPAIGNS_START",
            Self::TemplatesRead => "PERMISSION_TEMPLATES_READ",
            Self::TemplatesWrite => "PERMISSION_TEMPLATES_WRITE",
            Self::InboxRead => "PERMISSION_INBOX_READ",
            Self::InboxAct => "PERMISSION_INBOX_ACT",
            Self::GroupsAllRead => "PERMISSION_GROUPS_ALL_READ",
            Self::GroupsWrite => "PERMISSION_GROUPS_WRITE",
            Self::GroupsAllWrite => "PERMISSION_GROUPS_ALL_WRITE",
            Self::TeamsAllRead => "PERMISSION_TEAMS_ALL_READ",
            Self::TeamsWrite => "PERMISSION_TEAMS_WRITE",
            Self::TeamsAllWrite => "PERMISSION_TEAMS_ALL_WRITE",
            Self::PrivacyRead => "PERMISSION_PRIVACY_READ",
            Self::PrivacyWrite => "PERMISSION_PRIVACY_WRITE",
            Self::AuditRead => "PERMISSION_AUDIT_READ",
            Self::TemplatesReview => "PERMISSION_TEMPLATES_REVIEW",
            Self::PlatformSupport => "PERMISSION_PLATFORM_SUPPORT",
            Self::PlatformAccessCodes => "PERMISSION_PLATFORM_ACCESS_CODES",
            Self::PlatformProvision => "PERMISSION_PLATFORM_PROVISION",
            Self::PlatformAbuseResponse => "PERMISSION_PLATFORM_ABUSE_RESPONSE",
            Self::PlatformComplianceWrite => "PERMISSION_PLATFORM_COMPLIANCE_WRITE",
            Self::PlatformSynthetic => "PERMISSION_PLATFORM_SYNTHETIC",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "PERMISSION_UNSPECIFIED" => Some(Self::Unspecified),
            "PERMISSION_ORG_READ" => Some(Self::OrgRead),
            "PERMISSION_ORG_WRITE" => Some(Self::OrgWrite),
            "PERMISSION_MEMBERS_READ" => Some(Self::MembersRead),
            "PERMISSION_MEMBERS_INVITE" => Some(Self::MembersInvite),
            "PERMISSION_MEMBERS_MANAGE" => Some(Self::MembersManage),
            "PERMISSION_CAMPAIGNS_READ" => Some(Self::CampaignsRead),
            "PERMISSION_CAMPAIGNS_WRITE" => Some(Self::CampaignsWrite),
            "PERMISSION_CAMPAIGNS_START" => Some(Self::CampaignsStart),
            "PERMISSION_TEMPLATES_READ" => Some(Self::TemplatesRead),
            "PERMISSION_TEMPLATES_WRITE" => Some(Self::TemplatesWrite),
            "PERMISSION_INBOX_READ" => Some(Self::InboxRead),
            "PERMISSION_INBOX_ACT" => Some(Self::InboxAct),
            "PERMISSION_GROUPS_ALL_READ" => Some(Self::GroupsAllRead),
            "PERMISSION_GROUPS_WRITE" => Some(Self::GroupsWrite),
            "PERMISSION_GROUPS_ALL_WRITE" => Some(Self::GroupsAllWrite),
            "PERMISSION_TEAMS_ALL_READ" => Some(Self::TeamsAllRead),
            "PERMISSION_TEAMS_WRITE" => Some(Self::TeamsWrite),
            "PERMISSION_TEAMS_ALL_WRITE" => Some(Self::TeamsAllWrite),
            "PERMISSION_PRIVACY_READ" => Some(Self::PrivacyRead),
            "PERMISSION_PRIVACY_WRITE" => Some(Self::PrivacyWrite),
            "PERMISSION_AUDIT_READ" => Some(Self::AuditRead),
            "PERMISSION_TEMPLATES_REVIEW" => Some(Self::TemplatesReview),
            "PERMISSION_PLATFORM_SUPPORT" => Some(Self::PlatformSupport),
            "PERMISSION_PLATFORM_ACCESS_CODES" => Some(Self::PlatformAccessCodes),
            "PERMISSION_PLATFORM_PROVISION" => Some(Self::PlatformProvision),
            "PERMISSION_PLATFORM_ABUSE_RESPONSE" => Some(Self::PlatformAbuseResponse),
            "PERMISSION_PLATFORM_COMPLIANCE_WRITE" => Some(Self::PlatformComplianceWrite),
            "PERMISSION_PLATFORM_SYNTHETIC" => Some(Self::PlatformSynthetic),
            _ => None,
        }
    }
}
/// Type of action a recipient can perform on a message.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ActionType {
    /// Default value; not a valid action type.
    Unspecified = 0,
    /// Simple acknowledgment — recipient confirms they received the message.
    Ack = 1,
}
impl ActionType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ACTION_TYPE_UNSPECIFIED",
            Self::Ack => "ACTION_TYPE_ACK",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ACTION_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "ACTION_TYPE_ACK" => Some(Self::Ack),
            _ => None,
        }
    }
}
/// Type of step within a workflow definition DAG.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum StepType {
    /// Default value; not a valid step type.
    Unspecified = 0,
    /// Send the initial push notification to all recipients.
    SendNotification = 1,
    /// Sleep for a configurable deadline, then proceed to the next step.
    DeadlineCheck = 2,
    /// Send a follow-up reminder to recipients who have not acted.
    SendReminder = 3,
    /// Call an external webhook with campaign context.
    CallWebhook = 4,
    /// Mark unacknowledged deliveries (SENT/DELIVERED) as MISSED. No config required.
    MarkMissed = 5,
    /// Escalate unacknowledged deliveries to configured targets.
    Escalate = 6,
}
impl StepType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "STEP_TYPE_UNSPECIFIED",
            Self::SendNotification => "STEP_TYPE_SEND_NOTIFICATION",
            Self::DeadlineCheck => "STEP_TYPE_DEADLINE_CHECK",
            Self::SendReminder => "STEP_TYPE_SEND_REMINDER",
            Self::CallWebhook => "STEP_TYPE_CALL_WEBHOOK",
            Self::MarkMissed => "STEP_TYPE_MARK_MISSED",
            Self::Escalate => "STEP_TYPE_ESCALATE",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "STEP_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "STEP_TYPE_SEND_NOTIFICATION" => Some(Self::SendNotification),
            "STEP_TYPE_DEADLINE_CHECK" => Some(Self::DeadlineCheck),
            "STEP_TYPE_SEND_REMINDER" => Some(Self::SendReminder),
            "STEP_TYPE_CALL_WEBHOOK" => Some(Self::CallWebhook),
            "STEP_TYPE_MARK_MISSED" => Some(Self::MarkMissed),
            "STEP_TYPE_ESCALATE" => Some(Self::Escalate),
            _ => None,
        }
    }
}
/// Condition that must be met for an escalation to fire.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum EscalationCondition {
    Unspecified = 0,
    /// Escalate if the delivery has not been acknowledged.
    IfNotAcked = 1,
    /// Escalate if the campaign is still open (even if some deliveries are acknowledged).
    IfNotClosed = 2,
}
impl EscalationCondition {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ESCALATION_CONDITION_UNSPECIFIED",
            Self::IfNotAcked => "ESCALATION_CONDITION_IF_NOT_ACKED",
            Self::IfNotClosed => "ESCALATION_CONDITION_IF_NOT_CLOSED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ESCALATION_CONDITION_UNSPECIFIED" => Some(Self::Unspecified),
            "ESCALATION_CONDITION_IF_NOT_ACKED" => Some(Self::IfNotAcked),
            "ESCALATION_CONDITION_IF_NOT_CLOSED" => Some(Self::IfNotClosed),
            _ => None,
        }
    }
}
/// Type of escalation target.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum EscalationTargetType {
    Unspecified = 0,
    /// Escalate to a specific user by ID.
    User = 1,
    /// Escalate to all members of a group.
    Group = 2,
    /// Escalate to the recipient's direct manager (resolved from manager_id at runtime).
    Manager = 3,
    /// Escalate to all users with a specific role in the org.
    Role = 4,
}
impl EscalationTargetType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ESCALATION_TARGET_TYPE_UNSPECIFIED",
            Self::User => "ESCALATION_TARGET_TYPE_USER",
            Self::Group => "ESCALATION_TARGET_TYPE_GROUP",
            Self::Manager => "ESCALATION_TARGET_TYPE_MANAGER",
            Self::Role => "ESCALATION_TARGET_TYPE_ROLE",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ESCALATION_TARGET_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "ESCALATION_TARGET_TYPE_USER" => Some(Self::User),
            "ESCALATION_TARGET_TYPE_GROUP" => Some(Self::Group),
            "ESCALATION_TARGET_TYPE_MANAGER" => Some(Self::Manager),
            "ESCALATION_TARGET_TYPE_ROLE" => Some(Self::Role),
            _ => None,
        }
    }
}
/// Behavior mode controlling what an escalation produces for its targets.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum EscalateMode {
    /// Default value; servers normalize this to ESCALATE_MODE_DELIVER.
    Unspecified = 0,
    /// Targets receive a delivery for the campaign just like primary recipients.
    Deliver = 1,
    /// Targets receive an out-of-band alert only; no delivery is created.
    AlertOnly = 2,
}
impl EscalateMode {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ESCALATE_MODE_UNSPECIFIED",
            Self::Deliver => "ESCALATE_MODE_DELIVER",
            Self::AlertOnly => "ESCALATE_MODE_ALERT_ONLY",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ESCALATE_MODE_UNSPECIFIED" => Some(Self::Unspecified),
            "ESCALATE_MODE_DELIVER" => Some(Self::Deliver),
            "ESCALATE_MODE_ALERT_ONLY" => Some(Self::AlertOnly),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A scoped API key for programmatic access (MCP agents, service integrations).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ApiKey {
    /// Unique identifier.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Human-friendly label (e.g. "MCP Production", "CI Pipeline").
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Displayable prefix of the key (e.g. "pidgr_k_abc12345").
    /// Used for identification — the full key is only returned on creation.
    #[prost(string, tag="3")]
    pub key_prefix: ::prost::alloc::string::String,
    /// Permissions granted to this key.
    #[prost(enumeration="Permission", repeated, tag="4")]
    pub permissions: ::prost::alloc::vec::Vec<i32>,
    /// When the key was created.
    #[prost(message, optional, tag="5")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Last time the key was used to authenticate a request. Empty if never used.
    #[prost(message, optional, tag="6")]
    pub last_used_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the key expires. Empty means no expiration.
    #[prost(message, optional, tag="7")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Type of this key (API key or SCIM token).
    /// Defaults to KEY_TYPE_API_KEY for existing keys.
    #[prost(enumeration="KeyType", tag="8")]
    pub key_type: i32,
}
/// Request to create a new API key.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateApiKeyRequest {
    /// Human-friendly label. Required, max 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Permissions to grant. Required, at least one.
    /// PERMISSION_UNSPECIFIED values are rejected.
    #[prost(enumeration="Permission", repeated, tag="2")]
    pub permissions: ::prost::alloc::vec::Vec<i32>,
    /// Optional expiration time. If omitted, the key does not expire.
    #[prost(message, optional, tag="3")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Type of key to create. Defaults to KEY_TYPE_API_KEY.
    /// SCIM tokens use the "pidgr_scim_" prefix instead of "pidgr_k_".
    #[prost(enumeration="KeyType", tag="4")]
    pub key_type: i32,
}
/// Response after creating an API key.
/// IMPORTANT: The full key is only returned here — it cannot be retrieved later.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateApiKeyResponse {
    /// The created API key metadata.
    #[prost(message, optional, tag="1")]
    pub api_key: ::core::option::Option<ApiKey>,
    /// The full secret key value (e.g. "pidgr_k_abc12345...").
    /// Store this securely — it is not retrievable after this response.
    #[prost(string, tag="2")]
    pub key: ::prost::alloc::string::String,
}
/// Request to list all API keys in the caller's organization.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListApiKeysRequest {
    /// Optional filter by key type. Unspecified returns all keys.
    #[prost(enumeration="KeyType", tag="1")]
    pub key_type: i32,
}
/// Response containing the organization's API keys.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListApiKeysResponse {
    /// All active (non-revoked) API keys. Full key values are not included.
    #[prost(message, repeated, tag="1")]
    pub api_keys: ::prost::alloc::vec::Vec<ApiKey>,
}
/// Request to revoke an API key.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeApiKeyRequest {
    /// ID of the API key to revoke. Required.
    #[prost(string, tag="1")]
    pub api_key_id: ::prost::alloc::string::String,
}
/// Response after revoking an API key.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeApiKeyResponse {
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Type of API key, distinguishing platform keys from SCIM provisioning tokens.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum KeyType {
    Unspecified = 0,
    ApiKey = 1,
    ScimToken = 2,
}
impl KeyType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "KEY_TYPE_UNSPECIFIED",
            Self::ApiKey => "KEY_TYPE_API_KEY",
            Self::ScimToken => "KEY_TYPE_SCIM_TOKEN",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "KEY_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "KEY_TYPE_API_KEY" => Some(Self::ApiKey),
            "KEY_TYPE_SCIM_TOKEN" => Some(Self::ScimToken),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Request to export all personal data associated with a user.
/// Auth: Requires JWT. Callable by the user themselves or an org admin.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ExportUserDataRequest {
    /// Internal user ID whose data is being exported.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response containing the export status and download location.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ExportUserDataResponse {
    /// Current status of the export request.
    #[prost(enumeration="PrivacyRequestStatus", tag="1")]
    pub status: i32,
    /// Pre-signed S3 URL to download the exported data (ZIP format).
    /// Only populated when status is COMPLETED.
    #[prost(string, tag="2")]
    pub result_url: ::prost::alloc::string::String,
    /// Unique identifier for this export request.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="3")]
    pub export_id: ::prost::alloc::string::String,
}
/// Request to delete or anonymize all personal data associated with a user.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteUserDataRequest {
    /// Internal user ID whose data is being deleted.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// When true, PII is replaced with placeholders instead of hard-deleted.
    /// This preserves audit trail integrity while removing personal data.
    #[prost(bool, tag="2")]
    pub anonymize: bool,
}
/// Response confirming the deletion request.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteUserDataResponse {
    /// Current status of the deletion request.
    #[prost(enumeration="PrivacyRequestStatus", tag="1")]
    pub status: i32,
    /// Timestamp when deletion was completed (or scheduled).
    /// Only populated when status is COMPLETED.
    #[prost(message, optional, tag="2")]
    pub deleted_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Unique identifier for this deletion request.
    #[prost(string, tag="3")]
    pub request_id: ::prost::alloc::string::String,
}
/// Request to list privacy requests for the organization.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListPrivacyRequestsRequest {
    /// Maximum number of results per page.
    /// Constraints: 1–100, default 25.
    #[prost(int32, tag="1")]
    pub page_size: i32,
    /// Continuation token from a previous response.
    #[prost(string, tag="2")]
    pub page_token: ::prost::alloc::string::String,
    /// Filter by request type (export, delete, rectify, restrict). Empty = all.
    #[prost(string, tag="3")]
    pub request_type: ::prost::alloc::string::String,
    /// Filter by status. UNSPECIFIED = all.
    #[prost(enumeration="PrivacyRequestStatus", tag="4")]
    pub status: i32,
}
/// Response containing privacy requests.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListPrivacyRequestsResponse {
    /// The privacy requests matching the filters.
    #[prost(message, repeated, tag="1")]
    pub requests: ::prost::alloc::vec::Vec<PrivacyRequest>,
    /// Token for the next page. Empty if no more results.
    #[prost(string, tag="2")]
    pub next_page_token: ::prost::alloc::string::String,
}
/// A privacy request record.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PrivacyRequest {
    /// Unique identifier.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// The user this request applies to.
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    /// Email of the target user.
    #[prost(string, tag="3")]
    pub user_email: ::prost::alloc::string::String,
    /// Type of request (export, delete, rectify, restrict).
    #[prost(string, tag="4")]
    pub request_type: ::prost::alloc::string::String,
    /// Current status.
    #[prost(enumeration="PrivacyRequestStatus", tag="5")]
    pub status: i32,
    /// Whether to anonymize (true) or hard-delete (false). Only for delete requests.
    #[prost(bool, tag="6")]
    pub anonymize: bool,
    /// Email of the admin who initiated this request.
    #[prost(string, tag="7")]
    pub requested_by_email: ::prost::alloc::string::String,
    /// When the request was created.
    #[prost(message, optional, tag="8")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the request was completed (if applicable).
    #[prost(message, optional, tag="9")]
    pub completed_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Additional metadata (JSON).
    #[prost(map="string, string", tag="10")]
    pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// Request to cancel a pending deletion.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CancelDeletionRequest {
    /// The privacy request ID to cancel.
    #[prost(string, tag="1")]
    pub request_id: ::prost::alloc::string::String,
    /// Admin must type the target user's email to confirm.
    #[prost(string, tag="2")]
    pub confirmation_email: ::prost::alloc::string::String,
}
/// Response confirming the cancellation.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CancelDeletionResponse {
    /// Updated status (should be FAILED with reason cancelled).
    #[prost(enumeration="PrivacyRequestStatus", tag="1")]
    pub status: i32,
}
/// Request to skip the grace period and delete immediately.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ImmediateDeleteRequest {
    /// The privacy request ID to expedite.
    #[prost(string, tag="1")]
    pub request_id: ::prost::alloc::string::String,
    /// Admin must type the target user's email to confirm.
    #[prost(string, tag="2")]
    pub confirmation_email: ::prost::alloc::string::String,
}
/// Response confirming the immediate deletion was triggered.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ImmediateDeleteResponse {
    /// Updated status (should be PROCESSING).
    #[prost(enumeration="PrivacyRequestStatus", tag="1")]
    pub status: i32,
}
/// Request to correct personal data for a user.
/// Auth: Requires JWT. Callable by the user themselves or an org admin.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RectifyUserDataRequest {
    /// Internal user ID whose data is being corrected.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// Map of field names to corrected values.
    /// Corrections are propagated to all stored locations.
    /// Constraints: Max 50 corrections per request.
    #[prost(map="string, string", tag="2")]
    pub corrections: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// Response listing which fields were successfully corrected.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RectifyUserDataResponse {
    /// Names of fields that were rectified.
    #[prost(string, repeated, tag="1")]
    pub rectified_fields: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Request to restrict or unrestrict processing for a user.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RestrictProcessingRequest {
    /// Internal user ID whose processing is being restricted.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// When true, processing is restricted. When false, restriction is lifted.
    #[prost(bool, tag="2")]
    pub restricted: bool,
}
/// Response confirming the processing restriction status.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RestrictProcessingResponse {
    /// Current restriction status.
    #[prost(bool, tag="1")]
    pub restricted: bool,
    /// Timestamp when the restriction was applied or removed.
    #[prost(message, optional, tag="2")]
    pub restricted_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to confirm whether personal data exists for a user.
/// LGPD-specific: confirmação de existência (Art. 18, I).
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetDataExistenceConfirmationRequest {
    /// Internal user ID to check.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response confirming data existence and listing data categories.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetDataExistenceConfirmationResponse {
    /// Whether any personal data exists for this user.
    #[prost(bool, tag="1")]
    pub exists: bool,
    /// Categories of data stored (e.g., "profile", "deliveries", "analytics").
    #[prost(string, repeated, tag="2")]
    pub data_categories: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Request to list the calling user's own privacy requests.
/// Auth: Requires JWT. No admin permission required — returns only the caller's requests.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListMyPrivacyRequestsRequest {
    /// Maximum number of results per page.
    /// Constraints: 1–100, default 25.
    #[prost(int32, tag="1")]
    pub page_size: i32,
    /// Continuation token from a previous response.
    #[prost(string, tag="2")]
    pub page_token: ::prost::alloc::string::String,
    /// Filter by request type (export, rectify). Empty = all.
    #[prost(string, tag="3")]
    pub request_type: ::prost::alloc::string::String,
    /// Filter by status. UNSPECIFIED = all.
    #[prost(enumeration="PrivacyRequestStatus", tag="4")]
    pub status: i32,
}
/// Response containing the calling user's privacy requests.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListMyPrivacyRequestsResponse {
    /// The privacy requests belonging to the calling user.
    #[prost(message, repeated, tag="1")]
    pub requests: ::prost::alloc::vec::Vec<PrivacyRequest>,
    /// Token for the next page. Empty if no more results.
    #[prost(string, tag="2")]
    pub next_page_token: ::prost::alloc::string::String,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Status of a privacy request (export, delete, rectify, restrict).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum PrivacyRequestStatus {
    /// Default value; should not be used explicitly.
    Unspecified = 0,
    /// Request has been created but not yet started.
    Pending = 1,
    /// Request is currently being processed.
    Processing = 2,
    /// Request completed successfully.
    Completed = 3,
    /// Request failed during processing.
    Failed = 4,
}
impl PrivacyRequestStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "PRIVACY_REQUEST_STATUS_UNSPECIFIED",
            Self::Pending => "PRIVACY_REQUEST_STATUS_PENDING",
            Self::Processing => "PRIVACY_REQUEST_STATUS_PROCESSING",
            Self::Completed => "PRIVACY_REQUEST_STATUS_COMPLETED",
            Self::Failed => "PRIVACY_REQUEST_STATUS_FAILED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "PRIVACY_REQUEST_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "PRIVACY_REQUEST_STATUS_PENDING" => Some(Self::Pending),
            "PRIVACY_REQUEST_STATUS_PROCESSING" => Some(Self::Processing),
            "PRIVACY_REQUEST_STATUS_COMPLETED" => Some(Self::Completed),
            "PRIVACY_REQUEST_STATUS_FAILED" => Some(Self::Failed),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// An immutable audit event capturing a significant platform action.
/// Audit events are append-only — they cannot be updated or deleted.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AuditEvent {
    /// Unique identifier for this audit event.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Organization in which the event occurred.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="2")]
    pub org_id: ::prost::alloc::string::String,
    /// User who performed the action. Empty for system-initiated events.
    /// Constraints: UUID format (36 characters) when present.
    #[prost(string, tag="3")]
    pub actor_id: ::prost::alloc::string::String,
    /// Type of action that was performed.
    #[prost(enumeration="AuditEventType", tag="4")]
    pub event_type: i32,
    /// Type of entity affected (e.g., "campaign", "user", "template").
    /// Constraints: Max length 50 characters.
    #[prost(string, tag="5")]
    pub entity_type: ::prost::alloc::string::String,
    /// Identifier of the entity affected.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="6")]
    pub entity_id: ::prost::alloc::string::String,
    /// Additional context about the event (e.g., old/new values for changes).
    /// Constraints: Max 20 key-value pairs, keys max 50 chars, values max 500 chars.
    #[prost(map="string, string", tag="7")]
    pub metadata: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    /// True when this event is synthetic (artificially injected) data — used for
    /// demos, sandbox testing, or issue reproduction — rather than the record of
    /// a real user action.
    #[prost(bool, tag="8")]
    pub synthetic: bool,
    /// Timestamp when the event was recorded.
    #[prost(message, optional, tag="10")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to list audit events with optional filters.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListAuditEventsRequest {
    /// Pagination token from a previous response.
    #[prost(string, tag="1")]
    pub page_token: ::prost::alloc::string::String,
    /// Maximum number of events to return.
    /// Constraints: Min 1, max 100. Default 50.
    #[prost(int32, tag="2")]
    pub page_size: i32,
    /// Optional filter: only return events of this type.
    #[prost(enumeration="AuditEventType", tag="3")]
    pub event_type: i32,
    /// Optional filter: only return events by this actor.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="4")]
    pub actor_id: ::prost::alloc::string::String,
    /// Optional filter: events after this timestamp (inclusive).
    #[prost(message, optional, tag="5")]
    pub start_time: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional filter: events before this timestamp (exclusive).
    #[prost(message, optional, tag="6")]
    pub end_time: ::core::option::Option<::prost_types::Timestamp>,
}
/// Response containing a paginated list of audit events.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListAuditEventsResponse {
    /// Audit events matching the request filters.
    #[prost(message, repeated, tag="1")]
    pub events: ::prost::alloc::vec::Vec<AuditEvent>,
    /// Token for fetching the next page. Empty when no more events.
    #[prost(string, tag="2")]
    pub next_page_token: ::prost::alloc::string::String,
}
/// Request to export the audit trail to S3 in a specified format.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ExportAuditTrailRequest {
    /// Export format.
    #[prost(enumeration="AuditExportFormat", tag="1")]
    pub format: i32,
    /// Optional: export events after this timestamp.
    #[prost(message, optional, tag="2")]
    pub start_time: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional: export events before this timestamp.
    #[prost(message, optional, tag="3")]
    pub end_time: ::core::option::Option<::prost_types::Timestamp>,
}
/// Response containing the export download URL.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ExportAuditTrailResponse {
    /// Pre-signed S3 URL to download the exported audit trail.
    /// Only populated when status is COMPLETED.
    #[prost(string, tag="1")]
    pub export_url: ::prost::alloc::string::String,
    /// Current status of the export request.
    #[prost(enumeration="PrivacyRequestStatus", tag="2")]
    pub status: i32,
}
/// A persistent record of an audit trail export request.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AuditExport {
    /// Unique identifier.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Export format (csv, json).
    #[prost(string, tag="2")]
    pub format: ::prost::alloc::string::String,
    /// Current status.
    #[prost(enumeration="PrivacyRequestStatus", tag="3")]
    pub status: i32,
    /// Pre-signed download URL. Only populated when status is COMPLETED.
    #[prost(string, tag="4")]
    pub result_url: ::prost::alloc::string::String,
    /// Error message if the export failed.
    #[prost(string, tag="5")]
    pub error_message: ::prost::alloc::string::String,
    /// Email of the admin who requested the export.
    #[prost(string, tag="6")]
    pub requested_by_email: ::prost::alloc::string::String,
    /// When the export was requested.
    #[prost(message, optional, tag="7")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the export completed (if applicable).
    #[prost(message, optional, tag="8")]
    pub completed_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to list audit export history.
/// Auth: Requires JWT. Admin only.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListAuditExportsRequest {
}
/// Response containing the list of audit exports.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListAuditExportsResponse {
    /// Audit export records, newest first.
    #[prost(message, repeated, tag="1")]
    pub exports: ::prost::alloc::vec::Vec<AuditExport>,
}
/// Request to append a single audit event from an internal service.
///
/// Auth: INTERNAL-mTLS ONLY. Unlike the read-side RPCs which authenticate
/// via Cognito JWT and infer `org_id` from the caller's claim, this RPC is
/// invoked by sibling services (e.g. pidgr-integrations) over the internal
/// mTLS mesh and therefore carries `org_id` in the request payload. The
/// server MUST reject any caller presenting only a JWT.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AppendRequest {
    /// String form of the event type. Sibling services use a stable string
    /// identifier (e.g. "REACHABILITY_UPSERT", "REACHABILITY_REMOVE") so a
    /// new event type does not require a coordinated proto release across
    /// every internal service before it can be recorded. The audit server
    /// is responsible for mapping the string into its internal taxonomy.
    #[prost(string, tag="1")]
    pub event_type: ::prost::alloc::string::String,
    /// Organization in which the event occurred. UUID.
    #[prost(string, tag="2")]
    pub org_id: ::prost::alloc::string::String,
    /// User the audit event is about, if applicable. UUID. Unset when the
    /// event is not subject-bound (e.g. an org-wide policy change).
    #[prost(string, optional, tag="3")]
    pub subject_user_id: ::core::option::Option<::prost::alloc::string::String>,
    /// Actor who initiated the action, if any. UUID. Unset for system-initiated
    /// or sibling-service-initiated events.
    #[prost(string, optional, tag="4")]
    pub actor_id: ::core::option::Option<::prost::alloc::string::String>,
    /// Structured event-specific payload. Used in lieu of the rigid
    /// `map<string, string> metadata` on `AuditEvent` so sibling services
    /// can record nested objects (e.g. a `prefetch_signals` block) without
    /// string-encoding every value. Servers SHOULD redact PII before persist
    /// and MUST NOT log this field at INFO or above. Sensitive cryptographic
    /// material (plaintext identifiers, envelope ciphertext, raw HMAC keys)
    /// MUST NOT be placed here.
    #[prost(message, optional, tag="5")]
    pub details: ::core::option::Option<::prost_types::Struct>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AppendResponse {
    /// Server-assigned audit event identifier (UUID).
    #[prost(string, tag="1")]
    pub event_id: ::prost::alloc::string::String,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Type of auditable platform action.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum AuditEventType {
    /// Default value; should not be used explicitly.
    Unspecified = 0,
    /// ── Campaign lifecycle ───────────────────────────────────────────────────
    /// A campaign was created.
    CampaignCreated = 1,
    /// A message was sent to a recipient.
    MessageSent = 2,
    /// A message was opened by a recipient.
    MessageOpened = 3,
    /// A recipient acknowledged a campaign.
    AckRegistered = 4,
    /// An escalation was triggered by the workflow.
    EscalationExecuted = 5,
    /// A campaign was started.
    CampaignStarted = 12,
    /// A campaign was cancelled.
    CampaignCancelled = 13,
    /// A campaign was updated.
    CampaignUpdated = 14,
    /// ── User lifecycle ───────────────────────────────────────────────────────
    /// A user was invited to the organization.
    UserInvited = 6,
    /// A user was deactivated.
    UserDeactivated = 7,
    /// A user was reactivated.
    UserReactivated = 15,
    /// A user's role was changed (assigned to a different role).
    RoleChanged = 10,
    /// A user's invite was revoked.
    InviteRevoked = 16,
    /// A user's profile was updated.
    ProfileUpdated = 17,
    /// A user's settings were updated.
    SettingsUpdated = 18,
    /// A user enrolled a passkey.
    PasskeyEnrolled = 19,
    /// ── GDPR / Privacy ──────────────────────────────────────────────────────
    /// A data export was requested (GDPR Art. 15).
    DataExportRequested = 8,
    /// A data deletion was requested (GDPR Art. 17).
    DataDeletionRequested = 9,
    /// User data was rectified (GDPR Art. 16).
    DataRectified = 20,
    /// Data processing was restricted (GDPR Art. 18).
    ProcessingRestricted = 21,
    /// A scheduled deletion was cancelled.
    DeletionCancelled = 22,
    /// An immediate deletion was executed.
    DeletionImmediate = 23,
    /// ── Organization / SSO ───────────────────────────────────────────────────
    /// An SSO provider was configured.
    SsoConfigured = 11,
    /// An SSO provider was created.
    SsoProviderCreated = 24,
    /// An SSO provider was deleted.
    SsoProviderDeleted = 25,
    /// Organization settings were updated.
    OrgUpdated = 26,
    /// ── Roles ────────────────────────────────────────────────────────────────
    /// A role was created.
    RoleCreated = 27,
    /// A role's name or permissions were updated.
    RoleUpdated = 28,
    /// A role was deleted.
    RoleDeleted = 29,
    /// ── Templates ────────────────────────────────────────────────────────────
    /// A template was created.
    TemplateCreated = 30,
    /// A template was updated.
    TemplateUpdated = 31,
    /// ── API Keys ─────────────────────────────────────────────────────────────
    /// An API key was created.
    ApiKeyCreated = 32,
    /// An API key was revoked.
    ApiKeyRevoked = 33,
    /// ── Invite Links ─────────────────────────────────────────────────────────
    /// An invite link was created.
    InviteLinkCreated = 34,
    /// An invite link was revoked.
    InviteLinkRevoked = 35,
    /// ── Groups ───────────────────────────────────────────────────────────────
    /// A group was created.
    GroupCreated = 36,
    /// A group was updated.
    GroupUpdated = 37,
    /// A group was deleted.
    GroupDeleted = 38,
    /// Members were added to a group.
    GroupMembersAdded = 39,
    /// Members were removed from a group.
    GroupMembersRemoved = 40,
    /// ── Teams ────────────────────────────────────────────────────────────────
    /// A team was created.
    TeamCreated = 41,
    /// A team was updated.
    TeamUpdated = 42,
    /// A team was deleted.
    TeamDeleted = 43,
    /// Members were added to a team.
    TeamMembersAdded = 44,
    /// Members were removed from a team.
    TeamMembersRemoved = 45,
    /// ── SCIM Provisioning ───────────────────────────────────────────────────
    /// A user was provisioned via SCIM.
    ScimUserProvisioned = 46,
    /// A user was deprovisioned via SCIM.
    ScimUserDeprovisioned = 47,
    /// A user was updated via SCIM.
    ScimUserUpdated = 48,
    /// ── Translations ────────────────────────────────────────────────────────
    /// A template translation was created.
    TranslationCreated = 49,
    /// A template translation was approved.
    TranslationApproved = 50,
    /// ── Sandbox Orgs ────────────────────────────────────────────────────────
    /// A sandbox organization was created.
    SandboxCreated = 51,
    /// A sandbox organization expired and was deleted.
    SandboxExpired = 52,
    /// ── AI/Insights ─────────────────────────────────────────────────────────
    /// An AI prediction was served and logged (EU AI Act Art. 12).
    AiPredictionLogged = 53,
    /// The ML pipeline (archetype clustering + enrichment) was manually triggered.
    MlPipelineTriggered = 54,
    /// Per-group archetype clustering was manually triggered.
    ArchetypeClusteringTriggered = 55,
    /// ── Org lifecycle ───────────────────────────────────────────────────────
    /// An organization was created.
    OrgCreated = 56,
    /// An organization was deleted (sandbox cleanup or manual deletion).
    OrgDeleted = 57,
    /// ── Reachability registry (pidgr-integrations) ──────────────────────────
    /// A reachability identifier (email, phone, Slack ID, etc.) was upserted.
    /// GDPR-relevant per Chikorita audit classification.
    ReachabilityUpsert = 58,
    /// A reachability identifier was removed. GDPR Art. 17 "right to erasure"
    /// event; written BEFORE the registry row is deleted per Recital 30.
    ReachabilityRemove = 59,
}
impl AuditEventType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "AUDIT_EVENT_TYPE_UNSPECIFIED",
            Self::CampaignCreated => "AUDIT_EVENT_TYPE_CAMPAIGN_CREATED",
            Self::MessageSent => "AUDIT_EVENT_TYPE_MESSAGE_SENT",
            Self::MessageOpened => "AUDIT_EVENT_TYPE_MESSAGE_OPENED",
            Self::AckRegistered => "AUDIT_EVENT_TYPE_ACK_REGISTERED",
            Self::EscalationExecuted => "AUDIT_EVENT_TYPE_ESCALATION_EXECUTED",
            Self::CampaignStarted => "AUDIT_EVENT_TYPE_CAMPAIGN_STARTED",
            Self::CampaignCancelled => "AUDIT_EVENT_TYPE_CAMPAIGN_CANCELLED",
            Self::CampaignUpdated => "AUDIT_EVENT_TYPE_CAMPAIGN_UPDATED",
            Self::UserInvited => "AUDIT_EVENT_TYPE_USER_INVITED",
            Self::UserDeactivated => "AUDIT_EVENT_TYPE_USER_DEACTIVATED",
            Self::UserReactivated => "AUDIT_EVENT_TYPE_USER_REACTIVATED",
            Self::RoleChanged => "AUDIT_EVENT_TYPE_ROLE_CHANGED",
            Self::InviteRevoked => "AUDIT_EVENT_TYPE_INVITE_REVOKED",
            Self::ProfileUpdated => "AUDIT_EVENT_TYPE_PROFILE_UPDATED",
            Self::SettingsUpdated => "AUDIT_EVENT_TYPE_SETTINGS_UPDATED",
            Self::PasskeyEnrolled => "AUDIT_EVENT_TYPE_PASSKEY_ENROLLED",
            Self::DataExportRequested => "AUDIT_EVENT_TYPE_DATA_EXPORT_REQUESTED",
            Self::DataDeletionRequested => "AUDIT_EVENT_TYPE_DATA_DELETION_REQUESTED",
            Self::DataRectified => "AUDIT_EVENT_TYPE_DATA_RECTIFIED",
            Self::ProcessingRestricted => "AUDIT_EVENT_TYPE_PROCESSING_RESTRICTED",
            Self::DeletionCancelled => "AUDIT_EVENT_TYPE_DELETION_CANCELLED",
            Self::DeletionImmediate => "AUDIT_EVENT_TYPE_DELETION_IMMEDIATE",
            Self::SsoConfigured => "AUDIT_EVENT_TYPE_SSO_CONFIGURED",
            Self::SsoProviderCreated => "AUDIT_EVENT_TYPE_SSO_PROVIDER_CREATED",
            Self::SsoProviderDeleted => "AUDIT_EVENT_TYPE_SSO_PROVIDER_DELETED",
            Self::OrgUpdated => "AUDIT_EVENT_TYPE_ORG_UPDATED",
            Self::RoleCreated => "AUDIT_EVENT_TYPE_ROLE_CREATED",
            Self::RoleUpdated => "AUDIT_EVENT_TYPE_ROLE_UPDATED",
            Self::RoleDeleted => "AUDIT_EVENT_TYPE_ROLE_DELETED",
            Self::TemplateCreated => "AUDIT_EVENT_TYPE_TEMPLATE_CREATED",
            Self::TemplateUpdated => "AUDIT_EVENT_TYPE_TEMPLATE_UPDATED",
            Self::ApiKeyCreated => "AUDIT_EVENT_TYPE_API_KEY_CREATED",
            Self::ApiKeyRevoked => "AUDIT_EVENT_TYPE_API_KEY_REVOKED",
            Self::InviteLinkCreated => "AUDIT_EVENT_TYPE_INVITE_LINK_CREATED",
            Self::InviteLinkRevoked => "AUDIT_EVENT_TYPE_INVITE_LINK_REVOKED",
            Self::GroupCreated => "AUDIT_EVENT_TYPE_GROUP_CREATED",
            Self::GroupUpdated => "AUDIT_EVENT_TYPE_GROUP_UPDATED",
            Self::GroupDeleted => "AUDIT_EVENT_TYPE_GROUP_DELETED",
            Self::GroupMembersAdded => "AUDIT_EVENT_TYPE_GROUP_MEMBERS_ADDED",
            Self::GroupMembersRemoved => "AUDIT_EVENT_TYPE_GROUP_MEMBERS_REMOVED",
            Self::TeamCreated => "AUDIT_EVENT_TYPE_TEAM_CREATED",
            Self::TeamUpdated => "AUDIT_EVENT_TYPE_TEAM_UPDATED",
            Self::TeamDeleted => "AUDIT_EVENT_TYPE_TEAM_DELETED",
            Self::TeamMembersAdded => "AUDIT_EVENT_TYPE_TEAM_MEMBERS_ADDED",
            Self::TeamMembersRemoved => "AUDIT_EVENT_TYPE_TEAM_MEMBERS_REMOVED",
            Self::ScimUserProvisioned => "AUDIT_EVENT_TYPE_SCIM_USER_PROVISIONED",
            Self::ScimUserDeprovisioned => "AUDIT_EVENT_TYPE_SCIM_USER_DEPROVISIONED",
            Self::ScimUserUpdated => "AUDIT_EVENT_TYPE_SCIM_USER_UPDATED",
            Self::TranslationCreated => "AUDIT_EVENT_TYPE_TRANSLATION_CREATED",
            Self::TranslationApproved => "AUDIT_EVENT_TYPE_TRANSLATION_APPROVED",
            Self::SandboxCreated => "AUDIT_EVENT_TYPE_SANDBOX_CREATED",
            Self::SandboxExpired => "AUDIT_EVENT_TYPE_SANDBOX_EXPIRED",
            Self::AiPredictionLogged => "AUDIT_EVENT_TYPE_AI_PREDICTION_LOGGED",
            Self::MlPipelineTriggered => "AUDIT_EVENT_TYPE_ML_PIPELINE_TRIGGERED",
            Self::ArchetypeClusteringTriggered => "AUDIT_EVENT_TYPE_ARCHETYPE_CLUSTERING_TRIGGERED",
            Self::OrgCreated => "AUDIT_EVENT_TYPE_ORG_CREATED",
            Self::OrgDeleted => "AUDIT_EVENT_TYPE_ORG_DELETED",
            Self::ReachabilityUpsert => "AUDIT_EVENT_TYPE_REACHABILITY_UPSERT",
            Self::ReachabilityRemove => "AUDIT_EVENT_TYPE_REACHABILITY_REMOVE",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "AUDIT_EVENT_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "AUDIT_EVENT_TYPE_CAMPAIGN_CREATED" => Some(Self::CampaignCreated),
            "AUDIT_EVENT_TYPE_MESSAGE_SENT" => Some(Self::MessageSent),
            "AUDIT_EVENT_TYPE_MESSAGE_OPENED" => Some(Self::MessageOpened),
            "AUDIT_EVENT_TYPE_ACK_REGISTERED" => Some(Self::AckRegistered),
            "AUDIT_EVENT_TYPE_ESCALATION_EXECUTED" => Some(Self::EscalationExecuted),
            "AUDIT_EVENT_TYPE_CAMPAIGN_STARTED" => Some(Self::CampaignStarted),
            "AUDIT_EVENT_TYPE_CAMPAIGN_CANCELLED" => Some(Self::CampaignCancelled),
            "AUDIT_EVENT_TYPE_CAMPAIGN_UPDATED" => Some(Self::CampaignUpdated),
            "AUDIT_EVENT_TYPE_USER_INVITED" => Some(Self::UserInvited),
            "AUDIT_EVENT_TYPE_USER_DEACTIVATED" => Some(Self::UserDeactivated),
            "AUDIT_EVENT_TYPE_USER_REACTIVATED" => Some(Self::UserReactivated),
            "AUDIT_EVENT_TYPE_ROLE_CHANGED" => Some(Self::RoleChanged),
            "AUDIT_EVENT_TYPE_INVITE_REVOKED" => Some(Self::InviteRevoked),
            "AUDIT_EVENT_TYPE_PROFILE_UPDATED" => Some(Self::ProfileUpdated),
            "AUDIT_EVENT_TYPE_SETTINGS_UPDATED" => Some(Self::SettingsUpdated),
            "AUDIT_EVENT_TYPE_PASSKEY_ENROLLED" => Some(Self::PasskeyEnrolled),
            "AUDIT_EVENT_TYPE_DATA_EXPORT_REQUESTED" => Some(Self::DataExportRequested),
            "AUDIT_EVENT_TYPE_DATA_DELETION_REQUESTED" => Some(Self::DataDeletionRequested),
            "AUDIT_EVENT_TYPE_DATA_RECTIFIED" => Some(Self::DataRectified),
            "AUDIT_EVENT_TYPE_PROCESSING_RESTRICTED" => Some(Self::ProcessingRestricted),
            "AUDIT_EVENT_TYPE_DELETION_CANCELLED" => Some(Self::DeletionCancelled),
            "AUDIT_EVENT_TYPE_DELETION_IMMEDIATE" => Some(Self::DeletionImmediate),
            "AUDIT_EVENT_TYPE_SSO_CONFIGURED" => Some(Self::SsoConfigured),
            "AUDIT_EVENT_TYPE_SSO_PROVIDER_CREATED" => Some(Self::SsoProviderCreated),
            "AUDIT_EVENT_TYPE_SSO_PROVIDER_DELETED" => Some(Self::SsoProviderDeleted),
            "AUDIT_EVENT_TYPE_ORG_UPDATED" => Some(Self::OrgUpdated),
            "AUDIT_EVENT_TYPE_ROLE_CREATED" => Some(Self::RoleCreated),
            "AUDIT_EVENT_TYPE_ROLE_UPDATED" => Some(Self::RoleUpdated),
            "AUDIT_EVENT_TYPE_ROLE_DELETED" => Some(Self::RoleDeleted),
            "AUDIT_EVENT_TYPE_TEMPLATE_CREATED" => Some(Self::TemplateCreated),
            "AUDIT_EVENT_TYPE_TEMPLATE_UPDATED" => Some(Self::TemplateUpdated),
            "AUDIT_EVENT_TYPE_API_KEY_CREATED" => Some(Self::ApiKeyCreated),
            "AUDIT_EVENT_TYPE_API_KEY_REVOKED" => Some(Self::ApiKeyRevoked),
            "AUDIT_EVENT_TYPE_INVITE_LINK_CREATED" => Some(Self::InviteLinkCreated),
            "AUDIT_EVENT_TYPE_INVITE_LINK_REVOKED" => Some(Self::InviteLinkRevoked),
            "AUDIT_EVENT_TYPE_GROUP_CREATED" => Some(Self::GroupCreated),
            "AUDIT_EVENT_TYPE_GROUP_UPDATED" => Some(Self::GroupUpdated),
            "AUDIT_EVENT_TYPE_GROUP_DELETED" => Some(Self::GroupDeleted),
            "AUDIT_EVENT_TYPE_GROUP_MEMBERS_ADDED" => Some(Self::GroupMembersAdded),
            "AUDIT_EVENT_TYPE_GROUP_MEMBERS_REMOVED" => Some(Self::GroupMembersRemoved),
            "AUDIT_EVENT_TYPE_TEAM_CREATED" => Some(Self::TeamCreated),
            "AUDIT_EVENT_TYPE_TEAM_UPDATED" => Some(Self::TeamUpdated),
            "AUDIT_EVENT_TYPE_TEAM_DELETED" => Some(Self::TeamDeleted),
            "AUDIT_EVENT_TYPE_TEAM_MEMBERS_ADDED" => Some(Self::TeamMembersAdded),
            "AUDIT_EVENT_TYPE_TEAM_MEMBERS_REMOVED" => Some(Self::TeamMembersRemoved),
            "AUDIT_EVENT_TYPE_SCIM_USER_PROVISIONED" => Some(Self::ScimUserProvisioned),
            "AUDIT_EVENT_TYPE_SCIM_USER_DEPROVISIONED" => Some(Self::ScimUserDeprovisioned),
            "AUDIT_EVENT_TYPE_SCIM_USER_UPDATED" => Some(Self::ScimUserUpdated),
            "AUDIT_EVENT_TYPE_TRANSLATION_CREATED" => Some(Self::TranslationCreated),
            "AUDIT_EVENT_TYPE_TRANSLATION_APPROVED" => Some(Self::TranslationApproved),
            "AUDIT_EVENT_TYPE_SANDBOX_CREATED" => Some(Self::SandboxCreated),
            "AUDIT_EVENT_TYPE_SANDBOX_EXPIRED" => Some(Self::SandboxExpired),
            "AUDIT_EVENT_TYPE_AI_PREDICTION_LOGGED" => Some(Self::AiPredictionLogged),
            "AUDIT_EVENT_TYPE_ML_PIPELINE_TRIGGERED" => Some(Self::MlPipelineTriggered),
            "AUDIT_EVENT_TYPE_ARCHETYPE_CLUSTERING_TRIGGERED" => Some(Self::ArchetypeClusteringTriggered),
            "AUDIT_EVENT_TYPE_ORG_CREATED" => Some(Self::OrgCreated),
            "AUDIT_EVENT_TYPE_ORG_DELETED" => Some(Self::OrgDeleted),
            "AUDIT_EVENT_TYPE_REACHABILITY_UPSERT" => Some(Self::ReachabilityUpsert),
            "AUDIT_EVENT_TYPE_REACHABILITY_REMOVE" => Some(Self::ReachabilityRemove),
            _ => None,
        }
    }
}
/// Format for audit trail export.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum AuditExportFormat {
    /// Default value; should not be used explicitly.
    Unspecified = 0,
    /// Comma-separated values.
    Csv = 1,
    /// JSON lines format.
    Json = 2,
    /// Apache Parquet columnar format.
    Parquet = 3,
}
impl AuditExportFormat {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "AUDIT_EXPORT_FORMAT_UNSPECIFIED",
            Self::Csv => "AUDIT_EXPORT_FORMAT_CSV",
            Self::Json => "AUDIT_EXPORT_FORMAT_JSON",
            Self::Parquet => "AUDIT_EXPORT_FORMAT_PARQUET",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "AUDIT_EXPORT_FORMAT_UNSPECIFIED" => Some(Self::Unspecified),
            "AUDIT_EXPORT_FORMAT_CSV" => Some(Self::Csv),
            "AUDIT_EXPORT_FORMAT_JSON" => Some(Self::Json),
            "AUDIT_EXPORT_FORMAT_PARQUET" => Some(Self::Parquet),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A campaign that delivers structured messages to a set of recipients
/// and tracks their engagement through a workflow.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Campaign {
    /// Unique identifier for the campaign.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Human-readable campaign name.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// ID of the template used to render messages.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="3")]
    pub template_id: ::prost::alloc::string::String,
    /// Pinned version of the template used for this campaign.
    #[prost(int32, tag="4")]
    pub template_version: i32,
    /// Object storage reference to the audience snapshot taken at campaign creation.
    #[prost(string, tag="5")]
    pub audience_snapshot_ref: ::prost::alloc::string::String,
    /// Current lifecycle status of the campaign.
    #[prost(enumeration="CampaignStatus", tag="6")]
    pub status: i32,
    /// Workflow DAG that drives the campaign's automation logic.
    #[prost(message, optional, tag="7")]
    pub workflow: ::core::option::Option<WorkflowDefinition>,
    /// Total number of recipients in the audience snapshot.
    #[prost(int32, tag="8")]
    pub total_recipients: i32,
    /// Number of recipients who completed the required action.
    #[prost(int32, tag="9")]
    pub action_completed_count: i32,
    /// Number of recipients who did not act before the deadline.
    #[prost(int32, tag="10")]
    pub missed_count: i32,
    /// Timestamp when the campaign was created.
    #[prost(message, optional, tag="11")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the campaign was started (workflow execution began).
    #[prost(message, optional, tag="12")]
    pub started_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the campaign finished (completed, failed, or cancelled).
    #[prost(message, optional, tag="13")]
    pub completed_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Display name of the sender shown to recipients (e.g. "HR Team").
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="14")]
    pub sender_name: ::prost::alloc::string::String,
    /// Optional user-facing title override. If set, takes precedence over the template title.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="15")]
    pub title: ::prost::alloc::string::String,
    /// Whether this campaign's notifications break through Do Not Disturb / Focus mode.
    #[prost(bool, tag="16")]
    pub critical: bool,
    /// Optional locale override for all recipients in this campaign.
    /// When set, all recipients receive the campaign in this locale regardless of
    /// their preferred_locale. Empty means per-recipient locale resolution.
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="17")]
    pub default_locale: ::prost::alloc::string::String,
    /// Whether the campaign deadline waits for users without registered devices.
    /// When true, NO_DEVICE users remain in pending_count and can acknowledge
    /// via inbox after installing the app. Default false preserves current behavior.
    #[prost(bool, tag="18")]
    pub wait_for_enrollment: bool,
    /// Optional. Set when the campaign was created from a Compass archetype CTA.
    /// Drives post-campaign archetype-response analytics.
    #[prost(message, optional, tag="19")]
    pub originating_archetype: ::core::option::Option<CampaignOriginatingArchetype>,
    /// True when this campaign contains synthetic (artificially injected) data —
    /// created or populated for demos, sandbox testing, or issue reproduction.
    #[prost(bool, tag="20")]
    pub synthetic: bool,
}
/// Identifies the archetype that motivated the creation of a campaign.
/// The audience is NOT filtered by archetype membership — this is metadata
/// about the campaign's authoring intent only. See OpenSpec change
/// archetype-targeted-campaign-cta.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CampaignOriginatingArchetype {
    /// UUID of the group whose archetype set the label belongs to.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Stable archetype label (e.g., "Swift Acknowledger"). Labels are stable
    /// across clustering retrains; archetype IDs are not.
    #[prost(string, tag="2")]
    pub archetype_label: ::prost::alloc::string::String,
}
/// A single audience member with optional per-user template variables.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AudienceMember {
    /// User ID (UUID).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// Template variable values for this user (e.g. {"name": "Alice"}).
    #[prost(map="string, string", tag="2")]
    pub variables: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// Request to create a new campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateCampaignRequest {
    /// Human-readable campaign name (admin-facing label).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// ID of the template to use for rendering messages.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="2")]
    pub template_id: ::prost::alloc::string::String,
    /// Version of the template to pin for this campaign.
    #[prost(int32, tag="3")]
    pub template_version: i32,
    /// List of user IDs that form the campaign audience.
    /// Constraints: Max 100000 items.
    #[prost(string, repeated, tag="4")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
    /// Workflow DAG defining the campaign's automation steps.
    /// Required: CreateCampaign rejects a request with no workflow
    /// (INVALID_ARGUMENT) and does not substitute a default. The definition
    /// MUST validate as an acyclic graph of well-formed steps.
    #[prost(message, optional, tag="5")]
    pub workflow: ::core::option::Option<WorkflowDefinition>,
    /// Display name of the sender shown to recipients (e.g. "HR Team").
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="6")]
    pub sender_name: ::prost::alloc::string::String,
    /// Optional user-facing title override. If empty, the template title is used.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="7")]
    pub title: ::prost::alloc::string::String,
    /// Rich audience with per-user template variables.
    /// When set, takes precedence over user_ids.
    /// Constraints: Max 100000 items.
    #[prost(message, repeated, tag="8")]
    pub audience: ::prost::alloc::vec::Vec<AudienceMember>,
    /// Whether to include users with processing_restricted=true in the audience.
    /// Default false: restricted users are excluded. Set true only with Art. 18(2) legal basis.
    #[prost(bool, tag="9")]
    pub include_restricted: bool,
    /// Whether this campaign's notifications break through Do Not Disturb / Focus mode.
    #[prost(bool, tag="10")]
    pub critical: bool,
    /// Optional locale override for all recipients.
    #[prost(string, tag="11")]
    pub default_locale: ::prost::alloc::string::String,
    /// Whether the campaign deadline should wait for users without registered devices.
    /// When true, NO_DEVICE users are not decremented from pending_count,
    /// allowing them to acknowledge via inbox after installing the app.
    #[prost(bool, tag="12")]
    pub wait_for_enrollment: bool,
    /// Optional. Set when the campaign is created from a Compass archetype CTA.
    /// The server validates the caller has access to group_id and that
    /// archetype_label exists in the group's current archetype set; cross-org
    /// group_id returns PERMISSION_DENIED, unknown label returns NOT_FOUND.
    #[prost(message, optional, tag="13")]
    pub originating_archetype: ::core::option::Option<CampaignOriginatingArchetype>,
}
/// Response after creating a campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateCampaignResponse {
    /// The newly created campaign.
    #[prost(message, optional, tag="1")]
    pub campaign: ::core::option::Option<Campaign>,
}
/// Request to start a campaign's workflow execution.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct StartCampaignRequest {
    /// ID of the campaign to start.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Response after starting a campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct StartCampaignResponse {
    /// The campaign with updated status.
    #[prost(message, optional, tag="1")]
    pub campaign: ::core::option::Option<Campaign>,
}
/// Request to retrieve a single campaign by ID.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCampaignRequest {
    /// ID of the campaign to retrieve.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Response containing the requested campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetCampaignResponse {
    /// The requested campaign.
    #[prost(message, optional, tag="1")]
    pub campaign: ::core::option::Option<Campaign>,
}
/// Request to list campaigns with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListCampaignsRequest {
    /// Pagination parameters.
    #[prost(message, optional, tag="1")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of campaigns.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListCampaignsResponse {
    /// List of campaigns in this page.
    #[prost(message, repeated, tag="1")]
    pub campaigns: ::prost::alloc::vec::Vec<Campaign>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to cancel a running campaign.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CancelCampaignRequest {
    /// ID of the campaign to cancel.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Response after cancelling a campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CancelCampaignResponse {
    /// The campaign with updated status (CANCELLED).
    #[prost(message, optional, tag="1")]
    pub campaign: ::core::option::Option<Campaign>,
}
/// Request to update a draft campaign (status must be CREATED).
/// Only non-empty/non-zero fields are updated; omitted fields remain unchanged.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateCampaignRequest {
    /// ID of the campaign to update.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Updated campaign name. Empty string means no change.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Updated sender display name. Empty string means no change.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="3")]
    pub sender_name: ::prost::alloc::string::String,
    /// Updated title override. Empty string means no change.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="4")]
    pub title: ::prost::alloc::string::String,
    /// Updated template ID. Empty string means no change.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="5")]
    pub template_id: ::prost::alloc::string::String,
    /// Updated template version. Zero means no change.
    #[prost(int32, tag="6")]
    pub template_version: i32,
    /// Updated workflow DAG. Null/omitted means no change.
    #[prost(message, optional, tag="7")]
    pub workflow: ::core::option::Option<WorkflowDefinition>,
}
/// Response after updating a campaign.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateCampaignResponse {
    /// The campaign with updated fields.
    #[prost(message, optional, tag="1")]
    pub campaign: ::core::option::Option<Campaign>,
}
/// A single delivery record tracking message delivery to one recipient.
/// Out-of-band context attached to a delivery beyond its canonical
/// recipient + status + content payload. Optional; fields are populated
/// per delivery kind. Currently only REMINDER_FYI children carry values,
/// to snapshot context from the parent delivery so clients can render
/// without fetching additional resources.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct DeliveryMetadata {
    /// REMINDER_FYI: the rendered Message payload from the parent delivery,
    /// used to render the blockquoted "Original message" panel on the
    /// notify-target's inbox card.
    #[prost(message, optional, tag="1")]
    pub original_message: ::core::option::Option<Message>,
    /// REMINDER_FYI: display name of the original recipient (the employee
    /// who hasn't responded). Used to interpolate the FYI title and banner.
    #[prost(string, tag="2")]
    pub original_recipient_name: ::prost::alloc::string::String,
    /// REMINDER_FYI: campaign title, denormalized so the notify-target's
    /// client can render without a separate campaign lookup.
    #[prost(string, tag="3")]
    pub campaign_title: ::prost::alloc::string::String,
    /// REMINDER_FYI: when the parent reminder step fired, used to render
    /// the "fired X ago" footer on the FYI card.
    #[prost(message, optional, tag="4")]
    pub reminder_fired_at: ::core::option::Option<::prost_types::Timestamp>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Delivery {
    /// Unique identifier for this delivery.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// ID of the recipient user.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    /// ID of the campaign this delivery belongs to.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="3")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Current delivery status.
    #[prost(enumeration="DeliveryStatus", tag="4")]
    pub status: i32,
    /// Timestamp when the message was delivered to the device.
    #[prost(message, optional, tag="5")]
    pub delivered_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the recipient read the message.
    #[prost(message, optional, tag="6")]
    pub read_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the recipient performed the required action.
    #[prost(message, optional, tag="7")]
    pub acted_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Email address of the recipient, populated from the users table on read.
    #[prost(string, tag="8")]
    pub recipient_email: ::prost::alloc::string::String,
    /// Discriminator distinguishing primary recipient deliveries from
    /// deliveries generated by downstream workflow steps.
    #[prost(enumeration="delivery::Kind", tag="12")]
    pub kind: i32,
    /// For non-primary deliveries, the UUID of the originating delivery this
    /// row was derived from. Empty for primary deliveries.
    /// Constraints: UUID format (36 characters) when set.
    #[prost(string, tag="13")]
    pub parent_delivery_id: ::prost::alloc::string::String,
    /// The locale this delivery's body was actually rendered in after fallback
    /// resolution (recipient preference, campaign override, template default).
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="14")]
    pub rendered_locale: ::prost::alloc::string::String,
    /// Optional out-of-band context. See `DeliveryMetadata` for which
    /// delivery kinds populate which fields. Empty for legacy / PRIMARY
    /// deliveries.
    #[prost(message, optional, tag="15")]
    pub metadata: ::core::option::Option<DeliveryMetadata>,
    /// True when this delivery's outcome is synthetic (artificially injected)
    /// data rather than the result of a real delivery and user response.
    #[prost(bool, tag="9")]
    pub synthetic: bool,
}
/// Nested message and enum types in `Delivery`.
pub mod delivery {
    /// Discriminator describing what produced this delivery row.
    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
    #[repr(i32)]
    pub enum Kind {
        /// Default value; not a valid kind.
        Unspecified = 0,
        /// Delivery generated for an audience recipient at campaign start.
        Primary = 1,
        /// Delivery generated by an escalation step targeting a non-audience user.
        Escalation = 2,
        /// Passive heads-up delivery generated when a reminder step fans out to
        /// its `notify_targets`. Carries no action button; auto-dismisses when
        /// the parent delivery is acknowledged. See
        /// `SendReminderConfig.notify_targets`.
        ReminderFyi = 3,
    }
    impl Kind {
        /// String value of the enum field names used in the ProtoBuf definition.
        ///
        /// The values are not transformed in any way and thus are considered stable
        /// (if the ProtoBuf definition does not change) and safe for programmatic use.
        pub fn as_str_name(&self) -> &'static str {
            match self {
                Self::Unspecified => "KIND_UNSPECIFIED",
                Self::Primary => "KIND_PRIMARY",
                Self::Escalation => "KIND_ESCALATION",
                Self::ReminderFyi => "KIND_REMINDER_FYI",
            }
        }
        /// Creates an enum from field names used in the ProtoBuf definition.
        pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
            match value {
                "KIND_UNSPECIFIED" => Some(Self::Unspecified),
                "KIND_PRIMARY" => Some(Self::Primary),
                "KIND_ESCALATION" => Some(Self::Escalation),
                "KIND_REMINDER_FYI" => Some(Self::ReminderFyi),
                _ => None,
            }
        }
    }
}
/// Request to list deliveries for a campaign with optional status filtering.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListDeliveriesRequest {
    /// ID of the campaign to list deliveries for.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Optional filter by delivery status. UNSPECIFIED returns all.
    #[prost(enumeration="DeliveryStatus", tag="2")]
    pub status_filter: i32,
    /// Pagination parameters.
    #[prost(message, optional, tag="3")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of delivery records.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListDeliveriesResponse {
    /// List of deliveries in this page.
    #[prost(message, repeated, tag="1")]
    pub deliveries: ::prost::alloc::vec::Vec<Delivery>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to compute the archetype-tendency-shift surface for a campaign:
/// how each archetype's share of the originating group has moved between
/// the snapshot closest to campaign-creation time and the most recent
/// snapshot. Only valid for campaigns whose originating_archetype is set.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCampaignArchetypeBreakdownRequest {
    /// ID of the campaign to break down.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Movement in one archetype's share of the originating group between the
/// "before" and "after" archetype-clustering snapshots. Cohort-level only;
/// no joining to user identity. The `is_origin` row is the archetype the
/// campaign was authored for.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ArchetypeShareShift {
    /// Stable archetype label, e.g. "Swift Acknowledger".
    #[prost(string, tag="1")]
    pub label: ::prost::alloc::string::String,
    /// Archetype's share of the group at the snapshot closest to (but not
    /// after) the campaign's created_at. Range 0.0 – 1.0.
    #[prost(double, tag="2")]
    pub share_before: f64,
    /// Archetype's share of the group at the most recent snapshot. Range
    /// 0.0 – 1.0. Equals share_before when no clustering has run since.
    #[prost(double, tag="3")]
    pub share_after: f64,
    /// True when this row's label matches the campaign's
    /// originating_archetype.archetype_label.
    #[prost(bool, tag="4")]
    pub is_origin: bool,
    /// Count of email DELIVERED events recorded for this archetype's members
    /// across the campaign window. Denominator for both open-rate fields.
    #[prost(uint64, tag="5")]
    pub email_delivered_count: u64,
    /// Open rate excluding events flagged as Apple-MPP prefetches
    /// (prefetch_suspected=true). Range 0.0 – 1.0.
    #[prost(double, tag="6")]
    pub email_open_rate_real: f64,
    /// Open rate including all OPENED events, prefetches included.
    /// Range 0.0 – 1.0.
    #[prost(double, tag="7")]
    pub email_open_rate_raw: f64,
}
/// Response containing per-archetype share shifts. The admin renders
/// these as a comparison table — origin row marked, others as peers, so
/// the admin can tell campaign-coincident drift apart from background
/// drift across the rest of the group.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetCampaignArchetypeBreakdownResponse {
    /// One entry per archetype in the originating group. Empty when
    /// insufficient_history is true.
    #[prost(message, repeated, tag="1")]
    pub shifts: ::prost::alloc::vec::Vec<ArchetypeShareShift>,
    /// When the "before" sample was taken (closest snapshot at or before
    /// campaign creation).
    #[prost(message, optional, tag="2")]
    pub before_snapshot_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the "after" sample was taken (most recent snapshot).
    #[prost(message, optional, tag="3")]
    pub after_snapshot_at: ::core::option::Option<::prost_types::Timestamp>,
    /// True when fewer than two clustering snapshots exist for the group,
    /// so no shift can be computed yet. Admin renders an "awaiting next
    /// clustering cycle" empty state.
    #[prost(bool, tag="4")]
    pub insufficient_history: bool,
}
// ─── Short-code messages ────────────────────────────────────────────────────

/// Request to resolve a campaign's short-code, lazily generating one on
/// first call. Used by internal-service callers (the dispatch layer)
/// when assembling a third-party-channel deeplink:
/// `links.pidgr.com/c/{short_code}?t={token}`.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ResolveOrCreateShortCodeRequest {
    /// The campaign whose short-code is being resolved.
    /// Constraints: Required, must be a UUID and exist within the caller's organization.
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Response carrying the resolved short-code. The same campaign always
/// resolves to the same code for its lifetime; the value is safe to
/// cache by the caller.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ResolveOrCreateShortCodeResponse {
    /// 8-character base62 short-code stable for the campaign's lifetime.
    #[prost(string, tag="1")]
    pub short_code: ::prost::alloc::string::String,
}
/// Request to look up a campaign by its public short-code. Called by the
/// native app when the recipient taps a third-party-channel deeplink and
/// the URL handler needs to route to the right campaign card. Designed to
/// be safe to call without authentication — the response carries no PII
/// and only enough context for the app to route correctly and show org
/// branding before the auth gate.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCampaignByShortCodeRequest {
    /// The 8-character short-code from the deeplink path.
    /// Constraints: Required, exactly 8 base62 characters.
    #[prost(string, tag="1")]
    pub short_code: ::prost::alloc::string::String,
}
/// Response carrying the minimum metadata the native app needs to route
/// the deeplink. Subject is the campaign's title text (already visible
/// in the recipient's inbox after dispatch — no new PII exposure). Body
/// content, audience size, delivery status and any other operational
/// fields are NOT included; the app fetches those via authenticated
/// `GetCampaign` after the recipient signs in.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCampaignByShortCodeResponse {
    /// Campaign UUID — the app uses this for the authenticated `GetCampaign`
    /// follow-up after the deeplink token validates.
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Organization UUID owning the campaign — lets the app pick the
    /// correct SSO / sign-in flow when the recipient is logged out.
    #[prost(string, tag="2")]
    pub org_id: ::prost::alloc::string::String,
    /// Display name of the organization for sign-in branding ("Sign in to
    /// Acme Inc to view this campaign"). Public information; the
    /// organization's profile already exposes it elsewhere.
    #[prost(string, tag="3")]
    pub organization_name: ::prost::alloc::string::String,
    /// Campaign subject (title). Same string the recipient already saw in
    /// their inbox; included so the deeplink interstitial can show
    /// "Acme Inc — All-hands Q3" before the auth gate.
    #[prost(string, tag="4")]
    pub subject: ::prost::alloc::string::String,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A registered device that can receive push notifications.
/// INTERNAL: This message is for server-side use only. Use DeviceSummary for API responses.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Device {
    /// Unique identifier for this device.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub device_id: ::prost::alloc::string::String,
    /// ID of the user who owns this device.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    /// Mobile platform (iOS or Android).
    #[prost(enumeration="Platform", tag="3")]
    pub platform: i32,
    /// Push token used to send notifications to this device.
    #[prost(string, tag="4")]
    pub push_token: ::prost::alloc::string::String,
    /// Whether the device is currently active and eligible for push delivery.
    #[prost(bool, tag="5")]
    pub active: bool,
    /// Timestamp of the last activity from this device.
    #[prost(message, optional, tag="6")]
    pub last_seen: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the device was first registered.
    #[prost(message, optional, tag="7")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// A device summary safe for API responses — excludes sensitive push_token.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeviceSummary {
    /// Unique identifier for this device.
    #[prost(string, tag="1")]
    pub device_id: ::prost::alloc::string::String,
    /// ID of the user who owns this device.
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    /// Mobile platform (iOS or Android).
    #[prost(enumeration="Platform", tag="3")]
    pub platform: i32,
    /// Whether the device is currently active and eligible for push delivery.
    #[prost(bool, tag="4")]
    pub active: bool,
    /// Timestamp of the last activity from this device.
    #[prost(message, optional, tag="5")]
    pub last_seen: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the device was first registered.
    #[prost(message, optional, tag="6")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to register a device for push notifications.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RegisterRequest {
    /// Client-generated unique device identifier.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub device_id: ::prost::alloc::string::String,
    /// Mobile platform of the device.
    #[prost(enumeration="Platform", tag="2")]
    pub platform: i32,
    /// Push token obtained from the push notification provider on the client.
    /// Constraints: Max length 4096 characters.
    #[prost(string, tag="3")]
    pub push_token: ::prost::alloc::string::String,
}
/// Response after registering a device.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RegisterResponse {
    /// The registered device summary (excludes push_token).
    #[prost(message, optional, tag="1")]
    pub device: ::core::option::Option<DeviceSummary>,
}
/// Request to deactivate a device, stopping push notifications.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeactivateRequest {
    /// ID of the device to deactivate.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub device_id: ::prost::alloc::string::String,
}
/// Response after deactivating a device.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeactivateResponse {
    /// Whether the device was successfully deactivated.
    #[prost(bool, tag="1")]
    pub success: bool,
}
/// Request to list all devices for the authenticated user.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListDevicesRequest {
}
/// Response containing all devices for the user.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListDevicesResponse {
    /// List of devices registered to the authenticated user.
    #[prost(message, repeated, tag="1")]
    pub devices: ::prost::alloc::vec::Vec<DeviceSummary>,
}
/// Request to list devices for a specific member (admin use).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListMemberDevicesRequest {
    /// ID of the user whose devices to list.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response containing all devices for the specified member.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListMemberDevicesResponse {
    /// List of devices registered to the specified user.
    #[prost(message, repeated, tag="1")]
    pub devices: ::prost::alloc::vec::Vec<DeviceSummary>,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// User-configurable platform settings that apply across all clients.
/// All fields use their UNSPECIFIED/zero value to mean "no change" in updates.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UserSettings {
    /// Preferred color scheme for the UI.
    #[prost(enumeration="ThemePreference", tag="1")]
    pub theme_preference: i32,
    /// User's preferred language for the UI and push notifications.
    /// Empty string means "use organization default" or "auto-detect".
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="2")]
    pub preferred_locale: ::prost::alloc::string::String,
}
/// Structured profile attributes for a user within an organization.
/// Populated through admin invitation, mobile onboarding, or SSO attribute sync.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UserProfile {
    /// User's given name.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub first_name: ::prost::alloc::string::String,
    /// User's family name.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub last_name: ::prost::alloc::string::String,
    /// Department or team within the organization.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="3")]
    pub department: ::prost::alloc::string::String,
    /// Job title.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="4")]
    pub title: ::prost::alloc::string::String,
    /// Phone number.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="5")]
    pub phone: ::prost::alloc::string::String,
    /// Office or geographic location.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="6")]
    pub location: ::prost::alloc::string::String,
    /// Organization-specific employee identifier.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="7")]
    pub employee_id: ::prost::alloc::string::String,
    /// Display name of the user's direct manager.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="8")]
    pub manager_name: ::prost::alloc::string::String,
    /// Employment start date in ISO 8601 format (YYYY-MM-DD).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="9")]
    pub start_date: ::prost::alloc::string::String,
    /// Organization-defined custom attributes for fields not covered by the fixed schema.
    /// Constraints: Max 50 entries. Key max length 100 characters, value max length 1000 characters.
    #[prost(map="string, string", tag="10")]
    pub custom_attributes: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    /// UUID of the user's direct manager within the same organization.
    /// Populated from SCIM enterprise extension (manager.value), manual admin
    /// assignment, or SSO attribute mapping. Empty if not set.
    #[prost(string, tag="11")]
    pub manager_id: ::prost::alloc::string::String,
}
/// A user within an organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct User {
    /// Unique identifier for the user (internal platform UUID, not identity provider subject ID).
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// User's email address.
    /// Constraints: Max length 254 characters (RFC 5321).
    #[prost(string, tag="2")]
    pub email: ::prost::alloc::string::String,
    /// User's display name.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="3")]
    pub name: ::prost::alloc::string::String,
    /// Current account status.
    #[prost(enumeration="UserStatus", tag="5")]
    pub status: i32,
    /// Timestamp when the user was created.
    #[prost(message, optional, tag="6")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// The user's role with its permission set.
    #[prost(message, optional, tag="7")]
    pub role: ::core::option::Option<Role>,
    /// ID of the user's role (for assignment operations).
    #[prost(string, tag="8")]
    pub role_id: ::prost::alloc::string::String,
    /// Structured profile attributes (department, title, etc.).
    /// May be empty if the user has not completed their profile.
    #[prost(message, optional, tag="9")]
    pub profile: ::core::option::Option<UserProfile>,
    /// Whether data processing is restricted for this user (GDPR Art. 18).
    /// When true, the user is excluded from campaign audiences by default.
    #[prost(bool, tag="10")]
    pub processing_restricted: bool,
    /// Data governance region override. Empty string means "inherit from org default".
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="11")]
    pub data_governance_region: ::prost::alloc::string::String,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Lifecycle status of a user account.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum UserStatus {
    /// Default value; not a valid status.
    Unspecified = 0,
    /// User has been invited but has not completed onboarding.
    Invited = 1,
    /// User is active and can receive messages.
    Active = 2,
    /// User has been deactivated and will not receive messages.
    Deactivated = 3,
}
impl UserStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "USER_STATUS_UNSPECIFIED",
            Self::Invited => "USER_STATUS_INVITED",
            Self::Active => "USER_STATUS_ACTIVE",
            Self::Deactivated => "USER_STATUS_DEACTIVATED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "USER_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "USER_STATUS_INVITED" => Some(Self::Invited),
            "USER_STATUS_ACTIVE" => Some(Self::Active),
            "USER_STATUS_DEACTIVATED" => Some(Self::Deactivated),
            _ => None,
        }
    }
}
/// User's preferred color scheme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ThemePreference {
    /// Default value; treated as SYSTEM when reading, "no change" when updating.
    Unspecified = 0,
    /// Always use light mode regardless of system setting.
    Light = 1,
    /// Always use dark mode regardless of system setting.
    Dark = 2,
    /// Follow the operating system or browser preference.
    System = 3,
}
impl ThemePreference {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "THEME_PREFERENCE_UNSPECIFIED",
            Self::Light => "THEME_PREFERENCE_LIGHT",
            Self::Dark => "THEME_PREFERENCE_DARK",
            Self::System => "THEME_PREFERENCE_SYSTEM",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "THEME_PREFERENCE_UNSPECIFIED" => Some(Self::Unspecified),
            "THEME_PREFERENCE_LIGHT" => Some(Self::Light),
            "THEME_PREFERENCE_DARK" => Some(Self::Dark),
            "THEME_PREFERENCE_SYSTEM" => Some(Self::System),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A named collection of users within an organization, used for campaign
/// audience targeting (recipient groups).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Group {
    /// Unique identifier for the group.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Human-readable display name (unique within the organization).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Optional description of the group's purpose.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="3")]
    pub description: ::prost::alloc::string::String,
    /// Number of users currently in the group.
    #[prost(int32, tag="4")]
    pub member_count: i32,
    /// Timestamp when the group was created.
    #[prost(message, optional, tag="5")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the group was last updated.
    #[prost(message, optional, tag="6")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Whether this is the organization's default group (cannot be deleted or renamed).
    #[prost(bool, tag="7")]
    pub is_default: bool,
    /// ID of the user who created this group. Empty for system-seeded defaults.
    #[prost(string, tag="8")]
    pub created_by: ::prost::alloc::string::String,
}
/// Request to create a new group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateGroupRequest {
    /// Display name for the group. Required.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Optional description.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="2")]
    pub description: ::prost::alloc::string::String,
}
/// Response after creating a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateGroupResponse {
    /// The newly created group.
    #[prost(message, optional, tag="1")]
    pub group: ::core::option::Option<Group>,
}
/// Request to retrieve a group by ID.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetGroupRequest {
    /// ID of the group to retrieve. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
}
/// Response containing the requested group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetGroupResponse {
    /// The requested group.
    #[prost(message, optional, tag="1")]
    pub group: ::core::option::Option<Group>,
}
/// Request to list groups in the organization with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListGroupsRequest {
    /// Pagination parameters.
    #[prost(message, optional, tag="1")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of groups.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListGroupsResponse {
    /// Groups in this page.
    #[prost(message, repeated, tag="1")]
    pub groups: ::prost::alloc::vec::Vec<Group>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to update a group's name and/or description.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateGroupRequest {
    /// ID of the group to update. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// New display name. If empty, the name is not changed.
    /// Default groups cannot be renamed.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// New description. If empty, the description is not changed.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="3")]
    pub description: ::prost::alloc::string::String,
}
/// Response after updating a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateGroupResponse {
    /// The updated group.
    #[prost(message, optional, tag="1")]
    pub group: ::core::option::Option<Group>,
}
/// Request to delete a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteGroupRequest {
    /// ID of the group to delete. Required.
    /// Default groups cannot be deleted.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
}
/// Response after deleting a group.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteGroupResponse {
}
/// Request to add users to a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AddGroupMembersRequest {
    /// ID of the group to add members to. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// IDs of users to add. Must belong to the same organization.
    /// Adding an existing member is a no-op (idempotent).
    /// Constraints: Max 100 user IDs per request.
    #[prost(string, repeated, tag="2")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Response after adding group members.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AddGroupMembersResponse {
    /// The group with updated member_count.
    #[prost(message, optional, tag="1")]
    pub group: ::core::option::Option<Group>,
}
/// Request to remove users from a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveGroupMembersRequest {
    /// ID of the group to remove members from. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// IDs of users to remove. Removing a non-member is a no-op (idempotent).
    /// Constraints: Max 100 user IDs per request.
    #[prost(string, repeated, tag="2")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Response after removing group members.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveGroupMembersResponse {
    /// The group with updated member_count.
    #[prost(message, optional, tag="1")]
    pub group: ::core::option::Option<Group>,
}
/// Request to list members of a group with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListGroupMembersRequest {
    /// ID of the group whose members to list. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Pagination parameters.
    #[prost(message, optional, tag="2")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of group members.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListGroupMembersResponse {
    /// Users in this page.
    #[prost(message, repeated, tag="1")]
    pub users: ::prost::alloc::vec::Vec<User>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// A group membership entry for batch lookups.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UserGroupMembership {
    /// ID of the user.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// Groups the user belongs to.
    #[prost(message, repeated, tag="2")]
    pub groups: ::prost::alloc::vec::Vec<Group>,
}
/// Request to get group memberships for a batch of users.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetUserGroupMembershipsRequest {
    /// IDs of users to look up. Required.
    /// Constraints: Max 200 user IDs per request.
    #[prost(string, repeated, tag="1")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Response containing group memberships for the requested users.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetUserGroupMembershipsResponse {
    /// Group memberships per user. Only users with at least one group are included.
    #[prost(message, repeated, tag="1")]
    pub memberships: ::prost::alloc::vec::Vec<UserGroupMembership>,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A single touch event captured from the mobile app.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TouchEvent {
    /// Screen name from React Navigation route.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub screen_name: ::prost::alloc::string::String,
    /// Horizontal coordinate as a percentage of screen width (0.0–1.0).
    /// Constraints: Range 0.0 to 1.0 inclusive.
    #[prost(float, tag="2")]
    pub x_pct: f32,
    /// Vertical coordinate as a percentage of screen height (0.0–1.0).
    /// Constraints: Range 0.0 to 1.0 inclusive.
    #[prost(float, tag="3")]
    pub y_pct: f32,
    /// Type of touch event.
    #[prost(enumeration="TouchEventType", tag="4")]
    pub event_type: i32,
    /// Screen width in device pixels at the time of capture.
    #[prost(int32, tag="5")]
    pub screen_width: i32,
    /// Screen height in device pixels at the time of capture.
    #[prost(int32, tag="6")]
    pub screen_height: i32,
    /// Client-side timestamp when the touch occurred.
    #[prost(message, optional, tag="7")]
    pub client_timestamp: ::core::option::Option<::prost_types::Timestamp>,
    /// Campaign ID if the touch occurred during a campaign message view.
    /// Empty string for organic (non-campaign) navigation.
    #[prost(string, tag="8")]
    pub campaign_id: ::prost::alloc::string::String,
}
/// Request to ingest a batch of touch events from the mobile app.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct IngestTouchEventsRequest {
    /// Batch of touch events to ingest.
    /// Constraints: Max 100 events per batch.
    #[prost(message, repeated, tag="1")]
    pub events: ::prost::alloc::vec::Vec<TouchEvent>,
}
/// Response after ingesting touch events.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct IngestTouchEventsResponse {
    /// Number of events successfully ingested.
    #[prost(int32, tag="1")]
    pub ingested_count: i32,
}
/// A single aggregated data point in a heatmap grid cell.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct HeatmapDataPoint {
    /// Grid cell horizontal center as a percentage (0.0–1.0).
    #[prost(float, tag="1")]
    pub x_pct: f32,
    /// Grid cell vertical center as a percentage (0.0–1.0).
    #[prost(float, tag="2")]
    pub y_pct: f32,
    /// Aggregated value for this cell (count, median, or z-score depending on mode).
    #[prost(float, tag="3")]
    pub value: f32,
}
/// Request to query aggregated heatmap data for a screen.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct QueryHeatmapDataRequest {
    /// Screen name to query.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub screen_name: ::prost::alloc::string::String,
    /// Start of the time range filter (inclusive).
    #[prost(message, optional, tag="2")]
    pub date_from: ::core::option::Option<::prost_types::Timestamp>,
    /// End of the time range filter (inclusive).
    #[prost(message, optional, tag="3")]
    pub date_to: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional: filter by campaign ID.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="4")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Grid resolution for coordinate rounding. Default: 0.02 (50×50 grid).
    /// Constraints: Range 0.005 to 0.1.
    #[prost(float, tag="6")]
    pub grid_resolution: f32,
    /// Aggregation mode (TOTAL or MEDIAN).
    #[prost(enumeration="HeatmapMode", tag="7")]
    pub mode: i32,
    /// Optional: filter by event types. Empty list means all types.
    #[prost(enumeration="TouchEventType", repeated, tag="8")]
    pub event_types: ::prost::alloc::vec::Vec<i32>,
}
/// Response containing aggregated heatmap data.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct QueryHeatmapDataResponse {
    /// Aggregated data points for heatmap rendering.
    #[prost(message, repeated, tag="1")]
    pub data_points: ::prost::alloc::vec::Vec<HeatmapDataPoint>,
    /// URL to a mobile-captured screenshot for this screen, if available.
    /// Empty string when no screenshot exists.
    #[prost(string, tag="3")]
    pub screenshot_url: ::prost::alloc::string::String,
    /// Whether per-cohort bucket breakdowns are available (k >= 5).
    #[prost(bool, tag="4")]
    pub cohort_enabled: bool,
}
/// Request to upload a screenshot captured from the mobile app.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UploadScreenshotRequest {
    /// Screen name matching React Navigation route (e.g. "MessageDetail::<campaign_uuid>").
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub screen_name: ::prost::alloc::string::String,
    /// App version that captured the screenshot (e.g. "1.15.0").
    #[prost(string, tag="2")]
    pub app_version: ::prost::alloc::string::String,
    /// PNG image data.
    /// Constraints: Max 512KB.
    #[prost(bytes="vec", tag="3")]
    pub image_data: ::prost::alloc::vec::Vec<u8>,
}
/// Response after uploading a screenshot.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UploadScreenshotResponse {
    /// S3 URL where the screenshot was stored.
    #[prost(string, tag="1")]
    pub url: ::prost::alloc::string::String,
}
/// A screen screenshot stored as a static asset.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ScreenScreenshot {
    /// Screen name matching React Navigation route.
    #[prost(string, tag="1")]
    pub screen_name: ::prost::alloc::string::String,
    /// S3 URL to the screenshot image.
    #[prost(string, tag="2")]
    pub url: ::prost::alloc::string::String,
    /// App version this screenshot corresponds to.
    #[prost(string, tag="3")]
    pub app_version: ::prost::alloc::string::String,
}
/// Request to list available screen screenshots.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListScreenshotsRequest {
}
/// Response containing available screen screenshots.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListScreenshotsResponse {
    /// Available screen screenshots with their URLs and versions.
    #[prost(message, repeated, tag="1")]
    pub screenshots: ::prost::alloc::vec::Vec<ScreenScreenshot>,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Type of touch event captured on the mobile app.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum TouchEventType {
    /// Default value; not a valid event type.
    Unspecified = 0,
    /// A single tap on the screen.
    Tap = 1,
    /// A long press (held for 500ms+).
    LongPress = 2,
    /// A periodic scroll position sample (viewport midpoint every 2s).
    Scroll = 3,
    /// The user tapped an action button (e.g. "Acknowledge").
    ActionClick = 4,
}
impl TouchEventType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "TOUCH_EVENT_TYPE_UNSPECIFIED",
            Self::Tap => "TOUCH_EVENT_TYPE_TAP",
            Self::LongPress => "TOUCH_EVENT_TYPE_LONG_PRESS",
            Self::Scroll => "TOUCH_EVENT_TYPE_SCROLL",
            Self::ActionClick => "TOUCH_EVENT_TYPE_ACTION_CLICK",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "TOUCH_EVENT_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "TOUCH_EVENT_TYPE_TAP" => Some(Self::Tap),
            "TOUCH_EVENT_TYPE_LONG_PRESS" => Some(Self::LongPress),
            "TOUCH_EVENT_TYPE_SCROLL" => Some(Self::Scroll),
            "TOUCH_EVENT_TYPE_ACTION_CLICK" => Some(Self::ActionClick),
            _ => None,
        }
    }
}
/// Aggregation mode for heatmap data queries.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum HeatmapMode {
    /// Default value; not a valid mode.
    Unspecified = 0,
    /// Sum of all cohort buckets' touches per grid cell (default).
    Total = 1,
    /// Median touch count per grid cell across cohort buckets.
    Median = 2,
}
impl HeatmapMode {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "HEATMAP_MODE_UNSPECIFIED",
            Self::Total => "HEATMAP_MODE_TOTAL",
            Self::Median => "HEATMAP_MODE_MEDIAN",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "HEATMAP_MODE_UNSPECIFIED" => Some(Self::Unspecified),
            "HEATMAP_MODE_TOTAL" => Some(Self::Total),
            "HEATMAP_MODE_MEDIAN" => Some(Self::Median),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A single entry in a user's inbox, combining a message with its delivery state.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InboxEntry {
    /// ID of the delivery record for this inbox entry.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub delivery_id: ::prost::alloc::string::String,
    /// The fully rendered message content.
    #[prost(message, optional, tag="2")]
    pub message: ::core::option::Option<Message>,
    /// Current delivery status (e.g. DELIVERED, ACKNOWLEDGED).
    #[prost(enumeration="DeliveryStatus", tag="3")]
    pub status: i32,
    /// Whether the user has read this message.
    #[prost(bool, tag="4")]
    pub read: bool,
    /// Timestamp when the message was received in the inbox.
    #[prost(message, optional, tag="5")]
    pub received_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Discriminator: PRIMARY for normal deliveries, ESCALATION for delivery-grade
    /// escalations. Mirrors Delivery.kind so inbox-sync clients can branch on the
    /// same dimension as listDeliveries clients.
    #[prost(enumeration="delivery::Kind", tag="6")]
    pub kind: i32,
    /// For ESCALATION entries, the UUID of the unacked delivery that triggered this
    /// entry. Empty for PRIMARY entries.
    #[prost(string, tag="7")]
    pub parent_delivery_id: ::prost::alloc::string::String,
    /// The locale the body actually rendered in after fallback resolution. Empty
    /// for legacy/PRIMARY entries.
    #[prost(string, tag="8")]
    pub rendered_locale: ::prost::alloc::string::String,
    /// Optional out-of-band context mirrored from the underlying delivery.
    /// See `DeliveryMetadata` for which delivery kinds populate which fields.
    /// Empty for PRIMARY entries.
    #[prost(message, optional, tag="9")]
    pub metadata: ::core::option::Option<DeliveryMetadata>,
}
/// Request to sync inbox entries since a given timestamp.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SyncRequest {
    /// Fetch entries newer than this timestamp. Omit for initial sync.
    #[prost(message, optional, tag="1")]
    pub since: ::core::option::Option<::prost_types::Timestamp>,
    /// Maximum number of entries to return.
    /// Constraints: Valid range 1 to 200.
    #[prost(int32, tag="2")]
    pub limit: i32,
}
/// Response containing synced inbox entries.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncResponse {
    /// Inbox entries newer than the requested timestamp.
    #[prost(message, repeated, tag="1")]
    pub entries: ::prost::alloc::vec::Vec<InboxEntry>,
    /// Cursor timestamp to use for the next sync call.
    #[prost(message, optional, tag="2")]
    pub next_since: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to mark a message as read.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct MarkReadRequest {
    /// ID of the delivery to mark as read.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub delivery_id: ::prost::alloc::string::String,
}
/// Response after marking a message as read.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct MarkReadResponse {
    /// Whether the read status was successfully updated.
    #[prost(bool, tag="1")]
    pub success: bool,
}
/// Request to retrieve a single message by delivery ID.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetMessageRequest {
    /// ID of the delivery to retrieve.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub delivery_id: ::prost::alloc::string::String,
}
/// Response containing the requested inbox entry.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetMessageResponse {
    /// The inbox entry for the requested delivery.
    #[prost(message, optional, tag="1")]
    pub entry: ::core::option::Option<InboxEntry>,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A behavioral archetype describing a cohort pattern (never an individual).
/// Derived from k-anonymized, DP-noised behavioral feature vectors.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Archetype {
    /// Human-readable label (e.g., "Swift Acknowledger", "Thorough Reader").
    #[prost(string, tag="1")]
    pub label: ::prost::alloc::string::String,
    /// Description of the behavioral pattern this archetype represents.
    #[prost(string, tag="2")]
    pub description: ::prost::alloc::string::String,
    /// Proportion of the group that belongs to this archetype (0.0-1.0).
    #[prost(float, tag="3")]
    pub percentage: f32,
    /// Centroid of the behavioral feature vector for this archetype.
    /// Keys are stable dimension names from the feature extractor
    /// vocabulary (e.g., "tap_density", "engagement_depth",
    /// "scroll_velocity_p50", "idle_gap_p75"). Single-letter keys are
    /// reserved for backward compatibility with pre-v0.64 servers and
    /// SHALL be ignored by clients.
    #[prost(map="string, double", tag="4")]
    pub feature_centroid: ::std::collections::HashMap<::prost::alloc::string::String, f64>,
    /// Per-dimension distribution of the archetype's members. Lets the
    /// admin render percentile bands instead of single-point centroids.
    /// Absent until at least k members exist in the cluster. Keys mirror
    /// `feature_centroid` keys.
    #[prost(map="string, message", tag="5")]
    pub feature_breakdown: ::std::collections::HashMap<::prost::alloc::string::String, DimensionStats>,
    /// Tap density heatmap aggregated across sessions for this
    /// archetype. Cohort-level only — never per-session timing.
    /// Absent when fewer than k sessions have tap data.
    #[prost(message, optional, tag="6")]
    pub tap_heatmap: ::core::option::Option<TapHeatmap>,
    /// Forecast of cluster share at fixed horizons (7/14/30/90 days).
    /// Absent during cold start before historical clustering runs exist
    /// to extrapolate from.
    #[prost(message, optional, tag="7")]
    pub forecast: ::core::option::Option<ArchetypeForecast>,
    /// Sessions that sit at the median and quartiles of the archetype's
    /// centroid distance, ranked by distance. Bounded at three entries.
    /// Absent until at least 50 sessions have been scored.
    /// Sessions can come from any client that emits to ReplayService —
    /// mobile (iOS, Android) or desktop (macOS, Windows, Linux).
    #[prost(message, repeated, tag="8")]
    pub exemplar_sessions: ::prost::alloc::vec::Vec<ExemplarSession>,
    /// Per-screen dwell time distribution, derived from session replay.
    /// Absent when fewer than k sessions per screen exist.
    #[prost(message, optional, tag="9")]
    pub screen_dwell: ::core::option::Option<ScreenDwell>,
    /// End-to-end response latencies (push delivered → read → ack) for
    /// members of this archetype, as percentiles. Absent until at least
    /// k campaign deliveries have been recorded for this archetype.
    #[prost(message, optional, tag="10")]
    pub response_timeline: ::core::option::Option<ResponseTimeline>,
    /// Where this archetype came from. UNSPECIFIED on responses from
    /// pre-v0.81 servers; clients SHOULD treat UNSPECIFIED as ML for
    /// backward compatibility (provisional output is always labelled).
    #[prost(enumeration="ArchetypeSource", tag="11")]
    pub source: i32,
}
/// Per-dimension distribution stats for one feature dimension within
/// an archetype's cohort. All values are in the same units as
/// `Archetype.feature_centroid`. Used to render percentile bands on
/// the admin's behavioral profile panel.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct DimensionStats {
    /// Centroid value (same as Archetype.feature_centroid\[key\]).
    #[prost(double, tag="1")]
    pub centroid: f64,
    /// 25th percentile across the archetype's members.
    #[prost(double, tag="2")]
    pub p25: f64,
    /// Median across the archetype's members.
    #[prost(double, tag="3")]
    pub p50: f64,
    /// 75th percentile across the archetype's members.
    #[prost(double, tag="4")]
    pub p75: f64,
    /// Median across the entire group (all archetypes), included so the
    /// admin can render "this archetype is X% above group median".
    #[prost(double, tag="5")]
    pub group_p50: f64,
}
/// A density grid of tap activity for one archetype, normalized to
/// \[0.0, 1.0\] where 1.0 is the hottest cell in the cohort. Cohort-
/// level only.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TapHeatmap {
    /// Width of the density grid in cells.
    #[prost(int32, tag="1")]
    pub width: i32,
    /// Height of the density grid in cells.
    #[prost(int32, tag="2")]
    pub height: i32,
    /// Row-major density values, length must equal width*height. All in
    /// \[0.0, 1.0\].
    #[prost(double, repeated, tag="3")]
    pub values: ::prost::alloc::vec::Vec<f64>,
    /// Number of sessions aggregated. Always >= MinFeatureVectorsForClustering
    /// when the field is present.
    #[prost(int32, tag="4")]
    pub session_count: i32,
    /// Optional per-event-type breakdown. When present, the writer
    /// SHALL emit one entry for each event type in the source data
    /// (TAP, LONG_PRESS, SCROLL, ACTION_CLICK).
    #[prost(message, repeated, tag="5")]
    pub layers: ::prost::alloc::vec::Vec<TapHeatmapLayer>,
}
/// One per-event-type layer of a TapHeatmap.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TapHeatmapLayer {
    /// Event type this layer represents (e.g., "TAP", "LONG_PRESS",
    /// "SCROLL", "ACTION_CLICK").
    #[prost(string, tag="1")]
    pub event_type: ::prost::alloc::string::String,
    /// Row-major density values, same dimensions as the parent
    /// TapHeatmap. Independently normalized to \[0.0, 1.0\].
    #[prost(double, repeated, tag="2")]
    pub values: ::prost::alloc::vec::Vec<f64>,
}
/// Predicted cluster share at fixed horizons with confidence bands.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ArchetypeForecast {
    /// Horizons in increasing days. Always one entry each for 7, 14,
    /// 30, and 90 days when the field is present.
    #[prost(message, repeated, tag="1")]
    pub horizons: ::prost::alloc::vec::Vec<ForecastHorizon>,
}
/// Predicted share at one horizon with a 90% prediction interval.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct ForecastHorizon {
    /// Horizon length in days (one of: 7, 14, 30, 90).
    #[prost(int32, tag="1")]
    pub days: i32,
    /// Predicted fraction of the group falling in this archetype at the
    /// horizon (0.0-1.0).
    #[prost(double, tag="2")]
    pub predicted_share: f64,
    /// 5th-percentile lower bound of the prediction interval.
    #[prost(double, tag="3")]
    pub lower: f64,
    /// 95th-percentile upper bound of the prediction interval.
    #[prost(double, tag="4")]
    pub upper: f64,
    /// Confidence in this horizon's prediction.
    #[prost(enumeration="ConfidenceLevel", tag="5")]
    pub confidence: i32,
}
/// Pointer to a representative session for one archetype, ranked by
/// distance to the archetype centroid.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ExemplarSession {
    /// Session recording ID retrievable via ReplayService for the same
    /// org. Linkable from the admin regardless of originating platform.
    #[prost(string, tag="1")]
    pub session_id: ::prost::alloc::string::String,
    /// Quantile rank within the archetype: 25, 50, or 75. The writer
    /// emits at most one session per rank.
    #[prost(int32, tag="2")]
    pub rank: i32,
    /// L2 distance from the session's feature vector to the centroid.
    #[prost(double, tag="3")]
    pub distance: f64,
    /// Optional duration metadata for quick admin labelling.
    #[prost(int32, tag="4")]
    pub duration_seconds: i32,
    /// Optional platform identifier from the vocabulary
    /// {"ios", "android", "macos", "windows", "linux"}. The admin
    /// renders unknown values verbatim for forward compatibility.
    #[prost(string, tag="5")]
    pub platform: ::prost::alloc::string::String,
}
/// Per-screen dwell distribution within an archetype. Lets the admin
/// surface "this archetype lingers 8.2s on the Message Detail screen
/// vs 0.4s on the Inbox list".
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScreenDwell {
    /// One entry per screen. Screens with fewer than k members in the
    /// archetype are dropped from the list (not marked as absent).
    #[prost(message, repeated, tag="1")]
    pub entries: ::prost::alloc::vec::Vec<ScreenDwellEntry>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScreenDwellEntry {
    /// Stable screen identifier (e.g., "MessageDetail", "Inbox",
    /// "ProfileSettings"). Sourced from the same screen_name vocabulary
    /// used by heatmap_cells.
    #[prost(string, tag="1")]
    pub screen_name: ::prost::alloc::string::String,
    /// Median dwell time in seconds for this archetype on this screen.
    #[prost(double, tag="2")]
    pub median_seconds: f64,
    /// 75th-percentile dwell time in seconds.
    #[prost(double, tag="3")]
    pub p75_seconds: f64,
    /// Number of distinct sessions aggregated for this screen.
    #[prost(int32, tag="4")]
    pub session_count: i32,
}
/// End-to-end response latencies for members of one archetype, in
/// seconds. Each percentile is computed across all qualifying campaign
/// deliveries for the archetype's members within the rolling window.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct ResponseTimeline {
    /// Time from `delivered_at` to `read_at`, in seconds.
    #[prost(message, optional, tag="1")]
    pub read_after_delivered: ::core::option::Option<LatencyPercentiles>,
    /// Time from `read_at` to `acknowledged_at`, in seconds. Only
    /// includes deliveries that were both read and acknowledged.
    #[prost(message, optional, tag="2")]
    pub ack_after_read: ::core::option::Option<LatencyPercentiles>,
    /// End-to-end time from `delivered_at` to `acknowledged_at`, in
    /// seconds. Only includes deliveries that were acknowledged.
    #[prost(message, optional, tag="3")]
    pub ack_after_delivered: ::core::option::Option<LatencyPercentiles>,
    /// Number of deliveries the timeline is computed over.
    #[prost(int32, tag="4")]
    pub delivery_count: i32,
}
/// Latency distribution stats. Values are in seconds.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct LatencyPercentiles {
    #[prost(double, tag="1")]
    pub p50: f64,
    #[prost(double, tag="2")]
    pub p75: f64,
    #[prost(double, tag="3")]
    pub p95: f64,
}
/// A cohort-level prediction for campaign acknowledgment rate.
/// Never targets or scores individuals — always represents an audience aggregate.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct CohortPrediction {
    /// Predicted ACK rate for the audience (0.0-1.0).
    #[prost(float, tag="1")]
    pub predicted_ack_rate: f32,
    /// Lower bound of the confidence interval.
    #[prost(float, tag="2")]
    pub confidence_low: f32,
    /// Upper bound of the confidence interval.
    #[prost(float, tag="3")]
    pub confidence_high: f32,
    /// Confidence level based on available data volume.
    #[prost(enumeration="ConfidenceLevel", tag="4")]
    pub confidence_level: i32,
    /// Number of anonymous data points used for this prediction.
    #[prost(int32, tag="5")]
    pub data_point_count: i32,
}
/// Advisory information for campaign configuration, combining predictions and archetypes.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CampaignAdvisory {
    /// Cohort-level ACK prediction for the target audience.
    #[prost(message, optional, tag="1")]
    pub predicted_ack: ::core::option::Option<CohortPrediction>,
    /// Suggested escalation delay in minutes based on historical cohort patterns.
    /// 0 if insufficient data.
    #[prost(int32, tag="2")]
    pub suggested_escalation_delay_minutes: i32,
    /// Behavioral archetypes for the target audience.
    #[prost(message, repeated, tag="3")]
    pub archetypes: ::prost::alloc::vec::Vec<Archetype>,
}
/// Request to retrieve behavioral archetypes for a group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetGroupArchetypesRequest {
    /// ID of the group to query archetypes for. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
}
/// Response containing behavioral archetypes for a group.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetGroupArchetypesResponse {
    /// Behavioral archetypes for the group (empty if insufficient data).
    #[prost(message, repeated, tag="1")]
    pub archetypes: ::prost::alloc::vec::Vec<Archetype>,
    /// Number of anonymous feature vectors used for clustering.
    #[prost(int32, tag="2")]
    pub data_point_count: i32,
    /// Why `archetypes` looks the way it does. Lets the UI render a
    /// distinct empty-state affordance for "never trained" vs
    /// "below threshold" vs "no clusters" vs "ready". See PipelineState.
    #[prost(enumeration="PipelineState", tag="3")]
    pub pipeline_state: i32,
    /// Confidence in the returned archetypes, derived from available data
    /// volume. Always CONFIDENCE_LEVEL_LOW when provisional archetypes
    /// are returned — clients use this plus `Archetype.source` to render
    /// the low-confidence disclaimer.
    #[prost(enumeration="ConfidenceLevel", tag="4")]
    pub confidence_level: i32,
}
/// Request to predict cohort-level ACK rate for a campaign configuration.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct PredictCampaignAckRequest {
    /// ID of the target audience group. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Template type (optional, for prediction refinement).
    #[prost(string, tag="2")]
    pub template_type: ::prost::alloc::string::String,
    /// Number of workflow steps (optional, for prediction refinement).
    #[prost(int32, tag="3")]
    pub workflow_step_count: i32,
}
/// Response containing a cohort-level ACK prediction.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct PredictCampaignAckResponse {
    /// Cohort-level prediction.
    #[prost(message, optional, tag="1")]
    pub prediction: ::core::option::Option<CohortPrediction>,
}
/// Request for campaign configuration advisory.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCampaignAdvisoryRequest {
    /// ID of the target audience group. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Template ID (optional, for advisory context).
    #[prost(string, tag="2")]
    pub template_id: ::prost::alloc::string::String,
    /// Template version (optional).
    #[prost(int32, tag="3")]
    pub template_version: i32,
    /// Number of workflow steps (optional).
    #[prost(int32, tag="4")]
    pub workflow_step_count: i32,
}
/// Response containing campaign advisory information.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetCampaignAdvisoryResponse {
    /// Campaign advisory with prediction, suggested escalation, and archetypes.
    #[prost(message, optional, tag="1")]
    pub advisory: ::core::option::Option<CampaignAdvisory>,
}
/// Request to generate an AI narrative for a group's insights.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetInsightNarrativeRequest {
    /// ID of the group to generate a narrative for. Required.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Name of the prompt template to use (e.g., "campaign-advisory", "archetype-explanation").
    #[prost(string, tag="2")]
    pub prompt_name: ::prost::alloc::string::String,
}
/// Response containing an AI-generated narrative.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetInsightNarrativeResponse {
    /// AI-generated narrative text (Markdown formatted).
    #[prost(string, tag="1")]
    pub narrative: ::prost::alloc::string::String,
    /// Timestamp when the narrative was generated.
    #[prost(message, optional, tag="2")]
    pub generated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Model identifier used for generation.
    #[prost(string, tag="3")]
    pub model_id: ::prost::alloc::string::String,
}
/// Request to manually trigger the ML training pipeline.
/// Empty — organization is extracted from the JWT.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TriggerMlPipelineRequest {
}
/// Response after triggering the ML pipeline.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TriggerMlPipelineResponse {
    /// Remaining manual retrains allowed this month.
    #[prost(int32, tag="1")]
    pub remaining_this_month: i32,
    /// Timestamp of the last successful training (null if never trained).
    #[prost(message, optional, tag="2")]
    pub last_trained_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to manually retrigger archetype clustering for a single group
/// without rerunning the full SageMaker training pipeline. Reuses the
/// already-deployed clustering model.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TriggerArchetypeClusteringRequest {
    /// Group to recluster. Org is extracted from the JWT.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
}
/// Response after triggering archetype clustering for one group.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TriggerArchetypeClusteringResponse {
    /// Temporal workflow id — useful for client-side dedupe + operator
    /// debugging via the Temporal UI.
    #[prost(string, tag="1")]
    pub workflow_id: ::prost::alloc::string::String,
    /// Remaining manual retrains allowed this month. Shares the same
    /// monthly counter as TriggerMLPipeline (ml_manual_limit_monthly).
    #[prost(int32, tag="2")]
    pub remaining_this_month: i32,
    /// Timestamp of the last successful archetype clustering for this
    /// (org, group), null if never clustered.
    #[prost(message, optional, tag="3")]
    pub last_clustered_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to draft a campaign body for a given archetype using Bedrock.
/// Used by the Compass "Target this archetype in a new campaign" CTA to
/// pre-fill the campaign creation wizard's body field.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GenerateCampaignBodyDraftRequest {
    /// UUID of the source group whose archetype set the label belongs to.
    #[prost(string, tag="1")]
    pub group_id: ::prost::alloc::string::String,
    /// Stable archetype label, e.g. "Swift Acknowledger".
    #[prost(string, tag="2")]
    pub archetype_label: ::prost::alloc::string::String,
    /// Lane-recommended action copy passed through from the admin (e.g.
    /// "Simplify the call-to-action"). Used as a tone hint for the prompt.
    #[prost(string, tag="3")]
    pub lane_action: ::prost::alloc::string::String,
}
/// Response containing the generated draft body in Markdown.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GenerateCampaignBodyDraftResponse {
    /// Draft Markdown body, 3-5 sentences. Authored as if written for the
    /// recipient — does not mention the archetype name.
    #[prost(string, tag="1")]
    pub body_markdown: ::prost::alloc::string::String,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Confidence level for cohort-level predictions, based on available data volume.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ConfidenceLevel {
    Unspecified = 0,
    /// Fewer than 50 campaigns — predictions based on heuristics/industry benchmarks.
    Low = 1,
    /// 50-200 campaigns — basic clustering available, wide confidence intervals.
    Medium = 2,
    /// 200+ campaigns — full ML pipeline, narrow confidence intervals.
    High = 3,
}
impl ConfidenceLevel {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "CONFIDENCE_LEVEL_UNSPECIFIED",
            Self::Low => "CONFIDENCE_LEVEL_LOW",
            Self::Medium => "CONFIDENCE_LEVEL_MEDIUM",
            Self::High => "CONFIDENCE_LEVEL_HIGH",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "CONFIDENCE_LEVEL_UNSPECIFIED" => Some(Self::Unspecified),
            "CONFIDENCE_LEVEL_LOW" => Some(Self::Low),
            "CONFIDENCE_LEVEL_MEDIUM" => Some(Self::Medium),
            "CONFIDENCE_LEVEL_HIGH" => Some(Self::High),
            _ => None,
        }
    }
}
/// Pipeline state for a group's archetypes. Lets the admin UI render
/// distinct empty-state affordances ("run clustering" vs "need N more
/// sessions" vs "pipeline ran but audience was too homogeneous") instead
/// of treating every empty archetype list the same. Populated by
/// InsightsService.GetGroupArchetypes.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum PipelineState {
    Unspecified = 0,
    /// The ML pipeline has never fired for this org. Archetypes are
    /// empty because nothing ran, not because of data shape.
    NeverRun = 1,
    /// The pipeline ran but the group had fewer than the k-anonymization
    /// minimum feature vectors (50), so clustering was skipped. UI
    /// renders "keep running campaigns" affordance.
    BelowThreshold = 2,
    /// The pipeline ran with enough vectors but the clustering provider
    /// returned zero clusters — typically means the audience is too
    /// homogeneous to separate into distinct archetypes.
    NoClusters = 3,
    /// Archetypes are populated and ready to render.
    Ready = 4,
}
impl PipelineState {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "PIPELINE_STATE_UNSPECIFIED",
            Self::NeverRun => "PIPELINE_STATE_NEVER_RUN",
            Self::BelowThreshold => "PIPELINE_STATE_BELOW_THRESHOLD",
            Self::NoClusters => "PIPELINE_STATE_NO_CLUSTERS",
            Self::Ready => "PIPELINE_STATE_READY",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "PIPELINE_STATE_UNSPECIFIED" => Some(Self::Unspecified),
            "PIPELINE_STATE_NEVER_RUN" => Some(Self::NeverRun),
            "PIPELINE_STATE_BELOW_THRESHOLD" => Some(Self::BelowThreshold),
            "PIPELINE_STATE_NO_CLUSTERS" => Some(Self::NoClusters),
            "PIPELINE_STATE_READY" => Some(Self::Ready),
            _ => None,
        }
    }
}
/// Where an archetype came from. Lets clients distinguish trained ML
/// clustering output from low-confidence provisional output generated
/// for sandboxes and opted-in organizations before enough engagement
/// data exists. Clients MUST render a low-confidence disclaimer for
/// PROVISIONAL archetypes.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ArchetypeSource {
    Unspecified = 0,
    /// Produced by the trained ML clustering pipeline (k-anonymized,
    /// DP-noised behavioral feature vectors).
    Ml = 1,
    /// Rule-based provisional output derived from coarse delivery/read/
    /// ack activity (or a stable starter distribution for sandboxes with
    /// no activity). Low confidence, never written to the ML artifact
    /// path, and always superseded by ML output once available.
    Provisional = 2,
}
impl ArchetypeSource {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ARCHETYPE_SOURCE_UNSPECIFIED",
            Self::Ml => "ARCHETYPE_SOURCE_ML",
            Self::Provisional => "ARCHETYPE_SOURCE_PROVISIONAL",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ARCHETYPE_SOURCE_UNSPECIFIED" => Some(Self::Unspecified),
            "ARCHETYPE_SOURCE_ML" => Some(Self::Ml),
            "ARCHETYPE_SOURCE_PROVISIONAL" => Some(Self::Provisional),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A single reachability registry row, returned by `GetReachability` and
/// `ListReachabilityForUser`. The plaintext identifier and envelope ciphertext
/// are NEVER returned over the wire — only metadata. The dispatch worker reads
/// the plaintext directly from the database and decrypts via KMS.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Reachability {
    /// Server-assigned row identifier (UUID).
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Organization that owns this reachability entry.
    #[prost(string, tag="2")]
    pub org_id: ::prost::alloc::string::String,
    /// User this reachability entry is for.
    #[prost(string, tag="3")]
    pub user_id: ::prost::alloc::string::String,
    /// Channel for which this entry stores a contact identifier.
    #[prost(enumeration="ChannelName", tag="4")]
    pub channel: i32,
    /// When the row was first written.
    #[prost(message, optional, tag="5")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the row was last upserted.
    #[prost(message, optional, tag="6")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional AWS region identifier (e.g. "eu-west-1") this user's data must
    /// remain in for GDPR/residency reasons. Unset means "no constraint."
    /// Enforcement happens at dispatch time, not write time.
    #[prost(string, optional, tag="7")]
    pub region_constraint: ::core::option::Option<::prost::alloc::string::String>,
}
/// Per-(org, channel) region allowlist used by the dispatch worker to enforce
/// data-residency policy. An empty `allowed_regions` list means "no policy
/// configured" — NOT "no regions allowed."
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RegionPolicy {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
    /// AWS region identifiers (e.g. "eu-west-1", "us-east-1"). Empty list ==
    /// "no policy configured" — the dispatch worker SHALL NOT block on empty.
    #[prost(string, repeated, tag="3")]
    pub allowed_regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
    #[prost(message, optional, tag="4")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Terminal status of a single dispatch attempt as returned by the worker-mode
/// `DispatchToChannel` RPC. Distinct from the richer `ChannelEventStatus` in
/// `channel_events.proto`, which models the audit-trail row for every state
/// transition (SENT → DELIVERED → OPENED → …). DispatchStatus is the immediate
/// outcome of one worker call.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum DispatchStatus {
    /// Default value; should not be used explicitly.
    Unspecified = 0,
    /// The adapter accepted the message for delivery (provider returned success).
    Sent = 1,
    /// The adapter returned a terminal error (e.g. recipient blocked, domain not
    /// verified). Retries SHALL NOT be attempted; consult `failure_reason`.
    Failed = 2,
    /// An existing `(dispatch_id, SENT)` row was found by the idempotency guard
    /// before the adapter was called; the prior receipt was returned without a
    /// second provider call.
    Deduped = 3,
}
impl DispatchStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "DISPATCH_STATUS_UNSPECIFIED",
            Self::Sent => "DISPATCH_STATUS_SENT",
            Self::Failed => "DISPATCH_STATUS_FAILED",
            Self::Deduped => "DISPATCH_STATUS_DEDUPED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "DISPATCH_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "DISPATCH_STATUS_SENT" => Some(Self::Sent),
            "DISPATCH_STATUS_FAILED" => Some(Self::Failed),
            "DISPATCH_STATUS_DEDUPED" => Some(Self::Deduped),
            _ => None,
        }
    }
}
// ─── DispatchToChannel ──────────────────────────────────────────────────────

/// Worker-mode entry point invoked by the Temporal worker for one recipient.
/// Idempotent on `dispatch_id`: if a `(dispatch_id, SENT)` row already exists
/// in `channel_dispatches`, the worker SHALL return DISPATCH_STATUS_DEDUPED
/// without re-invoking the channel adapter.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct DispatchToChannelRequest {
    /// Idempotency key. Must be stable across retries from pidgr-api side.
    #[prost(string, tag="1")]
    pub dispatch_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="3")]
    pub user_id: ::prost::alloc::string::String,
    /// Which channel adapter to invoke (EMAIL is the Wave 1 implementation).
    #[prost(enumeration="ChannelName", tag="4")]
    pub channel: i32,
    /// Template to render before dispatch.
    #[prost(string, tag="5")]
    pub template_id: ::prost::alloc::string::String,
    /// Per-recipient template variables.
    #[prost(map="string, string", tag="6")]
    pub template_vars: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    /// BCP-47 locale used to select the template translation.
    #[prost(string, tag="7")]
    pub locale: ::prost::alloc::string::String,
    /// Optional AWS region the worker MUST dispatch from (typically copied from
    /// the recipient's reachability row). Unset means "no constraint."
    #[prost(string, optional, tag="8")]
    pub region_constraint: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DispatchToChannelResponse {
    /// Echoes back the request's `dispatch_id`.
    #[prost(string, tag="1")]
    pub dispatch_id: ::prost::alloc::string::String,
    /// Terminal outcome of this call.
    #[prost(enumeration="DispatchStatus", tag="2")]
    pub status: i32,
    /// Human-readable failure reason; set only when `status` is
    /// DISPATCH_STATUS_FAILED.
    #[prost(string, optional, tag="3")]
    pub failure_reason: ::core::option::Option<::prost::alloc::string::String>,
}
// ─── UpsertReachability ─────────────────────────────────────────────────────

/// Records a recipient identifier for a (user, channel) tuple. The plaintext
/// identifier is column-level KMS-encrypted on insert and never logged or
/// returned. The server computes the org-scoped HMAC lookup hash so opt-out
/// webhooks can find the row without decrypt.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpsertReachabilityRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="3")]
    pub channel: i32,
    /// The plaintext identifier (email address, phone number, Slack user ID,
    /// Telegram chat ID, etc.). Encrypted at rest server-side. Servers MUST NOT
    /// log this field. Clients SHOULD treat this message as sensitive.
    #[prost(string, tag="4")]
    pub identifier_plaintext: ::prost::alloc::string::String,
    /// Optional AWS region this user's data must remain in (e.g. "eu-west-1").
    /// Recorded but NOT enforced at write time; enforcement is at dispatch.
    #[prost(string, optional, tag="5")]
    pub region_constraint: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpsertReachabilityResponse {
    /// The metadata for the upserted row. Plaintext identifier and envelope
    /// ciphertext are intentionally absent.
    #[prost(message, optional, tag="1")]
    pub reachability: ::core::option::Option<Reachability>,
}
// ─── RemoveReachability ─────────────────────────────────────────────────────

/// Idempotent removal. GDPR Recital 30 audit row is appended via internal-mTLS
/// BEFORE the registry row is deleted (see AuditService.Append). If no row
/// existed, `removed = false` and no audit row is emitted.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveReachabilityRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="3")]
    pub channel: i32,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveReachabilityResponse {
    /// True if a row was deleted. False if no row existed for the tuple
    /// (idempotent success).
    #[prost(bool, tag="1")]
    pub removed: bool,
}
// ─── GetReachability ────────────────────────────────────────────────────────

/// Returns the reachability metadata for a single (user, channel) tuple.
/// Returns NOT_FOUND if no row exists.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetReachabilityRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="3")]
    pub channel: i32,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetReachabilityResponse {
    /// Plaintext identifier and envelope ciphertext are intentionally absent.
    #[prost(message, optional, tag="1")]
    pub reachability: ::core::option::Option<Reachability>,
}
// ─── ListReachabilityForUser ────────────────────────────────────────────────

/// Returns one Reachability entry per channel configured for a (org, user)
/// pair. Used by the admin-side per-user matrix view. Plaintext identifiers
/// and envelope ciphertext are intentionally absent — the admin UI only needs
/// to know which channels are configured.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListReachabilityForUserRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub user_id: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListReachabilityForUserResponse {
    /// One entry per channel that has a row for the (org_id, user_id) pair.
    #[prost(message, repeated, tag="1")]
    pub reachabilities: ::prost::alloc::vec::Vec<Reachability>,
}
// ─── GetRegionPolicy / SetRegionPolicy ──────────────────────────────────────

#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetRegionPolicyRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetRegionPolicyResponse {
    /// Always populated. Empty `allowed_regions` means "no policy configured"
    /// — NOT "no regions allowed."
    #[prost(message, optional, tag="1")]
    pub policy: ::core::option::Option<RegionPolicy>,
}
/// Admin-only upsert. Empty `allowed_regions` clears the policy.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SetRegionPolicyRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
    /// AWS region identifiers (e.g. "eu-west-1"). Empty list == "no policy."
    #[prost(string, repeated, tag="3")]
    pub allowed_regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SetRegionPolicyResponse {
    #[prost(message, optional, tag="1")]
    pub policy: ::core::option::Option<RegionPolicy>,
}
// ─── GetCostCapPolicy / SetCostCapPolicy ────────────────────────────────────

/// Get the cost-cap state for the current calendar-month period (UTC). When
/// no row exists for `(org_id, channel, period_yyyymm)`, the server returns
/// the channel default cap from server config
/// (`COST_CAP_DEFAULT_${CHANNEL}_MICROS`) with `used_micros = 0`.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCostCapPolicyRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetCostCapPolicyResponse {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
    /// Current period's cap in micros (1/1_000_000 of a USD).
    #[prost(int64, tag="3")]
    pub cap_micros: i64,
    /// Current period's accumulated spend in micros.
    #[prost(int64, tag="4")]
    pub used_micros: i64,
    /// Calendar-month period in integer YYYYMM form (e.g. 202605 for May 2026).
    #[prost(int32, tag="5")]
    pub period_yyyymm: i32,
}
/// Admin-only upsert of the cap for the current calendar-month period. Future
/// periods inherit the most recent SetCostCapPolicy value until the next call.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SetCostCapPolicyRequest {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
    #[prost(int64, tag="3")]
    pub cap_micros: i64,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SetCostCapPolicyResponse {
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    #[prost(enumeration="ChannelName", tag="2")]
    pub channel: i32,
    #[prost(int64, tag="3")]
    pub cap_micros: i64,
    #[prost(int64, tag="4")]
    pub used_micros: i64,
    #[prost(int32, tag="5")]
    pub period_yyyymm: i32,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A shareable invite link that allows users to self-join an organization.
/// Links carry a role assignment and optional usage/expiry constraints.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct InviteLink {
    /// Unique identifier for the invite link.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Cryptographically random base64url-encoded token (43 characters).
    #[prost(string, tag="2")]
    pub token: ::prost::alloc::string::String,
    /// ID of the role assigned to users who redeem this link.
    #[prost(string, tag="3")]
    pub role_id: ::prost::alloc::string::String,
    /// Maximum number of times this link can be redeemed.
    /// 0 means unlimited.
    #[prost(int32, tag="4")]
    pub max_uses: i32,
    /// Number of times this link has been redeemed.
    #[prost(int32, tag="5")]
    pub use_count: i32,
    /// When the link expires. Empty if no expiry.
    #[prost(message, optional, tag="6")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the link was revoked. Empty if not revoked.
    #[prost(message, optional, tag="7")]
    pub revoked_at: ::core::option::Option<::prost_types::Timestamp>,
    /// ID of the admin who created the link.
    #[prost(string, tag="8")]
    pub created_by: ::prost::alloc::string::String,
    /// When the link was created.
    #[prost(message, optional, tag="9")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Data governance region assigned to users who redeem this link. Empty means inherit from org default.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="10")]
    pub data_governance_region: ::prost::alloc::string::String,
}
/// Request to create a new invite link for the organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateInviteLinkRequest {
    /// ID of the role to assign. Defaults to the organization's employee role if empty.
    #[prost(string, tag="1")]
    pub role_id: ::prost::alloc::string::String,
    /// Maximum number of redemptions. 0 means unlimited.
    #[prost(int32, tag="2")]
    pub max_uses: i32,
    /// Number of hours until the link expires. 0 means no expiry.
    /// Constraints: Valid range 0 to 8760 (1 year).
    #[prost(int32, tag="3")]
    pub expires_in_hours: i32,
    /// Optional data governance region. Users who redeem this link inherit this region. Empty means inherit from org default.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="4")]
    pub data_governance_region: ::prost::alloc::string::String,
}
/// Response after creating an invite link.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateInviteLinkResponse {
    /// The newly created invite link.
    #[prost(message, optional, tag="1")]
    pub invite_link: ::core::option::Option<InviteLink>,
    /// Full URL for sharing (e.g. "<https://app.pidgr.com/join?token=<TOKEN>">).
    #[prost(string, tag="2")]
    pub url: ::prost::alloc::string::String,
}
/// Request to list all invite links for the organization.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListInviteLinksRequest {
}
/// Response containing all invite links for the organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListInviteLinksResponse {
    /// All invite links (active, expired, maxed-out, and revoked), ordered by creation date descending.
    #[prost(message, repeated, tag="1")]
    pub invite_links: ::prost::alloc::vec::Vec<InviteLink>,
}
/// Request to revoke an invite link.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeInviteLinkRequest {
    /// ID of the invite link to revoke. Required.
    #[prost(string, tag="1")]
    pub invite_link_id: ::prost::alloc::string::String,
}
/// Response after revoking an invite link.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeInviteLinkResponse {
}
/// Request to redeem an invite link (authenticated — email extracted from JWT).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RedeemInviteLinkRequest {
    /// The invite link token from the URL query parameter.
    #[prost(string, tag="1")]
    pub token: ::prost::alloc::string::String,
}
/// Response after redeeming an invite link.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RedeemInviteLinkResponse {
    /// Name of the organization the user was added to.
    #[prost(string, tag="1")]
    pub organization_name: ::prost::alloc::string::String,
}
/// Request to validate an invite link and provision a user account if needed (unauthenticated).
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ValidateInviteLinkRequest {
    /// The invite link token from the URL query parameter.
    #[prost(string, tag="1")]
    pub token: ::prost::alloc::string::String,
    /// Email address of the user joining the organization.
    /// Constraints: Max length 254 characters (RFC 5321).
    #[prost(string, tag="2")]
    pub email: ::prost::alloc::string::String,
}
/// Response after validating an invite link.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ValidateInviteLinkResponse {
    /// Name of the organization the invite link belongs to.
    #[prost(string, tag="1")]
    pub organization_name: ::prost::alloc::string::String,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Request to invite a new user to the organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InviteUserRequest {
    /// Email address to send the invitation to.
    /// Constraints: Max length 254 characters (RFC 5321).
    #[prost(string, tag="1")]
    pub email: ::prost::alloc::string::String,
    /// Display name for the invited user.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// ID of the role to assign. Defaults to the organization's employee role if empty.
    #[prost(string, tag="4")]
    pub role_id: ::prost::alloc::string::String,
    /// Optional profile attributes to pre-fill at invitation time.
    #[prost(message, optional, tag="5")]
    pub profile: ::core::option::Option<UserProfile>,
    /// Optional data governance region for the invited user. Empty means inherit from org default.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="6")]
    pub data_governance_region: ::prost::alloc::string::String,
}
/// Response after inviting a user.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InviteUserResponse {
    /// The newly created user (status: INVITED).
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to retrieve a user by ID.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetUserRequest {
    /// ID of the user to retrieve.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response containing the requested user.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetUserResponse {
    /// The requested user.
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to list users in the organization with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListUsersRequest {
    /// Pagination parameters.
    #[prost(message, optional, tag="1")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of users.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListUsersResponse {
    /// List of users in this page.
    #[prost(message, repeated, tag="1")]
    pub users: ::prost::alloc::vec::Vec<User>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to change a user's role within the organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateUserRoleRequest {
    /// ID of the user whose role to update.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// ID of the new role to assign.
    #[prost(string, tag="2")]
    pub role_id: ::prost::alloc::string::String,
}
/// Response after updating a user's role.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateUserRoleResponse {
    /// The updated user with the new role.
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to deactivate a user within the organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeactivateUserRequest {
    /// ID of the user to deactivate.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response after deactivating a user.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct DeactivateUserResponse {
    /// The deactivated user (status: DEACTIVATED).
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to reactivate a deactivated user.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ReactivateUserRequest {
    /// ID of the user to reactivate.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response after reactivating a user.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ReactivateUserResponse {
    /// The reactivated user (status: INVITED).
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to revoke an invitation for a user who has not yet registered.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeInviteRequest {
    /// ID of the invited user to remove.
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
}
/// Response after revoking an invitation. Empty on success.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RevokeInviteResponse {
}
/// Request to update a user's profile attributes.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateUserProfileRequest {
    /// ID of the user whose profile to update.
    /// Empty or matching the caller's own ID allows self-update without PERMISSION_MEMBERS_MANAGE.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// Profile attributes to set. All provided fields overwrite existing values.
    #[prost(message, optional, tag="2")]
    pub profile: ::core::option::Option<UserProfile>,
}
/// Response after updating a user's profile.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateUserProfileResponse {
    /// The updated user with the new profile.
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
}
/// Request to retrieve the caller's platform settings.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetUserSettingsRequest {
}
/// Response containing the caller's platform settings.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetUserSettingsResponse {
    /// Current settings. Fields at their default value indicate the platform default.
    #[prost(message, optional, tag="1")]
    pub settings: ::core::option::Option<UserSettings>,
}
/// Request to update the caller's platform settings.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateUserSettingsRequest {
    /// Settings to update. Only fields with non-default (non-UNSPECIFIED) values
    /// are applied; default-valued fields are left unchanged.
    #[prost(message, optional, tag="1")]
    pub settings: ::core::option::Option<UserSettings>,
}
/// Response after updating the caller's platform settings.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateUserSettingsResponse {
    /// The full settings after the update.
    #[prost(message, optional, tag="1")]
    pub settings: ::core::option::Option<UserSettings>,
}
/// Request to invite multiple users to the organization in a single call.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct BulkInviteUsersRequest {
    /// Email addresses to invite.
    /// Constraints: Min 1, max 100 emails. Duplicates are deduplicated before processing.
    #[prost(string, repeated, tag="1")]
    pub emails: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
    /// ID of the role to assign. Defaults to the organization's employee role if empty.
    #[prost(string, tag="2")]
    pub role_id: ::prost::alloc::string::String,
}
/// Per-email result within a bulk invite operation.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BulkInviteResult {
    /// The email address that was processed.
    #[prost(string, tag="1")]
    pub email: ::prost::alloc::string::String,
    /// Whether the invitation succeeded.
    #[prost(bool, tag="2")]
    pub success: bool,
    /// Error message if the invitation failed (e.g. "user already exists").
    /// Empty on success.
    #[prost(string, tag="3")]
    pub error: ::prost::alloc::string::String,
    /// The created user. Only set on success.
    #[prost(message, optional, tag="4")]
    pub user: ::core::option::Option<User>,
}
/// Response after bulk inviting users.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BulkInviteUsersResponse {
    /// Per-email results in the same order as the deduplicated input.
    #[prost(message, repeated, tag="1")]
    pub results: ::prost::alloc::vec::Vec<BulkInviteResult>,
    /// Number of users successfully invited.
    #[prost(int32, tag="2")]
    pub invited_count: i32,
    /// Number of emails that failed.
    #[prost(int32, tag="3")]
    pub failed_count: i32,
}
/// Request to confirm passkey enrollment after client-side WebAuthn registration.
/// The server verifies that the caller has at least one registered WebAuthn
/// credential before setting the enrollment attribute.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ConfirmPasskeyEnrollmentRequest {
}
/// Response after confirming passkey enrollment.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ConfirmPasskeyEnrollmentResponse {
    /// Whether enrollment was confirmed and the user attribute was updated.
    #[prost(bool, tag="1")]
    pub confirmed: bool,
}
/// Request to update a user's data governance region.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateUserRegionRequest {
    /// ID of the user whose region to update. Required.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// New governance region, or empty to inherit from org default.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="2")]
    pub data_governance_region: ::prost::alloc::string::String,
}
/// Response after updating a user's governance region.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateUserRegionResponse {
    /// The updated user.
    #[prost(message, optional, tag="1")]
    pub user: ::core::option::Option<User>,
    /// Temporal workflow ID for the region migration, if a migration was triggered.
    /// Empty if the region didn't actually change.
    #[prost(string, tag="2")]
    pub migration_workflow_id: ::prost::alloc::string::String,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A single non-retired pepper version. Returned by GetPeppers.
///
/// During a rotation overlap, multiple versions are returned — callers
/// (e.g. pidgr-integrations) compute lookup hashes under EVERY returned
/// version to write or match against `identifier_lookup_hash_v1` and
/// `identifier_lookup_hash_v2` on the reachability registry.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Pepper {
    /// Monotonically-increasing version number. Lower versions retire first.
    #[prost(int32, tag="1")]
    pub version: i32,
    /// Raw HMAC key material. Sensitive — callers MUST NOT log or persist
    /// this value to disk. In-memory caching keyed on (org_id, version) with
    /// a short TTL is permitted and expected.
    #[prost(bytes="vec", tag="2")]
    pub key_material: ::prost::alloc::vec::Vec<u8>,
}
/// Request to fetch the active (non-retired) peppers for one org/purpose.
///
/// Auth: internal-mTLS only. This RPC exposes raw cryptographic key material
/// and MUST NOT be reachable from the public ingress or from JWT-authenticated
/// clients. The server SHALL reject any caller whose mTLS identity is not on
/// the configured allowlist.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetPeppersRequest {
    /// Organization whose peppers are requested.
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
    /// Purpose identifier scoping which key family to return. Use
    /// `"reachability_lookup"` for the pidgr-integrations registry lookup hash.
    #[prost(string, tag="2")]
    pub purpose: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetPeppersResponse {
    /// All non-retired pepper versions for the (org_id, purpose) pair, in
    /// ascending version order. Typically exactly one entry; two during a
    /// rotation overlap window; zero only when no pepper has ever been
    /// generated for this (org, purpose).
    #[prost(message, repeated, tag="1")]
    pub peppers: ::prost::alloc::vec::Vec<Pepper>,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Maps an identity provider claim to a user profile field.
/// Used for automatic profile population when users authenticate via SSO/SAML.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SsoAttributeMapping {
    /// Claim name from the identity provider (e.g. "urn:oid:2.5.4.11", "given_name").
    /// Constraints: Max length 500 characters.
    #[prost(string, tag="1")]
    pub idp_claim: ::prost::alloc::string::String,
    /// Target UserProfile field name (e.g. "department", "first_name").
    /// For custom attributes, use "custom:" prefix (e.g. "custom:cost_center").
    /// Constraints: Max length 100 characters.
    #[prost(string, tag="2")]
    pub profile_field: ::prost::alloc::string::String,
}
/// An organization (tenant) in the Pidgr platform.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Organization {
    /// Unique identifier for the organization.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Organization display name.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Default workflow used when campaigns don't specify one.
    #[prost(message, optional, tag="3")]
    pub default_workflow: ::core::option::Option<WorkflowDefinition>,
    /// Timestamp when the organization was created.
    #[prost(message, optional, tag="4")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Industry vertical.
    #[prost(enumeration="Industry", tag="5")]
    pub industry: i32,
    /// Employee headcount range.
    #[prost(enumeration="CompanySize", tag="6")]
    pub company_size: i32,
    /// SSO identity provider claim-to-profile mappings.
    /// Empty when the organization does not use SSO.
    #[prost(message, repeated, tag="7")]
    pub sso_attribute_mappings: ::prost::alloc::vec::Vec<SsoAttributeMapping>,
    /// Default language for new users in this organization.
    /// Empty means no org default (users auto-detect from device/browser).
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="8")]
    pub default_locale: ::prost::alloc::string::String,
    /// Organization lifecycle type.
    #[prost(enumeration="OrgType", tag="9")]
    pub org_type: i32,
    /// Expiration time for sandbox organizations. Empty for standard orgs.
    #[prost(message, optional, tag="10")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Data governance framework (EU, LATAM, BR, APAC, US).
    /// Determines legal framework, DPA template, and Bedrock endpoint routing.
    #[prost(string, tag="11")]
    pub data_governance_region: ::prost::alloc::string::String,
    /// AWS region for content storage (resolved from data_governance_region).
    /// e.g., "eu-west-1", "us-east-1".
    #[prost(string, tag="12")]
    pub data_content_region: ::prost::alloc::string::String,
    /// ─── ML pipeline settings ──────────────────────────────────────────────────
    /// Cold-start threshold: completed campaigns below this count trigger immediate
    /// retraining. At or above, the org is flagged for the weekly cron.
    /// Default 10, range 1-100.
    #[prost(int32, tag="13")]
    pub ml_retrain_cold_threshold: i32,
    /// Whether cancelled campaigns count toward the training counter. Default true.
    #[prost(bool, tag="14")]
    pub ml_cancelled_counts: bool,
    /// Monthly limit on manual retrain triggers. Default 3, range 0-10.
    #[prost(int32, tag="15")]
    pub ml_manual_limit_monthly: i32,
    /// Number of manual retrains used in the current month (resets monthly).
    #[prost(int32, tag="16")]
    pub ml_manual_retrains_used: i32,
    /// Whether the org is flagged for the next weekly cron run.
    #[prost(bool, tag="17")]
    pub ml_needs_retrain: bool,
    /// Campaigns completed since the last ML training run.
    #[prost(int32, tag="18")]
    pub campaigns_since_last_training: i32,
    /// Total campaigns completed across the organization lifetime.
    #[prost(int32, tag="19")]
    pub total_completed_campaigns: i32,
    /// Timestamp of the most recent successful ML training. Empty if never trained.
    #[prost(message, optional, tag="20")]
    pub last_ml_training_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Controls whether aggregate stats (campaign recipient/ack/missed counts)
    /// include synthetic data. Unset = default by org type: sandbox orgs include,
    /// standard orgs exclude. Derived intelligence (ML, analytics, attestation
    /// evidence) always excludes synthetic regardless of this setting.
    #[prost(bool, optional, tag="21")]
    pub include_synthetic_in_aggregates: ::core::option::Option<bool>,
    /// Whether the organization has opted into provisional (rule-based,
    /// low-confidence) archetypes for groups that don't yet have trained
    /// ML archetypes. Only meaningful for ORG_TYPE_STANDARD — sandbox
    /// organizations are always eligible regardless of this setting.
    /// Default false: production analytics stay conservative.
    #[prost(bool, tag="22")]
    pub provisional_archetypes_enabled: bool,
}
/// Request to create a new organization.
/// JWT auth only — the authenticated caller becomes the initial admin. Additional
/// admins are added via CreateInviteLink after the org exists.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateOrganizationRequest {
    /// Name for the new organization.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Industry vertical for the organization.
    #[prost(enumeration="Industry", tag="2")]
    pub industry: i32,
    /// Employee headcount range.
    #[prost(enumeration="CompanySize", tag="3")]
    pub company_size: i32,
    /// Access code required during early access.
    /// Format: PIDGR-XXXXXXXX (8 alphanumeric characters).
    #[prost(string, tag="4")]
    pub access_code: ::prost::alloc::string::String,
    /// Data governance framework. Defaults to "US" if omitted.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="5")]
    pub data_governance_region: ::prost::alloc::string::String,
    /// Optional bootstrap fixture to seed the organization with starter data.
    /// Empty string means the default fixture.
    #[prost(string, tag="6")]
    pub fixture_id: ::prost::alloc::string::String,
}
/// Response after creating an organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateOrganizationResponse {
    /// The newly created organization.
    #[prost(message, optional, tag="1")]
    pub organization: ::core::option::Option<Organization>,
    /// The admin user created for the organization.
    #[prost(message, optional, tag="2")]
    pub admin_user: ::core::option::Option<User>,
}
/// Request to retrieve the organization for the authenticated user.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetOrganizationRequest {
}
/// Response containing the organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetOrganizationResponse {
    /// The organization the authenticated user belongs to.
    #[prost(message, optional, tag="1")]
    pub organization: ::core::option::Option<Organization>,
}
/// Request to update organization settings.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateOrganizationRequest {
    /// New organization name. Empty string leaves unchanged.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// New default workflow definition. Null leaves unchanged.
    #[prost(message, optional, tag="2")]
    pub default_workflow: ::core::option::Option<WorkflowDefinition>,
    /// New industry vertical. UNSPECIFIED leaves unchanged.
    #[prost(enumeration="Industry", tag="3")]
    pub industry: i32,
    /// New employee headcount range. UNSPECIFIED leaves unchanged.
    #[prost(enumeration="CompanySize", tag="4")]
    pub company_size: i32,
    /// New default language for new users. Empty string leaves unchanged.
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="5")]
    pub default_locale: ::prost::alloc::string::String,
    /// New ML cold-start threshold. 0 leaves unchanged, otherwise must be in \[1, 100\].
    #[prost(int32, tag="6")]
    pub ml_retrain_cold_threshold: i32,
    /// New ML cancelled-counts flag. Uses google.protobuf.BoolValue-style semantics
    /// via optional to distinguish "not provided" from "set to false".
    #[prost(bool, optional, tag="7")]
    pub ml_cancelled_counts: ::core::option::Option<bool>,
    /// New ML monthly manual limit. Negative leaves unchanged, otherwise must be in \[0, 10\].
    /// Encoded as int32 with -1 meaning "leave unchanged".
    #[prost(int32, tag="8")]
    pub ml_manual_limit_monthly: i32,
    /// Set the synthetic-aggregates override; unset leaves it unchanged.
    #[prost(bool, optional, tag="9")]
    pub include_synthetic_in_aggregates: ::core::option::Option<bool>,
    /// New provisional-archetypes opt-in for standard organizations.
    /// Unset leaves unchanged. Rejected for sandbox organizations, which
    /// are always eligible automatically.
    #[prost(bool, optional, tag="10")]
    pub provisional_archetypes_enabled: ::core::option::Option<bool>,
}
/// Response after updating the organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateOrganizationResponse {
    /// The updated organization.
    #[prost(message, optional, tag="1")]
    pub organization: ::core::option::Option<Organization>,
}
/// Request to replace all SSO attribute mappings for the organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateSsoAttributeMappingsRequest {
    /// Complete list of SSO mappings (replaces all existing mappings).
    #[prost(message, repeated, tag="1")]
    pub sso_attribute_mappings: ::prost::alloc::vec::Vec<SsoAttributeMapping>,
}
/// Response after updating SSO attribute mappings.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateSsoAttributeMappingsResponse {
    /// The updated organization with the new SSO mappings.
    #[prost(message, optional, tag="1")]
    pub organization: ::core::option::Option<Organization>,
}
/// Request to rotate the analytics salt and optionally increase the bucket count.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RotateAnalyticsSaltRequest {
    /// New bucket count. Must be >= current bucket count. 0 means keep current.
    #[prost(int32, tag="1")]
    pub new_bucket_count: i32,
}
/// Response after rotating the analytics salt.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RotateAnalyticsSaltResponse {
    /// The new bucket count after rotation.
    #[prost(int32, tag="1")]
    pub bucket_count: i32,
}
/// Request to update the analytics epsilon (differential privacy parameter).
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct UpdateAnalyticsEpsilonRequest {
    /// New epsilon value. Must be in range \[0.5, 5.0\].
    #[prost(float, tag="1")]
    pub epsilon: f32,
}
/// Response after updating the analytics epsilon.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct UpdateAnalyticsEpsilonResponse {
    /// The new epsilon value.
    #[prost(float, tag="1")]
    pub epsilon: f32,
}
/// Request to create a sandbox organization for testing.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateSandboxOrganizationRequest {
    /// Name for the sandbox organization.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Required expiration time. Max 30 days from now for interactive callers;
    /// API-key callers may set shorter TTLs for ephemeral test sandboxes.
    #[prost(message, optional, tag="2")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Data governance framework. Defaults to "US" if omitted.
    /// Valid values: EU, LATAM, BR, APAC, US.
    #[prost(string, tag="3")]
    pub data_governance_region: ::prost::alloc::string::String,
    /// Optional bootstrap fixture to seed the sandbox with starter data.
    /// Empty string means the default fixture.
    /// Must match an id returned by ListSandboxFixtures.
    #[prost(string, tag="4")]
    pub fixture_id: ::prost::alloc::string::String,
}
/// Response after creating a sandbox organization.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateSandboxOrganizationResponse {
    /// The newly created sandbox organization (org_type: SANDBOX).
    #[prost(message, optional, tag="1")]
    pub organization: ::core::option::Option<Organization>,
    /// The admin user created for the sandbox.
    #[prost(message, optional, tag="2")]
    pub admin_user: ::core::option::Option<User>,
}
/// Request to delete a sandbox organization. Only callable for orgs with
/// org_type=SANDBOX. Allowed for super admins of the sandbox or the creator.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteSandboxOrganizationRequest {
    /// ID of the sandbox organization to delete.
    #[prost(string, tag="1")]
    pub org_id: ::prost::alloc::string::String,
}
/// Response after requesting deletion. Deletion runs asynchronously via
/// the DeleteOrgWorkflow; a success response means the workflow started.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteSandboxOrganizationResponse {
    /// ID of the Temporal workflow handling the deletion.
    #[prost(string, tag="1")]
    pub workflow_id: ::prost::alloc::string::String,
}
/// A bootstrap fixture that can be applied when creating a new organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SandboxFixture {
    /// Stable slug for referencing this fixture (e.g. "starter", "empty",
    /// "fintech", "sales"). Pass it back as the fixture_id on create.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Display name for admin UI (e.g. "Starter").
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Description shown alongside the fixture option in the UI.
    #[prost(string, tag="3")]
    pub description: ::prost::alloc::string::String,
    /// Exactly one fixture has is_default=true. Clients that show a simple
    /// "seed initial data" control select this fixture's id by default.
    #[prost(bool, tag="4")]
    pub is_default: bool,
}
/// Request to list all bootstrap fixtures available for seeding.
/// No parameters — catalog is the same for all callers.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListSandboxFixturesRequest {
}
/// Response containing the bootstrap fixture catalog.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListSandboxFixturesResponse {
    /// All registered fixtures, ordered by name.
    #[prost(message, repeated, tag="1")]
    pub fixtures: ::prost::alloc::vec::Vec<SandboxFixture>,
}
/// Request to list all organizations the authenticated user belongs to.
/// No parameters — user identity is extracted from the JWT sub claim.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListUserOrganizationsRequest {
}
/// Response containing all organizations the authenticated user belongs to.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListUserOrganizationsResponse {
    /// Organizations the user belongs to, ordered by created_at ascending.
    /// Excludes expired sandbox organizations.
    #[prost(message, repeated, tag="1")]
    pub organizations: ::prost::alloc::vec::Vec<Organization>,
}
/// Request to list only the sandbox organizations the authenticated user
/// belongs to (i.e. orgs where org_type = SANDBOX, filtered from the full
/// membership set). No parameters — user identity is extracted from the JWT
/// sub claim.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListUserSandboxesRequest {
}
/// Response containing the user's sandbox organizations.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListUserSandboxesResponse {
    /// Sandbox organizations the user belongs to, ordered by expires_at
    /// ascending (soonest-expiring first — matches the admin UI
    /// /organization/sandboxes ordering). Excludes already-expired sandboxes
    /// (those are pending cleanup by SandboxCleanupWorkflow).
    #[prost(message, repeated, tag="1")]
    pub sandboxes: ::prost::alloc::vec::Vec<Organization>,
}
// ─── Enums ───────────────────────────────────────────────────────────────────

/// Industry vertical for an organization.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Industry {
    Unspecified = 0,
    Technology = 1,
    Finance = 2,
    Healthcare = 3,
    Education = 4,
    Retail = 5,
    Manufacturing = 6,
    Media = 7,
    Other = 8,
}
impl Industry {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "INDUSTRY_UNSPECIFIED",
            Self::Technology => "INDUSTRY_TECHNOLOGY",
            Self::Finance => "INDUSTRY_FINANCE",
            Self::Healthcare => "INDUSTRY_HEALTHCARE",
            Self::Education => "INDUSTRY_EDUCATION",
            Self::Retail => "INDUSTRY_RETAIL",
            Self::Manufacturing => "INDUSTRY_MANUFACTURING",
            Self::Media => "INDUSTRY_MEDIA",
            Self::Other => "INDUSTRY_OTHER",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "INDUSTRY_UNSPECIFIED" => Some(Self::Unspecified),
            "INDUSTRY_TECHNOLOGY" => Some(Self::Technology),
            "INDUSTRY_FINANCE" => Some(Self::Finance),
            "INDUSTRY_HEALTHCARE" => Some(Self::Healthcare),
            "INDUSTRY_EDUCATION" => Some(Self::Education),
            "INDUSTRY_RETAIL" => Some(Self::Retail),
            "INDUSTRY_MANUFACTURING" => Some(Self::Manufacturing),
            "INDUSTRY_MEDIA" => Some(Self::Media),
            "INDUSTRY_OTHER" => Some(Self::Other),
            _ => None,
        }
    }
}
/// Employee headcount range for an organization.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum CompanySize {
    Unspecified = 0,
    CompanySize1200 = 1,
    CompanySize200500 = 2,
    CompanySize5001000 = 3,
    CompanySize10005000 = 4,
    CompanySize5000Plus = 5,
}
impl CompanySize {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "COMPANY_SIZE_UNSPECIFIED",
            Self::CompanySize1200 => "COMPANY_SIZE_1_200",
            Self::CompanySize200500 => "COMPANY_SIZE_200_500",
            Self::CompanySize5001000 => "COMPANY_SIZE_500_1000",
            Self::CompanySize10005000 => "COMPANY_SIZE_1000_5000",
            Self::CompanySize5000Plus => "COMPANY_SIZE_5000_PLUS",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "COMPANY_SIZE_UNSPECIFIED" => Some(Self::Unspecified),
            "COMPANY_SIZE_1_200" => Some(Self::CompanySize1200),
            "COMPANY_SIZE_200_500" => Some(Self::CompanySize200500),
            "COMPANY_SIZE_500_1000" => Some(Self::CompanySize5001000),
            "COMPANY_SIZE_1000_5000" => Some(Self::CompanySize10005000),
            "COMPANY_SIZE_5000_PLUS" => Some(Self::CompanySize5000Plus),
            _ => None,
        }
    }
}
/// Classification of an organization's lifecycle type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum OrgType {
    Unspecified = 0,
    Standard = 1,
    Sandbox = 2,
    /// Reserved for platform operations. At most one per deployment, seeded
    /// by migration. Cannot be created via CreateOrganization.
    Staff = 3,
}
impl OrgType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "ORG_TYPE_UNSPECIFIED",
            Self::Standard => "ORG_TYPE_STANDARD",
            Self::Sandbox => "ORG_TYPE_SANDBOX",
            Self::Staff => "ORG_TYPE_STAFF",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "ORG_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "ORG_TYPE_STANDARD" => Some(Self::Standard),
            "ORG_TYPE_SANDBOX" => Some(Self::Sandbox),
            "ORG_TYPE_STAFF" => Some(Self::Staff),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Per-user rendering context containing variable substitutions.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UserRenderContext {
    /// ID of the user being rendered for.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// Variable name-value pairs to substitute into the template.
    /// Constraints: Max 100 entries. Key max length 100 characters, value max length 10000 characters.
    #[prost(map="string, string", tag="2")]
    pub variables: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
/// Request to render a template for a batch of users.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RenderBatchRequest {
    /// ID of the template to render.
    #[prost(string, tag="1")]
    pub template_id: ::prost::alloc::string::String,
    /// Version of the template to render.
    #[prost(int32, tag="2")]
    pub version: i32,
    /// Per-user rendering contexts with variable substitutions.
    /// Constraints: Max 10000 users per batch.
    #[prost(message, repeated, tag="3")]
    pub users: ::prost::alloc::vec::Vec<UserRenderContext>,
}
/// Streamed response for each user's rendered message.
/// One response is emitted per user in the batch.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RenderBatchResponse {
    /// ID of the user this result is for.
    #[prost(string, tag="1")]
    pub user_id: ::prost::alloc::string::String,
    /// The rendered message (set on success).
    #[prost(message, optional, tag="2")]
    pub message: ::core::option::Option<Message>,
    /// Error message if rendering failed for this user (empty on success).
    #[prost(string, tag="3")]
    pub error: ::prost::alloc::string::String,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A session recording summary from the analytics provider.
/// Anonymous: no user identifiers are included.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SessionRecording {
    /// Recording ID from the analytics provider.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Timestamp when the recording started.
    #[prost(message, optional, tag="2")]
    pub start_time: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the recording ended.
    #[prost(message, optional, tag="3")]
    pub end_time: ::core::option::Option<::prost_types::Timestamp>,
    /// Duration of the recording in seconds.
    #[prost(int32, tag="4")]
    pub duration_seconds: i32,
    /// Activity score (0.0–1.0).
    #[prost(float, tag="5")]
    pub activity_score: f32,
}
/// Request to list session recordings.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListSessionRecordingsRequest {
    /// Optional: filter recordings by campaign ID (mapped to analytics property filter).
    /// Constraints: UUID format (36 characters).
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Optional: start of the time range filter (inclusive).
    #[prost(message, optional, tag="2")]
    pub date_from: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional: end of the time range filter (inclusive).
    #[prost(message, optional, tag="3")]
    pub date_to: ::core::option::Option<::prost_types::Timestamp>,
    /// Pagination parameters.
    #[prost(message, optional, tag="4")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of session recordings.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListSessionRecordingsResponse {
    /// List of session recordings in this page.
    #[prost(message, repeated, tag="1")]
    pub recordings: ::prost::alloc::vec::Vec<SessionRecording>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to fetch rrweb snapshot events for a recording.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetSessionSnapshotsRequest {
    /// Recording ID from the analytics provider.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub recording_id: ::prost::alloc::string::String,
}
/// Response containing rrweb snapshot events.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetSessionSnapshotsResponse {
    /// JSON-encoded array of rrweb eventWithTime objects.
    /// Clients parse this JSON to feed into rrweb-player.
    #[prost(string, tag="1")]
    pub snapshot_data: ::prost::alloc::string::String,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Request to list all roles in the caller's organization.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListRolesRequest {
}
/// Response containing the organization's roles.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListRolesResponse {
    /// All roles in the organization, including their permission sets.
    #[prost(message, repeated, tag="1")]
    pub roles: ::prost::alloc::vec::Vec<Role>,
}
/// Request to create a new role in the caller's organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateRoleRequest {
    /// Display name for the role (e.g. "Team Lead"). Required.
    /// A slug is auto-generated from the name.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Initial permission set for the role.
    /// PERMISSION_UNSPECIFIED values are rejected.
    #[prost(enumeration="Permission", repeated, tag="2")]
    pub permissions: ::prost::alloc::vec::Vec<i32>,
}
/// Response after creating a role.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateRoleResponse {
    /// The newly created role with its generated slug and permission set.
    #[prost(message, optional, tag="1")]
    pub role: ::core::option::Option<Role>,
}
/// Request to update a role's name and/or permissions.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateRoleRequest {
    /// ID of the role to update. Required.
    #[prost(string, tag="1")]
    pub role_id: ::prost::alloc::string::String,
    /// New display name. If empty, the name is not changed.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// New permission set (replaces existing permissions entirely).
    /// If empty, permissions are not changed.
    /// PERMISSION_UNSPECIFIED values are rejected.
    #[prost(enumeration="Permission", repeated, tag="3")]
    pub permissions: ::prost::alloc::vec::Vec<i32>,
}
/// Response after updating a role.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateRoleResponse {
    /// The updated role.
    #[prost(message, optional, tag="1")]
    pub role: ::core::option::Option<Role>,
}
/// Request to delete a role.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteRoleRequest {
    /// ID of the role to delete. Required.
    #[prost(string, tag="1")]
    pub role_id: ::prost::alloc::string::String,
}
/// Response after deleting a role.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteRoleResponse {
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Custom SAML attribute name overrides for identity providers that use
/// non-standard attribute names. When provided, these override the
/// auto-detected values from the metadata URL host.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SamlAttributeNames {
    /// SAML attribute name for the user's email address.
    #[prost(string, tag="1")]
    pub email: ::prost::alloc::string::String,
    /// SAML attribute name for the user's first name.
    #[prost(string, tag="2")]
    pub given_name: ::prost::alloc::string::String,
    /// SAML attribute name for the user's last name.
    #[prost(string, tag="3")]
    pub family_name: ::prost::alloc::string::String,
}
/// An SSO identity provider configured for an organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SsoProvider {
    /// Unique identifier for the provider.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Email domain that triggers this SSO provider (e.g. "acme.com").
    /// Constraints: Max length 253 characters (RFC 1035).
    #[prost(string, tag="2")]
    pub domain: ::prost::alloc::string::String,
    /// Type of identity provider.
    #[prost(enumeration="SsoProviderType", tag="3")]
    pub r#type: i32,
    /// SAML metadata URL or OIDC discovery URL.
    /// Constraints: Max length 2048 characters. HTTPS required.
    #[prost(string, tag="4")]
    pub metadata_url: ::prost::alloc::string::String,
    /// Name of the identity provider (used for signInWithRedirect).
    /// Set by the API when the IdP is created.
    #[prost(string, tag="5")]
    pub idp_provider_name: ::prost::alloc::string::String,
    /// Timestamp when the provider was created.
    #[prost(message, optional, tag="6")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the provider was last updated.
    #[prost(message, optional, tag="7")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Optional custom SAML attribute name overrides.
    #[prost(message, optional, tag="8")]
    pub attribute_mapping: ::core::option::Option<SamlAttributeNames>,
}
/// Request to check if an email domain has SSO configured.
/// This RPC is pre-authentication — no JWT required.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CheckSsoByDomainRequest {
    /// Email address to check. The domain part is extracted.
    /// Constraints: Max length 254 characters (RFC 5321).
    #[prost(string, tag="1")]
    pub email: ::prost::alloc::string::String,
}
/// Response for SSO domain check.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CheckSsoByDomainResponse {
    /// Whether SSO is enabled for the email's domain.
    #[prost(bool, tag="1")]
    pub sso_enabled: bool,
    /// Identity provider name for signInWithRedirect.
    /// Empty if sso_enabled is false.
    #[prost(string, tag="2")]
    pub provider_name: ::prost::alloc::string::String,
}
/// Request to create an SSO provider for the organization.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateSsoProviderRequest {
    /// Email domain to associate (e.g. "acme.com").
    /// Constraints: Max length 253 characters (RFC 1035).
    #[prost(string, tag="1")]
    pub domain: ::prost::alloc::string::String,
    /// Type of identity provider.
    #[prost(enumeration="SsoProviderType", tag="2")]
    pub r#type: i32,
    /// SAML metadata URL or OIDC discovery URL.
    /// Constraints: Max length 2048 characters. HTTPS required.
    #[prost(string, tag="3")]
    pub metadata_url: ::prost::alloc::string::String,
    /// Optional custom SAML attribute name overrides.
    /// When omitted, attribute names are auto-detected from the metadata URL.
    #[prost(message, optional, tag="4")]
    pub attribute_mapping: ::core::option::Option<SamlAttributeNames>,
}
/// Response after creating an SSO provider.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateSsoProviderResponse {
    /// The newly created SSO provider.
    #[prost(message, optional, tag="1")]
    pub provider: ::core::option::Option<SsoProvider>,
}
/// Request to get the SSO provider for the organization.
/// Returns the provider if one is configured, or empty if not.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetSsoProviderRequest {
}
/// Response containing the organization's SSO provider.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetSsoProviderResponse {
    /// The organization's SSO provider, or null if not configured.
    #[prost(message, optional, tag="1")]
    pub provider: ::core::option::Option<SsoProvider>,
}
/// Request to delete the organization's SSO provider.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteSsoProviderRequest {
    /// ID of the provider to delete.
    #[prost(string, tag="1")]
    pub provider_id: ::prost::alloc::string::String,
}
/// Response after deleting an SSO provider.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteSsoProviderResponse {
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Type of SSO identity provider.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum SsoProviderType {
    /// Default value; not a valid type.
    Unspecified = 0,
    /// SAML 2.0 identity provider (e.g. Okta, Azure AD).
    Saml = 1,
    /// OpenID Connect identity provider (e.g. Google Workspace, Auth0).
    Oidc = 2,
}
impl SsoProviderType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "SSO_PROVIDER_TYPE_UNSPECIFIED",
            Self::Saml => "SSO_PROVIDER_TYPE_SAML",
            Self::Oidc => "SSO_PROVIDER_TYPE_OIDC",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "SSO_PROVIDER_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "SSO_PROVIDER_TYPE_SAML" => Some(Self::Saml),
            "SSO_PROVIDER_TYPE_OIDC" => Some(Self::Oidc),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// An organizational unit within an organization (e.g. department, division).
/// Teams represent the organizational structure and can serve as sender identity
/// in campaigns.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct Team {
    /// Unique identifier for the team.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Human-readable display name (unique within the organization).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Optional description of the team's purpose.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="3")]
    pub description: ::prost::alloc::string::String,
    /// Number of users currently in the team.
    #[prost(int32, tag="4")]
    pub member_count: i32,
    /// Timestamp when the team was created.
    #[prost(message, optional, tag="5")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp when the team was last updated.
    #[prost(message, optional, tag="6")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Whether this is the organization's default team (cannot be deleted or renamed).
    #[prost(bool, tag="7")]
    pub is_default: bool,
    /// ID of the user who created this team. Empty for system-seeded defaults.
    #[prost(string, tag="8")]
    pub created_by: ::prost::alloc::string::String,
}
/// Request to create a new team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateTeamRequest {
    /// Display name for the team. Required.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Optional description.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="2")]
    pub description: ::prost::alloc::string::String,
}
/// Response after creating a team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateTeamResponse {
    /// The newly created team.
    #[prost(message, optional, tag="1")]
    pub team: ::core::option::Option<Team>,
}
/// Request to retrieve a team by ID.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetTeamRequest {
    /// ID of the team to retrieve. Required.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
}
/// Response containing the requested team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetTeamResponse {
    /// The requested team.
    #[prost(message, optional, tag="1")]
    pub team: ::core::option::Option<Team>,
}
/// Request to list teams in the organization with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListTeamsRequest {
    /// Pagination parameters.
    #[prost(message, optional, tag="1")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of teams.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListTeamsResponse {
    /// Teams in this page.
    #[prost(message, repeated, tag="1")]
    pub teams: ::prost::alloc::vec::Vec<Team>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to update a team's name and/or description.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateTeamRequest {
    /// ID of the team to update. Required.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
    /// New display name. If empty, the name is not changed.
    /// Default teams cannot be renamed.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// New description. If empty, the description is not changed.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="3")]
    pub description: ::prost::alloc::string::String,
}
/// Response after updating a team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateTeamResponse {
    /// The updated team.
    #[prost(message, optional, tag="1")]
    pub team: ::core::option::Option<Team>,
}
/// Request to delete a team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteTeamRequest {
    /// ID of the team to delete. Required.
    /// Default teams cannot be deleted.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
}
/// Response after deleting a team.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeleteTeamResponse {
}
/// Request to add users to a team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AddTeamMembersRequest {
    /// ID of the team to add members to. Required.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
    /// IDs of users to add. Must belong to the same organization.
    /// Adding an existing member is a no-op (idempotent).
    /// Constraints: Max 100 user IDs per request.
    #[prost(string, repeated, tag="2")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Response after adding team members.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct AddTeamMembersResponse {
    /// The team with updated member_count.
    #[prost(message, optional, tag="1")]
    pub team: ::core::option::Option<Team>,
}
/// Request to remove users from a team.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveTeamMembersRequest {
    /// ID of the team to remove members from. Required.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
    /// IDs of users to remove. Removing a non-member is a no-op (idempotent).
    /// Constraints: Max 100 user IDs per request.
    #[prost(string, repeated, tag="2")]
    pub user_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// Response after removing team members.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RemoveTeamMembersResponse {
    /// The team with updated member_count.
    #[prost(message, optional, tag="1")]
    pub team: ::core::option::Option<Team>,
}
/// Request to list members of a team with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListTeamMembersRequest {
    /// ID of the team whose members to list. Required.
    #[prost(string, tag="1")]
    pub team_id: ::prost::alloc::string::String,
    /// Pagination parameters.
    #[prost(message, optional, tag="2")]
    pub pagination: ::core::option::Option<Pagination>,
}
/// Response containing a page of team members.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListTeamMembersResponse {
    /// Users in this page.
    #[prost(message, repeated, tag="1")]
    pub users: ::prost::alloc::vec::Vec<User>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// A variable placeholder within a template that gets substituted during rendering.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TemplateVariable {
    /// Variable name used in the template body (e.g. "employee_name").
    /// Constraints: Max length 100 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Human-readable description of what this variable represents.
    /// Constraints: Max length 500 characters.
    #[prost(string, tag="2")]
    pub description: ::prost::alloc::string::String,
    /// Whether this variable must be provided during rendering.
    #[prost(bool, tag="3")]
    pub required: bool,
    /// Where this variable's value comes from (profile attribute or campaign config).
    #[prost(enumeration="TemplateVariableSource", tag="4")]
    pub source: i32,
    /// Fallback value used when the source does not provide a value.
    /// Constraints: Max length 1000 characters.
    #[prost(string, tag="5")]
    pub default_value: ::prost::alloc::string::String,
    /// When true, this variable's rendered value is masked in session replay
    /// and heatmap screenshots. Org admin controls per variable.
    #[prost(bool, tag="6")]
    pub pii: bool,
}
/// A versioned message template with variable placeholders.
/// Templates are append-only — updates create new versions.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Template {
    /// Unique identifier for the template.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// Human-readable template name (admin-facing label).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="2")]
    pub name: ::prost::alloc::string::String,
    /// Template body with {{variable}} placeholders for substitution.
    /// Constraints: Max length 50000 characters.
    #[prost(string, tag="3")]
    pub body: ::prost::alloc::string::String,
    /// Variables that can be substituted into the template body.
    #[prost(message, repeated, tag="4")]
    pub variables: ::prost::alloc::vec::Vec<TemplateVariable>,
    /// Version number (auto-incremented on each update).
    #[prost(int32, tag="5")]
    pub version: i32,
    /// Timestamp when this version was created.
    #[prost(message, optional, tag="6")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
    /// Timestamp of the most recent update (same as created_at for the latest version).
    #[prost(message, optional, tag="7")]
    pub updated_at: ::core::option::Option<::prost_types::Timestamp>,
    /// User-facing title shown as the message subject to recipients.
    /// Serves as the default title; campaigns can override it.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="8")]
    pub title: ::prost::alloc::string::String,
    /// Content format of this template (markdown, rich, HTML).
    /// UNSPECIFIED is treated as MARKDOWN for backward compatibility.
    #[prost(enumeration="TemplateType", tag="9")]
    pub r#type: i32,
    /// Language of the template body content (e.g., "en", "es", "ja").
    /// Defaults to the org's default_locale, falling back to "en".
    /// Translations are created as locale variants of this source.
    #[prost(string, tag="10")]
    pub source_locale: ::prost::alloc::string::String,
}
/// A locale-specific translation of a template's title and body.
/// Translations are created per template version and go through a review workflow.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct TemplateTranslation {
    /// Unique identifier for this translation.
    #[prost(string, tag="1")]
    pub id: ::prost::alloc::string::String,
    /// ID of the source template.
    #[prost(string, tag="2")]
    pub template_id: ::prost::alloc::string::String,
    /// Version of the source template this translation is for.
    #[prost(int32, tag="3")]
    pub version: i32,
    /// Target locale (e.g., "es", "pt-BR", "zh", "ja").
    #[prost(string, tag="4")]
    pub locale: ::prost::alloc::string::String,
    /// Translated title.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="5")]
    pub title: ::prost::alloc::string::String,
    /// Translated body content with {{variable}} placeholders preserved.
    /// Constraints: Max length 50000 characters.
    #[prost(string, tag="6")]
    pub body: ::prost::alloc::string::String,
    /// Current review status.
    #[prost(enumeration="TranslationStatus", tag="7")]
    pub status: i32,
    /// Who created this translation ("ai:bedrock", "ai:deepl", or user UUID).
    #[prost(string, tag="8")]
    pub translated_by: ::prost::alloc::string::String,
    /// User who approved the translation. Empty until approved.
    #[prost(string, tag="9")]
    pub reviewed_by: ::prost::alloc::string::String,
    /// When the translation was approved.
    #[prost(message, optional, tag="10")]
    pub reviewed_at: ::core::option::Option<::prost_types::Timestamp>,
    /// When the translation was created.
    #[prost(message, optional, tag="11")]
    pub created_at: ::core::option::Option<::prost_types::Timestamp>,
}
/// Request to create a new template.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateTemplateRequest {
    /// Human-readable template name (admin-facing label).
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="1")]
    pub name: ::prost::alloc::string::String,
    /// Template body with {{variable}} placeholders.
    /// Constraints: Max length 50000 characters.
    #[prost(string, tag="2")]
    pub body: ::prost::alloc::string::String,
    /// Variables available for substitution in the body.
    #[prost(message, repeated, tag="3")]
    pub variables: ::prost::alloc::vec::Vec<TemplateVariable>,
    /// User-facing title shown as the message subject to recipients.
    /// Constraints: Max length 200 characters.
    #[prost(string, tag="4")]
    pub title: ::prost::alloc::string::String,
    /// Content format of the template. Defaults to MARKDOWN if unspecified.
    #[prost(enumeration="TemplateType", tag="5")]
    pub r#type: i32,
    /// Language of the template body content. Defaults to org's default_locale.
    /// Valid values: en, es, pt-BR, zh, ja.
    #[prost(string, tag="6")]
    pub source_locale: ::prost::alloc::string::String,
}
/// Response after creating a template.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateTemplateResponse {
    /// The newly created template (version 1).
    #[prost(message, optional, tag="1")]
    pub template: ::core::option::Option<Template>,
}
/// Request to update a template, creating a new version.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateTemplateRequest {
    /// ID of the template to update.
    #[prost(string, tag="1")]
    pub template_id: ::prost::alloc::string::String,
    /// New template body with {{variable}} placeholders.
    /// Constraints: Max length 50000 characters.
    #[prost(string, tag="2")]
    pub body: ::prost::alloc::string::String,
    /// Updated variables for substitution.
    #[prost(message, repeated, tag="3")]
    pub variables: ::prost::alloc::vec::Vec<TemplateVariable>,
}
/// Response after updating a template.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateTemplateResponse {
    /// The updated template with incremented version number.
    #[prost(message, optional, tag="1")]
    pub template: ::core::option::Option<Template>,
}
/// Request to retrieve a specific template version.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct GetTemplateRequest {
    /// ID of the template to retrieve.
    #[prost(string, tag="1")]
    pub template_id: ::prost::alloc::string::String,
    /// Version to retrieve. 0 returns the latest version.
    #[prost(int32, tag="2")]
    pub version: i32,
}
/// Response containing the requested template.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTemplateResponse {
    /// The requested template.
    #[prost(message, optional, tag="1")]
    pub template: ::core::option::Option<Template>,
}
/// Request to list templates with pagination.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListTemplatesRequest {
    /// Pagination parameters.
    #[prost(message, optional, tag="1")]
    pub pagination: ::core::option::Option<Pagination>,
    /// Filter by template type. UNSPECIFIED returns all templates.
    #[prost(enumeration="TemplateType", tag="2")]
    pub r#type: i32,
}
/// Response containing a page of templates.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListTemplatesResponse {
    /// List of templates in this page (latest version of each).
    #[prost(message, repeated, tag="1")]
    pub templates: ::prost::alloc::vec::Vec<Template>,
    /// Pagination metadata for fetching subsequent pages.
    #[prost(message, optional, tag="2")]
    pub pagination_meta: ::core::option::Option<PaginationMeta>,
}
/// Request to create a translation for a template.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateTemplateTranslationRequest {
    /// ID of the template to translate.
    #[prost(string, tag="1")]
    pub template_id: ::prost::alloc::string::String,
    /// Version of the template to translate.
    #[prost(int32, tag="2")]
    pub version: i32,
    /// Target locale.
    #[prost(string, tag="3")]
    pub locale: ::prost::alloc::string::String,
    /// Translated title.
    #[prost(string, tag="4")]
    pub title: ::prost::alloc::string::String,
    /// Translated body content.
    #[prost(string, tag="5")]
    pub body: ::prost::alloc::string::String,
    /// Who created this translation ("ai:bedrock" or user UUID).
    #[prost(string, tag="6")]
    pub translated_by: ::prost::alloc::string::String,
    /// Initial status (typically DRAFT or AI_TRANSLATED).
    #[prost(enumeration="TranslationStatus", tag="7")]
    pub status: i32,
}
/// Response after creating a template translation.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct CreateTemplateTranslationResponse {
    /// The created translation.
    #[prost(message, optional, tag="1")]
    pub translation: ::core::option::Option<TemplateTranslation>,
}
/// Request to update an existing template translation.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateTemplateTranslationRequest {
    /// ID of the translation to update.
    #[prost(string, tag="1")]
    pub translation_id: ::prost::alloc::string::String,
    /// Updated title. Empty leaves unchanged.
    #[prost(string, tag="2")]
    pub title: ::prost::alloc::string::String,
    /// Updated body. Empty leaves unchanged.
    #[prost(string, tag="3")]
    pub body: ::prost::alloc::string::String,
    /// Updated status.
    #[prost(enumeration="TranslationStatus", tag="4")]
    pub status: i32,
}
/// Response after updating a template translation.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UpdateTemplateTranslationResponse {
    /// The updated translation.
    #[prost(message, optional, tag="1")]
    pub translation: ::core::option::Option<TemplateTranslation>,
}
/// Request to list translations for a template version.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ListTemplateTranslationsRequest {
    /// ID of the template.
    #[prost(string, tag="1")]
    pub template_id: ::prost::alloc::string::String,
    /// Version of the template. 0 returns translations for the latest version.
    #[prost(int32, tag="2")]
    pub version: i32,
}
/// Response containing all translations for a template version.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListTemplateTranslationsResponse {
    /// Translations for the requested template version.
    #[prost(message, repeated, tag="1")]
    pub translations: ::prost::alloc::vec::Vec<TemplateTranslation>,
}
/// Request to approve a template translation.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ApproveTemplateTranslationRequest {
    /// ID of the translation to approve.
    #[prost(string, tag="1")]
    pub translation_id: ::prost::alloc::string::String,
}
/// Response after approving a template translation.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ApproveTemplateTranslationResponse {
    /// The approved translation (status: APPROVED, reviewed_by and reviewed_at set).
    #[prost(message, optional, tag="1")]
    pub translation: ::core::option::Option<TemplateTranslation>,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Content format of a template, determining which editor and renderer to use.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum TemplateType {
    /// Default value; treated as MARKDOWN for backward compatibility.
    Unspecified = 0,
    /// Markdown with {{variable}} placeholders.
    Markdown = 1,
    /// Rich text format (reserved for future use).
    Rich = 2,
    /// Raw HTML format (reserved for future use).
    Html = 3,
}
impl TemplateType {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "TEMPLATE_TYPE_UNSPECIFIED",
            Self::Markdown => "TEMPLATE_TYPE_MARKDOWN",
            Self::Rich => "TEMPLATE_TYPE_RICH",
            Self::Html => "TEMPLATE_TYPE_HTML",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "TEMPLATE_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
            "TEMPLATE_TYPE_MARKDOWN" => Some(Self::Markdown),
            "TEMPLATE_TYPE_RICH" => Some(Self::Rich),
            "TEMPLATE_TYPE_HTML" => Some(Self::Html),
            _ => None,
        }
    }
}
/// Source from which a template variable's value is resolved at render time.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum TemplateVariableSource {
    /// Default value; treated as CUSTOM for backward compatibility.
    Unspecified = 0,
    /// Auto-resolved from the target user's profile attributes.
    Profile = 1,
    /// Provided manually in the campaign or workflow step configuration.
    Custom = 2,
}
impl TemplateVariableSource {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "TEMPLATE_VARIABLE_SOURCE_UNSPECIFIED",
            Self::Profile => "TEMPLATE_VARIABLE_SOURCE_PROFILE",
            Self::Custom => "TEMPLATE_VARIABLE_SOURCE_CUSTOM",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "TEMPLATE_VARIABLE_SOURCE_UNSPECIFIED" => Some(Self::Unspecified),
            "TEMPLATE_VARIABLE_SOURCE_PROFILE" => Some(Self::Profile),
            "TEMPLATE_VARIABLE_SOURCE_CUSTOM" => Some(Self::Custom),
            _ => None,
        }
    }
}
/// Review status of a template translation.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum TranslationStatus {
    Unspecified = 0,
    /// Translation draft, not yet reviewed.
    Draft = 1,
    /// Translation generated by AI, pending human review.
    AiTranslated = 2,
    /// Translation is being reviewed by a human.
    InReview = 3,
    /// Translation has been approved for use.
    Approved = 4,
}
impl TranslationStatus {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "TRANSLATION_STATUS_UNSPECIFIED",
            Self::Draft => "TRANSLATION_STATUS_DRAFT",
            Self::AiTranslated => "TRANSLATION_STATUS_AI_TRANSLATED",
            Self::InReview => "TRANSLATION_STATUS_IN_REVIEW",
            Self::Approved => "TRANSLATION_STATUS_APPROVED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "TRANSLATION_STATUS_UNSPECIFIED" => Some(Self::Unspecified),
            "TRANSLATION_STATUS_DRAFT" => Some(Self::Draft),
            "TRANSLATION_STATUS_AI_TRANSLATED" => Some(Self::AiTranslated),
            "TRANSLATION_STATUS_IN_REVIEW" => Some(Self::InReview),
            "TRANSLATION_STATUS_APPROVED" => Some(Self::Approved),
            _ => None,
        }
    }
}
// ─── Messages ───────────────────────────────────────────────────────────────

/// Decoded deeplink-token payload. Populated by ValidateDeeplinkToken
/// only when validation succeeds.
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct DeeplinkTokenPayload {
    /// Campaign UUID the deeplink targets. The native app uses this for the
    /// authenticated GetCampaign follow-up post-recipient-auth.
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Recipient UUID the token authorizes. The token does not authenticate
    /// the recipient (that's the auth flow's job); it authorizes "this
    /// deeplink path is for this recipient" so the native app can refuse
    /// to render a token whose embedded recipient mismatches the signed-in
    /// user.
    #[prost(string, tag="2")]
    pub recipient_user_id: ::prost::alloc::string::String,
    /// Step kind the deeplink targets — REMINDER vs ESCALATION. Lets the
    /// native app pick the right campaign-card variant before the auth
    /// gate.
    #[prost(enumeration="ChannelStepKind", tag="3")]
    pub step_kind: i32,
    /// Expiry the token carries. Validation rejects tokens past this time
    /// even if the signature checks out.
    #[prost(message, optional, tag="4")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SignDeeplinkTokenRequest {
    /// Campaign whose deeplink this token authorizes. Constraints: required,
    /// must be a UUID and exist within the caller's organization.
    #[prost(string, tag="1")]
    pub campaign_id: ::prost::alloc::string::String,
    /// Recipient the token authorizes. Constraints: required, must be a UUID
    /// and a member of the campaign's audience.
    #[prost(string, tag="2")]
    pub recipient_user_id: ::prost::alloc::string::String,
    /// Step kind the deeplink targets. Required.
    #[prost(enumeration="ChannelStepKind", tag="3")]
    pub step_kind: i32,
    /// Token lifetime in seconds from now. Constraints: required, must be
    /// in (0, 30 * 24 * 3600] (1 second to 30 days). 30 days matches the
    /// platform's outer bound on actionable campaign lifetimes; longer
    /// tokens are not signed.
    #[prost(int64, tag="4")]
    pub ttl_seconds: i64,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct SignDeeplinkTokenResponse {
    /// The signed token, ready to URL-embed in
    /// links.pidgr.com/c/{short_code}?t={token}. Format: base64url-encoded
    /// payload (JSON) + base64url-encoded HMAC-SHA256 trailer, joined by
    /// a single dot. Implementation detail — clients SHOULD NOT parse or
    /// mutate the token; they pass it back to ValidateDeeplinkToken.
    #[prost(string, tag="1")]
    pub token: ::prost::alloc::string::String,
    /// The expiry the token carries. Echoed back so clients don't need to
    /// redo the time-math the caller passed in via ttl_seconds.
    #[prost(message, optional, tag="2")]
    pub expires_at: ::core::option::Option<::prost_types::Timestamp>,
    /// The platform key version used to sign. Clients MAY record for
    /// telemetry but SHOULD NOT branch logic on it — the platform manages
    /// overlap windows during rotation transparently.
    #[prost(int32, tag="3")]
    pub key_version: i32,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ValidateDeeplinkTokenRequest {
    /// The token bytes from the deeplink URL's `t` query parameter.
    /// Constraints: required, non-empty.
    #[prost(string, tag="1")]
    pub token: ::prost::alloc::string::String,
    /// Campaign UUID embedded in the URL path (translated from the
    /// short-code by the native app via CampaignService.GetCampaignByShortCode).
    /// Validation rejects when the token's embedded campaign_id does not
    /// match — defense against replay attacks that swap the short-code
    /// path component while reusing a signed token from a different
    /// campaign.
    #[prost(string, tag="2")]
    pub campaign_id: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ValidateDeeplinkTokenResponse {
    /// True when signature + expiry both check out under any active or
    /// overlap-window key version.
    #[prost(bool, tag="1")]
    pub valid: bool,
    /// Reason validation failed. Set only when valid=false; UNSPECIFIED
    /// when valid=true. The native app uses this to drive UX (silent retry
    /// vs. "this link expired" message vs. "this link looks tampered").
    #[prost(enumeration="ValidationFailureReason", tag="2")]
    pub failure_reason: i32,
    /// Decoded payload. Populated only when valid=true. The native app
    /// SHOULD compare payload.recipient_user_id against the signed-in user
    /// and refuse to render the campaign card on mismatch.
    #[prost(message, optional, tag="3")]
    pub payload: ::core::option::Option<DeeplinkTokenPayload>,
}
// ─── Enums ──────────────────────────────────────────────────────────────────

/// Reason a deeplink-token validation failed. Empty when valid=true.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ValidationFailureReason {
    Unspecified = 0,
    /// Token bytes parsed but the HMAC signature did not verify under any
    /// active or overlap-window key version.
    InvalidSignature = 1,
    /// Token signature verified but its embedded expiry has passed.
    Expired = 2,
    /// Signature would have verified, but the key version that signed the
    /// token is past the rotation overlap window and has been hard-deleted.
    /// This means the token is older than the platform's retention bound
    /// (rotation cadence + overlap window) — operationally equivalent to
    /// EXPIRED but distinguishable for telemetry.
    KeyRetired = 3,
    /// Token bytes could not be parsed at all (not base64url, wrong length,
    /// missing payload separator, etc.). Indicates a tampered or
    /// truncated URL.
    Malformed = 4,
}
impl ValidationFailureReason {
    /// String value of the enum field names used in the ProtoBuf definition.
    ///
    /// The values are not transformed in any way and thus are considered stable
    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
    pub fn as_str_name(&self) -> &'static str {
        match self {
            Self::Unspecified => "VALIDATION_FAILURE_REASON_UNSPECIFIED",
            Self::InvalidSignature => "VALIDATION_FAILURE_REASON_INVALID_SIGNATURE",
            Self::Expired => "VALIDATION_FAILURE_REASON_EXPIRED",
            Self::KeyRetired => "VALIDATION_FAILURE_REASON_KEY_RETIRED",
            Self::Malformed => "VALIDATION_FAILURE_REASON_MALFORMED",
        }
    }
    /// Creates an enum from field names used in the ProtoBuf definition.
    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
        match value {
            "VALIDATION_FAILURE_REASON_UNSPECIFIED" => Some(Self::Unspecified),
            "VALIDATION_FAILURE_REASON_INVALID_SIGNATURE" => Some(Self::InvalidSignature),
            "VALIDATION_FAILURE_REASON_EXPIRED" => Some(Self::Expired),
            "VALIDATION_FAILURE_REASON_KEY_RETIRED" => Some(Self::KeyRetired),
            "VALIDATION_FAILURE_REASON_MALFORMED" => Some(Self::Malformed),
            _ => None,
        }
    }
}
include!("pidgr.v1.tonic.rs");
// @@protoc_insertion_point(module)