domain

package
v0.0.0-...-2f587aa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2026 License: AGPL-3.0, GPL-2.0 Imports: 30 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ErrCodeThemeNotFound       = "theme_not_found"
	ErrCodeThemeNotPublished   = "theme_not_published"
	ErrCodePostNotFound        = "post_not_found"
	ErrCodeCategoryNotFound    = "category_not_found"
	ErrCodeRenderFailed        = "render_failed"
	ErrCodeInvalidLiquidSyntax = "invalid_liquid_syntax"
)

Error codes for blog rendering

View Source
const (
	UpsertContactOperationCreate = "create"
	UpsertContactOperationUpdate = "update"
	UpsertContactOperationError  = "error"
)
View Source
const (
	GoalTypePurchase     = "purchase"     // Transaction with revenue (goal_value REQUIRED)
	GoalTypeSubscription = "subscription" // Recurring revenue started (goal_value REQUIRED)
	GoalTypeLead         = "lead"         // Form/inquiry submission (goal_value optional)
	GoalTypeSignup       = "signup"       // Registration/account creation (goal_value optional)
	GoalTypeBooking      = "booking"      // Appointment/demo scheduled (goal_value optional)
	GoalTypeTrial        = "trial"        // Trial started (goal_value optional)
	GoalTypeOther        = "other"        // Custom goal (goal_value optional)
)

Goal type constants

View Source
const (
	ChannelEmail = "email"
	ChannelWeb   = "web"
)

Channel constants for templates

View Source
const (
	UserIDKey        contextKey = "user_id"
	SessionIDKey     contextKey = "session_id"
	UserTypeKey      contextKey = "type"
	UserWorkspaceKey contextKey = "user_workspace"
)
View Source
const (
	WebhookDeliveryStatusPending    = "pending"
	WebhookDeliveryStatusDelivering = "delivering"
	WebhookDeliveryStatusDelivered  = "delivered"
	WebhookDeliveryStatusFailed     = "failed"
)

WebhookDeliveryStatus constants

View Source
const (
	BlogCacheTTL = 5 * time.Minute // TTL for cached blog pages
)

Blog cache configuration

View Source
const EmailQueuePriorityMarketing = 5

Default priority for marketing emails (broadcasts and automations)

Variables

View Source
var (
	ErrContactNotFound = errors.New("contact not found")
)
View Source
var ErrInsufficientPermissions = NewPermissionError(
	PermissionResourceWorkspace,
	PermissionTypeRead,
	"Insufficient permissions",
)

ErrInsufficientPermissions is the default insufficient permissions error

View Source
var GoalTypesRequiringValue = []string{
	GoalTypePurchase,
	GoalTypeSubscription,
}

GoalTypesRequiringValue is the list of goal types that require goal_value

View Source
var PredefinedSchemas = map[string]analytics.SchemaDefinition{
	"message_history": {
		Name: "message_history",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Messages",
				SQL:         "COUNT(*)",
				Description: "Total number of message history records",
			},
			"count_sent": {
				Type:        "count",
				Title:       "Sent",
				SQL:         "*",
				Description: "Total number of sent messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "sent_at IS NOT NULL"},
				},
			},
			"count_delivered": {
				Type:        "count",
				Title:       "Delivered",
				SQL:         "*",
				Description: "Total number of delivered messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "delivered_at IS NOT NULL"},
				},
			},
			"count_bounced": {
				Type:        "count",
				Title:       "Bounced",
				SQL:         "*",
				Description: "Total number of bounced messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "bounced_at IS NOT NULL"},
				},
			},
			"count_complained": {
				Type:        "count",
				Title:       "Complaints",
				SQL:         "*",
				Description: "Total number of complained messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "complained_at IS NOT NULL"},
				},
			},
			"count_opened": {
				Type:        "count",
				Title:       "Opens",
				SQL:         "*",
				Description: "Total number of opened messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "opened_at IS NOT NULL"},
				},
			},
			"count_clicked": {
				Type:        "count",
				Title:       "Clicks",
				SQL:         "*",
				Description: "Total number of clicked messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "clicked_at IS NOT NULL"},
				},
			},
			"count_unsubscribed": {
				Type:        "count",
				Title:       "Unsubscribes",
				SQL:         "*",
				Description: "Total number of unsubscribed messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "unsubscribed_at IS NOT NULL"},
				},
			},
			"count_failed": {
				Type:        "count",
				Title:       "Failed",
				SQL:         "*",
				Description: "Total number of failed messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "failed_at IS NOT NULL"},
				},
			},
			"count_sent_emails": {
				Type:        "count",
				Title:       "Sent Emails",
				SQL:         "*",
				Description: "Total number of sent email messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "sent_at IS NOT NULL"},
					{SQL: "channel = 'email'"},
				},
			},
			"count_delivered_emails": {
				Type:        "count",
				Title:       "Delivered Emails",
				SQL:         "*",
				Description: "Total number of delivered email messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "delivered_at IS NOT NULL"},
					{SQL: "channel = 'email'"},
				},
			},
			"count_broadcast_messages": {
				Type:        "count",
				Title:       "Broadcast Messages",
				SQL:         "*",
				Description: "Total number of broadcast messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "broadcast_id IS NOT NULL"},
				},
			},
			"count_transactional_messages": {
				Type:        "count",
				Title:       "Transactional Messages",
				SQL:         "*",
				Description: "Total number of transactional messages",
				Filters: []analytics.MeasureFilter{
					{SQL: "broadcast_id IS NULL"},
				},
			},
			"count_recent_messages": {
				Type:        "count",
				Title:       "Recent Messages",
				SQL:         "*",
				Description: "Messages from the last 30 days",
				Filters: []analytics.MeasureFilter{
					{SQL: "created_at >= NOW() - INTERVAL '30 days'"},
				},
			},
			"count_successful_deliveries": {
				Type:        "count",
				Title:       "Successful Deliveries",
				SQL:         "*",
				Description: "Successfully delivered messages (not bounced or failed)",
				Filters: []analytics.MeasureFilter{
					{SQL: "delivered_at IS NOT NULL"},
					{SQL: "bounced_at IS NULL"},
					{SQL: "failed_at IS NULL"},
				},
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"created_at": {
				Type:        "time",
				Title:       "Created At",
				SQL:         "created_at",
				Description: "Message creation timestamp",
			},
			"sent_at": {
				Type:        "time",
				Title:       "Sent At",
				SQL:         "sent_at",
				Description: "Message sent timestamp",
			},
			"contact_email": {
				Type:        "string",
				Title:       "Contact Email",
				SQL:         "contact_email",
				Description: "Recipient email address",
			},
			"broadcast_id": {
				Type:        "string",
				Title:       "Broadcast ID",
				SQL:         "broadcast_id",
				Description: "Associated broadcast ID",
			},
			"channel": {
				Type:        "string",
				Title:       "Channel",
				SQL:         "channel",
				Description: "Message channel (email, sms, etc.)",
			},
			"template_id": {
				Type:        "string",
				Title:       "Template ID",
				SQL:         "template_id",
				Description: "Template identifier",
			},
		},
	},
	"contacts": {
		Name: "contacts",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Contacts",
				SQL:         "*",
				Description: "Total number of contacts",
			},
			"count_active": {
				Type:        "count",
				Title:       "Active Contacts",
				SQL:         "*",
				Description: "Total number of active contacts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'active'"},
				},
			},
			"count_unsubscribed": {
				Type:        "count",
				Title:       "Unsubscribed Contacts",
				SQL:         "*",
				Description: "Total number of unsubscribed contacts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'unsubscribed'"},
				},
			},
			"count_bounced": {
				Type:        "count",
				Title:       "Bounced Contacts",
				SQL:         "*",
				Description: "Total number of bounced contacts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'bounced'"},
				},
			},
			"count_recent_contacts": {
				Type:        "count",
				Title:       "Recent Contacts",
				SQL:         "*",
				Description: "Contacts created in the last 30 days",
				Filters: []analytics.MeasureFilter{
					{SQL: "created_at >= NOW() - INTERVAL '30 days'"},
				},
			},
			"count_with_source": {
				Type:        "count",
				Title:       "Contacts with Source",
				SQL:         "*",
				Description: "Contacts with a known source",
				Filters: []analytics.MeasureFilter{
					{SQL: "source IS NOT NULL"},
					{SQL: "source != ''"},
				},
			},
			"avg_created_days_ago": {
				Type:        "avg",
				Title:       "Average Days Since Creation",
				SQL:         "EXTRACT(EPOCH FROM (NOW() - created_at)) / 86400",
				Description: "Average days since contact creation",
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"created_at": {
				Type:        "time",
				Title:       "Created At",
				SQL:         "created_at",
				Description: "Contact creation timestamp",
			},
			"email": {
				Type:        "string",
				Title:       "Email",
				SQL:         "email",
				Description: "Contact email address",
			},
			"first_name": {
				Type:        "string",
				Title:       "First Name",
				SQL:         "first_name",
				Description: "Contact first name",
			},
			"last_name": {
				Type:        "string",
				Title:       "Last Name",
				SQL:         "last_name",
				Description: "Contact last name",
			},
			"external_id": {
				Type:        "string",
				Title:       "External ID",
				SQL:         "external_id",
				Description: "External contact identifier",
			},
			"timezone": {
				Type:        "string",
				Title:       "Timezone",
				SQL:         "timezone",
				Description: "Contact timezone",
			},
			"country": {
				Type:        "string",
				Title:       "Country",
				SQL:         "country",
				Description: "Contact country",
			},
		},
	},
	"broadcasts": {
		Name: "broadcasts",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Broadcasts",
				SQL:         "*",
				Description: "Total number of broadcasts",
			},
			"count_draft": {
				Type:        "count",
				Title:       "Draft Broadcasts",
				SQL:         "*",
				Description: "Total number of draft broadcasts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'draft'"},
				},
			},
			"count_scheduled": {
				Type:        "count",
				Title:       "Scheduled Broadcasts",
				SQL:         "*",
				Description: "Total number of scheduled broadcasts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'scheduled'"},
				},
			},
			"count_sending": {
				Type:        "count",
				Title:       "Sending Broadcasts",
				SQL:         "*",
				Description: "Total number of broadcasts currently sending",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'sending'"},
				},
			},
			"count_recent": {
				Type:        "count",
				Title:       "Recent Broadcasts",
				SQL:         "*",
				Description: "Broadcasts created in the last 30 days",
				Filters: []analytics.MeasureFilter{
					{SQL: "created_at >= NOW() - INTERVAL '30 days'"},
				},
			},
			"avg_recipients": {
				Type:        "avg",
				Title:       "Average Recipients",
				SQL:         "recipient_count",
				Description: "Average number of recipients per broadcast",
			},
			"sum_recipients": {
				Type:        "sum",
				Title:       "Total Recipients",
				SQL:         "recipient_count",
				Description: "Total number of recipients across all broadcasts",
			},
			"max_recipients": {
				Type:        "max",
				Title:       "Max Recipients",
				SQL:         "recipient_count",
				Description: "Maximum recipients in a single broadcast",
			},
			"min_recipients": {
				Type:        "min",
				Title:       "Min Recipients",
				SQL:         "recipient_count",
				Description: "Minimum recipients in a single broadcast",
			},
			"test_recipients": {
				Type:        "sum",
				Title:       "Test Recipients",
				SQL:         "test_phase_recipient_count",
				Description: "Total test phase recipients",
			},
			"completed_broadcasts_count": {
				Type:        "count",
				Title:       "Completed Broadcasts",
				SQL:         "*",
				Description: "Total number of completed broadcasts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'completed'"},
				},
			},
			"avg_recipients_completed": {
				Type:        "avg",
				SQL:         "recipient_count",
				Description: "Average recipients for completed broadcasts only",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'completed'"},
				},
			},
			"winner_recipients": {
				Type:        "sum",
				SQL:         "winner_phase_recipient_count",
				Description: "Total winner phase recipients",
			},
			"avg_test_recipients": {
				Type:        "avg",
				SQL:         "test_phase_recipient_count",
				Description: "Average test phase recipients per broadcast",
				Filters: []analytics.MeasureFilter{
					{SQL: "test_phase_recipient_count > 0"},
				},
			},
			"sum_recipients_completed": {
				Type:        "sum",
				SQL:         "recipient_count",
				Description: "Total recipients for completed broadcasts",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'completed'"},
				},
			},
			"count_with_ab_test": {
				Type:        "count",
				SQL:         "*",
				Description: "Broadcasts with A/B testing enabled",
				Filters: []analytics.MeasureFilter{
					{SQL: "test_phase_recipient_count > 0"},
				},
			},
			"count_large_broadcasts": {
				Type:        "count",
				SQL:         "*",
				Description: "Broadcasts with more than 1000 recipients",
				Filters: []analytics.MeasureFilter{
					{SQL: "recipient_count > 1000"},
				},
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"id": {
				Type:        "string",
				SQL:         "id",
				Description: "Broadcast identifier",
			},
			"name": {
				Type:        "string",
				SQL:         "name",
				Description: "Broadcast name",
			},
			"status": {
				Type:        "string",
				SQL:         "status",
				Description: "Broadcast status",
			},
			"created_at": {
				Type:        "time",
				SQL:         "created_at",
				Description: "Broadcast creation timestamp",
			},
			"started_at": {
				Type:        "time",
				SQL:         "started_at",
				Description: "Broadcast start timestamp",
			},
			"completed_at": {
				Type:        "time",
				SQL:         "completed_at",
				Description: "Broadcast completion timestamp",
			},
			"workspace_id": {
				Type:        "string",
				SQL:         "workspace_id",
				Description: "Associated workspace ID",
			},
		},
	},
	"webhook_deliveries": {
		Name: "webhook_deliveries",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Deliveries",
				SQL:         "*",
				Description: "Total number of webhook deliveries",
			},
			"count_delivered": {
				Type:        "count",
				Title:       "Delivered",
				SQL:         "*",
				Description: "Successfully delivered webhooks",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'delivered'"},
				},
			},
			"count_failed": {
				Type:        "count",
				Title:       "Failed",
				SQL:         "*",
				Description: "Failed webhook deliveries",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'failed'"},
				},
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"created_at": {
				Type:        "time",
				Title:       "Created At",
				SQL:         "created_at",
				Description: "Delivery creation timestamp",
			},
			"subscription_id": {
				Type:        "string",
				Title:       "Subscription ID",
				SQL:         "subscription_id",
				Description: "Associated webhook subscription",
			},
			"status": {
				Type:        "string",
				Title:       "Status",
				SQL:         "status",
				Description: "Delivery status",
			},
		},
	},
	"email_queue": {
		Name: "email_queue",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Entries",
				SQL:         "*",
				Description: "Total queue entries",
			},
			"count_pending": {
				Type:        "count",
				Title:       "Pending",
				SQL:         "*",
				Description: "Emails waiting to be sent",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'pending'"},
				},
			},
			"count_processing": {
				Type:        "count",
				Title:       "Processing",
				SQL:         "*",
				Description: "Emails currently being processed",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'processing'"},
				},
			},
			"count_failed": {
				Type:        "count",
				Title:       "Failed",
				SQL:         "*",
				Description: "Emails that failed and awaiting retry",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'failed'"},
				},
			},
			"count_broadcast": {
				Type:        "count",
				Title:       "Broadcast Emails",
				SQL:         "*",
				Description: "Emails from broadcasts",
				Filters: []analytics.MeasureFilter{
					{SQL: "source_type = 'broadcast'"},
				},
			},
			"count_automation": {
				Type:        "count",
				Title:       "Automation Emails",
				SQL:         "*",
				Description: "Emails from automations",
				Filters: []analytics.MeasureFilter{
					{SQL: "source_type = 'automation'"},
				},
			},
			"avg_attempts": {
				Type:        "avg",
				Title:       "Average Attempts",
				SQL:         "attempts",
				Description: "Average number of send attempts",
			},
			"max_attempts": {
				Type:        "max",
				Title:       "Max Attempts",
				SQL:         "attempts",
				Description: "Maximum number of send attempts",
			},
			"count_retryable": {
				Type:        "count",
				Title:       "Retryable",
				SQL:         "*",
				Description: "Failed emails that can still be retried",
				Filters: []analytics.MeasureFilter{
					{SQL: "status = 'failed'"},
					{SQL: "attempts < max_attempts"},
				},
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"created_at": {
				Type:        "time",
				Title:       "Created At",
				SQL:         "created_at",
				Description: "When the email was queued",
			},
			"updated_at": {
				Type:        "time",
				Title:       "Updated At",
				SQL:         "updated_at",
				Description: "Last update timestamp",
			},
			"next_retry_at": {
				Type:        "time",
				Title:       "Next Retry At",
				SQL:         "next_retry_at",
				Description: "Scheduled retry time for failed emails",
			},
			"status": {
				Type:        "string",
				Title:       "Status",
				SQL:         "status",
				Description: "Queue entry status (pending, processing, failed)",
			},
			"source_type": {
				Type:        "string",
				Title:       "Source Type",
				SQL:         "source_type",
				Description: "Origin type (broadcast, automation)",
			},
			"source_id": {
				Type:        "string",
				Title:       "Source ID",
				SQL:         "source_id",
				Description: "Broadcast or automation ID",
			},
			"integration_id": {
				Type:        "string",
				Title:       "Integration ID",
				SQL:         "integration_id",
				Description: "Email provider integration ID",
			},
			"provider_kind": {
				Type:        "string",
				Title:       "Provider Kind",
				SQL:         "provider_kind",
				Description: "Email provider type (ses, smtp, etc.)",
			},
			"priority": {
				Type:        "number",
				Title:       "Priority",
				SQL:         "priority",
				Description: "Queue priority (lower = higher priority)",
			},
			"template_id": {
				Type:        "string",
				Title:       "Template ID",
				SQL:         "template_id",
				Description: "Email template identifier",
			},
			"contact_email": {
				Type:        "string",
				Title:       "Contact Email",
				SQL:         "contact_email",
				Description: "Recipient email address",
			},
		},
	},
	"automation_node_executions": {
		Name: "automation_node_executions",
		Measures: map[string]analytics.MeasureDefinition{
			"count": {
				Type:        "count",
				Title:       "Total Executions",
				SQL:         "*",
				Description: "Total node executions",
			},
			"count_entered": {
				Type:        "count",
				Title:       "Entered",
				SQL:         "*",
				Description: "Contacts that entered nodes",
				Filters: []analytics.MeasureFilter{
					{SQL: "action = 'entered'"},
				},
			},
			"count_completed": {
				Type:        "count",
				Title:       "Completed",
				SQL:         "*",
				Description: "Successfully completed executions",
				Filters: []analytics.MeasureFilter{
					{SQL: "action = 'completed'"},
				},
			},
			"count_failed": {
				Type:        "count",
				Title:       "Failed",
				SQL:         "*",
				Description: "Failed executions",
				Filters: []analytics.MeasureFilter{
					{SQL: "action = 'failed'"},
				},
			},
			"count_skipped": {
				Type:        "count",
				Title:       "Skipped",
				SQL:         "*",
				Description: "Skipped executions",
				Filters: []analytics.MeasureFilter{
					{SQL: "action = 'skipped'"},
				},
			},
		},
		Dimensions: map[string]analytics.DimensionDefinition{
			"automation_id": {
				Type:        "string",
				Title:       "Automation ID",
				SQL:         "automation_id",
				Description: "Automation identifier",
			},
			"node_id": {
				Type:        "string",
				Title:       "Node ID",
				SQL:         "node_id",
				Description: "Node identifier",
			},
			"node_type": {
				Type:        "string",
				Title:       "Node Type",
				SQL:         "node_type",
				Description: "Type of node",
			},
			"action": {
				Type:        "string",
				Title:       "Action",
				SQL:         "action",
				Description: "Execution action",
			},
			"entered_at": {
				Type:        "time",
				Title:       "Entered At",
				SQL:         "entered_at",
				Description: "When node was entered",
			},
		},
	},
}

PredefinedSchemas contains all available analytics schemas for Notifuse

View Source
var Timezones = []string{}/* 594 elements not displayed */

Timezones contains all valid IANA timezone identifiers This list is generated from Go's embedded timezone database It includes both canonical zones and aliases (links)

To regenerate this list, run: go generate ./internal/domain

View Source
var ValidEventKinds = []string{

	"contact.created", "contact.updated", "contact.deleted",

	"list.subscribed", "list.unsubscribed", "list.confirmed", "list.resubscribed",
	"list.bounced", "list.complained", "list.pending", "list.removed",

	"segment.joined", "segment.left",

	"email.sent", "email.delivered", "email.opened", "email.clicked",
	"email.bounced", "email.complained", "email.unsubscribed",

	"custom_event",
}

ValidEventKinds defines all allowed automation trigger event kinds

ValidGoalTypes is the list of all valid goal types

View Source
var WebhookEventTypes = []string{

	"contact.created",
	"contact.updated",
	"contact.deleted",

	"list.subscribed",
	"list.unsubscribed",
	"list.confirmed",
	"list.resubscribed",
	"list.bounced",
	"list.complained",
	"list.pending",
	"list.removed",

	"segment.joined",
	"segment.left",

	"email.sent",
	"email.delivered",
	"email.opened",
	"email.clicked",
	"email.bounced",
	"email.complained",
	"email.unsubscribed",

	"custom_event.created",
	"custom_event.updated",
	"custom_event.deleted",
}

Available webhook event types

Functions

func CalculateNextRetryTime

func CalculateNextRetryTime(attempts int) time.Time

CalculateNextRetryTime calculates the next retry time using exponential backoff Backoff: base, 2*base, 4*base for attempts 1, 2, 3 (default base = 1min)

func ComputeEmailHMAC

func ComputeEmailHMAC(email string, secretKey string) string

ComputeEmailHMAC computes an HMAC for an email address using the workspace secret key

func DecryptString

func DecryptString(encrypted, passphrase string) (string, error)

DecryptString decrypts an encrypted string

func EncryptString

func EncryptString(plaintext, passphrase string) (string, error)

EncryptString encrypts a string using the same encryption as other sensitive data

func GenerateWebhookCallbackURL

func GenerateWebhookCallbackURL(baseURL string, provider EmailProviderKind, workspaceID string, integrationID string) string

GenerateWebhookCallbackURL generates a standardized webhook callback URL for a specific provider The URL follows the format: {baseURL}/webhooks/email?provider={provider}&workspace_id={workspaceID}&integration_id={integrationID} This ensures a consistent URL pattern across all email provider integrations.

Parameters:

  • baseURL: The base URL of the application (e.g., "https://api.example.com")
  • provider: The email provider kind (e.g., domain.EmailProviderKindPostmark)
  • workspaceID: The workspace ID
  • integrationID: The integration ID

Returns:

  • The fully formatted webhook callback URL

func HasEmailNodes

func HasEmailNodes(nodes []*AutomationNode) bool

HasEmailNodes checks if any nodes in the provided list are email nodes

func IsValidEventKind

func IsValidEventKind(kind string) bool

IsValidEventKind checks if the given event kind is valid

func IsValidTimezone

func IsValidTimezone(timezone string) bool

IsValidTimezone checks if the given timezone is valid

func NewValidationError

func NewValidationError(message string) error

NewValidationError creates a new validation error with the given message

func NormalizeSlug

func NormalizeSlug(s string) string

NormalizeSlug normalizes a string to be a valid slug

func ParseBoolParam

func ParseBoolParam(s string) (bool, error)

parseBoolParam parses a string to a boolean

func ParseIntParam

func ParseIntParam(s string) (int, error)

parseIntParam parses a string to an integer

func ValidateAttachments

func ValidateAttachments(attachments []Attachment) error

ValidateAttachments validates a slice of attachments

func ValidateSupabaseWebhookSignature

func ValidateSupabaseWebhookSignature(payload []byte, signatureHeader, timestampHeader, idHeader, secret string) error

ValidateSupabaseWebhookSignature validates a Supabase webhook signature Supabase uses the standard-webhooks format with webhook-id, webhook-timestamp, and webhook-signature headers

func VerifyEmailHMAC

func VerifyEmailHMAC(email string, providedHMAC string, secretKey string) bool

VerifyEmailHMAC verifies if the provided HMAC for an email is valid

func WorkspaceUserKey

func WorkspaceUserKey(workspaceID string) contextKey

WorkspaceUserKey creates a context key for storing a workspace-specific user

Types

type ABTestNodeConfig

type ABTestNodeConfig struct {
	Variants []ABTestVariant `json:"variants"`
}

ABTestNodeConfig configures an A/B test node

func (ABTestNodeConfig) Validate

func (c ABTestNodeConfig) Validate() error

Validate validates the A/B test node config

type ABTestVariant

type ABTestVariant struct {
	ID         string `json:"id"`           // "A", "B", etc.
	Name       string `json:"name"`         // "Control", "Variant B", etc.
	Weight     int    `json:"weight"`       // 1-100
	NextNodeID string `json:"next_node_id"` // Node to execute for this variant
}

ABTestVariant represents a variant in an A/B test node

func (ABTestVariant) Validate

func (v ABTestVariant) Validate() error

Validate validates the A/B test variant

type ActivateAutomationRequest

type ActivateAutomationRequest struct {
	WorkspaceID  string `json:"workspace_id"`
	AutomationID string `json:"automation_id"`
}

ActivateAutomationRequest represents the request to activate an automation

func (*ActivateAutomationRequest) Validate

func (r *ActivateAutomationRequest) Validate() error

Validate validates the activate automation request

type AddToListNodeConfig

type AddToListNodeConfig struct {
	ListID   string                 `json:"list_id"`
	Status   string                 `json:"status"` // "active", "pending"
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

AddToListNodeConfig configures an add-to-list node

func (AddToListNodeConfig) Validate

func (c AddToListNodeConfig) Validate() error

Validate validates the add-to-list node config

type AmazonSESSettings

type AmazonSESSettings struct {
	Region             string `json:"region"`
	AccessKey          string `json:"access_key"`
	EncryptedSecretKey string `json:"encrypted_secret_key,omitempty"`

	// decoded secret key, not stored in the database
	SecretKey string `json:"secret_key,omitempty"`
}

AmazonSESSettings contains SES email provider settings

func (*AmazonSESSettings) DecryptSecretKey

func (a *AmazonSESSettings) DecryptSecretKey(passphrase string) error

func (*AmazonSESSettings) EncryptSecretKey

func (a *AmazonSESSettings) EncryptSecretKey(passphrase string) error

func (*AmazonSESSettings) Validate

func (a *AmazonSESSettings) Validate(passphrase string) error

type AnalyticsRepository

type AnalyticsRepository interface {
	Query(ctx context.Context, workspaceID string, query analytics.Query) (*analytics.Response, error)
	GetSchemas(ctx context.Context, workspaceID string) (map[string]analytics.SchemaDefinition, error)
}

AnalyticsRepository defines the analytics data access interface

type AnalyticsService

type AnalyticsService interface {
	Query(ctx context.Context, workspaceID string, query analytics.Query) (*analytics.Response, error)
	GetSchemas(ctx context.Context, workspaceID string) (map[string]analytics.SchemaDefinition, error)
}

AnalyticsService defines the analytics business logic interface

type AnthropicSettings

type AnthropicSettings struct {
	EncryptedAPIKey string `json:"encrypted_api_key,omitempty"`
	Model           string `json:"model"` // free text - e.g. claude-sonnet-4-20250514

	// Decoded API key, not stored in the database
	APIKey string `json:"api_key,omitempty"`
}

AnthropicSettings contains configuration for Anthropic Claude

func (*AnthropicSettings) DecryptAPIKey

func (a *AnthropicSettings) DecryptAPIKey(passphrase string) error

DecryptAPIKey decrypts the encrypted API key

func (*AnthropicSettings) EncryptAPIKey

func (a *AnthropicSettings) EncryptAPIKey(passphrase string) error

EncryptAPIKey encrypts the API key

func (*AnthropicSettings) Validate

func (a *AnthropicSettings) Validate(passphrase string) error

Validate validates the Anthropic settings

type Attachment

type Attachment struct {
	Filename    string `json:"filename" validate:"required"`
	Content     string `json:"content" validate:"required"` // base64 encoded
	ContentType string `json:"content_type,omitempty"`
	Disposition string `json:"disposition,omitempty"` // "attachment" (default) or "inline"
}

Attachment represents an email attachment

func (*Attachment) CalculateChecksum

func (a *Attachment) CalculateChecksum() (string, error)

CalculateChecksum calculates SHA256 checksum of the content

func (*Attachment) DecodeContent

func (a *Attachment) DecodeContent() ([]byte, error)

DecodeContent decodes the base64 content

func (*Attachment) DetectContentType

func (a *Attachment) DetectContentType() error

DetectContentType detects content type if not provided

func (*Attachment) ToMetadata

func (a *Attachment) ToMetadata(checksum string) *AttachmentMetadata

ToMetadata converts an Attachment to AttachmentMetadata

func (*Attachment) Validate

func (a *Attachment) Validate() error

Validate validates an attachment

type AttachmentMetadata

type AttachmentMetadata struct {
	Checksum    string `json:"checksum"`
	Filename    string `json:"filename"`
	ContentType string `json:"content_type"`
	Disposition string `json:"disposition"`
}

AttachmentMetadata represents metadata stored in message_history

type AttachmentRecord

type AttachmentRecord struct {
	Checksum    string
	Content     []byte
	ContentType string
	SizeBytes   int64
}

AttachmentRecord represents a stored attachment in the database

type AttachmentRepository

type AttachmentRepository interface {
	// Store saves an attachment and returns its checksum
	Store(ctx context.Context, workspaceID string, record *AttachmentRecord) error

	// Get retrieves an attachment by checksum
	Get(ctx context.Context, workspaceID string, checksum string) (*AttachmentRecord, error)

	// Exists checks if an attachment exists by checksum
	Exists(ctx context.Context, workspaceID string, checksum string) (bool, error)
}

AttachmentRepository defines methods for attachment persistence

type AudienceSettings

type AudienceSettings struct {
	List                string   `json:"list,omitempty"`
	Segments            []string `json:"segments,omitempty"`
	ExcludeUnsubscribed bool     `json:"exclude_unsubscribed"`
}

AudienceSettings defines how recipients are determined for a broadcast

func (*AudienceSettings) Scan

func (a *AudienceSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (AudienceSettings) Value

func (a AudienceSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type AuthRepository

type AuthRepository interface {
	GetSessionByID(ctx context.Context, sessionID string, userID string) (*time.Time, error)
	GetUserByID(ctx context.Context, userID string) (*User, error)
}

AuthRepository defines the interface for auth-related database operations

type AuthResponse

type AuthResponse struct {
	Token     string    `json:"token"`
	User      User      `json:"user"`
	ExpiresAt time.Time `json:"expires_at"`
}

type AuthService

type AuthService interface {
	AuthenticateUserFromContext(ctx context.Context) (*User, error)
	AuthenticateUserForWorkspace(ctx context.Context, workspaceID string) (context.Context, *User, *UserWorkspace, error)
	VerifyUserSession(ctx context.Context, userID, sessionID string) (*User, error)
	GenerateUserAuthToken(user *User, sessionID string, expiresAt time.Time) string
	GenerateAPIAuthToken(user *User) string
	GenerateInvitationToken(invitation *WorkspaceInvitation) string
	ValidateInvitationToken(token string) (invitationID, workspaceID, email string, err error)
	InvalidateSecretCache()
}

type Automation

type Automation struct {
	ID          string                 `json:"id"`
	WorkspaceID string                 `json:"workspace_id"`
	Name        string                 `json:"name"`
	Status      AutomationStatus       `json:"status"`
	ListID      string                 `json:"list_id"`
	Trigger     *TimelineTriggerConfig `json:"trigger"`
	TriggerSQL  *string                `json:"trigger_sql,omitempty"` // Generated SQL for WHEN clause
	RootNodeID  string                 `json:"root_node_id"`
	Nodes       []*AutomationNode      `json:"nodes"` // Embedded workflow nodes
	Stats       *AutomationStats       `json:"stats,omitempty"`
	CreatedAt   time.Time              `json:"created_at"`
	UpdatedAt   time.Time              `json:"updated_at"`
	DeletedAt   *time.Time             `json:"deleted_at,omitempty"` // Soft-delete timestamp
}

Automation represents an email marketing automation workflow

func (*Automation) GetNodeByID

func (a *Automation) GetNodeByID(nodeID string) *AutomationNode

GetNodeByID finds a node in the automation's Nodes array by ID

func (*Automation) HasEmailNodeRestriction

func (a *Automation) HasEmailNodeRestriction() bool

HasEmailNodeRestriction returns true if email nodes are not allowed for this automation. Email nodes require a list to be configured because emails need contact data from list membership.

func (*Automation) Validate

func (a *Automation) Validate() error

Validate validates the automation

type AutomationFilter

type AutomationFilter struct {
	Status         []AutomationStatus
	ListID         string
	IncludeDeleted bool // When true, includes soft-deleted automations in results
	Limit          int
	Offset         int
}

AutomationFilter defines filtering options for listing automations

type AutomationNode

type AutomationNode struct {
	ID           string                 `json:"id"`
	AutomationID string                 `json:"automation_id"`
	Type         NodeType               `json:"type"`
	Config       map[string]interface{} `json:"config"`
	NextNodeID   *string                `json:"next_node_id,omitempty"`
	Position     NodePosition           `json:"position"`
	CreatedAt    time.Time              `json:"created_at"`
}

AutomationNode represents a node in an automation workflow

func (*AutomationNode) Validate

func (n *AutomationNode) Validate() error

Validate validates the automation node

func (*AutomationNode) ValidateForAutomation

func (n *AutomationNode) ValidateForAutomation(automation *Automation) error

ValidateForAutomation validates the node in context of its parent automation. This includes additional checks like email node restrictions.

type AutomationNodeStats

type AutomationNodeStats struct {
	NodeID    string `json:"node_id"`
	NodeType  string `json:"node_type"`
	Entered   int64  `json:"entered"`
	Completed int64  `json:"completed"`
	Failed    int64  `json:"failed"`
	Skipped   int64  `json:"skipped"`
}

AutomationNodeStats holds statistics for a single automation node

type AutomationRepository

type AutomationRepository interface {
	// Transaction support
	WithTransaction(ctx context.Context, fn func(*sql.Tx) error) error

	// Automation CRUD (nodes are embedded in automation as JSONB)
	Create(ctx context.Context, workspaceID string, automation *Automation) error
	CreateTx(ctx context.Context, tx *sql.Tx, workspaceID string, automation *Automation) error
	GetByID(ctx context.Context, workspaceID, id string) (*Automation, error)
	GetByIDTx(ctx context.Context, tx *sql.Tx, workspaceID, id string) (*Automation, error)
	List(ctx context.Context, workspaceID string, filter AutomationFilter) ([]*Automation, int, error)
	Update(ctx context.Context, workspaceID string, automation *Automation) error
	UpdateTx(ctx context.Context, tx *sql.Tx, workspaceID string, automation *Automation) error
	Delete(ctx context.Context, workspaceID, id string) error
	DeleteTx(ctx context.Context, tx *sql.Tx, workspaceID, id string) error

	// Trigger management (dynamic SQL execution)
	CreateAutomationTrigger(ctx context.Context, workspaceID string, automation *Automation) error
	DropAutomationTrigger(ctx context.Context, workspaceID, automationID string) error

	// Contact automation operations
	GetContactAutomation(ctx context.Context, workspaceID, id string) (*ContactAutomation, error)
	GetContactAutomationTx(ctx context.Context, tx *sql.Tx, workspaceID, id string) (*ContactAutomation, error)
	GetContactAutomationByEmail(ctx context.Context, workspaceID, automationID, email string) (*ContactAutomation, error)
	ListContactAutomations(ctx context.Context, workspaceID string, filter ContactAutomationFilter) ([]*ContactAutomation, int, error)
	UpdateContactAutomation(ctx context.Context, workspaceID string, ca *ContactAutomation) error
	UpdateContactAutomationTx(ctx context.Context, tx *sql.Tx, workspaceID string, ca *ContactAutomation) error
	GetScheduledContactAutomations(ctx context.Context, workspaceID string, beforeTime time.Time, limit int) ([]*ContactAutomation, error)

	// Global scheduling (across all workspaces with round-robin)
	GetScheduledContactAutomationsGlobal(ctx context.Context, beforeTime time.Time, limit int) ([]*ContactAutomationWithWorkspace, error)

	// Node execution logging
	CreateNodeExecution(ctx context.Context, workspaceID string, entry *NodeExecution) error
	CreateNodeExecutionTx(ctx context.Context, tx *sql.Tx, workspaceID string, entry *NodeExecution) error
	GetNodeExecutions(ctx context.Context, workspaceID, contactAutomationID string) ([]*NodeExecution, error)
	UpdateNodeExecution(ctx context.Context, workspaceID string, entry *NodeExecution) error
	UpdateNodeExecutionTx(ctx context.Context, tx *sql.Tx, workspaceID string, entry *NodeExecution) error

	// Stats
	UpdateAutomationStats(ctx context.Context, workspaceID, automationID string, stats *AutomationStats) error
	UpdateAutomationStatsTx(ctx context.Context, tx *sql.Tx, workspaceID, automationID string, stats *AutomationStats) error
	IncrementAutomationStat(ctx context.Context, workspaceID, automationID, statName string) error
}

AutomationRepository defines the interface for automation persistence

type AutomationService

type AutomationService interface {
	// CRUD (nodes are embedded in automation)
	Create(ctx context.Context, workspaceID string, automation *Automation) error
	Get(ctx context.Context, workspaceID, automationID string) (*Automation, error)
	List(ctx context.Context, workspaceID string, filter AutomationFilter) ([]*Automation, int, error)
	Update(ctx context.Context, workspaceID string, automation *Automation) error
	Delete(ctx context.Context, workspaceID, automationID string) error

	// Status management
	Activate(ctx context.Context, workspaceID, automationID string) error
	Pause(ctx context.Context, workspaceID, automationID string) error

	// Node executions/debugging
	GetContactNodeExecutions(ctx context.Context, workspaceID, automationID, email string) (*ContactAutomation, []*NodeExecution, error)
}

AutomationService defines the interface for automation business logic

type AutomationStats

type AutomationStats struct {
	Enrolled  int64 `json:"enrolled"`
	Completed int64 `json:"completed"`
	Exited    int64 `json:"exited"`
	Failed    int64 `json:"failed"`
}

AutomationStats holds statistics for an automation

type AutomationStatus

type AutomationStatus string

AutomationStatus represents the status of an automation

const (
	AutomationStatusDraft  AutomationStatus = "draft"
	AutomationStatusLive   AutomationStatus = "live"
	AutomationStatusPaused AutomationStatus = "paused"
)

func (AutomationStatus) IsValid

func (s AutomationStatus) IsValid() bool

IsValid checks if the automation status is valid

type BatchImportContactsRequest

type BatchImportContactsRequest struct {
	WorkspaceID      string          `json:"workspace_id" valid:"required"`
	Contacts         json.RawMessage `json:"contacts" valid:"required"`
	SubscribeToLists []string        `json:"subscribe_to_lists,omitempty"` // Optional: subscribe contacts to these lists
}

Add the request type for batch importing contacts

func (*BatchImportContactsRequest) Validate

func (r *BatchImportContactsRequest) Validate() (contacts []*Contact, workspaceID string, err error)

type BatchImportContactsResponse

type BatchImportContactsResponse struct {
	Operations []*UpsertContactOperation `json:"operations"`
	Error      string                    `json:"error,omitempty"`
}

type BlogAuthor

type BlogAuthor struct {
	Name      string `json:"name"`
	AvatarURL string `json:"avatar_url,omitempty"`
}

BlogAuthor represents an author of a blog post

type BlogCategory

type BlogCategory struct {
	ID        string               `json:"id"`
	Slug      string               `json:"slug"` // URL identifier
	Settings  BlogCategorySettings `json:"settings"`
	CreatedAt time.Time            `json:"created_at"`
	UpdatedAt time.Time            `json:"updated_at"`
	DeletedAt *time.Time           `json:"deleted_at,omitempty"`
}

BlogCategory represents a blog category

func (*BlogCategory) Validate

func (c *BlogCategory) Validate() error

Validate validates the blog category

type BlogCategoryListResponse

type BlogCategoryListResponse struct {
	Categories []*BlogCategory `json:"categories"`
	TotalCount int             `json:"total_count"`
}

BlogCategoryListResponse defines the response for listing blog categories

type BlogCategoryRepository

type BlogCategoryRepository interface {
	CreateCategory(ctx context.Context, category *BlogCategory) error
	GetCategory(ctx context.Context, id string) (*BlogCategory, error)
	GetCategoryBySlug(ctx context.Context, slug string) (*BlogCategory, error)
	GetCategoriesByIDs(ctx context.Context, ids []string) ([]*BlogCategory, error)
	UpdateCategory(ctx context.Context, category *BlogCategory) error
	DeleteCategory(ctx context.Context, id string) error
	ListCategories(ctx context.Context) ([]*BlogCategory, error)

	// Transaction management
	WithTransaction(ctx context.Context, workspaceID string, fn func(*sql.Tx) error) error
	CreateCategoryTx(ctx context.Context, tx *sql.Tx, category *BlogCategory) error
	GetCategoryTx(ctx context.Context, tx *sql.Tx, id string) (*BlogCategory, error)
	GetCategoryBySlugTx(ctx context.Context, tx *sql.Tx, slug string) (*BlogCategory, error)
	UpdateCategoryTx(ctx context.Context, tx *sql.Tx, category *BlogCategory) error
	DeleteCategoryTx(ctx context.Context, tx *sql.Tx, id string) error
}

BlogCategoryRepository defines the data access layer for blog categories

type BlogCategorySettings

type BlogCategorySettings struct {
	Name        string       `json:"name"`
	Description string       `json:"description,omitempty"`
	SEO         *SEOSettings `json:"seo,omitempty"` // SEO metadata
}

BlogCategorySettings contains the settings for a blog category

func (*BlogCategorySettings) Scan

func (s *BlogCategorySettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BlogCategorySettings) Value

func (s BlogCategorySettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BlogPost

type BlogPost struct {
	ID          string           `json:"id"`
	CategoryID  string           `json:"category_id"`
	Slug        string           `json:"slug"` // URL identifier
	Settings    BlogPostSettings `json:"settings"`
	PublishedAt *time.Time       `json:"published_at,omitempty"` // null = draft
	CreatedAt   time.Time        `json:"created_at"`
	UpdatedAt   time.Time        `json:"updated_at"`
	DeletedAt   *time.Time       `json:"deleted_at,omitempty"`
}

BlogPost represents a blog post

func (*BlogPost) GetEffectiveSEOSettings

func (p *BlogPost) GetEffectiveSEOSettings(category *BlogCategory) *SEOSettings

GetEffectiveSEOSettings merges the post's SEO settings with the category's defaults

func (*BlogPost) IsDraft

func (p *BlogPost) IsDraft() bool

IsDraft returns true if the post is a draft

func (*BlogPost) IsPublished

func (p *BlogPost) IsPublished() bool

IsPublished returns true if the post is published

func (*BlogPost) Validate

func (p *BlogPost) Validate() error

Validate validates the blog post

type BlogPostListResponse

type BlogPostListResponse struct {
	Posts           []*BlogPost `json:"posts"`
	TotalCount      int         `json:"total_count"`
	CurrentPage     int         `json:"current_page"`
	TotalPages      int         `json:"total_pages"`
	HasNextPage     bool        `json:"has_next_page"`
	HasPreviousPage bool        `json:"has_previous_page"`
}

BlogPostListResponse defines the response for listing blog posts

type BlogPostRepository

type BlogPostRepository interface {
	CreatePost(ctx context.Context, post *BlogPost) error
	GetPost(ctx context.Context, id string) (*BlogPost, error)
	GetPostBySlug(ctx context.Context, slug string) (*BlogPost, error)
	GetPostByCategoryAndSlug(ctx context.Context, categorySlug, postSlug string) (*BlogPost, error)
	UpdatePost(ctx context.Context, post *BlogPost) error
	DeletePost(ctx context.Context, id string) error
	ListPosts(ctx context.Context, params ListBlogPostsRequest) (*BlogPostListResponse, error)
	PublishPost(ctx context.Context, id string, publishedAt *time.Time) error
	UnpublishPost(ctx context.Context, id string) error

	// Transaction management
	WithTransaction(ctx context.Context, workspaceID string, fn func(*sql.Tx) error) error
	CreatePostTx(ctx context.Context, tx *sql.Tx, post *BlogPost) error
	GetPostTx(ctx context.Context, tx *sql.Tx, id string) (*BlogPost, error)
	GetPostBySlugTx(ctx context.Context, tx *sql.Tx, slug string) (*BlogPost, error)
	UpdatePostTx(ctx context.Context, tx *sql.Tx, post *BlogPost) error
	DeletePostTx(ctx context.Context, tx *sql.Tx, id string) error
	DeletePostsByCategoryIDTx(ctx context.Context, tx *sql.Tx, categoryID string) (int64, error)
	PublishPostTx(ctx context.Context, tx *sql.Tx, id string, publishedAt *time.Time) error
	UnpublishPostTx(ctx context.Context, tx *sql.Tx, id string) error
}

BlogPostRepository defines the data access layer for blog posts

type BlogPostSettings

type BlogPostSettings struct {
	Title              string                    `json:"title"` // H1 displayed on page
	Template           BlogPostTemplateReference `json:"template"`
	Excerpt            string                    `json:"excerpt,omitempty"`
	FeaturedImageURL   string                    `json:"featured_image_url,omitempty"`
	Authors            []BlogAuthor              `json:"authors"`
	ReadingTimeMinutes int                       `json:"reading_time_minutes"`
	SEO                *SEOSettings              `json:"seo,omitempty"` // SEO metadata
}

BlogPostSettings contains the settings for a blog post

func (*BlogPostSettings) Scan

func (s *BlogPostSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BlogPostSettings) Value

func (s BlogPostSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BlogPostStatus

type BlogPostStatus string

BlogPostStatus represents the status filter for listing posts

const (
	BlogPostStatusAll       BlogPostStatus = "all"
	BlogPostStatusDraft     BlogPostStatus = "draft"
	BlogPostStatusPublished BlogPostStatus = "published"
)

type BlogPostTemplateReference

type BlogPostTemplateReference struct {
	TemplateID      string `json:"template_id"`
	TemplateVersion int    `json:"template_version"`
}

BlogPostTemplateReference contains template information for a blog post

type BlogRenderError

type BlogRenderError struct {
	Code    string // Error code for handler mapping
	Message string // Human-readable message
	Details error  // Underlying error
}

BlogRenderError represents a structured error for blog page rendering

func (*BlogRenderError) Error

func (e *BlogRenderError) Error() string

type BlogService

type BlogService interface {
	// Category operations
	CreateCategory(ctx context.Context, request *CreateBlogCategoryRequest) (*BlogCategory, error)
	GetCategory(ctx context.Context, id string) (*BlogCategory, error)
	GetCategoryBySlug(ctx context.Context, slug string) (*BlogCategory, error)
	UpdateCategory(ctx context.Context, request *UpdateBlogCategoryRequest) (*BlogCategory, error)
	DeleteCategory(ctx context.Context, request *DeleteBlogCategoryRequest) error
	ListCategories(ctx context.Context) (*BlogCategoryListResponse, error)

	// Post operations
	CreatePost(ctx context.Context, request *CreateBlogPostRequest) (*BlogPost, error)
	GetPost(ctx context.Context, id string) (*BlogPost, error)
	GetPostBySlug(ctx context.Context, slug string) (*BlogPost, error)
	GetPostByCategoryAndSlug(ctx context.Context, categorySlug, postSlug string) (*BlogPost, error)
	UpdatePost(ctx context.Context, request *UpdateBlogPostRequest) (*BlogPost, error)
	DeletePost(ctx context.Context, request *DeleteBlogPostRequest) error
	ListPosts(ctx context.Context, params *ListBlogPostsRequest) (*BlogPostListResponse, error)
	PublishPost(ctx context.Context, request *PublishBlogPostRequest) error
	UnpublishPost(ctx context.Context, request *UnpublishBlogPostRequest) error

	// Public operations (no auth required)
	GetPublicCategoryBySlug(ctx context.Context, slug string) (*BlogCategory, error)
	GetPublicPostByCategoryAndSlug(ctx context.Context, categorySlug, postSlug string) (*BlogPost, error)
	ListPublicPosts(ctx context.Context, params *ListBlogPostsRequest) (*BlogPostListResponse, error)

	// Theme operations
	CreateTheme(ctx context.Context, request *CreateBlogThemeRequest) (*BlogTheme, error)
	GetTheme(ctx context.Context, version int) (*BlogTheme, error)
	GetPublishedTheme(ctx context.Context) (*BlogTheme, error)
	UpdateTheme(ctx context.Context, request *UpdateBlogThemeRequest) (*BlogTheme, error)
	PublishTheme(ctx context.Context, request *PublishBlogThemeRequest) error
	ListThemes(ctx context.Context, params *ListBlogThemesRequest) (*BlogThemeListResponse, error)

	// Blog page rendering (public, no auth	// Rendering
	RenderHomePage(ctx context.Context, workspaceID string, page int, themeVersion *int) (string, error)
	RenderPostPage(ctx context.Context, workspaceID, categorySlug, postSlug string, themeVersion *int) (string, error)
	RenderCategoryPage(ctx context.Context, workspaceID, categorySlug string, page int, themeVersion *int) (string, error)
}

BlogService defines the business logic layer for blog operations

type BlogSettings

type BlogSettings struct {
	Title            string       `json:"title,omitempty"`
	LogoURL          *string      `json:"logo_url,omitempty"`
	IconURL          *string      `json:"icon_url,omitempty"`
	SEO              *SEOSettings `json:"seo,omitempty"`
	HomePageSize     int          `json:"home_page_size,omitempty"`     // Posts per page on home (default: 20)
	CategoryPageSize int          `json:"category_page_size,omitempty"` // Posts per page on category (default: 20)
}

BlogSettings contains blog title and SEO configuration

func (*BlogSettings) GetCategoryPageSize

func (bs *BlogSettings) GetCategoryPageSize() int

GetCategoryPageSize returns the category page size with validation and default

func (*BlogSettings) GetHomePageSize

func (bs *BlogSettings) GetHomePageSize() int

GetHomePageSize returns the home page size with validation and default

func (*BlogSettings) Scan

func (b *BlogSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BlogSettings) Value

func (b BlogSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BlogTemplateDataRequest

type BlogTemplateDataRequest struct {
	Workspace      *Workspace
	Post           *BlogPost             // Optional, for post pages
	Category       *BlogCategory         // Optional, for category pages
	PublicLists    []*List               // Always included (empty array if none)
	Posts          []*BlogPost           // For listings (home/category pages)
	Categories     []*BlogCategory       // For navigation
	ThemeVersion   int                   // Theme version number for cache-busting
	CustomData     MapOfAny              // Optional additional data
	PaginationData *BlogPostListResponse // Pagination metadata (optional, for paginated pages)
}

BlogTemplateDataRequest groups parameters for building blog template data Similar to TemplateDataRequest for email templates

type BlogTheme

type BlogTheme struct {
	Version           int            `json:"version"`
	PublishedAt       *time.Time     `json:"published_at,omitempty"`         // non-null = published
	PublishedByUserID *string        `json:"published_by_user_id,omitempty"` // user who published this theme
	Files             BlogThemeFiles `json:"files"`
	Notes             *string        `json:"notes,omitempty"` // optional notes/description for this version
	CreatedAt         time.Time      `json:"created_at"`
	UpdatedAt         time.Time      `json:"updated_at"`
}

BlogTheme represents a blog theme with versioned Liquid template files

func (*BlogTheme) IsPublished

func (t *BlogTheme) IsPublished() bool

IsPublished returns true if the theme is published

func (*BlogTheme) Validate

func (t *BlogTheme) Validate() error

Validate validates the blog theme

type BlogThemeFileType

type BlogThemeFileType string

BlogThemeFileType represents the type of blog theme file

const (
	BlogThemeFileTypeHome     BlogThemeFileType = "home"
	BlogThemeFileTypeCategory BlogThemeFileType = "category"
	BlogThemeFileTypePost     BlogThemeFileType = "post"
	BlogThemeFileTypeHeader   BlogThemeFileType = "header"
	BlogThemeFileTypeFooter   BlogThemeFileType = "footer"
	BlogThemeFileTypeShared   BlogThemeFileType = "shared"
)

type BlogThemeFiles

type BlogThemeFiles struct {
	HomeLiquid     string `json:"home.liquid"`
	CategoryLiquid string `json:"category.liquid"`
	PostLiquid     string `json:"post.liquid"`
	HeaderLiquid   string `json:"header.liquid"`
	FooterLiquid   string `json:"footer.liquid"`
	SharedLiquid   string `json:"shared.liquid"`
	StylesCSS      string `json:"styles.css"`
	ScriptsJS      string `json:"scripts.js"`
}

BlogThemeFiles contains Liquid template files and CSS for a blog theme

func (*BlogThemeFiles) Scan

func (f *BlogThemeFiles) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BlogThemeFiles) Value

func (f BlogThemeFiles) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BlogThemeListResponse

type BlogThemeListResponse struct {
	Themes     []*BlogTheme `json:"themes"`
	TotalCount int          `json:"total_count"`
}

BlogThemeListResponse defines the response for listing blog themes

type BlogThemeRepository

type BlogThemeRepository interface {
	CreateTheme(ctx context.Context, theme *BlogTheme) error
	GetTheme(ctx context.Context, version int) (*BlogTheme, error)
	GetPublishedTheme(ctx context.Context) (*BlogTheme, error)
	UpdateTheme(ctx context.Context, theme *BlogTheme) error
	PublishTheme(ctx context.Context, version int, publishedByUserID string) error
	ListThemes(ctx context.Context, params ListBlogThemesRequest) (*BlogThemeListResponse, error)

	// Transaction management
	WithTransaction(ctx context.Context, workspaceID string, fn func(*sql.Tx) error) error
	CreateThemeTx(ctx context.Context, tx *sql.Tx, theme *BlogTheme) error
	GetThemeTx(ctx context.Context, tx *sql.Tx, version int) (*BlogTheme, error)
	GetPublishedThemeTx(ctx context.Context, tx *sql.Tx) (*BlogTheme, error)
	UpdateThemeTx(ctx context.Context, tx *sql.Tx, theme *BlogTheme) error
	PublishThemeTx(ctx context.Context, tx *sql.Tx, version int, publishedByUserID string) error
}

BlogThemeRepository defines the data access layer for blog themes

type BranchNodeConfig

type BranchNodeConfig struct {
	Paths         []BranchPath `json:"paths"`
	DefaultPathID string       `json:"default_path_id"`
}

BranchNodeConfig configures a branch node

type BranchPath

type BranchPath struct {
	ID         string    `json:"id"`
	Name       string    `json:"name"`
	Conditions *TreeNode `json:"conditions"`
	NextNodeID string    `json:"next_node_id"`
}

BranchPath represents a branch path in a branch node

type Broadcast

type Broadcast struct {
	ID                        string                `json:"id"`
	WorkspaceID               string                `json:"workspace_id"`
	Name                      string                `json:"name"`
	ChannelType               string                `json:"channel_type"` // email, sms, push, etc.
	Status                    BroadcastStatus       `json:"status"`       // pending, sending, completed, failed
	Audience                  AudienceSettings      `json:"audience"`
	Schedule                  ScheduleSettings      `json:"schedule"`
	TestSettings              BroadcastTestSettings `json:"test_settings"`
	UTMParameters             *UTMParameters        `json:"utm_parameters,omitempty"`
	Metadata                  MapOfAny              `json:"metadata,omitempty"`
	WinningTemplate           *string               `json:"winning_template,omitempty"`
	TestSentAt                *time.Time            `json:"test_sent_at,omitempty"`
	WinnerSentAt              *time.Time            `json:"winner_sent_at,omitempty"`
	TestPhaseRecipientCount   int                   `json:"test_phase_recipient_count"`
	WinnerPhaseRecipientCount int                   `json:"winner_phase_recipient_count"`
	EnqueuedCount             int                   `json:"enqueued_count"` // Emails added to queue
	CreatedAt                 time.Time             `json:"created_at"`
	UpdatedAt                 time.Time             `json:"updated_at"`
	StartedAt                 *time.Time            `json:"started_at,omitempty"`
	CompletedAt               *time.Time            `json:"completed_at,omitempty"`
	CancelledAt               *time.Time            `json:"cancelled_at,omitempty"`
	PausedAt                  *time.Time            `json:"paused_at,omitempty"`
	PauseReason               *string               `json:"pause_reason,omitempty"`
}

Broadcast represents a broadcast message campaign

func (*Broadcast) SetTemplateForVariation

func (b *Broadcast) SetTemplateForVariation(variationIndex int, template *Template)

SetTemplateForVariation assigns a template to a specific variation

func (*Broadcast) Validate

func (b *Broadcast) Validate() error

Validate validates the broadcast struct

type BroadcastListResponse

type BroadcastListResponse struct {
	Broadcasts []*Broadcast `json:"broadcasts"`
	TotalCount int          `json:"total_count"`
}

BroadcastListResponse defines the response for listing broadcasts

type BroadcastRepository

type BroadcastRepository interface {
	CreateBroadcast(ctx context.Context, broadcast *Broadcast) error
	GetBroadcast(ctx context.Context, workspaceID, broadcastID string) (*Broadcast, error)
	UpdateBroadcast(ctx context.Context, broadcast *Broadcast) error
	DeleteBroadcast(ctx context.Context, workspaceID, broadcastID string) error
	ListBroadcasts(ctx context.Context, params ListBroadcastsParams) (*BroadcastListResponse, error)

	// Transaction management
	WithTransaction(ctx context.Context, workspaceID string, fn func(*sql.Tx) error) error

	// Transaction-aware methods
	CreateBroadcastTx(ctx context.Context, tx *sql.Tx, broadcast *Broadcast) error
	GetBroadcastTx(ctx context.Context, tx *sql.Tx, workspaceID, broadcastID string) (*Broadcast, error)
	UpdateBroadcastTx(ctx context.Context, tx *sql.Tx, broadcast *Broadcast) error
	DeleteBroadcastTx(ctx context.Context, tx *sql.Tx, workspaceID, broadcastID string) error
	ListBroadcastsTx(ctx context.Context, tx *sql.Tx, params ListBroadcastsParams) (*BroadcastListResponse, error)
}

BroadcastRepository defines the data access layer for broadcasts

type BroadcastSender

type BroadcastSender interface {
	GetBroadcast(ctx context.Context, workspaceID, broadcastID string) (*Broadcast, error)
	GetTemplateByID(ctx context.Context, workspaceID, templateID string) (*Template, error)

	// Message history tracking methods
	RecordMessageSent(ctx context.Context, workspaceID string, message *MessageHistory) error
	UpdateMessageStatus(ctx context.Context, workspaceID string, messageID string, event MessageEvent, timestamp time.Time) error
}

BroadcastSender is a minimal interface needed for sending broadcasts, used by task processors to avoid circular dependencies

type BroadcastService

type BroadcastService interface {
	// CreateBroadcast creates a new broadcast
	CreateBroadcast(ctx context.Context, request *CreateBroadcastRequest) (*Broadcast, error)

	// GetBroadcast retrieves a broadcast by ID
	GetBroadcast(ctx context.Context, workspaceID, id string) (*Broadcast, error)

	// UpdateBroadcast updates an existing broadcast
	UpdateBroadcast(ctx context.Context, request *UpdateBroadcastRequest) (*Broadcast, error)

	// ListBroadcasts retrieves a list of broadcasts with pagination
	ListBroadcasts(ctx context.Context, params ListBroadcastsParams) (*BroadcastListResponse, error)

	// ScheduleBroadcast schedules a broadcast for sending
	ScheduleBroadcast(ctx context.Context, request *ScheduleBroadcastRequest) error

	// PauseBroadcast pauses a sending broadcast
	PauseBroadcast(ctx context.Context, request *PauseBroadcastRequest) error

	// ResumeBroadcast resumes a paused broadcast
	ResumeBroadcast(ctx context.Context, request *ResumeBroadcastRequest) error

	// CancelBroadcast cancels a scheduled broadcast
	CancelBroadcast(ctx context.Context, request *CancelBroadcastRequest) error

	// DeleteBroadcast deletes a broadcast
	DeleteBroadcast(ctx context.Context, request *DeleteBroadcastRequest) error

	// SendToIndividual sends a broadcast to an individual recipient
	SendToIndividual(ctx context.Context, request *SendToIndividualRequest) error

	// GetTestResults retrieves A/B test results for a broadcast
	GetTestResults(ctx context.Context, workspaceID, broadcastID string) (*TestResultsResponse, error)

	// SelectWinner manually selects the winning variation for an A/B test
	SelectWinner(ctx context.Context, workspaceID, broadcastID, templateID string) error
}

BroadcastService defines the interface for broadcast operations

type BroadcastStatus

type BroadcastStatus string

BroadcastStatus defines the current status of a broadcast

const (
	BroadcastStatusDraft          BroadcastStatus = "draft"
	BroadcastStatusScheduled      BroadcastStatus = "scheduled"
	BroadcastStatusProcessing     BroadcastStatus = "processing" // Orchestrator is enqueueing emails
	BroadcastStatusPaused         BroadcastStatus = "paused"
	BroadcastStatusProcessed      BroadcastStatus = "processed" // Enqueueing complete
	BroadcastStatusCancelled      BroadcastStatus = "cancelled"
	BroadcastStatusFailed         BroadcastStatus = "failed"
	BroadcastStatusTesting        BroadcastStatus = "testing"         // A/B test in progress
	BroadcastStatusTestCompleted  BroadcastStatus = "test_completed"  // Test done, awaiting winner selection
	BroadcastStatusWinnerSelected BroadcastStatus = "winner_selected" // Winner chosen, enqueueing to remaining
)

type BroadcastTestSettings

type BroadcastTestSettings struct {
	Enabled              bool                 `json:"enabled"`
	SamplePercentage     int                  `json:"sample_percentage"`
	AutoSendWinner       bool                 `json:"auto_send_winner"`
	AutoSendWinnerMetric TestWinnerMetric     `json:"auto_send_winner_metric,omitempty"`
	TestDurationHours    int                  `json:"test_duration_hours,omitempty"`
	Variations           []BroadcastVariation `json:"variations"`
}

BroadcastTestSettings contains configuration for A/B testing

func (*BroadcastTestSettings) Scan

func (b *BroadcastTestSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BroadcastTestSettings) Value

func (b BroadcastTestSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BroadcastVariation

type BroadcastVariation struct {
	VariationName string            `json:"variation_name"`
	TemplateID    string            `json:"template_id"`
	Metrics       *VariationMetrics `json:"metrics,omitempty"`
	// joined servers-side
	Template *Template `json:"template,omitempty"`
}

BroadcastVariation represents a single variation in an A/B test

func (*BroadcastVariation) Scan

func (v *BroadcastVariation) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (BroadcastVariation) Value

func (v BroadcastVariation) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type BuildSegmentState

type BuildSegmentState struct {
	SegmentID      string `json:"segment_id"`
	Version        int64  `json:"version"`
	TotalContacts  int    `json:"total_contacts"`
	ProcessedCount int    `json:"processed_count"`
	MatchedCount   int    `json:"matched_count"`
	ContactOffset  int64  `json:"contact_offset"` // For resumable processing
	BatchSize      int    `json:"batch_size"`     // Process 1000 at a time
	StartedAt      string `json:"started_at"`
}

BuildSegmentState contains state specific to segment building tasks

type BulkUpsertResult

type BulkUpsertResult struct {
	Email string
	IsNew bool // true if inserted, false if updated
}

ContactRepository is the interface for contact operations BulkUpsertResult represents the result of a single contact upsert operation in a bulk operation

type CancelBroadcastRequest

type CancelBroadcastRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

CancelBroadcastRequest defines the request to cancel a scheduled broadcast

func (*CancelBroadcastRequest) Validate

func (r *CancelBroadcastRequest) Validate() error

Validate validates the cancel broadcast request

type ChannelOptions

type ChannelOptions struct {
	// Email-specific options
	FromName *string  `json:"from_name,omitempty"`
	CC       []string `json:"cc,omitempty"`
	BCC      []string `json:"bcc,omitempty"`
	ReplyTo  string   `json:"reply_to,omitempty"`
}

ChannelOptions represents channel-specific delivery options This structure allows future extension for SMS/push without breaking changes

func (*ChannelOptions) Scan

func (co *ChannelOptions) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database retrieval

func (ChannelOptions) Value

func (co ChannelOptions) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database storage

type ChannelTemplate

type ChannelTemplate struct {
	TemplateID string   `json:"template_id"`
	Settings   MapOfAny `json:"settings,omitempty"`
}

ChannelTemplate represents template configuration for a specific channel

type ChannelTemplates

type ChannelTemplates map[TransactionalChannel]ChannelTemplate

ChannelTemplates maps channels to their template configurations

func (*ChannelTemplates) Scan

func (ct *ChannelTemplates) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database retrieval

func (ChannelTemplates) Value

func (ct ChannelTemplates) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database storage

type CompileTemplateRequest

type CompileTemplateRequest = notifuse_mjml.CompileTemplateRequest

Use types from notifuse_mjml package

type CompileTemplateResponse

type CompileTemplateResponse = notifuse_mjml.CompileTemplateResponse

type Contact

type Contact struct {
	// Required fields
	Email string `json:"email" valid:"required,email"`

	// Optional fields
	ExternalID   *NullableString `json:"external_id,omitempty" valid:"optional"`
	Timezone     *NullableString `json:"timezone,omitempty" valid:"optional,timezone"`
	Language     *NullableString `json:"language,omitempty" valid:"optional"`
	FirstName    *NullableString `json:"first_name,omitempty" valid:"optional"`
	LastName     *NullableString `json:"last_name,omitempty" valid:"optional"`
	FullName     *NullableString `json:"full_name,omitempty" valid:"optional"`
	Phone        *NullableString `json:"phone,omitempty" valid:"optional"`
	AddressLine1 *NullableString `json:"address_line_1,omitempty" valid:"optional"`
	AddressLine2 *NullableString `json:"address_line_2,omitempty" valid:"optional"`
	Country      *NullableString `json:"country,omitempty" valid:"optional"`
	Postcode     *NullableString `json:"postcode,omitempty" valid:"optional"`
	State        *NullableString `json:"state,omitempty" valid:"optional"`
	JobTitle     *NullableString `json:"job_title,omitempty" valid:"optional"`

	// Custom fields
	CustomString1 *NullableString `json:"custom_string_1,omitempty" valid:"optional"`
	CustomString2 *NullableString `json:"custom_string_2,omitempty" valid:"optional"`
	CustomString3 *NullableString `json:"custom_string_3,omitempty" valid:"optional"`
	CustomString4 *NullableString `json:"custom_string_4,omitempty" valid:"optional"`
	CustomString5 *NullableString `json:"custom_string_5,omitempty" valid:"optional"`

	CustomNumber1 *NullableFloat64 `json:"custom_number_1,omitempty" valid:"optional"`
	CustomNumber2 *NullableFloat64 `json:"custom_number_2,omitempty" valid:"optional"`
	CustomNumber3 *NullableFloat64 `json:"custom_number_3,omitempty" valid:"optional"`
	CustomNumber4 *NullableFloat64 `json:"custom_number_4,omitempty" valid:"optional"`
	CustomNumber5 *NullableFloat64 `json:"custom_number_5,omitempty" valid:"optional"`

	CustomDatetime1 *NullableTime `json:"custom_datetime_1,omitempty" valid:"optional"`
	CustomDatetime2 *NullableTime `json:"custom_datetime_2,omitempty" valid:"optional"`
	CustomDatetime3 *NullableTime `json:"custom_datetime_3,omitempty" valid:"optional"`
	CustomDatetime4 *NullableTime `json:"custom_datetime_4,omitempty" valid:"optional"`
	CustomDatetime5 *NullableTime `json:"custom_datetime_5,omitempty" valid:"optional"`

	CustomJSON1 *NullableJSON `json:"custom_json_1,omitempty" valid:"optional"`
	CustomJSON2 *NullableJSON `json:"custom_json_2,omitempty" valid:"optional"`
	CustomJSON3 *NullableJSON `json:"custom_json_3,omitempty" valid:"optional"`
	CustomJSON4 *NullableJSON `json:"custom_json_4,omitempty" valid:"optional"`
	CustomJSON5 *NullableJSON `json:"custom_json_5,omitempty" valid:"optional"`

	// Timestamps
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// Database timestamps for internal tracking (not exposed via JSON)
	DBCreatedAt time.Time `json:"-"`
	DBUpdatedAt time.Time `json:"-"`

	// Join contact_lists
	ContactLists []*ContactList `json:"contact_lists"`
	// Join contact_segments
	ContactSegments []*ContactSegment `json:"contact_segments"`
	// Not persisted
	EmailHMAC string `json:"email_hmac,omitempty"`
}

Contact represents a contact in the system

func FromJSON

func FromJSON(data interface{}) (*Contact, error)

FromJSON parses JSON data into a Contact struct The JSON data can be provided as a []byte or as a gjson.Result

func ScanContact

func ScanContact(scanner interface {
	Scan(dest ...interface{}) error
}) (*Contact, error)

ScanContact scans a contact from the database

func (*Contact) Merge

func (c *Contact) Merge(other *Contact)

Merge updates non-nil fields from another contact

func (*Contact) MergeContactLists

func (c *Contact) MergeContactLists(list *ContactList)

MergeContactLists merges a new contact list into the contact's existing lists

func (*Contact) ToMapOfAny

func (c *Contact) ToMapOfAny() (MapOfAny, error)

ToMapOfAny converts the contact to a MapOfAny using JSON marshal/unmarshal This is useful for template rendering or API responses

func (*Contact) Validate

func (c *Contact) Validate() error

Validate ensures that the contact has all required fields

type ContactAutomation

type ContactAutomation struct {
	ID            string                  `json:"id"`
	AutomationID  string                  `json:"automation_id"`
	ContactEmail  string                  `json:"contact_email"`
	CurrentNodeID *string                 `json:"current_node_id,omitempty"`
	Status        ContactAutomationStatus `json:"status"`
	ExitReason    *string                 `json:"exit_reason,omitempty"` // Why contact exited: completed, filter_rejected, automation_node_deleted, manual, unsubscribed
	EnteredAt     time.Time               `json:"entered_at"`
	ScheduledAt   *time.Time              `json:"scheduled_at,omitempty"`
	Context       map[string]interface{}  `json:"context,omitempty"`
	RetryCount    int                     `json:"retry_count"`
	LastError     *string                 `json:"last_error,omitempty"`
	LastRetryAt   *time.Time              `json:"last_retry_at,omitempty"`
	MaxRetries    int                     `json:"max_retries"`
}

ContactAutomation tracks a contact's journey through an automation

func (*ContactAutomation) Validate

func (ca *ContactAutomation) Validate() error

Validate validates the contact automation

type ContactAutomationFilter

type ContactAutomationFilter struct {
	AutomationID string
	ContactEmail string
	Status       []ContactAutomationStatus
	ScheduledBy  *time.Time // Get contacts scheduled before this time
	Limit        int
	Offset       int
}

ContactAutomationFilter defines filtering options for listing contact automations

type ContactAutomationStatus

type ContactAutomationStatus string

ContactAutomationStatus represents the status of a contact's journey in an automation

const (
	ContactAutomationStatusActive    ContactAutomationStatus = "active"
	ContactAutomationStatusCompleted ContactAutomationStatus = "completed"
	ContactAutomationStatusExited    ContactAutomationStatus = "exited"
	ContactAutomationStatusFailed    ContactAutomationStatus = "failed"
)

func (ContactAutomationStatus) IsValid

func (s ContactAutomationStatus) IsValid() bool

IsValid checks if the contact automation status is valid

type ContactAutomationWithWorkspace

type ContactAutomationWithWorkspace struct {
	WorkspaceID string
	ContactAutomation
}

ContactAutomationWithWorkspace includes workspace ID for global processing

type ContactCondition

type ContactCondition struct {
	Filters []*DimensionFilter `json:"filters"`
}

ContactCondition represents filters on the contacts table

func (*ContactCondition) Validate

func (c *ContactCondition) Validate() error

Validate validates contact conditions

type ContactList

type ContactList struct {
	Email     string            `json:"email"`
	ListID    string            `json:"list_id"`
	ListName  string            `json:"list_name"`
	Status    ContactListStatus `json:"status"`
	CreatedAt time.Time         `json:"created_at"`
	UpdatedAt time.Time         `json:"updated_at"`
	DeletedAt *time.Time        `json:"deleted_at"`
}

ContactList represents the relationship between a contact and a list

func ScanContactList

func ScanContactList(scanner interface {
	Scan(dest ...interface{}) error
}) (*ContactList, error)

ScanContactList scans a contact list from the database

func (*ContactList) Validate

func (cl *ContactList) Validate() error

Validate performs validation on the contact list fields

type ContactListCondition

type ContactListCondition struct {
	Operator string  `json:"operator"` // "in" or "not_in"
	ListID   string  `json:"list_id"`
	Status   *string `json:"status,omitempty"`
}

ContactListCondition represents membership conditions for contact lists

func (*ContactListCondition) Validate

func (c *ContactListCondition) Validate() error

Validate validates contact list conditions

type ContactListRepository

type ContactListRepository interface {
	// AddContactToList adds a contact to a list
	AddContactToList(ctx context.Context, workspaceID string, contactList *ContactList) error

	// BulkAddContactsToLists adds multiple contacts to multiple lists in a single operation
	BulkAddContactsToLists(ctx context.Context, workspaceID string, emails []string, listIDs []string, status ContactListStatus) error

	// GetContactListByIDs retrieves a contact list by email and list ID
	GetContactListByIDs(ctx context.Context, workspaceID string, email, listID string) (*ContactList, error)

	// GetContactsByListID retrieves all contacts for a list
	GetContactsByListID(ctx context.Context, workspaceID string, listID string) ([]*ContactList, error)

	// GetListsByEmail retrieves all lists for a contact
	GetListsByEmail(ctx context.Context, workspaceID string, email string) ([]*ContactList, error)

	// UpdateContactListStatus updates the status of a contact on a list
	UpdateContactListStatus(ctx context.Context, workspaceID string, email, listID string, status ContactListStatus) error

	// RemoveContactFromList removes a contact from a list
	RemoveContactFromList(ctx context.Context, workspaceID string, email, listID string) error

	// DeleteForEmail deletes all contact list relationships for a specific email
	DeleteForEmail(ctx context.Context, workspaceID, email string) error
}

type ContactListService

type ContactListService interface {

	// GetContactListByIDs retrieves a contact list by email and list ID
	GetContactListByIDs(ctx context.Context, workspaceID string, email, listID string) (*ContactList, error)

	// GetContactsByListID retrieves all contacts for a list
	GetContactsByListID(ctx context.Context, workspaceID string, listID string) ([]*ContactList, error)

	// GetListsByEmail retrieves all lists for a contact
	GetListsByEmail(ctx context.Context, workspaceID string, email string) ([]*ContactList, error)

	// UpdateContactListStatus updates the status of a contact on a list
	UpdateContactListStatus(ctx context.Context, workspaceID string, email, listID string, status ContactListStatus) (*UpdateContactListStatusResult, error)

	// RemoveContactFromList removes a contact from a list
	RemoveContactFromList(ctx context.Context, workspaceID string, email, listID string) error
}

ContactListService provides operations for managing contact list relationships

type ContactListStatus

type ContactListStatus string

ContactListStatus represents the status of a contact's subscription to a list

const (
	// ContactListStatusActive indicates an active subscription
	ContactListStatusActive ContactListStatus = "active"
	// ContactListStatusPending indicates a pending subscription (e.g., waiting for double opt-in)
	ContactListStatusPending ContactListStatus = "pending"
	// ContactListStatusUnsubscribed indicates an unsubscribed status
	ContactListStatusUnsubscribed ContactListStatus = "unsubscribed"
	// ContactListStatusBounced indicates the contact's email has bounced
	ContactListStatusBounced ContactListStatus = "bounced"
	// ContactListStatusComplained indicates the contact has complained (e.g., marked as spam)
	ContactListStatusComplained ContactListStatus = "complained"
)

type ContactPreferencesResponse

type ContactPreferencesResponse struct {
	Contact      *Contact       `json:"contact"`
	PublicLists  []*List        `json:"public_lists"`
	ContactLists []*ContactList `json:"contact_lists"`
	LogoURL      string         `json:"logo_url"`
	WebsiteURL   string         `json:"website_url"`
}

ContactPreferencesResponse contains the response data for the notification center

type ContactRepository

type ContactRepository interface {
	// GetContactByEmail retrieves a contact by email
	GetContactByEmail(ctx context.Context, workspaceID, email string) (*Contact, error)

	// GetContactByExternalID retrieves a contact by external ID
	GetContactByExternalID(ctx context.Context, workspaceID string, externalID string) (*Contact, error)

	// GetContacts retrieves contacts with filtering and pagination
	GetContacts(ctx context.Context, req *GetContactsRequest) (*GetContactsResponse, error)

	// DeleteContact deletes a contact
	DeleteContact(ctx context.Context, workspaceID string, email string) error

	// UpsertContact creates or updates a contact
	UpsertContact(ctx context.Context, workspaceID string, contact *Contact) (bool, error)

	// BulkUpsertContacts creates or updates multiple contacts in a single operation
	BulkUpsertContacts(ctx context.Context, workspaceID string, contacts []*Contact) ([]BulkUpsertResult, error)

	// GetContactsForBroadcast retrieves contacts based on broadcast audience settings
	// Uses cursor-based pagination: afterEmail is the last email from the previous batch (empty for first batch)
	GetContactsForBroadcast(ctx context.Context, workspaceID string, audience AudienceSettings, limit int, afterEmail string) ([]*ContactWithList, error)

	// CountContactsForBroadcast counts contacts based on broadcast audience settings
	CountContactsForBroadcast(ctx context.Context, workspaceID string, audience AudienceSettings) (int, error)

	// Count returns the total number of contacts in a workspace
	Count(ctx context.Context, workspaceID string) (int, error)

	// GetBatchForSegment retrieves a batch of email addresses for segment processing
	GetBatchForSegment(ctx context.Context, workspaceID string, offset int64, limit int) ([]string, error)
}

type ContactSegment

type ContactSegment struct {
	Email      string    `json:"email"`
	SegmentID  string    `json:"segment_id"`
	Version    int64     `json:"version"`
	MatchedAt  time.Time `json:"matched_at"`
	ComputedAt time.Time `json:"computed_at"`
}

ContactSegment represents the relationship between a contact and a segment

type ContactSegmentQueueItem

type ContactSegmentQueueItem struct {
	Email    string    `json:"email"`
	QueuedAt time.Time `json:"queued_at"`
}

ContactSegmentQueueItem represents a contact that needs segment recomputation

type ContactSegmentQueueRepository

type ContactSegmentQueueRepository interface {
	// GetPendingEmails retrieves emails that need segment recomputation
	GetPendingEmails(ctx context.Context, workspaceID string, limit int) ([]string, error)

	// RemoveFromQueue removes an email from the queue after processing
	RemoveFromQueue(ctx context.Context, workspaceID string, email string) error

	// RemoveBatchFromQueue removes multiple emails from the queue
	RemoveBatchFromQueue(ctx context.Context, workspaceID string, emails []string) error

	// GetQueueSize returns the number of contacts in the queue
	GetQueueSize(ctx context.Context, workspaceID string) (int, error)

	// ClearQueue removes all items from the queue
	ClearQueue(ctx context.Context, workspaceID string) error
}

ContactSegmentQueueRepository defines the interface for contact segment queue operations

type ContactService

type ContactService interface {
	// GetContactByEmail retrieves a contact by email
	GetContactByEmail(ctx context.Context, workspaceID string, email string) (*Contact, error)

	// GetContactByExternalID retrieves a contact by external ID
	GetContactByExternalID(ctx context.Context, workspaceID string, externalID string) (*Contact, error)

	// GetContacts retrieves contacts with filters and pagination
	GetContacts(ctx context.Context, req *GetContactsRequest) (*GetContactsResponse, error)

	// DeleteContact deletes a contact by email
	DeleteContact(ctx context.Context, workspaceID string, email string) error

	// BatchImportContacts imports a batch of contacts (create or update)
	BatchImportContacts(ctx context.Context, workspaceID string, contacts []*Contact, listIDs []string) *BatchImportContactsResponse

	// UpsertContact creates a new contact or updates an existing one
	UpsertContact(ctx context.Context, workspaceID string, contact *Contact) UpsertContactOperation

	// CountContacts returns the total number of contacts in a workspace
	CountContacts(ctx context.Context, workspaceID string) (int, error)
}

ContactService provides operations for managing contacts

type ContactTimelineCondition

type ContactTimelineCondition struct {
	Kind              string             `json:"kind"`           // Timeline event kind
	CountOperator     string             `json:"count_operator"` // "at_least", "at_most", "exactly"
	CountValue        int                `json:"count_value"`
	TimeframeOperator *string            `json:"timeframe_operator,omitempty"` // "anytime", "in_date_range", "before_date", "after_date", "in_the_last_days"
	TimeframeValues   []string           `json:"timeframe_values,omitempty"`
	Filters           []*DimensionFilter `json:"filters,omitempty"`
}

ContactTimelineCondition represents conditions on contact timeline events

func (*ContactTimelineCondition) Validate

func (c *ContactTimelineCondition) Validate() error

Validate validates contact timeline conditions

type ContactTimelineEntry

type ContactTimelineEntry struct {
	ID          string                 `json:"id"`
	Email       string                 `json:"email"`
	Operation   string                 `json:"operation"`   // 'insert', 'update', 'delete'
	EntityType  string                 `json:"entity_type"` // 'contact', 'contact_list', 'message_history'
	Kind        string                 `json:"kind"`        // operation_entityType (e.g., 'insert_contact', 'update_message_history')
	Changes     map[string]interface{} `json:"changes"`
	EntityID    *string                `json:"entity_id,omitempty"`   // NULL for contact, list_id for contact_list, message_id for message_history
	EntityData  map[string]interface{} `json:"entity_data,omitempty"` // Joined entity data (contact, list, or message details)
	CreatedAt   time.Time              `json:"created_at"`            // Can be set to historical data
	DBCreatedAt time.Time              `json:"db_created_at"`         // Timestamp when record was inserted into database
}

ContactTimelineEntry represents a timeline entry for a contact

type ContactTimelineRepository

type ContactTimelineRepository interface {
	// Create inserts a new timeline entry
	Create(ctx context.Context, workspaceID string, entry *ContactTimelineEntry) error
	// List retrieves timeline entries for a contact
	List(ctx context.Context, workspaceID string, email string, limit int, cursor *string) ([]*ContactTimelineEntry, *string, error)
	// DeleteForEmail deletes all timeline entries for a contact
	DeleteForEmail(ctx context.Context, workspaceID string, email string) error
}

ContactTimelineRepository defines methods for contact timeline persistence

type ContactTimelineService

type ContactTimelineService interface {
	// List retrieves timeline entries for a contact with pagination
	List(ctx context.Context, workspaceID string, email string, limit int, cursor *string) ([]*ContactTimelineEntry, *string, error)
}

ContactTimelineService defines business logic for contact timeline

type ContactWithList

type ContactWithList struct {
	Contact  *Contact `json:"contact"`   // The contact
	ListID   string   `json:"list_id"`   // ID of the list that the contact belongs to
	ListName string   `json:"list_name"` // Name of the list that the contact belongs to
}

ContactWithList represents a contact with information about which list it belongs to

type ContextKey

type ContextKey string
const SystemCallKey ContextKey = "system_call"
const WorkspaceIDKey ContextKey = "workspace_id"

WorkspaceIDKey is the context key for workspace ID

type CreateAPIKeyRequest

type CreateAPIKeyRequest struct {
	WorkspaceID string `json:"workspace_id"`
	EmailPrefix string `json:"email_prefix"`
}

CreateAPIKeyRequest defines the request structure for creating an API key

func (*CreateAPIKeyRequest) Validate

func (r *CreateAPIKeyRequest) Validate() error

Validate validates the create API key request

type CreateAutomationRequest

type CreateAutomationRequest struct {
	WorkspaceID string      `json:"workspace_id"`
	Automation  *Automation `json:"automation"`
}

CreateAutomationRequest represents the request to create an automation

func (*CreateAutomationRequest) Validate

func (r *CreateAutomationRequest) Validate() error

Validate validates the create automation request

type CreateBlogCategoryRequest

type CreateBlogCategoryRequest struct {
	Name        string       `json:"name"`
	Slug        string       `json:"slug"`
	Description string       `json:"description,omitempty"`
	SEO         *SEOSettings `json:"seo,omitempty"`
}

CreateBlogCategoryRequest defines the request to create a blog category

func (*CreateBlogCategoryRequest) Validate

func (r *CreateBlogCategoryRequest) Validate() error

Validate validates the create blog category request

type CreateBlogPostRequest

type CreateBlogPostRequest struct {
	CategoryID         string       `json:"category_id"`
	Slug               string       `json:"slug"`
	Title              string       `json:"title"`
	TemplateID         string       `json:"template_id"`
	TemplateVersion    int          `json:"template_version"`
	Excerpt            string       `json:"excerpt,omitempty"`
	FeaturedImageURL   string       `json:"featured_image_url,omitempty"`
	Authors            []BlogAuthor `json:"authors"`
	ReadingTimeMinutes int          `json:"reading_time_minutes"`
	SEO                *SEOSettings `json:"seo,omitempty"`
}

CreateBlogPostRequest defines the request to create a blog post

func (*CreateBlogPostRequest) Validate

func (r *CreateBlogPostRequest) Validate() error

Validate validates the create blog post request

type CreateBlogThemeRequest

type CreateBlogThemeRequest struct {
	Files BlogThemeFiles `json:"files"`
	Notes *string        `json:"notes,omitempty"`
}

CreateBlogThemeRequest defines the request to create a blog theme

func (*CreateBlogThemeRequest) Validate

func (r *CreateBlogThemeRequest) Validate() error

Validate validates the create blog theme request

type CreateBroadcastRequest

type CreateBroadcastRequest struct {
	WorkspaceID     string                `json:"workspace_id"`
	Name            string                `json:"name"`
	Audience        AudienceSettings      `json:"audience"`
	TestSettings    BroadcastTestSettings `json:"test_settings"`
	TrackingEnabled bool                  `json:"tracking_enabled"`
	UTMParameters   *UTMParameters        `json:"utm_parameters,omitempty"`
	Metadata        MapOfAny              `json:"metadata,omitempty"`
}

CreateBroadcastRequest defines the request to create a new broadcast. Note: Scheduling must be done via the ScheduleBroadcastRequest after creation.

func (*CreateBroadcastRequest) Validate

func (r *CreateBroadcastRequest) Validate() (*Broadcast, error)

Validate validates the create broadcast request

type CreateIntegrationRequest

type CreateIntegrationRequest struct {
	WorkspaceID       string                       `json:"workspace_id"`
	Name              string                       `json:"name"`
	Type              IntegrationType              `json:"type"`
	Provider          EmailProvider                `json:"provider,omitempty"`           // For email integrations
	SupabaseSettings  *SupabaseIntegrationSettings `json:"supabase_settings,omitempty"`  // For Supabase integrations
	LLMProvider       *LLMProvider                 `json:"llm_provider,omitempty"`       // For LLM integrations
	FirecrawlSettings *FirecrawlSettings           `json:"firecrawl_settings,omitempty"` // For Firecrawl integrations
}

CreateIntegrationRequest defines the request structure for creating an integration

func (*CreateIntegrationRequest) Validate

func (r *CreateIntegrationRequest) Validate(passphrase string) error

type CreateListRequest

type CreateListRequest struct {
	WorkspaceID         string             `json:"workspace_id"`
	ID                  string             `json:"id"`
	Name                string             `json:"name"`
	IsDoubleOptin       bool               `json:"is_double_optin"`
	IsPublic            bool               `json:"is_public"`
	Description         string             `json:"description,omitempty"`
	DoubleOptInTemplate *TemplateReference `json:"double_optin_template,omitempty"`
}

Request/Response types

func (*CreateListRequest) Validate

func (r *CreateListRequest) Validate() (list *List, workspaceID string, err error)

type CreateSegmentRequest

type CreateSegmentRequest struct {
	WorkspaceID string    `json:"workspace_id"`
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Color       string    `json:"color"`
	Tree        *TreeNode `json:"tree"`
	Timezone    string    `json:"timezone"`
}

Request/Response types

func (*CreateSegmentRequest) Validate

func (r *CreateSegmentRequest) Validate() (segment *Segment, workspaceID string, err error)

type CreateTaskRequest

type CreateTaskRequest struct {
	WorkspaceID   string     `json:"workspace_id"`
	Type          string     `json:"type"`
	State         *TaskState `json:"state,omitempty"` // New typed state struct
	MaxRuntime    int        `json:"max_runtime"`
	MaxRetries    int        `json:"max_retries"`
	RetryInterval int        `json:"retry_interval"`
	NextRunAfter  *time.Time `json:"next_run_after,omitempty"`
}

CreateTaskRequest defines the request to create a new task

func (*CreateTaskRequest) Validate

func (r *CreateTaskRequest) Validate() (*Task, error)

Validate validates the create task request

type CreateTemplateBlockRequest

type CreateTemplateBlockRequest struct {
	WorkspaceID string                   `json:"workspace_id"`
	Name        string                   `json:"name"`
	Block       notifuse_mjml.EmailBlock `json:"block"`
}

CreateTemplateBlockRequest defines the request structure for creating a template block

func (*CreateTemplateBlockRequest) UnmarshalJSON

func (r *CreateTemplateBlockRequest) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for CreateTemplateBlockRequest

func (*CreateTemplateBlockRequest) Validate

func (r *CreateTemplateBlockRequest) Validate() (block *TemplateBlock, workspaceID string, err error)

Validate validates the create template block request

type CreateTemplateRequest

type CreateTemplateRequest struct {
	WorkspaceID     string         `json:"workspace_id"`
	ID              string         `json:"id"`
	Name            string         `json:"name"`
	Channel         string         `json:"channel"`
	Email           *EmailTemplate `json:"email,omitempty"`
	Web             *WebTemplate   `json:"web,omitempty"`
	Category        string         `json:"category"`
	TemplateMacroID *string        `json:"template_macro_id,omitempty"`
	TestData        MapOfAny       `json:"test_data,omitempty"`
	Settings        MapOfAny       `json:"settings,omitempty"`
}

Request/Response types

func (*CreateTemplateRequest) Validate

func (r *CreateTemplateRequest) Validate() (template *Template, workspaceID string, err error)

type CreateTransactionalRequest

type CreateTransactionalRequest struct {
	WorkspaceID  string                                `json:"workspace_id"`
	Notification TransactionalNotificationCreateParams `json:"notification"`
}

CreateTransactionalRequest represents a request to create a transactional notification

func (*CreateTransactionalRequest) Validate

func (req *CreateTransactionalRequest) Validate() error

Validate validates the create request

type CreateWorkspaceRequest

type CreateWorkspaceRequest struct {
	ID       string            `json:"id"`
	Name     string            `json:"name"`
	Settings WorkspaceSettings `json:"settings"`
}

func (*CreateWorkspaceRequest) Validate

func (r *CreateWorkspaceRequest) Validate(passphrase string) error

type CustomEvent

type CustomEvent struct {
	ExternalID    string                 `json:"external_id"` // Primary key: external system's unique ID
	Email         string                 `json:"email"`
	EventName     string                 `json:"event_name"`               // Generic: "shopify.order", "stripe.payment"
	Properties    map[string]interface{} `json:"properties"`               // Current state of the resource
	OccurredAt    time.Time              `json:"occurred_at"`              // When this version was created
	Source        string                 `json:"source"`                   // "api", "integration", "import"
	IntegrationID *string                `json:"integration_id,omitempty"` // Optional integration ID

	// Goal tracking fields
	GoalName  *string  `json:"goal_name,omitempty"`  // Optional goal name for categorization
	GoalType  *string  `json:"goal_type,omitempty"`  // purchase, subscription, lead, signup, booking, trial, other
	GoalValue *float64 `json:"goal_value,omitempty"` // Monetary value (required for purchase/subscription, can be negative for refunds)

	// Soft delete
	DeletedAt *time.Time `json:"deleted_at,omitempty"` // Soft delete timestamp

	// Timestamps
	CreatedAt time.Time `json:"created_at"` // When first inserted
	UpdatedAt time.Time `json:"updated_at"` // When last updated
}

CustomEvent represents the current state of an external resource Note: ExternalID is the primary key and represents the unique identifier from the external system (e.g., "shopify_order_12345", "stripe_pi_abc123")

func (*CustomEvent) IsDeleted

func (e *CustomEvent) IsDeleted() bool

IsDeleted returns true if the event has been soft-deleted

func (*CustomEvent) Validate

func (e *CustomEvent) Validate() error

Validate validates the custom event

type CustomEventFilters

type CustomEventFilters struct {
	GoalTypes  []string `json:"goal_types,omitempty"`  // Filter by goal_type enum
	EventNames []string `json:"event_names,omitempty"` // Filter by event_name
}

CustomEventFilters defines filters for custom event subscriptions

type CustomEventRepository

type CustomEventRepository interface {
	Upsert(ctx context.Context, workspaceID string, event *CustomEvent) error
	BatchUpsert(ctx context.Context, workspaceID string, events []*CustomEvent) error
	GetByID(ctx context.Context, workspaceID, eventName, externalID string) (*CustomEvent, error)
	ListByEmail(ctx context.Context, workspaceID, email string, limit int, offset int) ([]*CustomEvent, error)
	ListByEventName(ctx context.Context, workspaceID, eventName string, limit int, offset int) ([]*CustomEvent, error)
	DeleteForEmail(ctx context.Context, workspaceID, email string) error
}

CustomEventRepository defines persistence methods

type CustomEventService

type CustomEventService interface {
	UpsertEvent(ctx context.Context, req *UpsertCustomEventRequest) (*CustomEvent, error)
	ImportEvents(ctx context.Context, req *ImportCustomEventsRequest) ([]string, error)
	GetEvent(ctx context.Context, workspaceID, eventName, externalID string) (*CustomEvent, error)
	ListEvents(ctx context.Context, req *ListCustomEventsRequest) ([]*CustomEvent, error)
}

CustomEventService defines business logic

type CustomEventsGoalCondition

type CustomEventsGoalCondition struct {
	GoalType          string   `json:"goal_type"`           // purchase, subscription, lead, signup, booking, trial, other, or "*" for all
	GoalName          *string  `json:"goal_name,omitempty"` // Optional filter by goal name
	AggregateOperator string   `json:"aggregate_operator"`  // sum, count, avg, min, max
	Operator          string   `json:"operator"`            // gte, lte, eq, between
	Value             float64  `json:"value"`
	Value2            *float64 `json:"value_2,omitempty"`  // For between operator
	TimeframeOperator string   `json:"timeframe_operator"` // anytime, in_the_last_days, in_date_range, before_date, after_date
	TimeframeValues   []string `json:"timeframe_values,omitempty"`
}

CustomEventsGoalCondition represents conditions on goal aggregations from custom_events Used for segmentation based on LTV, transaction counts, etc.

func (*CustomEventsGoalCondition) Validate

func (g *CustomEventsGoalCondition) Validate() error

Validate validates custom events goal conditions

type DelayNodeConfig

type DelayNodeConfig struct {
	Duration int    `json:"duration"`
	Unit     string `json:"unit"` // "minutes", "hours", "days"
}

DelayNodeConfig configures a delay node

func (DelayNodeConfig) Validate

func (c DelayNodeConfig) Validate() error

Validate validates the delay node config

type DeleteAutomationRequest

type DeleteAutomationRequest struct {
	WorkspaceID  string `json:"workspace_id"`
	AutomationID string `json:"automation_id"`
}

DeleteAutomationRequest represents the request to delete an automation

func (*DeleteAutomationRequest) Validate

func (r *DeleteAutomationRequest) Validate() error

Validate validates the delete automation request

type DeleteBlogCategoryRequest

type DeleteBlogCategoryRequest struct {
	ID string `json:"id"`
}

DeleteBlogCategoryRequest defines the request to delete a blog category

func (*DeleteBlogCategoryRequest) Validate

func (r *DeleteBlogCategoryRequest) Validate() error

Validate validates the delete blog category request

type DeleteBlogPostRequest

type DeleteBlogPostRequest struct {
	ID string `json:"id"`
}

DeleteBlogPostRequest defines the request to delete a blog post

func (*DeleteBlogPostRequest) Validate

func (r *DeleteBlogPostRequest) Validate() error

Validate validates the delete blog post request

type DeleteBroadcastRequest

type DeleteBroadcastRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

DeleteBroadcastRequest defines the request to delete a broadcast

func (*DeleteBroadcastRequest) Validate

func (r *DeleteBroadcastRequest) Validate() error

Validate validates the delete broadcast request

type DeleteContactRequest

type DeleteContactRequest struct {
	WorkspaceID string `json:"workspace_id" valid:"required"`
	Email       string `json:"email" valid:"required,email"`
}

func (*DeleteContactRequest) Validate

func (r *DeleteContactRequest) Validate() error

type DeleteIntegrationRequest

type DeleteIntegrationRequest struct {
	WorkspaceID   string `json:"workspace_id"`
	IntegrationID string `json:"integration_id"`
}

DeleteIntegrationRequest defines the request structure for deleting an integration

func (*DeleteIntegrationRequest) Validate

func (r *DeleteIntegrationRequest) Validate() error

type DeleteListRequest

type DeleteListRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

func (*DeleteListRequest) Validate

func (r *DeleteListRequest) Validate() (workspaceID string, err error)

type DeleteSegmentRequest

type DeleteSegmentRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

func (*DeleteSegmentRequest) Validate

func (r *DeleteSegmentRequest) Validate() (workspaceID string, id string, err error)

type DeleteTaskRequest

type DeleteTaskRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

DeleteTaskRequest defines the request to delete a task

func (*DeleteTaskRequest) FromURLParams

func (r *DeleteTaskRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

type DeleteTemplateBlockRequest

type DeleteTemplateBlockRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

DeleteTemplateBlockRequest defines the request structure for deleting a template block

func (*DeleteTemplateBlockRequest) Validate

func (r *DeleteTemplateBlockRequest) Validate() (workspaceID string, id string, err error)

Validate validates the delete template block request

type DeleteTemplateRequest

type DeleteTemplateRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

func (*DeleteTemplateRequest) Validate

func (r *DeleteTemplateRequest) Validate() (workspaceID string, id string, err error)

type DeleteTransactionalRequest

type DeleteTransactionalRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

DeleteTransactionalRequest represents a request to delete a transactional notification

func (*DeleteTransactionalRequest) Validate

func (req *DeleteTransactionalRequest) Validate() error

Validate validates the delete request

type DeleteWorkspaceRequest

type DeleteWorkspaceRequest struct {
	ID string `json:"id"`
}

func (*DeleteWorkspaceRequest) Validate

func (r *DeleteWorkspaceRequest) Validate() error

type DimensionFilter

type DimensionFilter struct {
	FieldName    string    `json:"field_name"`
	FieldType    string    `json:"field_type"` // "string", "number", "time", "json"
	Operator     string    `json:"operator"`   // "equals", "not_equals", "gt", "gte", "lt", "lte", "contains", etc.
	StringValues []string  `json:"string_values,omitempty"`
	NumberValues []float64 `json:"number_values,omitempty"`

	// JSON-specific field for navigating nested JSON structures
	// Each element is either a key name or a numeric index (as string)
	// Example: ["user", "tags", "0"] represents user.tags[0]
	JSONPath []string `json:"json_path,omitempty"`
}

DimensionFilter represents a single filter condition on a field

func (*DimensionFilter) Validate

func (f *DimensionFilter) Validate() error

Validate validates a dimension filter

type EmailEventType

type EmailEventType string

EmailEventType defines the type of email webhook event

const (
	// EmailEventDelivered indicates a successful email delivery
	EmailEventDelivered EmailEventType = "delivered"

	// EmailEventBounce indicates a bounced email
	EmailEventBounce EmailEventType = "bounce"

	// EmailEventComplaint indicates a complaint was filed for the email
	EmailEventComplaint EmailEventType = "complaint"

	// EmailEventAuthEmail indicates a Supabase auth email webhook
	EmailEventAuthEmail EmailEventType = "auth_email"

	// EmailEventBeforeUserCreated indicates a Supabase before user created webhook
	EmailEventBeforeUserCreated EmailEventType = "before_user_created"
)

type EmailNodeConfig

type EmailNodeConfig struct {
	TemplateID      string  `json:"template_id"`
	SubjectOverride *string `json:"subject_override,omitempty"`
	FromOverride    *string `json:"from_override,omitempty"`
}

EmailNodeConfig configures an email node

func (EmailNodeConfig) Validate

func (c EmailNodeConfig) Validate() error

Validate validates the email node config

type EmailOptions

type EmailOptions struct {
	FromName           *string      `json:"from_name,omitempty"` // Override default sender from name
	CC                 []string     `json:"cc,omitempty"`
	BCC                []string     `json:"bcc,omitempty"`
	ReplyTo            string       `json:"reply_to,omitempty"`
	Attachments        []Attachment `json:"attachments,omitempty"`
	ListUnsubscribeURL string       `json:"list_unsubscribe_url,omitempty"` // RFC-8058 one-click unsubscribe URL
}

func (EmailOptions) IsEmpty

func (eo EmailOptions) IsEmpty() bool

IsEmpty returns true if no email options are set

func (EmailOptions) ToChannelOptions

func (eo EmailOptions) ToChannelOptions() *ChannelOptions

ToChannelOptions converts EmailOptions to ChannelOptions for storage

type EmailProvider

type EmailProvider struct {
	Kind               EmailProviderKind  `json:"kind"`
	SES                *AmazonSESSettings `json:"ses,omitempty"`
	SMTP               *SMTPSettings      `json:"smtp,omitempty"`
	SparkPost          *SparkPostSettings `json:"sparkpost,omitempty"`
	Postmark           *PostmarkSettings  `json:"postmark,omitempty"`
	Mailgun            *MailgunSettings   `json:"mailgun,omitempty"`
	Mailjet            *MailjetSettings   `json:"mailjet,omitempty"`
	Senders            []EmailSender      `json:"senders"`
	RateLimitPerMinute int                `json:"rate_limit_per_minute"`
}

EmailProvider contains configuration for an email service provider

func (*EmailProvider) DecryptSecretKeys

func (e *EmailProvider) DecryptSecretKeys(passphrase string) error

DecryptSecretKeys decrypts all encrypted secret keys in the email provider

func (*EmailProvider) EncryptSecretKeys

func (e *EmailProvider) EncryptSecretKeys(passphrase string) error

EncryptSecretKeys encrypts all secret keys in the email provider

func (*EmailProvider) GetSender

func (e *EmailProvider) GetSender(id string) *EmailSender

func (*EmailProvider) Validate

func (e *EmailProvider) Validate(passphrase string) error

Validate validates the email provider settings

type EmailProviderKind

type EmailProviderKind string

EmailProviderKind defines the type of email provider

const (
	EmailProviderKindSMTP      EmailProviderKind = "smtp"
	EmailProviderKindSES       EmailProviderKind = "ses"
	EmailProviderKindSparkPost EmailProviderKind = "sparkpost"
	EmailProviderKindPostmark  EmailProviderKind = "postmark"
	EmailProviderKindMailgun   EmailProviderKind = "mailgun"
	EmailProviderKindMailjet   EmailProviderKind = "mailjet"
)

type EmailProviderService

type EmailProviderService interface {
	SendEmail(ctx context.Context, request SendEmailProviderRequest) error
}

type EmailQueueEntry

type EmailQueueEntry struct {
	ID            string               `json:"id"`
	Status        EmailQueueStatus     `json:"status"`
	Priority      int                  `json:"priority"`
	SourceType    EmailQueueSourceType `json:"source_type"`
	SourceID      string               `json:"source_id"` // BroadcastID or AutomationID
	IntegrationID string               `json:"integration_id"`
	ProviderKind  EmailProviderKind    `json:"provider_kind"`

	// Email identification
	ContactEmail string `json:"contact_email"`
	MessageID    string `json:"message_id"`
	TemplateID   string `json:"template_id"`

	// Serialized payload for sending (contains all data needed to send)
	Payload EmailQueuePayload `json:"payload"`

	// Retry tracking
	Attempts    int        `json:"attempts"`
	MaxAttempts int        `json:"max_attempts"`
	LastError   *string    `json:"last_error,omitempty"`
	NextRetryAt *time.Time `json:"next_retry_at,omitempty"`

	// Timestamps
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
	ProcessedAt *time.Time `json:"processed_at,omitempty"`
}

EmailQueueEntry represents a single email in the queue

type EmailQueuePayload

type EmailQueuePayload struct {
	// Email content (compiled and ready to send)
	FromAddress string `json:"from_address"`
	FromName    string `json:"from_name"`
	Subject     string `json:"subject"`
	HTMLContent string `json:"html_content"`

	// Options
	EmailOptions EmailOptions `json:"email_options"`

	// Provider configuration (rate limit needed for worker)
	RateLimitPerMinute int `json:"rate_limit_per_minute"`

	// Provider settings (encrypted, will be decrypted by worker)
	ProviderSettings map[string]interface{} `json:"provider_settings"`

	// Message history tracking fields
	TemplateVersion int                    `json:"template_version"`        // Needed for message_history
	ListID          string                 `json:"list_id,omitempty"`       // For broadcasts
	TemplateData    map[string]interface{} `json:"template_data,omitempty"` // For message history logging
}

EmailQueuePayload contains all data needed to send the email This is stored as JSONB in the database

func (*EmailQueuePayload) ToSendEmailProviderRequest

func (p *EmailQueuePayload) ToSendEmailProviderRequest(workspaceID, integrationID, messageID, toEmail string, provider *EmailProvider) *SendEmailProviderRequest

ToSendEmailProviderRequest converts the payload to a SendEmailProviderRequest The provider must be passed in separately as it's not stored in the payload

type EmailQueueRepository

type EmailQueueRepository interface {
	// Enqueue adds emails to the queue
	Enqueue(ctx context.Context, workspaceID string, entries []*EmailQueueEntry) error

	// EnqueueTx adds emails to the queue within an existing transaction
	EnqueueTx(ctx context.Context, tx *sql.Tx, entries []*EmailQueueEntry) error

	// FetchPending retrieves pending emails for processing
	// Uses FOR UPDATE SKIP LOCKED to allow concurrent workers
	// Orders by priority ASC (lower = higher priority), then created_at ASC
	FetchPending(ctx context.Context, workspaceID string, limit int) ([]*EmailQueueEntry, error)

	// MarkAsProcessing atomically marks an entry as processing
	MarkAsProcessing(ctx context.Context, workspaceID string, id string) error

	// MarkAsSent deletes the entry after successful send
	// (entries are removed immediately rather than marked with a "sent" status)
	MarkAsSent(ctx context.Context, workspaceID string, id string) error

	// MarkAsFailed marks an entry as failed and schedules retry
	MarkAsFailed(ctx context.Context, workspaceID string, id string, errorMsg string, nextRetryAt *time.Time) error

	// Delete removes a queue entry (used when max retries exhausted)
	Delete(ctx context.Context, workspaceID string, entryID string) error

	// SetNextRetry updates next_retry_at WITHOUT incrementing attempts
	// Used by circuit breaker to schedule retry without burning retry attempts
	SetNextRetry(ctx context.Context, workspaceID string, entryID string, nextRetry time.Time) error

	// GetStats returns queue statistics for a workspace
	GetStats(ctx context.Context, workspaceID string) (*EmailQueueStats, error)

	// GetBySourceID retrieves queue entries by source type and ID
	// Useful for tracking broadcast/automation progress
	GetBySourceID(ctx context.Context, workspaceID string, sourceType EmailQueueSourceType, sourceID string) ([]*EmailQueueEntry, error)

	// CountBySourceAndStatus counts entries by source and status
	CountBySourceAndStatus(ctx context.Context, workspaceID string, sourceType EmailQueueSourceType, sourceID string, status EmailQueueStatus) (int64, error)
}

EmailQueueRepository defines data access for the email queue

type EmailQueueSourceType

type EmailQueueSourceType string

EmailQueueSourceType identifies the origin of the queued email

const (
	EmailQueueSourceBroadcast  EmailQueueSourceType = "broadcast"
	EmailQueueSourceAutomation EmailQueueSourceType = "automation"
)

type EmailQueueStats

type EmailQueueStats struct {
	Pending    int64 `json:"pending"`
	Processing int64 `json:"processing"`
	Failed     int64 `json:"failed"`
}

EmailQueueStats provides queue statistics for a workspace

type EmailQueueStatus

type EmailQueueStatus string

EmailQueueStatus represents the status of a queued email

const (
	EmailQueueStatusPending    EmailQueueStatus = "pending"
	EmailQueueStatusProcessing EmailQueueStatus = "processing"
	EmailQueueStatusFailed     EmailQueueStatus = "failed"
)

type EmailSender

type EmailSender struct {
	ID        string `json:"id"`
	Email     string `json:"email"`
	Name      string `json:"name"`
	IsDefault bool   `json:"is_default"`
}

EmailSender represents an email sender with name and email address

func NewEmailSender

func NewEmailSender(email, name string) EmailSender

NewEmailSender creates a new sender with the given email and name

type EmailServiceInterface

type EmailServiceInterface interface {
	TestEmailProvider(ctx context.Context, workspaceID string, provider EmailProvider, to string) error
	SendEmail(ctx context.Context, request SendEmailProviderRequest, isMarketing bool) error
	SendEmailForTemplate(ctx context.Context, request SendEmailRequest) error
	VisitLink(ctx context.Context, messageID string, workspaceID string) error
	OpenEmail(ctx context.Context, messageID string, workspaceID string) error
}

EmailServiceInterface defines the interface for the email service

type EmailTemplate

type EmailTemplate struct {
	SenderID         string                   `json:"sender_id,omitempty"`
	ReplyTo          string                   `json:"reply_to,omitempty"`
	Subject          string                   `json:"subject"`
	SubjectPreview   *string                  `json:"subject_preview,omitempty"`
	CompiledPreview  string                   `json:"compiled_preview"` // compiled html
	VisualEditorTree notifuse_mjml.EmailBlock `json:"visual_editor_tree"`
	Text             *string                  `json:"text,omitempty"`
}

func (EmailTemplate) MarshalJSON

func (x EmailTemplate) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for EmailTemplate

func (*EmailTemplate) Scan

func (x *EmailTemplate) Scan(val interface{}) error

func (*EmailTemplate) UnmarshalJSON

func (x *EmailTemplate) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for EmailTemplate

func (*EmailTemplate) Validate

func (e *EmailTemplate) Validate(testData MapOfAny) error

func (EmailTemplate) Value

func (x EmailTemplate) Value() (driver.Value, error)

type ErrBroadcastNotFound

type ErrBroadcastNotFound struct {
	ID string
}

ErrBroadcastNotFound is an error type for when a broadcast is not found

func (*ErrBroadcastNotFound) Error

func (e *ErrBroadcastNotFound) Error() string

Error returns the error message

type ErrContactListNotFound

type ErrContactListNotFound struct {
	Message string
}

ErrContactListNotFound is returned when a contact list is not found

func (*ErrContactListNotFound) Error

func (e *ErrContactListNotFound) Error() string

type ErrInboundWebhookEventNotFound

type ErrInboundWebhookEventNotFound struct {
	ID string
}

ErrInboundWebhookEventNotFound is returned when an inbound webhook event is not found

func (*ErrInboundWebhookEventNotFound) Error

Error returns the error message

type ErrListNotFound

type ErrListNotFound struct {
	Message string
}

ErrListNotFound is returned when a list is not found

func (*ErrListNotFound) Error

func (e *ErrListNotFound) Error() string

type ErrNotFound

type ErrNotFound struct {
	Entity string
	ID     string
}

Common error types

func (*ErrNotFound) Error

func (e *ErrNotFound) Error() string

type ErrSegmentNotFound

type ErrSegmentNotFound struct {
	Message string
}

ErrSegmentNotFound is returned when a segment is not found

func (*ErrSegmentNotFound) Error

func (e *ErrSegmentNotFound) Error() string

type ErrSessionNotFound

type ErrSessionNotFound struct {
	Message string
}

ErrSessionNotFound is returned when a session is not found

func (*ErrSessionNotFound) Error

func (e *ErrSessionNotFound) Error() string

type ErrSettingNotFound

type ErrSettingNotFound struct {
	Key string
}

ErrSettingNotFound is returned when a setting is not found

func (*ErrSettingNotFound) Error

func (e *ErrSettingNotFound) Error() string

type ErrTaskAlreadyRunning

type ErrTaskAlreadyRunning struct {
	TaskID string
}

ErrTaskAlreadyRunning is returned when attempting to execute a task that is already running

func (*ErrTaskAlreadyRunning) Error

func (e *ErrTaskAlreadyRunning) Error() string

type ErrTaskExecution

type ErrTaskExecution struct {
	TaskID string
	Reason string
	Err    error
}

Task-specific errors

func (*ErrTaskExecution) Error

func (e *ErrTaskExecution) Error() string

func (*ErrTaskExecution) Unwrap

func (e *ErrTaskExecution) Unwrap() error

type ErrTaskTimeout

type ErrTaskTimeout struct {
	TaskID     string
	MaxRuntime int
}

func (*ErrTaskTimeout) Error

func (e *ErrTaskTimeout) Error() string

type ErrTemplateBlockNotFound

type ErrTemplateBlockNotFound struct {
	Message string
}

ErrTemplateBlockNotFound is returned when a template block is not found

func (*ErrTemplateBlockNotFound) Error

func (e *ErrTemplateBlockNotFound) Error() string

type ErrTemplateNotFound

type ErrTemplateNotFound struct {
	Message string
}

ErrTemplateNotFound is returned when a template is not found

func (*ErrTemplateNotFound) Error

func (e *ErrTemplateNotFound) Error() string

type ErrUnauthorized

type ErrUnauthorized struct {
	Message string
}

ErrUnauthorized is returned when a user is not authorized to perform an action

func (*ErrUnauthorized) Error

func (e *ErrUnauthorized) Error() string

type ErrUserExists

type ErrUserExists struct {
	Message string
}

ErrUserExists is returned when trying to create a user that already exists

func (*ErrUserExists) Error

func (e *ErrUserExists) Error() string

type ErrUserNotFound

type ErrUserNotFound struct {
	Message string
}

ErrUserNotFound is returned when a user is not found

func (*ErrUserNotFound) Error

func (e *ErrUserNotFound) Error() string

type ErrWorkspaceNotFound

type ErrWorkspaceNotFound struct {
	WorkspaceID string
}

ErrWorkspaceNotFound is returned when a workspace is not found

func (*ErrWorkspaceNotFound) Error

func (e *ErrWorkspaceNotFound) Error() string

type EventAckCallback

type EventAckCallback func(err error)

EventAckCallback is a function that's called after an event is processed to acknowledge success or failure

type EventBus

type EventBus interface {
	// Publish sends an event to all subscribers
	Publish(ctx context.Context, event EventPayload)

	// PublishWithAck sends an event to all subscribers and calls the acknowledgment callback
	// when all subscribers have processed the event or if an error occurs
	PublishWithAck(ctx context.Context, event EventPayload, callback EventAckCallback)

	// Subscribe registers a handler for a specific event type
	Subscribe(eventType EventType, handler EventHandler)

	// Unsubscribe removes a handler for an event type
	Unsubscribe(eventType EventType, handler EventHandler)
}

EventBus provides a way for services to publish and subscribe to events

type EventHandler

type EventHandler func(ctx context.Context, payload EventPayload)

EventHandler is a function that handles events

type EventPayload

type EventPayload struct {
	Type        EventType              `json:"type"`
	WorkspaceID string                 `json:"workspace_id"`
	EntityID    string                 `json:"entity_id"`
	Data        map[string]interface{} `json:"data,omitempty"`
}

EventPayload represents the data associated with an event

type EventType

type EventType string

EventType defines the type of an event

const (
	EventBroadcastScheduled      EventType = "broadcast.scheduled"
	EventBroadcastPaused         EventType = "broadcast.paused"
	EventBroadcastResumed        EventType = "broadcast.resumed"
	EventBroadcastSent           EventType = "broadcast.sent"
	EventBroadcastFailed         EventType = "broadcast.failed"
	EventBroadcastCancelled      EventType = "broadcast.cancelled"
	EventBroadcastCircuitBreaker EventType = "broadcast.circuit_breaker"
)

Define event types

type ExecutePendingTasksRequest

type ExecutePendingTasksRequest struct {
	MaxTasks int `json:"max_tasks,omitempty"`
}

ExecutePendingTasksRequest defines the request to execute pending tasks

func (*ExecutePendingTasksRequest) FromURLParams

func (r *ExecutePendingTasksRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

type ExecuteTaskRequest

type ExecuteTaskRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

ExecuteTaskRequest defines the request to execute a specific task

func (*ExecuteTaskRequest) Validate

func (r *ExecuteTaskRequest) Validate() error

Validate validates the execute task request

type FileManagerSettings

type FileManagerSettings struct {
	Provider           string  `json:"provider,omitempty"`
	Endpoint           string  `json:"endpoint"`
	Bucket             string  `json:"bucket"`
	AccessKey          string  `json:"access_key"`
	EncryptedSecretKey string  `json:"encrypted_secret_key,omitempty"`
	Region             *string `json:"region,omitempty"`
	CDNEndpoint        *string `json:"cdn_endpoint,omitempty"`
	ForcePathStyle     bool    `json:"force_path_style"`

	// decoded secret key, not stored in the database
	SecretKey string `json:"secret_key,omitempty"`
}

func (*FileManagerSettings) DecryptSecretKey

func (f *FileManagerSettings) DecryptSecretKey(passphrase string) error

func (*FileManagerSettings) EncryptSecretKey

func (f *FileManagerSettings) EncryptSecretKey(passphrase string) error

func (*FileManagerSettings) Validate

func (f *FileManagerSettings) Validate(passphrase string) error

type FilterNodeConfig

type FilterNodeConfig struct {
	Description    string    `json:"description,omitempty"`
	Conditions     *TreeNode `json:"conditions"`
	ContinueNodeID string    `json:"continue_node_id"`
	ExitNodeID     string    `json:"exit_node_id"`
}

FilterNodeConfig configures a filter node

type FirecrawlSettings

type FirecrawlSettings struct {
	EncryptedAPIKey string `json:"encrypted_api_key,omitempty"`
	BaseURL         string `json:"base_url,omitempty"` // Optional, for self-hosted

	// Decoded API key, not stored in the database
	APIKey string `json:"api_key,omitempty"`
}

FirecrawlSettings contains configuration for Firecrawl integration

func (*FirecrawlSettings) DecryptAPIKey

func (f *FirecrawlSettings) DecryptAPIKey(passphrase string) error

DecryptAPIKey decrypts the encrypted API key

func (*FirecrawlSettings) DecryptSecretKeys

func (f *FirecrawlSettings) DecryptSecretKeys(passphrase string) error

DecryptSecretKeys decrypts all secret keys (wrapper for integration compatibility)

func (*FirecrawlSettings) EncryptAPIKey

func (f *FirecrawlSettings) EncryptAPIKey(passphrase string) error

EncryptAPIKey encrypts the API key

func (*FirecrawlSettings) EncryptSecretKeys

func (f *FirecrawlSettings) EncryptSecretKeys(passphrase string) error

EncryptSecretKeys encrypts all secret keys (wrapper for integration compatibility)

func (*FirecrawlSettings) GetBaseURL

func (f *FirecrawlSettings) GetBaseURL() string

GetBaseURL returns the API base URL (default or custom)

func (*FirecrawlSettings) Validate

func (f *FirecrawlSettings) Validate(passphrase string) error

Validate validates the Firecrawl settings and encrypts API key

type GetAutomationRequest

type GetAutomationRequest struct {
	WorkspaceID  string `json:"workspace_id"`
	AutomationID string `json:"automation_id"`
}

GetAutomationRequest represents the request to get an automation

func (*GetAutomationRequest) FromURLParams

func (r *GetAutomationRequest) FromURLParams(params map[string][]string) error

FromURLParams parses the request from URL parameters

func (*GetAutomationRequest) Validate

func (r *GetAutomationRequest) Validate() error

Validate validates the get automation request

type GetBlogCategoryRequest

type GetBlogCategoryRequest struct {
	ID   string `json:"id,omitempty"`
	Slug string `json:"slug,omitempty"`
}

GetBlogCategoryRequest defines the request to get a blog category

func (*GetBlogCategoryRequest) Validate

func (r *GetBlogCategoryRequest) Validate() error

Validate validates the get blog category request

type GetBlogPostRequest

type GetBlogPostRequest struct {
	ID           string `json:"id,omitempty"`
	Slug         string `json:"slug,omitempty"`
	CategorySlug string `json:"category_slug,omitempty"`
}

GetBlogPostRequest defines the request to get a blog post

func (*GetBlogPostRequest) Validate

func (r *GetBlogPostRequest) Validate() error

Validate validates the get blog post request

type GetBlogThemeRequest

type GetBlogThemeRequest struct {
	Version int `json:"version"`
}

GetBlogThemeRequest defines the request to get a blog theme

func (*GetBlogThemeRequest) Validate

func (r *GetBlogThemeRequest) Validate() error

Validate validates the get blog theme request

type GetBroadcastRequest

type GetBroadcastRequest struct {
	WorkspaceID   string `json:"workspace_id"`
	ID            string `json:"id"`
	WithTemplates bool   `json:"with_templates,omitempty"`
}

GetBroadcastRequest represents the request to get a single broadcast

func (*GetBroadcastRequest) FromURLParams

func (r *GetBroadcastRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

type GetBroadcastsRequest

type GetBroadcastsRequest struct {
	WorkspaceID   string `json:"workspace_id"`
	Status        string `json:"status,omitempty"`
	Limit         int    `json:"limit,omitempty"`
	Offset        int    `json:"offset,omitempty"`
	WithTemplates bool   `json:"with_templates,omitempty"`
}

GetBroadcastsRequest is used to extract query parameters for listing broadcasts

func (*GetBroadcastsRequest) FromURLParams

func (r *GetBroadcastsRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

type GetContactByEmailRequest

type GetContactByEmailRequest struct {
	WorkspaceID string `json:"workspace_id" valid:"required"`
	Email       string `json:"email" valid:"required,email"`
}

Request/Response types

type GetContactByExternalIDRequest

type GetContactByExternalIDRequest struct {
	WorkspaceID string `json:"workspace_id" valid:"required"`
	ExternalID  string `json:"external_id" valid:"required"`
}

type GetContactListRequest

type GetContactListRequest struct {
	WorkspaceID string `json:"workspace_id"`
	Email       string `json:"email"`
	ListID      string `json:"list_id"`
}

func (*GetContactListRequest) FromURLParams

func (r *GetContactListRequest) FromURLParams(queryParams url.Values) (err error)

type GetContactNodeExecutionsRequest

type GetContactNodeExecutionsRequest struct {
	WorkspaceID  string `json:"workspace_id"`
	AutomationID string `json:"automation_id"`
	Email        string `json:"email"`
}

GetContactNodeExecutionsRequest represents the request to get a contact's node executions

func (*GetContactNodeExecutionsRequest) FromURLParams

func (r *GetContactNodeExecutionsRequest) FromURLParams(params map[string][]string) error

FromURLParams parses the request from URL parameters

func (*GetContactNodeExecutionsRequest) Validate

func (r *GetContactNodeExecutionsRequest) Validate() error

Validate validates the get contact node executions request

type GetContactsByListRequest

type GetContactsByListRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ListID      string `json:"list_id"`
}

func (*GetContactsByListRequest) FromURLParams

func (r *GetContactsByListRequest) FromURLParams(queryParams url.Values) (err error)

type GetContactsRequest

type GetContactsRequest struct {
	// Required fields
	WorkspaceID string `json:"workspace_id" valid:"required,alphanum,stringlength(1|20)"`

	// Optional filters
	Email             string   `json:"email,omitempty" valid:"optional,email"`
	ExternalID        string   `json:"external_id,omitempty" valid:"optional"`
	FirstName         string   `json:"first_name,omitempty" valid:"optional"`
	LastName          string   `json:"last_name,omitempty" valid:"optional"`
	FullName          string   `json:"full_name,omitempty" valid:"optional"`
	Phone             string   `json:"phone,omitempty" valid:"optional"`
	Country           string   `json:"country,omitempty" valid:"optional"`
	Language          string   `json:"language,omitempty" valid:"optional"`
	ListID            string   `json:"list_id,omitempty" valid:"optional"`
	ContactListStatus string   `json:"contact_list_status,omitempty" valid:"optional"`
	Segments          []string `json:"segments,omitempty" valid:"optional"`

	// Join contact_lists
	WithContactLists bool `json:"with_contact_lists,omitempty" valid:"optional"`

	// Pagination
	Limit  int    `json:"limit,omitempty" valid:"optional,range(1|100)"`
	Cursor string `json:"cursor,omitempty" valid:"optional"`
}

GetContactsRequest represents a request to get contacts with filters and pagination

func (*GetContactsRequest) FromQueryParams

func (r *GetContactsRequest) FromQueryParams(params url.Values) error

FromQueryParams populates the request from URL query parameters

func (*GetContactsRequest) Validate

func (r *GetContactsRequest) Validate() error

Validate ensures that the request has all required fields and valid values

type GetContactsResponse

type GetContactsResponse struct {
	Contacts   []*Contact `json:"contacts"`
	NextCursor string     `json:"next_cursor,omitempty"`
}

GetContactsResponse represents the response from getting contacts

type GetEventByIDRequest

type GetEventByIDRequest struct {
	ID string `json:"id"`
}

GetEventByIDRequest defines the parameters for retrieving a webhook event by ID

type GetEventsByMessageIDRequest

type GetEventsByMessageIDRequest struct {
	MessageID string `json:"message_id"`
	Limit     int    `json:"limit,omitempty"`
	Offset    int    `json:"offset,omitempty"`
}

GetEventsByMessageIDRequest defines the parameters for retrieving webhook events by message ID

type GetListRequest

type GetListRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

func (*GetListRequest) FromURLParams

func (r *GetListRequest) FromURLParams(queryParams url.Values) (err error)

type GetListsByContactRequest

type GetListsByContactRequest struct {
	WorkspaceID string `json:"workspace_id"`
	Email       string `json:"email"`
}

func (*GetListsByContactRequest) FromURLParams

func (r *GetListsByContactRequest) FromURLParams(queryParams url.Values) (err error)

type GetListsRequest

type GetListsRequest struct {
	WorkspaceID string `json:"workspace_id"`
}

func (*GetListsRequest) FromURLParams

func (r *GetListsRequest) FromURLParams(queryParams url.Values) (err error)

type GetSegmentRequest

type GetSegmentRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

func (*GetSegmentRequest) FromURLParams

func (r *GetSegmentRequest) FromURLParams(values url.Values) error

func (*GetSegmentRequest) Validate

func (r *GetSegmentRequest) Validate() (workspaceID string, id string, err error)

type GetSegmentsRequest

type GetSegmentsRequest struct {
	WorkspaceID string `json:"workspace_id"`
	WithCount   bool   `json:"with_count"` // Whether to include contact counts (can be expensive)
}

func (*GetSegmentsRequest) FromURLParams

func (r *GetSegmentsRequest) FromURLParams(values url.Values) error

type GetTaskRequest

type GetTaskRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

GetTaskRequest is used to extract query parameters for getting a single task

func (*GetTaskRequest) FromURLParams

func (r *GetTaskRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

type GetTemplateBlockRequest

type GetTemplateBlockRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

GetTemplateBlockRequest defines the request structure for getting a template block

func (*GetTemplateBlockRequest) FromURLParams

func (r *GetTemplateBlockRequest) FromURLParams(queryParams url.Values) error

FromURLParams parses the request from URL query parameters

type GetTemplateRequest

type GetTemplateRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
	Version     int64  `json:"version,omitempty"`
}

func (*GetTemplateRequest) FromURLParams

func (r *GetTemplateRequest) FromURLParams(queryParams url.Values) (err error)

type GetTemplatesRequest

type GetTemplatesRequest struct {
	WorkspaceID string `json:"workspace_id"`
	Category    string `json:"category,omitempty"`
	Channel     string `json:"channel,omitempty"`
}

func (*GetTemplatesRequest) FromURLParams

func (r *GetTemplatesRequest) FromURLParams(queryParams url.Values) (err error)

type GetTestResultsRequest

type GetTestResultsRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

GetTestResultsRequest represents the request to get A/B test results

func (*GetTestResultsRequest) FromURLParams

func (r *GetTestResultsRequest) FromURLParams(values url.Values) error

FromURLParams parses URL parameters into the request

func (*GetTestResultsRequest) Validate

func (r *GetTestResultsRequest) Validate() error

Validate validates the get test results request

type GetTransactionalRequest

type GetTransactionalRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

GetTransactionalRequest represents a request to get a transactional notification

func (*GetTransactionalRequest) FromURLParams

func (req *GetTransactionalRequest) FromURLParams(values map[string][]string) error

FromURLParams populates the request from URL query parameters

type GetWebhookStatusRequest

type GetWebhookStatusRequest struct {
	WorkspaceID   string `json:"workspace_id"`
	IntegrationID string `json:"integration_id"`
}

GetWebhookStatusRequest defines the request to get webhook status

func (*GetWebhookStatusRequest) Validate

func (r *GetWebhookStatusRequest) Validate() error

Validate validates the GetWebhookStatusRequest

type GetWorkspaceRequest

type GetWorkspaceRequest struct {
	ID string `json:"id"`
}

type HTTPClient

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPClient defines the interface for HTTP operations

type HttpAuth

type HttpAuth struct {
	Username string `json:"Username"`
	Password string `json:"Password"`
}

HttpAuth represents HTTP authentication for webhooks

type HttpHeader

type HttpHeader struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

HttpHeader represents a custom HTTP header

type ImportCustomEventsRequest

type ImportCustomEventsRequest struct {
	WorkspaceID string         `json:"workspace_id"`
	Events      []*CustomEvent `json:"events"`
}

ImportCustomEventsRequest for bulk import

func (*ImportCustomEventsRequest) Validate

func (r *ImportCustomEventsRequest) Validate() error

type InMemoryEventBus

type InMemoryEventBus struct {
	// contains filtered or unexported fields
}

InMemoryEventBus is a simple in-memory implementation of the EventBus

func NewInMemoryEventBus

func NewInMemoryEventBus() *InMemoryEventBus

NewInMemoryEventBus creates a new in-memory event bus

func (*InMemoryEventBus) Publish

func (b *InMemoryEventBus) Publish(ctx context.Context, event EventPayload)

Publish sends an event to all subscribers

func (*InMemoryEventBus) PublishWithAck

func (b *InMemoryEventBus) PublishWithAck(ctx context.Context, event EventPayload, callback EventAckCallback)

PublishWithAck sends an event to all subscribers and calls the acknowledgment callback

func (*InMemoryEventBus) Subscribe

func (b *InMemoryEventBus) Subscribe(eventType EventType, handler EventHandler)

Subscribe registers a handler for a specific event type

func (*InMemoryEventBus) Unsubscribe

func (b *InMemoryEventBus) Unsubscribe(eventType EventType, handler EventHandler)

Unsubscribe removes a handler for an event type

type InboundWebhookEvent

type InboundWebhookEvent struct {
	ID             string         `json:"id"`
	Type           EmailEventType `json:"type"`
	Source         WebhookSource  `json:"source"`
	IntegrationID  string         `json:"integration_id"`
	RecipientEmail string         `json:"recipient_email"`
	MessageID      *string        `json:"message_id,omitempty"`
	Timestamp      time.Time      `json:"timestamp"`
	RawPayload     string         `json:"raw_payload"`

	// Bounce specific fields
	BounceType       string `json:"bounce_type,omitempty"`
	BounceCategory   string `json:"bounce_category,omitempty"`
	BounceDiagnostic string `json:"bounce_diagnostic,omitempty"`

	// Complaint specific fields
	ComplaintFeedbackType string `json:"complaint_feedback_type,omitempty"`

	CreatedAt time.Time `json:"created_at"` // Creation timestamp in the database
}

InboundWebhookEvent represents an event received from an email provider or integration webhook

func NewInboundWebhookEvent

func NewInboundWebhookEvent(
	id string,
	eventType EmailEventType,
	source WebhookSource,
	integrationID string,
	recipientEmail string,
	messageID *string,
	timestamp time.Time,
	rawPayload string,
) *InboundWebhookEvent

NewInboundWebhookEvent creates a new inbound webhook event

type InboundWebhookEventListParams

type InboundWebhookEventListParams struct {
	// Cursor-based pagination
	Cursor string `json:"cursor,omitempty"`
	Limit  int    `json:"limit,omitempty"`

	// Workspace identification
	WorkspaceID string `json:"workspace_id"`

	// Filters
	EventType      EmailEventType `json:"event_type,omitempty"`
	RecipientEmail string         `json:"recipient_email,omitempty"`
	MessageID      string         `json:"message_id,omitempty"`

	// Time range filters
	TimestampAfter  *time.Time `json:"timestamp_after,omitempty"`
	TimestampBefore *time.Time `json:"timestamp_before,omitempty"`
}

func (*InboundWebhookEventListParams) FromQuery

func (p *InboundWebhookEventListParams) FromQuery(query url.Values) error

FromQuery creates InboundWebhookEventListParams from HTTP query parameters

func (*InboundWebhookEventListParams) Validate

func (p *InboundWebhookEventListParams) Validate() error

type InboundWebhookEventListResult

type InboundWebhookEventListResult struct {
	Events     []*InboundWebhookEvent `json:"events"`
	NextCursor string                 `json:"next_cursor,omitempty"`
	HasMore    bool                   `json:"has_more"`
}

InboundWebhookEventListResult contains the result of a ListInboundWebhookEvents operation

type InboundWebhookEventRepository

type InboundWebhookEventRepository interface {
	// StoreEvents stores an inbound webhook event in the database
	StoreEvents(ctx context.Context, workspaceID string, events []*InboundWebhookEvent) error

	// ListEvents retrieves all inbound webhook events for a workspace
	ListEvents(ctx context.Context, workspaceID string, params InboundWebhookEventListParams) (*InboundWebhookEventListResult, error)

	// DeleteForEmail deletes all inbound webhook events for a specific email
	DeleteForEmail(ctx context.Context, workspaceID, email string) error
}

InboundWebhookEventRepository is the interface for inbound webhook event operations

type InboundWebhookEventServiceInterface

type InboundWebhookEventServiceInterface interface {
	// ProcessWebhook processes a webhook event from an email provider
	ProcessWebhook(ctx context.Context, workspaceID, integrationID string, rawPayload []byte) error

	// ListEvents retrieves all inbound webhook events for a workspace
	ListEvents(ctx context.Context, workspaceID string, params InboundWebhookEventListParams) (*InboundWebhookEventListResult, error)
}

InboundWebhookEventServiceInterface defines the interface for inbound webhook event service

type Integration

type Integration struct {
	ID                string                       `json:"id"`
	Name              string                       `json:"name"`
	Type              IntegrationType              `json:"type"`
	EmailProvider     EmailProvider                `json:"email_provider,omitempty"`
	SupabaseSettings  *SupabaseIntegrationSettings `json:"supabase_settings,omitempty"`
	LLMProvider       *LLMProvider                 `json:"llm_provider,omitempty"`
	FirecrawlSettings *FirecrawlSettings           `json:"firecrawl_settings,omitempty"`
	CreatedAt         time.Time                    `json:"created_at"`
	UpdatedAt         time.Time                    `json:"updated_at"`
}

Integration represents a third-party service integration that's embedded in workspace settings

func (*Integration) AfterLoad

func (i *Integration) AfterLoad(secretkey string) error

AfterLoad processes an Integration after loading by decrypting secrets

func (*Integration) BeforeSave

func (i *Integration) BeforeSave(secretkey string) error

BeforeSave prepares an Integration for saving by encrypting secrets

func (*Integration) Scan

func (b *Integration) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (*Integration) Validate

func (i *Integration) Validate(passphrase string) error

Validate validates the integration

func (Integration) Value

func (b Integration) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type IntegrationType

type IntegrationType string

IntegrationType defines the type of integration

const (
	IntegrationTypeEmail     IntegrationType = "email"
	IntegrationTypeSupabase  IntegrationType = "supabase"
	IntegrationTypeLLM       IntegrationType = "llm"
	IntegrationTypeFirecrawl IntegrationType = "firecrawl"
)

type Integrations

type Integrations []Integration

Integrations is a slice of Integration with database serialization methods

func (*Integrations) Scan

func (i *Integrations) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (Integrations) Value

func (i Integrations) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type InviteMemberRequest

type InviteMemberRequest struct {
	WorkspaceID string          `json:"workspace_id"`
	Email       string          `json:"email"`
	Permissions UserPermissions `json:"permissions,omitempty"`
}

func (*InviteMemberRequest) Validate

func (r *InviteMemberRequest) Validate() error

type JSONArray

type JSONArray []interface{}

JSONArray is persisted as a JSON array in the database

func (*JSONArray) Scan

func (a *JSONArray) Scan(val interface{}) error

Scan implements the sql.Scanner interface

func (JSONArray) Value

func (a JSONArray) Value() (driver.Value, error)

Value implements the driver.Valuer interface

type LLMChatEvent

type LLMChatEvent struct {
	Type         string                 `json:"type"`                    // "text", "tool_use", "server_tool_start", "server_tool_result", "done", "error"
	Content      string                 `json:"content,omitempty"`       // Text content for "text" events
	Error        string                 `json:"error,omitempty"`         // Error message for "error" events
	ToolName     string                 `json:"tool_name,omitempty"`     // Tool name for "tool_use" events
	ToolInput    map[string]interface{} `json:"tool_input,omitempty"`    // Tool input for "tool_use" events
	InputTokens  *int64                 `json:"input_tokens,omitempty"`  // Token count (done event only)
	OutputTokens *int64                 `json:"output_tokens,omitempty"` // Token count (done event only)
	InputCost    *float64               `json:"input_cost,omitempty"`    // Cost in USD (done event only)
	OutputCost   *float64               `json:"output_cost,omitempty"`   // Cost in USD (done event only)
	TotalCost    *float64               `json:"total_cost,omitempty"`    // Total cost in USD (done event only)
	Model        string                 `json:"model,omitempty"`         // Model used (done event only)
}

LLMChatEvent represents an SSE event sent during streaming

type LLMChatRequest

type LLMChatRequest struct {
	WorkspaceID   string       `json:"workspace_id"`
	IntegrationID string       `json:"integration_id"`
	Messages      []LLMMessage `json:"messages"`
	MaxTokens     int          `json:"max_tokens,omitempty"`
	SystemPrompt  string       `json:"system_prompt,omitempty"`
	Tools         []LLMTool    `json:"tools,omitempty"`
}

LLMChatRequest represents a request to the LLM chat endpoint

func (*LLMChatRequest) Validate

func (r *LLMChatRequest) Validate() error

Validate validates the LLM chat request

type LLMMessage

type LLMMessage struct {
	Role    string `json:"role"` // "user" or "assistant"
	Content string `json:"content"`
}

LLMMessage represents a chat message

type LLMProvider

type LLMProvider struct {
	Kind      LLMProviderKind    `json:"kind"`
	Anthropic *AnthropicSettings `json:"anthropic,omitempty"`
}

LLMProvider contains configuration for an LLM service provider

func (*LLMProvider) DecryptSecretKeys

func (l *LLMProvider) DecryptSecretKeys(passphrase string) error

DecryptSecretKeys decrypts all encrypted secret keys in the LLM provider

func (*LLMProvider) EncryptSecretKeys

func (l *LLMProvider) EncryptSecretKeys(passphrase string) error

EncryptSecretKeys encrypts all secret keys in the LLM provider

func (*LLMProvider) Validate

func (l *LLMProvider) Validate(passphrase string) error

Validate validates the LLM provider settings

type LLMProviderKind

type LLMProviderKind string

LLMProviderKind defines the type of LLM provider

const (
	LLMProviderKindAnthropic LLMProviderKind = "anthropic"
)

type LLMService

type LLMService interface {
	// StreamChat sends a chat request and streams the response
	StreamChat(ctx context.Context, req *LLMChatRequest, onEvent func(LLMChatEvent) error) error
}

LLMService defines the interface for LLM operations

type LLMTool

type LLMTool struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	InputSchema json.RawMessage `json:"input_schema"`
}

LLMTool represents a tool the AI can use

type List

type List struct {
	ID                  string             `json:"id"`
	Name                string             `json:"name"`
	IsDoubleOptin       bool               `json:"is_double_optin" db:"is_double_optin"`
	IsPublic            bool               `json:"is_public" db:"is_public"`
	Description         string             `json:"description,omitempty"`
	DoubleOptInTemplate *TemplateReference `json:"double_optin_template,omitempty"`
	CreatedAt           time.Time          `json:"created_at"`
	UpdatedAt           time.Time          `json:"updated_at"`
	DeletedAt           *time.Time         `json:"-" db:"deleted_at"`
}

List represents a subscription list

func ScanList

func ScanList(scanner interface {
	Scan(dest ...interface{}) error
}) (*List, error)

ScanList scans a list from the database

func (*List) Validate

func (l *List) Validate() error

Validate performs validation on the list fields

type ListAutomationsRequest

type ListAutomationsRequest struct {
	WorkspaceID string             `json:"workspace_id"`
	Status      []AutomationStatus `json:"status,omitempty"`
	ListID      string             `json:"list_id,omitempty"`
	Limit       int                `json:"limit,omitempty"`
	Offset      int                `json:"offset,omitempty"`
}

ListAutomationsRequest represents the request to list automations

func (*ListAutomationsRequest) FromURLParams

func (r *ListAutomationsRequest) FromURLParams(params map[string][]string) error

FromURLParams parses the request from URL parameters

func (*ListAutomationsRequest) ToFilter

ToFilter converts the request to an AutomationFilter

func (*ListAutomationsRequest) Validate

func (r *ListAutomationsRequest) Validate() error

Validate validates the list automations request

type ListBlogPostsRequest

type ListBlogPostsRequest struct {
	CategoryID string         `json:"category_id,omitempty"`
	Status     BlogPostStatus `json:"status,omitempty"`
	Page       int            `json:"page,omitempty"`   // Page number (1-indexed)
	Limit      int            `json:"limit,omitempty"`  // Posts per page
	Offset     int            `json:"offset,omitempty"` // Calculated from Page
}

ListBlogPostsRequest defines the request to list blog posts

func (*ListBlogPostsRequest) Validate

func (r *ListBlogPostsRequest) Validate() error

Validate validates the list blog posts request

type ListBlogThemesRequest

type ListBlogThemesRequest struct {
	Limit  int `json:"limit,omitempty"`
	Offset int `json:"offset,omitempty"`
}

ListBlogThemesRequest defines the request to list blog themes

func (*ListBlogThemesRequest) Validate

func (r *ListBlogThemesRequest) Validate() error

Validate validates the list blog themes request

type ListBroadcastsParams

type ListBroadcastsParams struct {
	WorkspaceID   string
	Status        BroadcastStatus
	Limit         int
	Offset        int
	WithTemplates bool // Whether to fetch and include template details for each variation
}

ListBroadcastsParams defines parameters for listing broadcasts with pagination

type ListCustomEventsRequest

type ListCustomEventsRequest struct {
	WorkspaceID string
	Email       string
	EventName   *string // Optional filter by event name
	Limit       int
	Offset      int
}

ListCustomEventsRequest represents query parameters for listing custom events

func (*ListCustomEventsRequest) Validate

func (r *ListCustomEventsRequest) Validate() error

type ListRepository

type ListRepository interface {
	// CreateList creates a new list in the database
	CreateList(ctx context.Context, workspaceID string, list *List) error

	// GetListByID retrieves a list by its ID
	GetListByID(ctx context.Context, workspaceID string, id string) (*List, error)

	// GetLists retrieves all lists
	GetLists(ctx context.Context, workspaceID string) ([]*List, error)

	// UpdateList updates an existing list
	UpdateList(ctx context.Context, workspaceID string, list *List) error

	// DeleteList deletes a list
	DeleteList(ctx context.Context, workspaceID string, id string) error

	GetListStats(ctx context.Context, workspaceID string, id string) (*ListStats, error)
}

type ListService

type ListService interface {
	// SubscribeToLists subscribes a contact to a list
	SubscribeToLists(ctx context.Context, payload *SubscribeToListsRequest, hasBearerToken bool) error

	// UnsubscribeFromLists unsubscribes a contact from a list
	UnsubscribeFromLists(ctx context.Context, payload *UnsubscribeFromListsRequest, hasBearerToken bool) error

	// CreateList creates a new list
	CreateList(ctx context.Context, workspaceID string, list *List) error

	// GetListByID retrieves a list by ID
	GetListByID(ctx context.Context, workspaceID string, id string) (*List, error)

	// GetLists retrieves all lists
	GetLists(ctx context.Context, workspaceID string) ([]*List, error)

	// UpdateList updates an existing list
	UpdateList(ctx context.Context, workspaceID string, list *List) error

	// DeleteList deletes a list by ID
	DeleteList(ctx context.Context, workspaceID string, id string) error

	GetListStats(ctx context.Context, workspaceID string, id string) (*ListStats, error)
}

ListService provides operations for managing lists

type ListStats

type ListStats struct {
	TotalActive       int `json:"total_active"`
	TotalPending      int `json:"total_pending"`
	TotalUnsubscribed int `json:"total_unsubscribed"`
	TotalBounced      int `json:"total_bounced"`
	TotalComplained   int `json:"total_complained"`
}

type ListStatusBranchNodeConfig

type ListStatusBranchNodeConfig struct {
	ListID          string `json:"list_id"`             // List to check status in
	NotInListNodeID string `json:"not_in_list_node_id"` // Next node when contact is not in list
	ActiveNodeID    string `json:"active_node_id"`      // Next node when status is "active"
	NonActiveNodeID string `json:"non_active_node_id"`  // Next node when status is non-active (pending, unsubscribed, bounced, complained)
}

ListStatusBranchNodeConfig configures a list status branch node This node checks a contact's subscription status in a list and branches accordingly

func (ListStatusBranchNodeConfig) Validate

func (c ListStatusBranchNodeConfig) Validate() error

Validate validates the list status branch node config

type ListTasksRequest

type ListTasksRequest struct {
	WorkspaceID   string   `json:"workspace_id"`
	Status        []string `json:"status,omitempty"`
	Type          []string `json:"type,omitempty"`
	CreatedAfter  string   `json:"created_after,omitempty"`
	CreatedBefore string   `json:"created_before,omitempty"`
	Limit         int      `json:"limit,omitempty"`
	Offset        int      `json:"offset,omitempty"`
}

ListTasksRequest is used to extract query parameters for listing tasks

func (*ListTasksRequest) FromURLParams

func (r *ListTasksRequest) FromURLParams(values url.Values) error

FromURLParams parses URL query parameters into the request

func (*ListTasksRequest) ToFilter

func (r *ListTasksRequest) ToFilter() TaskFilter

ToFilter converts the request to a TaskFilter

type ListTemplateBlocksRequest

type ListTemplateBlocksRequest struct {
	WorkspaceID string `json:"workspace_id"`
}

ListTemplateBlocksRequest defines the request structure for listing template blocks

func (*ListTemplateBlocksRequest) FromURLParams

func (r *ListTemplateBlocksRequest) FromURLParams(queryParams url.Values) error

FromURLParams parses the request from URL query parameters

type ListTransactionalRequest

type ListTransactionalRequest struct {
	WorkspaceID string                 `json:"workspace_id"`
	Search      string                 `json:"search,omitempty"`
	Limit       int                    `json:"limit,omitempty"`
	Offset      int                    `json:"offset,omitempty"`
	Filter      map[string]interface{} `json:"filter,omitempty"`
}

ListTransactionalRequest represents a request to list transactional notifications

func (*ListTransactionalRequest) FromURLParams

func (req *ListTransactionalRequest) FromURLParams(values map[string][]string) error

FromURLParams populates the request from URL query parameters

type MailgunDelivery

type MailgunDelivery struct {
	Status           string                 `json:"status,omitempty"`
	Code             int                    `json:"code,omitempty"`
	Message          string                 `json:"message,omitempty"`
	AttemptNo        int                    `json:"attempt-no,omitempty"`
	Description      string                 `json:"description,omitempty"`
	SessionSeconds   float64                `json:"session-seconds,omitempty"`
	Certificate      bool                   `json:"certificate,omitempty"`
	TLS              bool                   `json:"tls,omitempty"`
	MXHost           string                 `json:"mx-host,omitempty"`
	DelvDataFeedback []interface{}          `json:"delivery-status,omitempty"`
	SMTP             map[string]interface{} `json:"smtp,omitempty"`
}

MailgunDelivery contains delivery information

type MailgunEventData

type MailgunEventData struct {
	Event         string                 `json:"event"`
	Timestamp     float64                `json:"timestamp"`
	ID            string                 `json:"id"`
	Recipient     string                 `json:"recipient"`
	Tags          []string               `json:"tags"`
	Message       MailgunMessage         `json:"message"`
	Delivery      MailgunDelivery        `json:"delivery,omitempty"`
	Reason        string                 `json:"reason,omitempty"`
	Severity      string                 `json:"severity,omitempty"`
	Storage       map[string]interface{} `json:"storage,omitempty"`
	UserVariables map[string]interface{} `json:"user-variables,omitempty"`
	Flags         map[string]interface{} `json:"flags,omitempty"`
}

MailgunEventData contains the main event data from Mailgun

type MailgunHeaders

type MailgunHeaders struct {
	To        string `json:"to"`
	MessageID string `json:"message-id"`
	From      string `json:"from"`
	Subject   string `json:"subject"`
}

MailgunHeaders contains email headers

type MailgunMessage

type MailgunMessage struct {
	Headers     MailgunHeaders `json:"headers"`
	Attachments []interface{}  `json:"attachments"`
	Size        int            `json:"size"`
}

MailgunMessage contains information about the email message

type MailgunServiceInterface

type MailgunServiceInterface interface {
	// ListWebhooks retrieves all registered webhooks for a domain
	ListWebhooks(ctx context.Context, config MailgunSettings) (*MailgunWebhookListResponse, error)

	// CreateWebhook creates a new webhook
	CreateWebhook(ctx context.Context, config MailgunSettings, webhook MailgunWebhook) (*MailgunWebhook, error)

	// GetWebhook retrieves a webhook by ID
	GetWebhook(ctx context.Context, config MailgunSettings, webhookID string) (*MailgunWebhook, error)

	// UpdateWebhook updates an existing webhook
	UpdateWebhook(ctx context.Context, config MailgunSettings, webhookID string, webhook MailgunWebhook) (*MailgunWebhook, error)

	// DeleteWebhook deletes a webhook by ID
	DeleteWebhook(ctx context.Context, config MailgunSettings, webhookID string) error

	// TestWebhook sends a test event to a webhook
	TestWebhook(ctx context.Context, config MailgunSettings, webhookID string, eventType string) error
}

MailgunServiceInterface defines operations for managing Mailgun webhooks

type MailgunSettings

type MailgunSettings struct {
	EncryptedAPIKey string `json:"encrypted_api_key,omitempty"`
	Domain          string `json:"domain"`
	Region          string `json:"region,omitempty"` // "US" or "EU"

	// decoded API key, not stored in the database
	APIKey string `json:"api_key,omitempty"`
}

MailgunSettings contains configuration for Mailgun

func (*MailgunSettings) DecryptAPIKey

func (m *MailgunSettings) DecryptAPIKey(passphrase string) error

func (*MailgunSettings) EncryptAPIKey

func (m *MailgunSettings) EncryptAPIKey(passphrase string) error

func (*MailgunSettings) Validate

func (m *MailgunSettings) Validate(passphrase string) error

type MailgunSignature

type MailgunSignature struct {
	Timestamp string `json:"timestamp"`
	Token     string `json:"token"`
	Signature string `json:"signature"`
}

MailgunSignature contains signature information for webhook authentication

type MailgunUrls

type MailgunUrls struct {
	URLs []string `json:"urls"`
}

type MailgunWebhook

type MailgunWebhook struct {
	ID     string   `json:"id,omitempty"`
	URL    string   `json:"url"`
	Events []string `json:"events"`
	Active bool     `json:"active"`
}

MailgunWebhook represents a webhook configuration in Mailgun

type MailgunWebhookListResponse

type MailgunWebhookListResponse struct {
	Webhooks MailgunWebhooks `json:"webhooks"`
}

type MailgunWebhookPayload

type MailgunWebhookPayload struct {
	Signature MailgunSignature `json:"signature"`
	EventData MailgunEventData `json:"event-data"`
}

MailgunWebhookPayload represents a Mailgun webhook payload

type MailgunWebhooks

type MailgunWebhooks struct {
	Delivered     MailgunUrls `json:"delivered"`
	PermanentFail MailgunUrls `json:"permanent_fail"`
	TemporaryFail MailgunUrls `json:"temporary_fail"`
	Complained    MailgunUrls `json:"complained"`
}

MailgunWebhookListResponse represents the response from listing webhooks

type MailjetServiceInterface

type MailjetServiceInterface interface {
	// ListWebhooks retrieves all registered webhooks
	ListWebhooks(ctx context.Context, config MailjetSettings) (*MailjetWebhookResponse, error)

	// CreateWebhook creates a new webhook
	CreateWebhook(ctx context.Context, config MailjetSettings, webhook MailjetWebhook) (*MailjetWebhook, error)

	// GetWebhook retrieves a webhook by ID
	GetWebhook(ctx context.Context, config MailjetSettings, webhookID int64) (*MailjetWebhook, error)

	// UpdateWebhook updates an existing webhook
	UpdateWebhook(ctx context.Context, config MailjetSettings, webhookID int64, webhook MailjetWebhook) (*MailjetWebhook, error)

	// DeleteWebhook deletes a webhook by ID
	DeleteWebhook(ctx context.Context, config MailjetSettings, webhookID int64) error
}

MailjetServiceInterface defines operations for managing Mailjet webhooks

type MailjetSettings

type MailjetSettings struct {
	EncryptedAPIKey    string `json:"encrypted_api_key,omitempty"`
	EncryptedSecretKey string `json:"encrypted_secret_key,omitempty"`
	SandboxMode        bool   `json:"sandbox_mode"`

	// decoded keys, not stored in the database
	APIKey    string `json:"api_key,omitempty"`
	SecretKey string `json:"secret_key,omitempty"`
}

MailjetSettings contains configuration for Mailjet

func (*MailjetSettings) DecryptAPIKey

func (m *MailjetSettings) DecryptAPIKey(passphrase string) error

func (*MailjetSettings) DecryptSecretKey

func (m *MailjetSettings) DecryptSecretKey(passphrase string) error

func (*MailjetSettings) EncryptAPIKey

func (m *MailjetSettings) EncryptAPIKey(passphrase string) error

func (*MailjetSettings) EncryptSecretKey

func (m *MailjetSettings) EncryptSecretKey(passphrase string) error

func (*MailjetSettings) Validate

func (m *MailjetSettings) Validate(passphrase string) error

type MailjetWebhook

type MailjetWebhook struct {
	ID        int64  `json:"ID,omitempty"`
	APIKey    string `json:"APIKey,omitempty"`
	Endpoint  string `json:"Url"`
	EventType string `json:"EventType"`
	Status    string `json:"Status,omitempty"`
	Version   int    `json:"Version"`
	IsBackup  bool   `json:"IsBackup,omitempty"`
}

MailjetWebhook represents a webhook configuration in Mailjet According to https://dev.mailjet.com/email/reference/webhook#v3_post_eventcallbackurl

type MailjetWebhookEventType

type MailjetWebhookEventType string

MailjetWebhookEventType represents the available event types for webhooks

const (
	// Event types as defined in Mailjet documentation
	MailjetEventSent    MailjetWebhookEventType = "sent"
	MailjetEventBounce  MailjetWebhookEventType = "bounce"
	MailjetEventBlocked MailjetWebhookEventType = "blocked"
	MailjetEventSpam    MailjetWebhookEventType = "spam"
	MailjetEventUnsub   MailjetWebhookEventType = "unsub"
	MailjetEventClick   MailjetWebhookEventType = "click"
	MailjetEventOpen    MailjetWebhookEventType = "open"
)

type MailjetWebhookPayload

type MailjetWebhookPayload struct {
	Event     string `json:"event"`
	Time      int64  `json:"time"`
	MessageID int64  `json:"MessageID"`
	Email     string `json:"email"`

	// Message identification
	MjCampaignID int64  `json:"mj_campaign_id,omitempty"`
	MjContactID  int64  `json:"mj_contact_id,omitempty"`
	CustomID     string `json:"CustomID,omitempty"`
	MessageUUID  string `json:"MessageUUID,omitempty"`

	// Campaign information
	CustomCampaign string `json:"CustomCampaign,omitempty"`
	Payload        string `json:"Payload,omitempty"`

	// Bounce specific fields
	Blocked        bool   `json:"blocked,omitempty"`
	HardBounce     bool   `json:"hard_bounce,omitempty"`
	ErrorRelatedTo string `json:"error_related_to,omitempty"`
	Error          string `json:"error,omitempty"`

	// Complaint specific fields
	Source string `json:"source,omitempty"`

	// Common fields
	Comment string `json:"comment,omitempty"`

	// Click/Open specific fields
	URL       string `json:"url,omitempty"`
	UserAgent string `json:"user_agent,omitempty"`
}

MailjetWebhookPayload represents the webhook payload from Mailjet According to https://dev.mailjet.com/email/guides/webhooks/

type MailjetWebhookResponse

type MailjetWebhookResponse struct {
	Count int              `json:"Count"`
	Data  []MailjetWebhook `json:"Data"`
	Total int              `json:"Total"`
}

MailjetWebhookResponse represents a response for webhook operations

type MapOfAny

type MapOfAny map[string]any

MapOfAny is persisted as JSON in the database

func BuildBlogTemplateData

func BuildBlogTemplateData(req BlogTemplateDataRequest) (MapOfAny, error)

BuildBlogTemplateData creates a template data map for blog Liquid templates This ensures consistent data structure across all blog pages

func BuildTemplateData

func BuildTemplateData(req TemplateDataRequest) (MapOfAny, error)

BuildTemplateData creates a template data map with flexible options

func (*MapOfAny) Scan

func (m *MapOfAny) Scan(val interface{}) error

Scan implements the sql.Scanner interface

func (MapOfAny) Value

func (m MapOfAny) Value() (driver.Value, error)

Value implements the driver.Valuer interface

type MessageData

type MessageData struct {
	// Custom fields used in template compilation
	Data map[string]interface{} `json:"data"`
	// Optional metadata for tracking
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

MessageData represents the JSON data used to compile a template

func (*MessageData) Scan

func (d *MessageData) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database retrieval

func (MessageData) Value

func (d MessageData) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database storage

type MessageEvent

type MessageEvent string

MessageStatus represents the current status of a message

const (
	// Message status constants
	MessageEventSent         MessageEvent = "sent"
	MessageEventDelivered    MessageEvent = "delivered"
	MessageEventFailed       MessageEvent = "failed"
	MessageEventOpened       MessageEvent = "opened"
	MessageEventClicked      MessageEvent = "clicked"
	MessageEventBounced      MessageEvent = "bounced"
	MessageEventComplained   MessageEvent = "complained"
	MessageEventUnsubscribed MessageEvent = "unsubscribed"
)

type MessageEventUpdate

type MessageEventUpdate struct {
	ID         string       `json:"id"`
	Event      MessageEvent `json:"event"`
	Timestamp  time.Time    `json:"timestamp"`
	StatusInfo *string      `json:"status_info,omitempty"`
}

MessageEventUpdate represents a status update for a message

type MessageHistory

type MessageHistory struct {
	ID              string               `json:"id"`
	ExternalID      *string              `json:"external_id,omitempty"` // For idempotency checks
	ContactEmail    string               `json:"contact_email"`
	BroadcastID     *string              `json:"broadcast_id,omitempty"`
	AutomationID    *string              `json:"automation_id,omitempty"` // Automation this message was sent from (nullable for broadcasts/transactional)
	ListID          *string              `json:"list_id,omitempty"`       // List this message was sent to (nullable for transactional emails)
	TemplateID      string               `json:"template_id"`
	TemplateVersion int64                `json:"template_version"`
	Channel         string               `json:"channel"` // email, sms, push, etc.
	StatusInfo      *string              `json:"status_info,omitempty"`
	MessageData     MessageData          `json:"message_data"`
	ChannelOptions  *ChannelOptions      `json:"channel_options,omitempty"` // Channel-specific delivery options
	Attachments     []AttachmentMetadata `json:"attachments,omitempty"`

	// Event timestamps
	SentAt         time.Time  `json:"sent_at"`
	DeliveredAt    *time.Time `json:"delivered_at,omitempty"`
	FailedAt       *time.Time `json:"failed_at,omitempty"`
	OpenedAt       *time.Time `json:"opened_at,omitempty"`
	ClickedAt      *time.Time `json:"clicked_at,omitempty"`
	BouncedAt      *time.Time `json:"bounced_at,omitempty"`
	ComplainedAt   *time.Time `json:"complained_at,omitempty"`
	UnsubscribedAt *time.Time `json:"unsubscribed_at,omitempty"`

	// System timestamps
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

MessageHistory represents a record of a message sent to a contact

type MessageHistoryRepository

type MessageHistoryRepository interface {
	// Create adds a new message history record
	Create(ctx context.Context, workspaceID string, secretKey string, message *MessageHistory) error

	// Upsert creates or updates a message history record (for retry handling)
	// On conflict, updates failed_at, status_info, and updated_at fields
	Upsert(ctx context.Context, workspaceID string, secretKey string, message *MessageHistory) error

	// Update updates an existing message history record
	Update(ctx context.Context, workspaceID string, message *MessageHistory) error

	// Get retrieves a message history by ID
	Get(ctx context.Context, workspaceID string, secretKey string, id string) (*MessageHistory, error)

	// GetByExternalID retrieves a message history by external ID for idempotency checks
	GetByExternalID(ctx context.Context, workspaceID string, secretKey string, externalID string) (*MessageHistory, error)

	// GetByContact retrieves message history for a specific contact
	GetByContact(ctx context.Context, workspaceID string, secretKey string, contactEmail string, limit, offset int) ([]*MessageHistory, int, error)

	// GetByBroadcast retrieves message history for a specific broadcast
	GetByBroadcast(ctx context.Context, workspaceID string, secretKey string, broadcastID string, limit, offset int) ([]*MessageHistory, int, error)

	// ListMessages retrieves message history with cursor-based pagination and filtering
	ListMessages(ctx context.Context, workspaceID string, secretKey string, params MessageListParams) ([]*MessageHistory, string, error)

	// SetStatusesIfNotSet updates multiple message statuses in a batch if they haven't been set before
	SetStatusesIfNotSet(ctx context.Context, workspaceID string, updates []MessageEventUpdate) error

	// SetClicked sets the clicked_at timestamp and ensures opened_at is also set
	SetClicked(ctx context.Context, workspaceID, id string, timestamp time.Time) error

	// SetOpened sets the opened_at timestamp if not already set
	SetOpened(ctx context.Context, workspaceID, id string, timestamp time.Time) error

	// GetBroadcastStats retrieves statistics for a broadcast
	GetBroadcastStats(ctx context.Context, workspaceID, broadcastID string) (*MessageHistoryStatusSum, error)

	// GetBroadcastVariationStats retrieves statistics for a specific variation of a broadcast
	GetBroadcastVariationStats(ctx context.Context, workspaceID, broadcastID, templateID string) (*MessageHistoryStatusSum, error)

	// DeleteForEmail deletes all message history records for a specific email
	DeleteForEmail(ctx context.Context, workspaceID, email string) error
}

MessageHistoryRepository defines methods for message history persistence

type MessageHistoryService

type MessageHistoryService interface {
	// ListMessages retrieves messages for a workspace with cursor-based pagination and filters
	ListMessages(ctx context.Context, workspaceID string, params MessageListParams) (*MessageListResult, error)

	// GetBroadcastStats retrieves statistics for a broadcast
	GetBroadcastStats(ctx context.Context, workspaceID, broadcastID string) (*MessageHistoryStatusSum, error)

	// GetBroadcastVariationStats retrieves statistics for a specific variation of a broadcast
	GetBroadcastVariationStats(ctx context.Context, workspaceID, broadcastID, templateID string) (*MessageHistoryStatusSum, error)
}

MessageHistoryService defines methods for interacting with message history

type MessageHistoryStatusSum

type MessageHistoryStatusSum struct {
	TotalSent         int `json:"total_sent"`
	TotalDelivered    int `json:"total_delivered"`
	TotalBounced      int `json:"total_bounced"`
	TotalComplained   int `json:"total_complained"`
	TotalFailed       int `json:"total_failed"`
	TotalOpened       int `json:"total_opened"`
	TotalClicked      int `json:"total_clicked"`
	TotalUnsubscribed int `json:"total_unsubscribed"`
}

type MessageListParams

type MessageListParams struct {
	// Cursor-based pagination
	Cursor string `json:"cursor,omitempty"`
	Limit  int    `json:"limit,omitempty"`

	// Filters
	ID             string `json:"id,omitempty"`              // filter by message ID
	ExternalID     string `json:"external_id,omitempty"`     // filter by external ID
	ListID         string `json:"list_id,omitempty"`         // filter by list ID (array contains)
	Channel        string `json:"channel,omitempty"`         // email, sms, push, etc.
	ContactEmail   string `json:"contact_email,omitempty"`   // filter by contact
	BroadcastID    string `json:"broadcast_id,omitempty"`    // filter by broadcast
	TemplateID     string `json:"template_id,omitempty"`     // filter by template
	IsSent         *bool  `json:"is_sent,omitempty"`         // filter messages that are sent
	IsDelivered    *bool  `json:"is_delivered,omitempty"`    // filter messages that are delivered
	IsFailed       *bool  `json:"is_failed,omitempty"`       // filter messages that are failed
	IsOpened       *bool  `json:"is_opened,omitempty"`       // filter messages that are opened
	IsClicked      *bool  `json:"is_clicked,omitempty"`      // filter messages that are clicked
	IsBounced      *bool  `json:"is_bounced,omitempty"`      // filter messages that are bounced
	IsComplained   *bool  `json:"is_complained,omitempty"`   // filter messages that are complained
	IsUnsubscribed *bool  `json:"is_unsubscribed,omitempty"` // filter messages that are unsubscribed
	// Time range filters
	SentAfter     *time.Time `json:"sent_after,omitempty"`
	SentBefore    *time.Time `json:"sent_before,omitempty"`
	UpdatedAfter  *time.Time `json:"updated_after,omitempty"`
	UpdatedBefore *time.Time `json:"updated_before,omitempty"`
}

MessageListParams contains parameters for listing messages with pagination and filtering

func (*MessageListParams) FromQuery

func (p *MessageListParams) FromQuery(query url.Values) error

FromQuery creates MessageListParams from HTTP query parameters

func (*MessageListParams) Validate

func (p *MessageListParams) Validate() error

type MessageListResult

type MessageListResult struct {
	Messages   []*MessageHistory `json:"messages"`
	NextCursor string            `json:"next_cursor,omitempty"`
	HasMore    bool              `json:"has_more"`
}

MessageListResult contains the result of a ListMessages operation

type NodeAction

type NodeAction string

NodeAction represents an action in the automation node execution log

const (
	NodeActionEntered    NodeAction = "entered"
	NodeActionProcessing NodeAction = "processing"
	NodeActionCompleted  NodeAction = "completed"
	NodeActionFailed     NodeAction = "failed"
	NodeActionSkipped    NodeAction = "skipped"
)

func (NodeAction) IsValid

func (a NodeAction) IsValid() bool

IsValid checks if the node action is valid

type NodeExecution

type NodeExecution struct {
	ID                  string                 `json:"id"`
	ContactAutomationID string                 `json:"contact_automation_id"`
	AutomationID        string                 `json:"automation_id"`
	NodeID              string                 `json:"node_id"`
	NodeType            NodeType               `json:"node_type"`
	Action              NodeAction             `json:"action"`
	EnteredAt           time.Time              `json:"entered_at"`
	CompletedAt         *time.Time             `json:"completed_at,omitempty"`
	DurationMs          *int64                 `json:"duration_ms,omitempty"`
	Output              map[string]interface{} `json:"output,omitempty"`
	Error               *string                `json:"error,omitempty"`
}

NodeExecution tracks a contact's progress through an automation node

func (*NodeExecution) Validate

func (e *NodeExecution) Validate() error

Validate validates the node execution entry

type NodePosition

type NodePosition struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

NodePosition represents the visual position of a node in the flow editor

type NodeType

type NodeType string

NodeType represents the type of automation node

const (
	NodeTypeTrigger          NodeType = "trigger"
	NodeTypeDelay            NodeType = "delay"
	NodeTypeEmail            NodeType = "email"
	NodeTypeBranch           NodeType = "branch"
	NodeTypeFilter           NodeType = "filter"
	NodeTypeAddToList        NodeType = "add_to_list"
	NodeTypeRemoveFromList   NodeType = "remove_from_list"
	NodeTypeABTest           NodeType = "ab_test"
	NodeTypeWebhook          NodeType = "webhook"
	NodeTypeListStatusBranch NodeType = "list_status_branch"
)

func (NodeType) IsValid

func (t NodeType) IsValid() bool

IsValid checks if the node type is valid

type NotificationCenterRequest

type NotificationCenterRequest struct {
	Email       string `json:"email"`
	EmailHMAC   string `json:"email_hmac"`
	WorkspaceID string `json:"workspace_id"`
	Action      string `json:"action,omitempty"`     // Optional action (e.g., "confirm", "unsubscribe")
	ListID      string `json:"list_id,omitempty"`    // List ID for actions
	MessageID   string `json:"message_id,omitempty"` // Message ID for tracking
}

func (*NotificationCenterRequest) FromURLValues

func (r *NotificationCenterRequest) FromURLValues(values url.Values) error

func (*NotificationCenterRequest) Validate

func (r *NotificationCenterRequest) Validate() error

type NotificationCenterService

type NotificationCenterService interface {
	// GetContactPreferences returns public lists and notifications for a contact
	GetContactPreferences(ctx context.Context, workspaceID string, email string, emailHMAC string) (*ContactPreferencesResponse, error)
}

type NullableFloat64

type NullableFloat64 struct {
	Float64 float64
	IsNull  bool
}

NullableFloat64 represents a float64 that can be null

func (NullableFloat64) MarshalJSON

func (nf NullableFloat64) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*NullableFloat64) Scan

func (nf *NullableFloat64) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database/sql

func (*NullableFloat64) UnmarshalJSON

func (nf *NullableFloat64) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler

func (NullableFloat64) Value

func (nf NullableFloat64) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database/sql

type NullableJSON

type NullableJSON struct {
	Data   interface{}
	IsNull bool
}

NullableJSON represents a JSON object that can be null. It implements database/sql.Scanner and driver.Valuer interfaces for proper database handling, as well as json.Marshaler and json.Unmarshaler for JSON encoding/decoding.

func (NullableJSON) MarshalJSON

func (nj NullableJSON) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface. It handles the JSON encoding of the NullableJSON value.

func (*NullableJSON) Scan

func (nj *NullableJSON) Scan(value interface{}) error

Scan implements the sql.Scanner interface. It scans a value from the database into the NullableJSON struct.

func (*NullableJSON) UnmarshalJSON

func (nj *NullableJSON) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface. It handles the JSON decoding into a NullableJSON value.

func (NullableJSON) Value

func (nj NullableJSON) Value() (driver.Value, error)

Value implements the driver.Valuer interface. It returns a value suitable for database storage.

type NullableString

type NullableString struct {
	String string
	IsNull bool
}

NullableString represents a string that can be null

func (NullableString) MarshalJSON

func (ns NullableString) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*NullableString) Scan

func (ns *NullableString) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database/sql

func (*NullableString) UnmarshalJSON

func (ns *NullableString) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler

func (NullableString) Value

func (ns NullableString) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database/sql

type NullableTime

type NullableTime struct {
	Time   time.Time
	IsNull bool
}

NullableTime represents a time.Time that can be null

func (NullableTime) MarshalJSON

func (nt NullableTime) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*NullableTime) Scan

func (nt *NullableTime) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database/sql

func (*NullableTime) UnmarshalJSON

func (nt *NullableTime) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler

func (NullableTime) Value

func (nt NullableTime) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database/sql

type PauseAutomationRequest

type PauseAutomationRequest struct {
	WorkspaceID  string `json:"workspace_id"`
	AutomationID string `json:"automation_id"`
}

PauseAutomationRequest represents the request to pause an automation

func (*PauseAutomationRequest) Validate

func (r *PauseAutomationRequest) Validate() error

Validate validates the pause automation request

type PauseBroadcastRequest

type PauseBroadcastRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

PauseBroadcastRequest defines the request to pause a sending broadcast

func (*PauseBroadcastRequest) Validate

func (r *PauseBroadcastRequest) Validate() error

Validate validates the pause broadcast request

type PermissionError

type PermissionError struct {
	Resource   PermissionResource `json:"resource"`
	Permission PermissionType     `json:"permission"`
	Message    string             `json:"message"`
}

PermissionError represents insufficient permissions for an operation

func NewPermissionError

func NewPermissionError(resource PermissionResource, permission PermissionType, message string) *PermissionError

NewPermissionError creates a new permission error

func (*PermissionError) Error

func (e *PermissionError) Error() string

Error implements the error interface

type PermissionResource

type PermissionResource string

PermissionResource defines the different resources that can have permissions

const (
	PermissionResourceContacts       PermissionResource = "contacts"
	PermissionResourceLists          PermissionResource = "lists"
	PermissionResourceTemplates      PermissionResource = "templates"
	PermissionResourceBroadcasts     PermissionResource = "broadcasts"
	PermissionResourceTransactional  PermissionResource = "transactional"
	PermissionResourceWorkspace      PermissionResource = "workspace"
	PermissionResourceMessageHistory PermissionResource = "message_history"
	PermissionResourceBlog           PermissionResource = "blog"
	PermissionResourceAutomations    PermissionResource = "automations"
	PermissionResourceLLM            PermissionResource = "llm"
)

type PermissionType

type PermissionType string

PermissionType defines the types of permissions (read/write)

const (
	PermissionTypeRead  PermissionType = "read"
	PermissionTypeWrite PermissionType = "write"
)

type PostmarkBounceFields

type PostmarkBounceFields struct {
	RecipientEmail string `json:"Email"`
	BouncedAt      string `json:"BouncedAt"`
	Type           string `json:"Type"`
	TypeCode       int    `json:"TypeCode"`
	Name           string `json:"Name"`
	Description    string `json:"Description,omitempty"`
	Details        string `json:"Details,omitempty"`
	DumpAvailable  bool   `json:"DumpAvailable"`
	CanActivate    bool   `json:"CanActivate"`
	Subject        string `json:"Subject"`
	Content        string `json:"Content,omitempty"`
}

PostmarkBounceFields contains fields specific to bounce events

type PostmarkBounceTrigger

type PostmarkBounceTrigger struct {
	Enabled        bool `json:"Enabled"`
	IncludeContent bool `json:"IncludeContent,omitempty"`
}

PostmarkBounceTrigger represents the bounce trigger configuration

type PostmarkClickTrigger

type PostmarkClickTrigger struct {
	Enabled bool `json:"Enabled"`
}

PostmarkClickTrigger represents the click trigger configuration

type PostmarkComplaintFields

type PostmarkComplaintFields struct {
	RecipientEmail string `json:"Email"`
	ComplainedAt   string `json:"ComplainedAt"`
	Type           string `json:"Type"`
	UserAgent      string `json:"UserAgent,omitempty"`
	Subject        string `json:"Subject"`
}

PostmarkComplaintFields contains fields specific to complaint events

type PostmarkDeliveredFields

type PostmarkDeliveredFields struct {
	RecipientEmail string `json:"Recipient"`
	DeliveredAt    string `json:"DeliveredAt"`
	Details        string `json:"Details"`
}

PostmarkDeliveredFields contains fields specific to delivery events

type PostmarkDeliveryTrigger

type PostmarkDeliveryTrigger struct {
	Enabled bool `json:"Enabled"`
}

PostmarkDeliveryTrigger represents the delivery trigger configuration

type PostmarkListWebhooksResponse

type PostmarkListWebhooksResponse struct {
	TotalCount int                       `json:"TotalCount"`
	Webhooks   []PostmarkWebhookResponse `json:"Webhooks"`
}

PostmarkListWebhooksResponse represents the response for listing webhooks

type PostmarkOpenTrigger

type PostmarkOpenTrigger struct {
	Enabled           bool `json:"Enabled"`
	PostFirstOpenOnly bool `json:"PostFirstOpenOnly,omitempty"`
}

PostmarkOpenTrigger represents the open trigger configuration

type PostmarkServiceInterface

type PostmarkServiceInterface interface {
	// ListWebhooks retrieves all registered webhooks
	ListWebhooks(ctx context.Context, config PostmarkSettings) (*PostmarkListWebhooksResponse, error)

	// RegisterWebhook registers a new webhook
	RegisterWebhook(ctx context.Context, config PostmarkSettings, webhook PostmarkWebhookConfig) (*PostmarkWebhookResponse, error)

	// UnregisterWebhook removes a webhook by ID
	UnregisterWebhook(ctx context.Context, config PostmarkSettings, webhookID int) error

	// GetWebhook retrieves a specific webhook by ID
	GetWebhook(ctx context.Context, config PostmarkSettings, webhookID int) (*PostmarkWebhookResponse, error)

	// UpdateWebhook updates an existing webhook
	UpdateWebhook(ctx context.Context, config PostmarkSettings, webhookID int, webhook PostmarkWebhookConfig) (*PostmarkWebhookResponse, error)

	// TestWebhook sends a test event to the webhook
	TestWebhook(ctx context.Context, config PostmarkSettings, webhookID int, eventType EmailEventType) error
}

PostmarkServiceInterface defines operations for managing Postmark webhooks

type PostmarkSettings

type PostmarkSettings struct {
	EncryptedServerToken string `json:"encrypted_server_token,omitempty"`
	ServerToken          string `json:"server_token,omitempty"`
}

func (*PostmarkSettings) DecryptServerToken

func (p *PostmarkSettings) DecryptServerToken(passphrase string) error

func (*PostmarkSettings) EncryptServerToken

func (p *PostmarkSettings) EncryptServerToken(passphrase string) error

func (*PostmarkSettings) Validate

func (p *PostmarkSettings) Validate(passphrase string) error

type PostmarkSpamComplaintTrigger

type PostmarkSpamComplaintTrigger struct {
	Enabled        bool `json:"Enabled"`
	IncludeContent bool `json:"IncludeContent,omitempty"`
}

PostmarkSpamComplaintTrigger represents the spam complaint trigger configuration

type PostmarkSubscriptionChangeTrigger

type PostmarkSubscriptionChangeTrigger struct {
	Enabled bool `json:"Enabled"`
}

PostmarkSubscriptionChangeTrigger represents the subscription change trigger configuration

type PostmarkTriggerRule

type PostmarkTriggerRule struct {
	Key   string `json:"Key"`
	Match string `json:"Match"`
	Value string `json:"Value"`
}

PostmarkTriggerRule represents a trigger for webhooks Note: This is kept for compatibility with existing code

type PostmarkTriggers

type PostmarkTriggers struct {
	Open               *PostmarkOpenTrigger               `json:"Open,omitempty"`
	Click              *PostmarkClickTrigger              `json:"Click,omitempty"`
	Delivery           *PostmarkDeliveryTrigger           `json:"Delivery,omitempty"`
	Bounce             *PostmarkBounceTrigger             `json:"Bounce,omitempty"`
	SpamComplaint      *PostmarkSpamComplaintTrigger      `json:"SpamComplaint,omitempty"`
	SubscriptionChange *PostmarkSubscriptionChangeTrigger `json:"SubscriptionChange,omitempty"`
}

PostmarkTriggers represents the webhook triggers configuration

type PostmarkWebhookConfig

type PostmarkWebhookConfig struct {
	ID            int               `json:"ID,omitempty"`
	URL           string            `json:"Url"`
	MessageStream string            `json:"MessageStream"`
	HttpAuth      *HttpAuth         `json:"HttpAuth,omitempty"`
	HttpHeaders   []HttpHeader      `json:"HttpHeaders,omitempty"`
	Triggers      *PostmarkTriggers `json:"Triggers"`
}

PostmarkWebhookConfig represents a webhook configuration in Postmark

type PostmarkWebhookPayload

type PostmarkWebhookPayload struct {
	RecordType    string            `json:"RecordType"`
	MessageStream string            `json:"MessageStream"`
	ID            string            `json:"ID"`
	MessageID     string            `json:"MessageID"`
	ServerID      int               `json:"ServerID"`
	Metadata      map[string]string `json:"Metadata,omitempty"`
	Tag           string            `json:"Tag,omitempty"`

	// Delivered event specific fields
	DeliveredFields *PostmarkDeliveredFields `json:"-"`

	// Bounce event specific fields
	BounceFields *PostmarkBounceFields `json:"-"`

	// Complaint event specific fields
	ComplaintFields *PostmarkComplaintFields `json:"-"`
}

PostmarkWebhookPayload represents the base webhook payload from Postmark

type PostmarkWebhookResponse

type PostmarkWebhookResponse struct {
	ID            int               `json:"ID"`
	URL           string            `json:"Url"`
	MessageStream string            `json:"MessageStream"`
	HttpAuth      *HttpAuth         `json:"HttpAuth,omitempty"`
	HttpHeaders   []HttpHeader      `json:"HttpHeaders,omitempty"`
	Triggers      *PostmarkTriggers `json:"Triggers"`
}

PostmarkWebhookResponse represents the response from Postmark API for webhook operations

type PreviewSegmentResponse

type PreviewSegmentResponse struct {
	Emails       []string      `json:"emails"`
	TotalCount   int           `json:"total_count"`
	Limit        int           `json:"limit"`
	GeneratedSQL string        `json:"generated_sql"`
	SQLArgs      []interface{} `json:"sql_args"`
}

type PublishBlogPostRequest

type PublishBlogPostRequest struct {
	ID          string     `json:"id"`
	PublishedAt *time.Time `json:"published_at,omitempty"` // Optional custom timestamp
	Timezone    string     `json:"timezone,omitempty"`     // Optional IANA timezone
}

PublishBlogPostRequest defines the request to publish a blog post

func (*PublishBlogPostRequest) Validate

func (r *PublishBlogPostRequest) Validate() error

Validate validates the publish blog post request

type PublishBlogThemeRequest

type PublishBlogThemeRequest struct {
	Version int `json:"version"`
}

PublishBlogThemeRequest defines the request to publish a blog theme

func (*PublishBlogThemeRequest) Validate

func (r *PublishBlogThemeRequest) Validate() error

Validate validates the publish blog theme request

type RegisterWebhookRequest

type RegisterWebhookRequest struct {
	WorkspaceID   string           `json:"workspace_id"`
	IntegrationID string           `json:"integration_id"`
	EventTypes    []EmailEventType `json:"event_types"`
}

RegisterWebhookRequest defines the request to register webhooks

func (*RegisterWebhookRequest) Validate

func (r *RegisterWebhookRequest) Validate() error

Validate validates the RegisterWebhookRequest

type RemoveContactFromListRequest

type RemoveContactFromListRequest struct {
	WorkspaceID string `json:"workspace_id"`
	Email       string `json:"email"`
	ListID      string `json:"list_id"`
}

func (*RemoveContactFromListRequest) Validate

func (r *RemoveContactFromListRequest) Validate() (err error)

type RemoveFromListNodeConfig

type RemoveFromListNodeConfig struct {
	ListID string `json:"list_id"`
}

RemoveFromListNodeConfig configures a remove-from-list node

func (RemoveFromListNodeConfig) Validate

func (c RemoveFromListNodeConfig) Validate() error

Validate validates the remove-from-list node config

type ResourcePermissions

type ResourcePermissions struct {
	Read  bool `json:"read"`
	Write bool `json:"write"`
}

ResourcePermissions defines read/write permissions for a specific resource

type ResumeBroadcastRequest

type ResumeBroadcastRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
}

ResumeBroadcastRequest defines the request to resume a paused broadcast

func (*ResumeBroadcastRequest) Validate

func (r *ResumeBroadcastRequest) Validate() error

Validate validates the resume broadcast request

type RootSigninInput

type RootSigninInput struct {
	Email     string `json:"email"`
	Timestamp int64  `json:"timestamp"`
	Signature string `json:"signature"`
}

RootSigninInput represents the request for root user programmatic signin

type SEOSettings

type SEOSettings struct {
	MetaTitle       string   `json:"meta_title,omitempty"`       // SEO meta title
	MetaDescription string   `json:"meta_description,omitempty"` // SEO meta description
	OGTitle         string   `json:"og_title,omitempty"`         // Open Graph title
	OGDescription   string   `json:"og_description,omitempty"`   // Open Graph description
	OGImage         string   `json:"og_image,omitempty"`         // Open Graph image URL
	CanonicalURL    string   `json:"canonical_url,omitempty"`    // Canonical URL
	Keywords        []string `json:"keywords,omitempty"`         // SEO keywords
	MetaRobots      string   `json:"meta_robots,omitempty"`      // Robots meta tag content (e.g., "index,follow", "noindex,nofollow")
}

SEOSettings contains web page SEO configuration (without slug) Reusable across workspace (homepage), blog categories, and blog posts

func (*SEOSettings) MergeWithDefaults

func (s *SEOSettings) MergeWithDefaults(defaults *SEOSettings) *SEOSettings

MergeWithDefaults merges the current SEO settings with defaults, preferring non-empty values

func (*SEOSettings) Scan

func (s *SEOSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (SEOSettings) Value

func (s SEOSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type SESBounce

type SESBounce struct {
	BounceType        string                `json:"bounceType"`
	BounceSubType     string                `json:"bounceSubType"`
	BouncedRecipients []SESBouncedRecipient `json:"bouncedRecipients"`
	Timestamp         string                `json:"timestamp"`
	FeedbackID        string                `json:"feedbackId"`
	ReportingMTA      string                `json:"reportingMTA"`
}

SESBounce represents a bounce in an SES notification

type SESBounceNotification

type SESBounceNotification struct {
	EventType string    `json:"eventType"`
	Bounce    SESBounce `json:"bounce"`
	Mail      SESMail   `json:"mail"`
}

SESBounceNotification represents an SES bounce notification

type SESBouncedRecipient

type SESBouncedRecipient struct {
	EmailAddress   string `json:"emailAddress"`
	Action         string `json:"action"`
	Status         string `json:"status"`
	DiagnosticCode string `json:"diagnosticCode"`
}

SESBouncedRecipient represents a bounced recipient in an SES notification

type SESClient

type SESClient interface {
	ListConfigurationSetsWithContext(ctx context.Context, input *ses.ListConfigurationSetsInput, opts ...request.Option) (*ses.ListConfigurationSetsOutput, error)
	CreateConfigurationSetWithContext(ctx context.Context, input *ses.CreateConfigurationSetInput, opts ...request.Option) (*ses.CreateConfigurationSetOutput, error)
	DeleteConfigurationSetWithContext(ctx context.Context, input *ses.DeleteConfigurationSetInput, opts ...request.Option) (*ses.DeleteConfigurationSetOutput, error)
	DescribeConfigurationSetWithContext(ctx context.Context, input *ses.DescribeConfigurationSetInput, opts ...request.Option) (*ses.DescribeConfigurationSetOutput, error)
	CreateConfigurationSetEventDestinationWithContext(ctx context.Context, input *ses.CreateConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.CreateConfigurationSetEventDestinationOutput, error)
	UpdateConfigurationSetEventDestinationWithContext(ctx context.Context, input *ses.UpdateConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.UpdateConfigurationSetEventDestinationOutput, error)
	DeleteConfigurationSetEventDestinationWithContext(ctx context.Context, input *ses.DeleteConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.DeleteConfigurationSetEventDestinationOutput, error)
	SendEmailWithContext(ctx context.Context, input *ses.SendEmailInput, opts ...request.Option) (*ses.SendEmailOutput, error)
	SendRawEmailWithContext(ctx context.Context, input *ses.SendRawEmailInput, opts ...request.Option) (*ses.SendRawEmailOutput, error)
}

SESWebhookClient defines the interface for SES client operations related to webhook management

type SESCommonHeaders

type SESCommonHeaders struct {
	From      []string `json:"from"`
	To        []string `json:"to"`
	MessageID string   `json:"messageId"`
	Subject   string   `json:"subject"`
}

SESCommonHeaders represents common headers in an SES notification

type SESComplainedRecipient

type SESComplainedRecipient struct {
	EmailAddress string `json:"emailAddress"`
}

SESComplainedRecipient represents a complained recipient in an SES notification

type SESComplaint

type SESComplaint struct {
	ComplainedRecipients  []SESComplainedRecipient `json:"complainedRecipients"`
	Timestamp             string                   `json:"timestamp"`
	FeedbackID            string                   `json:"feedbackId"`
	ComplaintFeedbackType string                   `json:"complaintFeedbackType"`
}

SESComplaint represents a complaint in an SES notification

type SESComplaintNotification

type SESComplaintNotification struct {
	EventType string       `json:"eventType"`
	Complaint SESComplaint `json:"complaint"`
	Mail      SESMail      `json:"mail"`
}

SESComplaintNotification represents an SES complaint notification

type SESConfigurationSetEventDestination

type SESConfigurationSetEventDestination struct {
	Name                 string          `json:"name"`
	ConfigurationSetName string          `json:"configuration_set_name"`
	Enabled              bool            `json:"enabled"`
	MatchingEventTypes   []string        `json:"matching_event_types"`
	SNSDestination       *SESTopicConfig `json:"sns_destination,omitempty"`
}

SESConfigurationSetEventDestination represents SES event destination configuration

type SESDelivery

type SESDelivery struct {
	Timestamp            string   `json:"timestamp"`
	ProcessingTimeMillis int      `json:"processingTimeMillis"`
	Recipients           []string `json:"recipients"`
	SMTPResponse         string   `json:"smtpResponse"`
	RemoteMtaIP          string   `json:"remoteMtaIp"`
	ReportingMTA         string   `json:"reportingMTA"`
}

SESDelivery represents a delivery in an SES notification

type SESDeliveryNotification

type SESDeliveryNotification struct {
	EventType string      `json:"eventType"`
	Delivery  SESDelivery `json:"delivery"`
	Mail      SESMail     `json:"mail"`
}

SESDeliveryNotification represents an SES delivery notification

type SESHeader

type SESHeader struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

SESHeader represents a header in an SES notification

type SESMail

type SESMail struct {
	Timestamp        string              `json:"timestamp"`
	MessageID        string              `json:"messageId"`
	Source           string              `json:"source"`
	Destination      []string            `json:"destination"`
	HeadersTruncated bool                `json:"headersTruncated"`
	Headers          []SESHeader         `json:"headers"`
	CommonHeaders    SESCommonHeaders    `json:"commonHeaders"`
	Tags             map[string][]string `json:"tags"`
}

SESMail represents the mail part of an SES notification

type SESMessageAttribute

type SESMessageAttribute struct {
	Type  string `json:"Type"`
	Value string `json:"Value"`
}

SESMessageAttribute represents a message attribute in SES webhook

type SESServiceInterface

type SESServiceInterface interface {
	// ListConfigurationSets lists all configuration sets
	ListConfigurationSets(ctx context.Context, config AmazonSESSettings) ([]string, error)

	// CreateConfigurationSet creates a new configuration set
	CreateConfigurationSet(ctx context.Context, config AmazonSESSettings, name string) error

	// DeleteConfigurationSet deletes a configuration set
	DeleteConfigurationSet(ctx context.Context, config AmazonSESSettings, name string) error

	// CreateSNSTopic creates a new SNS topic for notifications
	CreateSNSTopic(ctx context.Context, config AmazonSESSettings, topicConfig SESTopicConfig) (string, error)

	// DeleteSNSTopic deletes an SNS topic
	DeleteSNSTopic(ctx context.Context, config AmazonSESSettings, topicARN string) error

	// CreateEventDestination creates an event destination in a configuration set
	CreateEventDestination(ctx context.Context, config AmazonSESSettings, destination SESConfigurationSetEventDestination) error

	// UpdateEventDestination updates an event destination
	UpdateEventDestination(ctx context.Context, config AmazonSESSettings, destination SESConfigurationSetEventDestination) error

	// DeleteEventDestination deletes an event destination
	DeleteEventDestination(ctx context.Context, config AmazonSESSettings, configSetName, destinationName string) error

	// ListEventDestinations lists all event destinations for a configuration set
	ListEventDestinations(ctx context.Context, config AmazonSESSettings, configSetName string) ([]SESConfigurationSetEventDestination, error)
}

SESServiceInterface defines operations for managing Amazon SES webhooks via SNS

type SESTopicConfig

type SESTopicConfig struct {
	TopicARN             string `json:"topic_arn"`
	TopicName            string `json:"topic_name,omitempty"`
	NotificationEndpoint string `json:"notification_endpoint"`
	Protocol             string `json:"protocol"` // Usually "https"
}

SESTopicConfig represents AWS SNS topic configuration

type SESWebhookClient

type SESWebhookClient interface {
	CreateConfigurationSetWithContext(ctx aws.Context, input *ses.CreateConfigurationSetInput, opts ...request.Option) (*ses.CreateConfigurationSetOutput, error)
	DeleteConfigurationSetWithContext(ctx aws.Context, input *ses.DeleteConfigurationSetInput, opts ...request.Option) (*ses.DeleteConfigurationSetOutput, error)
	ListConfigurationSetsWithContext(ctx aws.Context, input *ses.ListConfigurationSetsInput, opts ...request.Option) (*ses.ListConfigurationSetsOutput, error)
	DescribeConfigurationSetWithContext(ctx aws.Context, input *ses.DescribeConfigurationSetInput, opts ...request.Option) (*ses.DescribeConfigurationSetOutput, error)
	CreateConfigurationSetEventDestinationWithContext(ctx aws.Context, input *ses.CreateConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.CreateConfigurationSetEventDestinationOutput, error)
	UpdateConfigurationSetEventDestinationWithContext(ctx aws.Context, input *ses.UpdateConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.UpdateConfigurationSetEventDestinationOutput, error)
	DeleteConfigurationSetEventDestinationWithContext(ctx aws.Context, input *ses.DeleteConfigurationSetEventDestinationInput, opts ...request.Option) (*ses.DeleteConfigurationSetEventDestinationOutput, error)
}

SESWebhookClient defines the interface for interacting with AWS SES service

type SESWebhookPayload

type SESWebhookPayload struct {
	Type              string                         `json:"Type"`
	MessageID         string                         `json:"MessageId"`
	TopicARN          string                         `json:"TopicArn"`
	Message           string                         `json:"Message"`
	Timestamp         string                         `json:"Timestamp"`
	SignatureVersion  string                         `json:"SignatureVersion"`
	Signature         string                         `json:"Signature"`
	SigningCertURL    string                         `json:"SigningCertURL"`
	UnsubscribeURL    string                         `json:"UnsubscribeURL"`
	SubscribeURL      string                         `json:"SubscribeURL,omitempty"`
	Token             string                         `json:"Token,omitempty"`
	MessageAttributes map[string]SESMessageAttribute `json:"MessageAttributes"`
}

SESWebhookPayload represents an Amazon SES webhook payload

type SMTPSettings

type SMTPSettings struct {
	Host              string `json:"host"`
	Port              int    `json:"port"`
	EncryptedUsername string `json:"encrypted_username,omitempty"`
	EncryptedPassword string `json:"encrypted_password,omitempty"`
	UseTLS            bool   `json:"use_tls"`

	// decoded username, not stored in the database
	// decoded password , not stored in the database
	Username string `json:"username"`
	Password string `json:"password,omitempty"`
}

SMTPSettings contains configuration for SMTP email server

func (*SMTPSettings) DecryptPassword

func (s *SMTPSettings) DecryptPassword(passphrase string) error

func (*SMTPSettings) DecryptUsername

func (s *SMTPSettings) DecryptUsername(passphrase string) error

func (*SMTPSettings) EncryptPassword

func (s *SMTPSettings) EncryptPassword(passphrase string) error

func (*SMTPSettings) EncryptUsername

func (s *SMTPSettings) EncryptUsername(passphrase string) error

func (*SMTPSettings) Validate

func (s *SMTPSettings) Validate(passphrase string) error

type SMTPWebhookPayload

type SMTPWebhookPayload struct {
	Event          string            `json:"event"`
	Timestamp      string            `json:"timestamp"`
	MessageID      string            `json:"message_id"`
	Recipient      string            `json:"recipient"`
	Metadata       map[string]string `json:"metadata,omitempty"`
	Tags           []string          `json:"tags,omitempty"`
	Reason         string            `json:"reason,omitempty"`
	Description    string            `json:"description,omitempty"`
	BounceCategory string            `json:"bounce_category,omitempty"`
	DiagnosticCode string            `json:"diagnostic_code,omitempty"`
	ComplaintType  string            `json:"complaint_type,omitempty"`
}

SMTPWebhookPayload represents an SMTP webhook payload SMTP doesn't typically have a built-in webhook system, so this is a generic structure that could be used with a third-party SMTP provider that offers webhooks

type SNSClient

type SNSClient interface {
	CreateTopicWithContext(ctx context.Context, input *sns.CreateTopicInput, opts ...request.Option) (*sns.CreateTopicOutput, error)
	DeleteTopicWithContext(ctx context.Context, input *sns.DeleteTopicInput, opts ...request.Option) (*sns.DeleteTopicOutput, error)
	SubscribeWithContext(ctx context.Context, input *sns.SubscribeInput, opts ...request.Option) (*sns.SubscribeOutput, error)
	GetTopicAttributesWithContext(ctx context.Context, input *sns.GetTopicAttributesInput, opts ...request.Option) (*sns.GetTopicAttributesOutput, error)
}

SNSWebhookClient defines the interface for SNS client operations related to webhook management

type SNSWebhookClient

type SNSWebhookClient interface {
	CreateTopicWithContext(ctx aws.Context, input *sns.CreateTopicInput, opts ...request.Option) (*sns.CreateTopicOutput, error)
	DeleteTopicWithContext(ctx aws.Context, input *sns.DeleteTopicInput, opts ...request.Option) (*sns.DeleteTopicOutput, error)
	SubscribeWithContext(ctx aws.Context, input *sns.SubscribeInput, opts ...request.Option) (*sns.SubscribeOutput, error)
	GetTopicAttributesWithContext(ctx aws.Context, input *sns.GetTopicAttributesInput, opts ...request.Option) (*sns.GetTopicAttributesOutput, error)
}

SNSWebhookClient defines the interface for interacting with AWS SNS service

type ScheduleBroadcastRequest

type ScheduleBroadcastRequest struct {
	WorkspaceID          string `json:"workspace_id"`
	ID                   string `json:"id"`
	SendNow              bool   `json:"send_now"`
	ScheduledDate        string `json:"scheduled_date,omitempty"`
	ScheduledTime        string `json:"scheduled_time,omitempty"`
	Timezone             string `json:"timezone,omitempty"`
	UseRecipientTimezone bool   `json:"use_recipient_timezone"`
}

ScheduleBroadcastRequest defines the request to schedule a broadcast

func (*ScheduleBroadcastRequest) Validate

func (r *ScheduleBroadcastRequest) Validate() error

Validate validates the schedule broadcast request

type ScheduleSettings

type ScheduleSettings struct {
	IsScheduled          bool   `json:"is_scheduled"`
	ScheduledDate        string `json:"scheduled_date,omitempty"` // Format: YYYY-MM-dd
	ScheduledTime        string `json:"scheduled_time,omitempty"` // Format: HH:mm
	Timezone             string `json:"timezone,omitempty"`       // IANA timezone format, e.g. "America/New_York"
	UseRecipientTimezone bool   `json:"use_recipient_timezone"`
}

ScheduleSettings defines when a broadcast will be sent

func (*ScheduleSettings) ParseScheduledDateTime

func (s *ScheduleSettings) ParseScheduledDateTime() (time.Time, error)

ParseScheduledDateTime parses the ScheduledDate and ScheduledTime fields and returns a time.Time

func (*ScheduleSettings) Scan

func (s *ScheduleSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (*ScheduleSettings) SetScheduledDateTime

func (s *ScheduleSettings) SetScheduledDateTime(t time.Time, timezone string) error

SetScheduledDateTime formats a time.Time as ScheduledDate and ScheduledTime strings

func (ScheduleSettings) Value

func (s ScheduleSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type Segment

type Segment struct {
	ID             string     `json:"id"`
	Name           string     `json:"name"`
	Color          string     `json:"color"`
	Tree           *TreeNode  `json:"tree"`
	Timezone       string     `json:"timezone"`
	Version        int64      `json:"version"`
	Status         string     `json:"status"`
	GeneratedSQL   *string    `json:"generated_sql,omitempty"`
	GeneratedArgs  JSONArray  `json:"generated_args,omitempty"`  // Array of query arguments in order
	RecomputeAfter *time.Time `json:"recompute_after,omitempty"` // When segment should be recomputed (for relative date filters)
	DBCreatedAt    time.Time  `json:"db_created_at"`
	DBUpdatedAt    time.Time  `json:"db_updated_at"`
	UsersCount     int        `json:"users_count"` // joined server-side
}

Segment represents a user segment for filtering contacts

func ScanSegment

func ScanSegment(scanner interface {
	Scan(dest ...interface{}) error
}) (*Segment, error)

ScanSegment scans a segment from the database

func (*Segment) Validate

func (s *Segment) Validate() error

Validate performs validation on the segment fields

type SegmentRepository

type SegmentRepository interface {
	// CreateSegment creates a new segment in the database
	CreateSegment(ctx context.Context, workspaceID string, segment *Segment) error

	// GetSegmentByID retrieves a segment by its ID
	GetSegmentByID(ctx context.Context, workspaceID string, id string) (*Segment, error)

	// GetSegments retrieves all segments, optionally with contact counts
	GetSegments(ctx context.Context, workspaceID string, withCount bool) ([]*Segment, error)

	// UpdateSegment updates an existing segment
	UpdateSegment(ctx context.Context, workspaceID string, segment *Segment) error

	// DeleteSegment deletes a segment
	DeleteSegment(ctx context.Context, workspaceID string, id string) error

	// AddContactToSegment adds a contact to a segment membership
	AddContactToSegment(ctx context.Context, workspaceID string, email string, segmentID string, version int64) error

	// RemoveContactFromSegment removes a contact from a segment
	RemoveContactFromSegment(ctx context.Context, workspaceID string, email string, segmentID string) error

	// RemoveOldMemberships removes contact_segment records with old versions
	RemoveOldMemberships(ctx context.Context, workspaceID string, segmentID string, currentVersion int64) error

	// GetContactSegments retrieves all segments a contact belongs to
	GetContactSegments(ctx context.Context, workspaceID string, email string) ([]*Segment, error)

	// GetSegmentContactCount gets the count of contacts in a segment
	GetSegmentContactCount(ctx context.Context, workspaceID string, segmentID string) (int, error)

	// PreviewSegment executes a segment query and returns the count of matching contacts
	PreviewSegment(ctx context.Context, workspaceID string, sqlQuery string, args []interface{}, limit int) (int, error)

	// GetSegmentsDueForRecompute retrieves segments that need recomputation (recompute_after <= now)
	GetSegmentsDueForRecompute(ctx context.Context, workspaceID string, limit int) ([]*Segment, error)

	// UpdateRecomputeAfter updates only the recompute_after field for a segment
	UpdateRecomputeAfter(ctx context.Context, workspaceID string, segmentID string, recomputeAfter *time.Time) error
}

type SegmentService

type SegmentService interface {
	// CreateSegment creates a new segment
	CreateSegment(ctx context.Context, req *CreateSegmentRequest) (*Segment, error)

	// GetSegment retrieves a segment by ID
	GetSegment(ctx context.Context, req *GetSegmentRequest) (*Segment, error)

	// ListSegments retrieves all segments
	ListSegments(ctx context.Context, req *GetSegmentsRequest) ([]*Segment, error)

	// UpdateSegment updates an existing segment
	UpdateSegment(ctx context.Context, req *UpdateSegmentRequest) (*Segment, error)

	// DeleteSegment deletes a segment by ID
	DeleteSegment(ctx context.Context, req *DeleteSegmentRequest) error

	// RebuildSegment triggers a rebuild of a segment
	RebuildSegment(ctx context.Context, workspaceID, segmentID string) error

	// PreviewSegment previews the contacts that would match a segment tree
	PreviewSegment(ctx context.Context, workspaceID string, tree *TreeNode, limit int) (*PreviewSegmentResponse, error)

	// GetSegmentContacts retrieves the contacts belonging to a segment
	GetSegmentContacts(ctx context.Context, workspaceID, segmentID string, limit, offset int) ([]string, error)
}

SegmentService provides operations for managing segments

type SegmentStatus

type SegmentStatus string

SegmentStatus represents the status of a segment

const (
	SegmentStatusActive   SegmentStatus = "active"
	SegmentStatusDeleted  SegmentStatus = "deleted"
	SegmentStatusBuilding SegmentStatus = "building"
)

func (SegmentStatus) Validate

func (s SegmentStatus) Validate() error

Validate checks if the segment status is valid

type SelectWinnerRequest

type SelectWinnerRequest struct {
	WorkspaceID string `json:"workspace_id"`
	ID          string `json:"id"`
	TemplateID  string `json:"template_id"`
}

SelectWinnerRequest represents the request to select a winning variation

func (*SelectWinnerRequest) Validate

func (r *SelectWinnerRequest) Validate() error

Validate validates the select winner request

type SendBroadcastState

type SendBroadcastState struct {
	BroadcastID     string `json:"broadcast_id"`
	TotalRecipients int    `json:"total_recipients"`
	EnqueuedCount   int    `json:"enqueued_count"` // Emails added to queue (was SentCount)
	FailedCount     int    `json:"failed_count"`   // Template/build failures during enqueueing
	ChannelType     string `json:"channel_type"`
	RecipientOffset int64  `json:"recipient_offset"`
	// LastProcessedEmail is the cursor for keyset pagination - stores the last email processed
	// to enable deterministic pagination across task executions (fixes Issue #157)
	LastProcessedEmail string `json:"last_processed_email,omitempty"`
	// New fields for A/B testing phases
	Phase                     string `json:"phase"` // "test", "winner", or "single"
	TestPhaseCompleted        bool   `json:"test_phase_completed"`
	TestPhaseRecipientCount   int    `json:"test_phase_recipient_count"`
	WinnerPhaseRecipientCount int    `json:"winner_phase_recipient_count"`
}

SendBroadcastState contains state specific to broadcast enqueueing tasks

type SendEmailProviderRequest

type SendEmailProviderRequest struct {
	WorkspaceID   string         `validate:"required"`
	IntegrationID string         `validate:"required"`
	MessageID     string         `validate:"required"`
	FromAddress   string         `validate:"required"`
	FromName      string         `validate:"required"`
	To            string         `validate:"required"`
	Subject       string         `validate:"required"`
	Content       string         `validate:"required"`
	Provider      *EmailProvider `validate:"required"`
	EmailOptions  EmailOptions
}

SendEmailProviderRequest encapsulates all parameters needed to send an email via a provider

func (*SendEmailProviderRequest) Validate

func (r *SendEmailProviderRequest) Validate() error

Validate ensures all required fields are present and valid

type SendEmailRequest

type SendEmailRequest struct {
	// Core identification
	WorkspaceID   string `validate:"required"`
	IntegrationID string `validate:"required"`
	MessageID     string `validate:"required"`
	ExternalID    *string
	AutomationID  *string // Automation this email is sent from (nullable for broadcasts/transactional)

	// Target and content
	Contact        *Contact        `validate:"required"`
	TemplateConfig ChannelTemplate `validate:"required"`
	MessageData    MessageData

	// Configuration
	TrackingSettings notifuse_mjml.TrackingSettings
	EmailProvider    *EmailProvider `validate:"required"`
	EmailOptions     EmailOptions
}

SendEmailRequest encapsulates all parameters needed to send an email using a template

func (*SendEmailRequest) Validate

func (r *SendEmailRequest) Validate() error

Validate ensures all required fields are present and valid

type SendToIndividualRequest

type SendToIndividualRequest struct {
	WorkspaceID    string `json:"workspace_id"`
	BroadcastID    string `json:"broadcast_id"`
	RecipientEmail string `json:"recipient_email"`
	TemplateID     string `json:"template_id,omitempty"`
}

SendToIndividualRequest defines the request to send a broadcast to an individual

func (*SendToIndividualRequest) Validate

func (r *SendToIndividualRequest) Validate() error

Validate validates the send to individual request

type SendTransactionalRequest

type SendTransactionalRequest struct {
	WorkspaceID  string                              `json:"workspace_id"`
	Notification TransactionalNotificationSendParams `json:"notification"`
}

SendTransactionalRequest represents a request to send a transactional notification

func (*SendTransactionalRequest) Validate

func (req *SendTransactionalRequest) Validate() error

Validate validates the send request

type Session

type Session struct {
	ID               string     `json:"id" db:"id"`
	UserID           string     `json:"user_id" db:"user_id"`
	ExpiresAt        time.Time  `json:"expires_at" db:"expires_at"`
	CreatedAt        time.Time  `json:"created_at" db:"created_at"`
	MagicCode        *string    `json:"magic_code,omitempty" db:"magic_code"`
	MagicCodeExpires *time.Time `json:"magic_code_expires,omitempty" db:"magic_code_expires_at"`
}

Session represents a user session

type SetUserPermissionsRequest

type SetUserPermissionsRequest struct {
	WorkspaceID string          `json:"workspace_id"`
	UserID      string          `json:"user_id"`
	Permissions UserPermissions `json:"permissions"`
}

SetUserPermissionsRequest defines the request structure for setting user permissions

func (*SetUserPermissionsRequest) Validate

func (r *SetUserPermissionsRequest) Validate() error

Validate validates the set user permissions request

type Setting

type Setting struct {
	Key       string    `json:"key"`
	Value     string    `json:"value"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Setting represents a system setting

type SettingRepository

type SettingRepository interface {
	// Get retrieves a setting by key
	Get(ctx context.Context, key string) (*Setting, error)

	// Set creates or updates a setting
	Set(ctx context.Context, key, value string) error

	// Delete removes a setting by key
	Delete(ctx context.Context, key string) error

	// List retrieves all settings
	List(ctx context.Context) ([]*Setting, error)

	// SetLastCronRun updates the last cron execution timestamp
	SetLastCronRun(ctx context.Context) error

	// GetLastCronRun retrieves the last cron execution timestamp
	GetLastCronRun(ctx context.Context) (*time.Time, error)
}

SettingRepository defines the interface for setting-related database operations

type SignInInput

type SignInInput struct {
	Email string `json:"email"`
}

type SparkPostMSys

type SparkPostMSys struct {
	MessageEvent *SparkPostMessageEvent `json:"message_event,omitempty"`
}

SparkPostMSys contains the event data from SparkPost

type SparkPostMessageEvent

type SparkPostMessageEvent struct {
	Type          string                 `json:"type"`
	CampaignID    string                 `json:"campaign_id"`
	MessageID     string                 `json:"message_id"`
	Timestamp     string                 `json:"timestamp"`
	RecipientTo   string                 `json:"rcpt_to"`
	RecipientMeta map[string]interface{} `json:"rcpt_meta,omitempty"`
	Tags          []string               `json:"tags,omitempty"`
	Transmission  string                 `json:"transmission_id,omitempty"`
	IPAddress     string                 `json:"ip_address,omitempty"`
	MessageFrom   string                 `json:"msg_from,omitempty"`
	QueueTime     string                 `json:"queue_time,omitempty"`
	// bounce fields
	BounceClass string `json:"bounce_class,omitempty"`
	Reason      string `json:"reason,omitempty"`
	RawReason   string `json:"raw_reason,omitempty"`
	Error       string `json:"error_code,omitempty"`
	// delivery fields
	DeliveryMethod        string `json:"delv_method,omitempty"`
	MailboxProvider       string `json:"mailbox_provider,omitempty"`
	MailboxProviderRegion string `json:"mailbox_provider_region,omitempty"`
	// spam fields
	FeedbackType string `json:"fbtype,omitempty"`
}

type SparkPostServiceInterface

type SparkPostServiceInterface interface {
	// ListWebhooks retrieves all registered webhooks
	ListWebhooks(ctx context.Context, config SparkPostSettings) (*SparkPostWebhookListResponse, error)

	// CreateWebhook creates a new webhook
	CreateWebhook(ctx context.Context, config SparkPostSettings, webhook SparkPostWebhook) (*SparkPostWebhookResponse, error)

	// GetWebhook retrieves a webhook by ID
	GetWebhook(ctx context.Context, config SparkPostSettings, webhookID string) (*SparkPostWebhookResponse, error)

	// UpdateWebhook updates an existing webhook
	UpdateWebhook(ctx context.Context, config SparkPostSettings, webhookID string, webhook SparkPostWebhook) (*SparkPostWebhookResponse, error)

	// DeleteWebhook deletes a webhook by ID
	DeleteWebhook(ctx context.Context, config SparkPostSettings, webhookID string) error

	// TestWebhook sends a test event to a webhook
	TestWebhook(ctx context.Context, config SparkPostSettings, webhookID string) error

	// ValidateWebhook validates a webhook's configuration
	ValidateWebhook(ctx context.Context, config SparkPostSettings, webhook SparkPostWebhook) (bool, error)
}

SparkPostServiceInterface defines operations for managing SparkPost webhooks

type SparkPostSettings

type SparkPostSettings struct {
	EncryptedAPIKey string `json:"encrypted_api_key,omitempty"`
	SandboxMode     bool   `json:"sandbox_mode"`
	Endpoint        string `json:"endpoint"`

	// decoded API key, not stored in the database
	APIKey string `json:"api_key,omitempty"`
}

SparkPostSettings contains configuration for SparkPost email provider

func (*SparkPostSettings) DecryptAPIKey

func (s *SparkPostSettings) DecryptAPIKey(passphrase string) error

func (*SparkPostSettings) EncryptAPIKey

func (s *SparkPostSettings) EncryptAPIKey(passphrase string) error

func (*SparkPostSettings) Validate

func (s *SparkPostSettings) Validate(passphrase string) error

type SparkPostWebhook

type SparkPostWebhook struct {
	ID            string                 `json:"id,omitempty"`
	Name          string                 `json:"name"`
	Target        string                 `json:"target"`
	Events        []string               `json:"events"`
	Active        bool                   `json:"active"`
	AuthType      string                 `json:"auth_type,omitempty"` // "none", "basic", "oauth2"
	AuthToken     string                 `json:"auth_token,omitempty"`
	AuthRequest   map[string]interface{} `json:"auth_request,omitempty"`
	CustomHeaders map[string]string      `json:"custom_headers,omitempty"`
}

SparkPostWebhook represents a webhook configuration in SparkPost

type SparkPostWebhookListResponse

type SparkPostWebhookListResponse struct {
	Results []SparkPostWebhook `json:"results"`
}

SparkPostWebhookListResponse represents the response for listing webhooks

type SparkPostWebhookPayload

type SparkPostWebhookPayload struct {
	MSys SparkPostMSys `json:"msys"`
}

SparkPostWebhookPayload represents the webhook payload from SparkPost

type SparkPostWebhookResponse

type SparkPostWebhookResponse struct {
	Results SparkPostWebhook `json:"results"`
}

SparkPostWebhookResponse represents a response for webhook operations

type SubscribeToListsRequest

type SubscribeToListsRequest struct {
	WorkspaceID string   `json:"workspace_id"`
	Contact     Contact  `json:"contact"`
	ListIDs     []string `json:"list_ids"`
}

func (*SubscribeToListsRequest) Validate

func (r *SubscribeToListsRequest) Validate() (err error)

type SupabaseAuthEmailHookSettings

type SupabaseAuthEmailHookSettings struct {
	SignatureKey          string `json:"signature_key,omitempty"`           // Accepts plaintext key in requests (cleared before API responses)
	EncryptedSignatureKey string `json:"encrypted_signature_key,omitempty"` // Encrypted key (stored and returned in API responses)
}

SupabaseAuthEmailHookSettings configures the Send Email Hook Hook activation is controlled in Supabase, not here

func (*SupabaseAuthEmailHookSettings) DecryptSignatureKey

func (s *SupabaseAuthEmailHookSettings) DecryptSignatureKey(passphrase string) error

DecryptSignatureKey decrypts the signature key for auth email hook

func (*SupabaseAuthEmailHookSettings) EncryptSignatureKey

func (s *SupabaseAuthEmailHookSettings) EncryptSignatureKey(passphrase string) error

EncryptSignatureKey encrypts the signature key for auth email hook

func (*SupabaseAuthEmailHookSettings) Validate

func (s *SupabaseAuthEmailHookSettings) Validate() error

Validate validates the auth email hook settings

type SupabaseAuthEmailWebhook

type SupabaseAuthEmailWebhook struct {
	User      SupabaseUser      `json:"user"`
	EmailData SupabaseEmailData `json:"email_data"`
}

SupabaseAuthEmailWebhook represents the webhook payload for Send Email Hook

type SupabaseBeforeUserCreatedWebhook

type SupabaseBeforeUserCreatedWebhook struct {
	Metadata SupabaseWebhookMetadata `json:"metadata"`
	User     SupabaseUser            `json:"user"`
}

SupabaseBeforeUserCreatedWebhook represents the webhook payload for Before User Created Hook

type SupabaseEmailActionType

type SupabaseEmailActionType string
const (
	SupabaseEmailActionSignup      SupabaseEmailActionType = "signup"
	SupabaseEmailActionInvite      SupabaseEmailActionType = "invite"
	SupabaseEmailActionMagicLink   SupabaseEmailActionType = "magiclink"
	SupabaseEmailActionRecovery    SupabaseEmailActionType = "recovery"
	SupabaseEmailActionEmailChange SupabaseEmailActionType = "email_change"
	// SupabaseEmailActionEmail            SupabaseEmailActionType = "email"
	SupabaseEmailActionReauthentication SupabaseEmailActionType = "reauthentication"
)

type SupabaseEmailData

type SupabaseEmailData struct {
	Token           string `json:"token"`
	TokenHash       string `json:"token_hash"`
	RedirectTo      string `json:"redirect_to"`
	EmailActionType string `json:"email_action_type"`
	SiteURL         string `json:"site_url"`
	TokenNew        string `json:"token_new,omitempty"`      // For email_change in secure mode
	TokenHashNew    string `json:"token_hash_new,omitempty"` // For email_change in secure mode
}

SupabaseEmailData contains email-specific data for auth hooks

type SupabaseIntegrationSettings

type SupabaseIntegrationSettings struct {
	AuthEmailHook         SupabaseAuthEmailHookSettings   `json:"auth_email_hook"`
	BeforeUserCreatedHook SupabaseUserCreatedHookSettings `json:"before_user_created_hook"`
}

SupabaseIntegrationSettings contains all Supabase integration configuration

func (*SupabaseIntegrationSettings) DecryptSignatureKeys

func (s *SupabaseIntegrationSettings) DecryptSignatureKeys(passphrase string) error

DecryptSignatureKeys decrypts both signature keys

func (*SupabaseIntegrationSettings) EncryptSignatureKeys

func (s *SupabaseIntegrationSettings) EncryptSignatureKeys(passphrase string) error

EncryptSignatureKeys encrypts both signature keys

func (*SupabaseIntegrationSettings) Validate

func (s *SupabaseIntegrationSettings) Validate(passphrase string) error

Validate validates the Supabase integration settings

type SupabaseTemplateMappings

type SupabaseTemplateMappings struct {
	Signup           string `json:"signup"`
	MagicLink        string `json:"magiclink"`
	Recovery         string `json:"recovery"`
	EmailChange      string `json:"email_change"` // Single template used for both current and new email addresses
	Invite           string `json:"invite"`
	Reauthentication string `json:"reauthentication"`
}

SupabaseTemplateMappings maps each email action type to a Notifuse template ID

func (*SupabaseTemplateMappings) GetTemplateID

func (m *SupabaseTemplateMappings) GetTemplateID(actionType SupabaseEmailActionType) (string, error)

GetTemplateID returns the template ID for a given email action type For email_change, the same template is used for both current and new email addresses (matching Supabase's behavior where there's only one customizable email_change template)

type SupabaseUser

type SupabaseUser struct {
	ID           string                 `json:"id"`
	Aud          string                 `json:"aud"`
	Role         string                 `json:"role"`
	Email        string                 `json:"email"`
	EmailNew     string                 `json:"new_email,omitempty"` // Present in email_change webhooks
	Phone        string                 `json:"phone"`
	AppMetadata  map[string]interface{} `json:"app_metadata"`
	UserMetadata map[string]interface{} `json:"user_metadata"`
	Identities   []interface{}          `json:"identities"`
	CreatedAt    string                 `json:"created_at"`
	UpdatedAt    string                 `json:"updated_at"`
	IsAnonymous  bool                   `json:"is_anonymous"`
}

SupabaseUser represents a Supabase user object

func (*SupabaseUser) ToContact

func (u *SupabaseUser) ToContact(customJSONField string) (*Contact, error)

ToContact converts a Supabase user to a Notifuse Contact customJSONField specifies which custom_json field to use (e.g., "custom_json_1", "custom_json_2", etc.) If empty, user_metadata will not be mapped

type SupabaseUserCreatedHookSettings

type SupabaseUserCreatedHookSettings struct {
	SignatureKey          string   `json:"signature_key,omitempty"`           // Accepts plaintext key in requests (cleared before API responses)
	EncryptedSignatureKey string   `json:"encrypted_signature_key,omitempty"` // Encrypted key (stored and returned in API responses)
	AddUserToLists        []string `json:"add_user_to_lists,omitempty"`       // Optional lists to add contacts to
	CustomJSONField       string   `json:"custom_json_field,omitempty"`       // Which custom_json field to use (default: custom_json_1)
	RejectDisposableEmail bool     `json:"reject_disposable_email,omitempty"` // Reject user creation if email is disposable
}

SupabaseUserCreatedHookSettings configures the Before User Created Hook Hook activation is controlled in Supabase, not here

func (*SupabaseUserCreatedHookSettings) DecryptSignatureKey

func (s *SupabaseUserCreatedHookSettings) DecryptSignatureKey(passphrase string) error

DecryptSignatureKey decrypts the signature key for user created hook

func (*SupabaseUserCreatedHookSettings) EncryptSignatureKey

func (s *SupabaseUserCreatedHookSettings) EncryptSignatureKey(passphrase string) error

EncryptSignatureKey encrypts the signature key for user created hook

func (*SupabaseUserCreatedHookSettings) Validate

func (s *SupabaseUserCreatedHookSettings) Validate() error

Validate validates the user created hook settings

type SupabaseWebhookMetadata

type SupabaseWebhookMetadata struct {
	UUID      string `json:"uuid"`       // Request ID
	Time      string `json:"time"`       // ISO 8601 timestamp
	Name      string `json:"name"`       // Hook name
	IPAddress string `json:"ip_address"` // User's IP address
}

SupabaseWebhookMetadata contains metadata about the webhook request

type TOCItem

type TOCItem struct {
	ID    string `json:"id"`    // Anchor ID for linking (e.g., "introduction")
	Level int    `json:"level"` // Heading level (2-6)
	Text  string `json:"text"`  // Heading text content
}

TOCItem represents a single item in the table of contents

type Task

type Task struct {
	ID            string     `json:"id"`
	WorkspaceID   string     `json:"workspace_id"`
	Type          string     `json:"type"`
	Status        TaskStatus `json:"status"`
	Progress      float64    `json:"progress"`
	State         *TaskState `json:"state,omitempty"` // Typed state struct
	ErrorMessage  *string    `json:"error_message,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
	LastRunAt     *time.Time `json:"last_run_at,omitempty"`
	CompletedAt   *time.Time `json:"completed_at,omitempty"`
	NextRunAfter  *time.Time `json:"next_run_after,omitempty"`
	TimeoutAfter  *time.Time `json:"timeout_after,omitempty"`
	MaxRuntime    int        `json:"max_runtime"` // Maximum runtime in seconds
	MaxRetries    int        `json:"max_retries"`
	RetryCount    int        `json:"retry_count"`
	RetryInterval int        `json:"retry_interval"`         // Retry interval in seconds
	BroadcastID   *string    `json:"broadcast_id,omitempty"` // Optional reference to a broadcast
}

Task represents a background task that can be executed in multiple steps

type TaskExecutor

type TaskExecutor interface {
	// ExecutePendingTasks finds and executes pending tasks
	ExecutePendingTasks(ctx context.Context, maxTasks int) error

	// ExecuteTask executes a specific task
	ExecuteTask(ctx context.Context, workspaceID, taskID string, timeoutAt time.Time) error

	// RegisterProcessor registers a task processor for a specific task type
	RegisterProcessor(processor TaskProcessor)
}

TaskExecutor is responsible for executing tasks

type TaskFilter

type TaskFilter struct {
	Status        []TaskStatus
	Type          []string
	CreatedAfter  *time.Time
	CreatedBefore *time.Time
	Limit         int
	Offset        int
}

TaskFilter defines the filtering criteria for task listing

type TaskListResponse

type TaskListResponse struct {
	Tasks      []*Task `json:"tasks"`
	TotalCount int     `json:"total_count"`
	Limit      int     `json:"limit"`
	Offset     int     `json:"offset"`
	HasMore    bool    `json:"has_more"`
}

TaskListResponse defines the response for listing tasks

type TaskProcessor

type TaskProcessor interface {
	// Process executes or continues a task, returns whether the task has been completed
	Process(ctx context.Context, task *Task, timeoutAt time.Time) (completed bool, err error)

	// CanProcess returns whether this processor can handle the given task type
	CanProcess(taskType string) bool
}

TaskProcessor defines the interface for task execution

type TaskRepository

type TaskRepository interface {
	// Transaction support
	WithTransaction(ctx context.Context, fn func(*sql.Tx) error) error

	// Create adds a new task
	Create(ctx context.Context, workspace string, task *Task) error
	CreateTx(ctx context.Context, tx *sql.Tx, workspace string, task *Task) error

	// Get retrieves a task by ID
	Get(ctx context.Context, workspace, id string) (*Task, error)
	GetTx(ctx context.Context, tx *sql.Tx, workspace, id string) (*Task, error)

	// Get a task by broadcast ID
	GetTaskByBroadcastID(ctx context.Context, workspace, broadcastID string) (*Task, error)
	GetTaskByBroadcastIDTx(ctx context.Context, tx *sql.Tx, workspace, broadcastID string) (*Task, error)

	// Update updates an existing task
	Update(ctx context.Context, workspace string, task *Task) error
	UpdateTx(ctx context.Context, tx *sql.Tx, workspace string, task *Task) error

	// Delete removes a task
	Delete(ctx context.Context, workspace, id string) error
	DeleteAll(ctx context.Context, workspace string) error

	// List retrieves tasks with optional filtering
	List(ctx context.Context, workspace string, filter TaskFilter) ([]*Task, int, error)

	// GetNextBatch retrieves tasks that are ready to be processed
	GetNextBatch(ctx context.Context, limit int) ([]*Task, error)

	// MarkAsRunning marks a task as running and sets timeout
	MarkAsRunning(ctx context.Context, workspace, id string, timeoutAfter time.Time) error
	MarkAsRunningTx(ctx context.Context, tx *sql.Tx, workspace, id string, timeoutAfter time.Time) error

	// SaveState saves the current state of a running task
	SaveState(ctx context.Context, workspace, id string, progress float64, state *TaskState) error
	SaveStateTx(ctx context.Context, tx *sql.Tx, workspace, id string, progress float64, state *TaskState) error

	// MarkAsCompleted marks a task as completed and saves the final state
	MarkAsCompleted(ctx context.Context, workspace, id string, state *TaskState) error
	MarkAsCompletedTx(ctx context.Context, tx *sql.Tx, workspace, id string, state *TaskState) error

	// MarkAsFailed marks a task as failed
	MarkAsFailed(ctx context.Context, workspace, id string, errorMsg string) error
	MarkAsFailedTx(ctx context.Context, tx *sql.Tx, workspace, id string, errorMsg string) error

	// MarkAsPaused marks a task as paused (e.g., due to timeout)
	MarkAsPaused(ctx context.Context, workspace, id string, nextRunAfter time.Time, progress float64, state *TaskState) error
	MarkAsPausedTx(ctx context.Context, tx *sql.Tx, workspace, id string, nextRunAfter time.Time, progress float64, state *TaskState) error

	// MarkAsPending marks a task as pending (e.g., for recurring tasks)
	MarkAsPending(ctx context.Context, workspace, id string, nextRunAfter time.Time, progress float64, state *TaskState) error
	MarkAsPendingTx(ctx context.Context, tx *sql.Tx, workspace, id string, nextRunAfter time.Time, progress float64, state *TaskState) error
}

TaskRepository defines methods for task persistence

type TaskService

type TaskService interface {
	RegisterProcessor(processor TaskProcessor)
	GetProcessor(taskType string) (TaskProcessor, error)
	CreateTask(ctx context.Context, workspace string, task *Task) error
	GetTask(ctx context.Context, workspace, id string) (*Task, error)
	ListTasks(ctx context.Context, workspace string, filter TaskFilter) (*TaskListResponse, error)
	DeleteTask(ctx context.Context, workspace, id string) error
	ExecutePendingTasks(ctx context.Context, maxTasks int) error
	ExecuteTask(ctx context.Context, workspace, taskID string, timeoutAt time.Time) error
	GetLastCronRun(ctx context.Context) (*time.Time, error)
	SubscribeToBroadcastEvents(eventBus EventBus)
	IsAutoExecuteEnabled() bool
}

type TaskState

type TaskState struct {
	// Common fields for all task types
	Progress float64 `json:"progress,omitempty"`
	Message  string  `json:"message,omitempty"`

	// Specialized states for different task types - only one will be used based on task type
	SendBroadcast *SendBroadcastState `json:"send_broadcast,omitempty"`
	BuildSegment  *BuildSegmentState  `json:"build_segment,omitempty"`
}

TaskState represents the state of a task, with specialized fields for different task types

func (*TaskState) Scan

func (s *TaskState) Scan(value interface{}) error

Scan implements the sql.Scanner interface for TaskState

func (TaskState) Value

func (s TaskState) Value() (driver.Value, error)

Value implements the driver.Valuer interface for TaskState

type TaskStatus

type TaskStatus string

TaskStatus represents the current state of a task

const (
	// TaskStatusPending is for tasks that haven't started yet
	TaskStatusPending TaskStatus = "pending"
	// TaskStatusRunning is for tasks that are currently running
	TaskStatusRunning TaskStatus = "running"
	// TaskStatusCompleted is for tasks that have completed successfully
	TaskStatusCompleted TaskStatus = "completed"
	// TaskStatusFailed is for tasks that have failed
	TaskStatusFailed TaskStatus = "failed"
	// TaskStatusPaused is for tasks that were paused due to timeout
	TaskStatusPaused TaskStatus = "paused"
)

type TelemetryMetrics

type TelemetryMetrics struct {
	ContactsCount      int    `json:"contacts_count"`
	BroadcastsCount    int    `json:"broadcasts_count"`
	TransactionalCount int    `json:"transactional_count"`
	MessagesCount      int    `json:"messages_count"`
	ListsCount         int    `json:"lists_count"`
	SegmentsCount      int    `json:"segments_count"`
	UsersCount         int    `json:"users_count"`
	BlogPostsCount     int    `json:"blog_posts_count"`
	LastMessageAt      string `json:"last_message_at"`
}

TelemetryMetrics represents aggregated metrics for a workspace

type TelemetryRepository

type TelemetryRepository interface {
	// GetWorkspaceMetrics retrieves aggregated metrics for a specific workspace
	GetWorkspaceMetrics(ctx context.Context, workspaceID string) (*TelemetryMetrics, error)

	// CountContacts counts the total number of contacts in a workspace
	CountContacts(ctx context.Context, db *sql.DB) (int, error)

	// CountBroadcasts counts the total number of broadcasts in a workspace
	CountBroadcasts(ctx context.Context, db *sql.DB) (int, error)

	// CountTransactional counts the total number of transactional notifications in a workspace
	CountTransactional(ctx context.Context, db *sql.DB) (int, error)

	// CountMessages counts the total number of messages in a workspace
	CountMessages(ctx context.Context, db *sql.DB) (int, error)

	// CountLists counts the total number of lists in a workspace
	CountLists(ctx context.Context, db *sql.DB) (int, error)

	// CountSegments counts the total number of segments in a workspace
	CountSegments(ctx context.Context, db *sql.DB) (int, error)

	// CountUsers counts the total number of users in a workspace from the system database
	CountUsers(ctx context.Context, systemDB *sql.DB, workspaceID string) (int, error)

	// CountBlogPosts counts the total number of blog posts in a workspace
	CountBlogPosts(ctx context.Context, db *sql.DB) (int, error)

	// GetLastMessageAt gets the timestamp of the last message sent from the workspace
	GetLastMessageAt(ctx context.Context, db *sql.DB) (string, error)
}

TelemetryRepository defines the interface for telemetry data operations

type Template

type Template struct {
	ID              string         `json:"id"`
	Name            string         `json:"name"`
	Version         int64          `json:"version"`
	Channel         string         `json:"channel"` // email or web
	Email           *EmailTemplate `json:"email,omitempty"`
	Web             *WebTemplate   `json:"web,omitempty"`
	Category        string         `json:"category"`
	TemplateMacroID *string        `json:"template_macro_id,omitempty"`
	IntegrationID   *string        `json:"integration_id,omitempty"` // Set if template is managed by an integration (e.g., Supabase)
	TestData        MapOfAny       `json:"test_data,omitempty"`
	Settings        MapOfAny       `json:"settings,omitempty"` // Channels specific 3rd-party settings
	CreatedAt       time.Time      `json:"created_at"`
	UpdatedAt       time.Time      `json:"updated_at"`
	DeletedAt       *time.Time     `json:"deleted_at,omitempty"`
}

func (*Template) Validate

func (t *Template) Validate() error

type TemplateBlock

type TemplateBlock struct {
	ID      string                   `json:"id"`
	Name    string                   `json:"name"`
	Block   notifuse_mjml.EmailBlock `json:"block"`
	Created time.Time                `json:"created"`
	Updated time.Time                `json:"updated"`
}

TemplateBlock represents a reusable email block template

func (TemplateBlock) MarshalJSON

func (tb TemplateBlock) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for TemplateBlock

func (*TemplateBlock) UnmarshalJSON

func (tb *TemplateBlock) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for TemplateBlock

type TemplateBlockService

type TemplateBlockService interface {
	// CreateTemplateBlock creates a new template block
	CreateTemplateBlock(ctx context.Context, workspaceID string, block *TemplateBlock) error

	// GetTemplateBlock retrieves a template block by ID
	GetTemplateBlock(ctx context.Context, workspaceID string, id string) (*TemplateBlock, error)

	// ListTemplateBlocks retrieves all template blocks for a workspace
	ListTemplateBlocks(ctx context.Context, workspaceID string) ([]*TemplateBlock, error)

	// UpdateTemplateBlock updates an existing template block
	UpdateTemplateBlock(ctx context.Context, workspaceID string, block *TemplateBlock) error

	// DeleteTemplateBlock deletes a template block by ID
	DeleteTemplateBlock(ctx context.Context, workspaceID string, id string) error
}

TemplateBlockService provides operations for managing template blocks

type TemplateCategory

type TemplateCategory string
const (
	TemplateCategoryMarketing     TemplateCategory = "marketing"
	TemplateCategoryTransactional TemplateCategory = "transactional"
	TemplateCategoryWelcome       TemplateCategory = "welcome"
	TemplateCategoryOptIn         TemplateCategory = "opt_in"
	TemplateCategoryUnsubscribe   TemplateCategory = "unsubscribe"
	TemplateCategoryBounce        TemplateCategory = "bounce"
	TemplateCategoryBlocklist     TemplateCategory = "blocklist"
	TemplateCategoryBlog          TemplateCategory = "blog"
	TemplateCategoryOther         TemplateCategory = "other"
)

func (TemplateCategory) Validate

func (t TemplateCategory) Validate() error

type TemplateDataRequest

type TemplateDataRequest struct {
	WorkspaceID        string                         `json:"workspace_id"`
	WorkspaceSecretKey string                         `json:"workspace_secret_key"`
	ContactWithList    ContactWithList                `json:"contact_with_list"`
	MessageID          string                         `json:"message_id"`
	ProvidedData       MapOfAny                       `json:"provided_data,omitempty"`
	TrackingSettings   notifuse_mjml.TrackingSettings `json:"tracking_settings"`
	Broadcast          *Broadcast                     `json:"broadcast,omitempty"`
}

TemplateDataRequest groups parameters for building template data

func (*TemplateDataRequest) Validate

func (r *TemplateDataRequest) Validate() error

Validate ensures that the template data request has all required fields

type TemplateReference

type TemplateReference struct {
	ID      string `json:"id"`
	Version int64  `json:"version"`
}

func (*TemplateReference) Scan

func (t *TemplateReference) Scan(val interface{}) error

scan implements the sql.Scanner interface

func (*TemplateReference) Validate

func (t *TemplateReference) Validate() error

func (TemplateReference) Value

func (t TemplateReference) Value() (driver.Value, error)

value implements the driver.Valuer interface

type TemplateRepository

type TemplateRepository interface {
	// CreateTemplate creates a new template in the database
	CreateTemplate(ctx context.Context, workspaceID string, template *Template) error

	// GetTemplateByID retrieves a template by its ID and optional version
	GetTemplateByID(ctx context.Context, workspaceID string, id string, version int64) (*Template, error)

	// GetTemplateLatestVersion retrieves the latest version of a template
	GetTemplateLatestVersion(ctx context.Context, workspaceID string, id string) (int64, error)

	// GetTemplates retrieves all templates
	GetTemplates(ctx context.Context, workspaceID string, category string, channel string) ([]*Template, error)

	// UpdateTemplate updates an existing template, creating a new version
	UpdateTemplate(ctx context.Context, workspaceID string, template *Template) error

	// DeleteTemplate deletes a template
	DeleteTemplate(ctx context.Context, workspaceID string, id string) error
}

TemplateRepository provides database operations for templates

type TemplateService

type TemplateService interface {
	// CreateTemplate creates a new template
	CreateTemplate(ctx context.Context, workspaceID string, template *Template) error

	// GetTemplateByID retrieves a template by ID and optional version
	GetTemplateByID(ctx context.Context, workspaceID string, id string, version int64) (*Template, error)

	// GetTemplates retrieves all templates
	GetTemplates(ctx context.Context, workspaceID string, category string, channel string) ([]*Template, error)

	// UpdateTemplate updates an existing template
	UpdateTemplate(ctx context.Context, workspaceID string, template *Template) error

	// DeleteTemplate deletes a template by ID
	DeleteTemplate(ctx context.Context, workspaceID string, id string) error

	// CompileTemplate compiles a visual editor tree to MJML and HTML
	CompileTemplate(ctx context.Context, payload CompileTemplateRequest) (*CompileTemplateResponse, error) // Use notifuse_mjml.EmailBlock
}

TemplateService provides operations for managing templates

type TestEmailProviderRequest

type TestEmailProviderRequest struct {
	Provider    EmailProvider `json:"provider"`
	To          string        `json:"to"`
	WorkspaceID string        `json:"workspace_id"`
}

TestEmailProviderRequest is the request for testing an email provider It includes the provider config, a recipient email, and the workspace ID

type TestEmailProviderResponse

type TestEmailProviderResponse struct {
	Success bool   `json:"success"`
	Error   string `json:"error,omitempty"`
}

TestEmailProviderResponse is the response for testing an email provider It can be extended to include more details if needed

type TestResultsResponse

type TestResultsResponse struct {
	BroadcastID       string                      `json:"broadcast_id"`
	Status            string                      `json:"status"`
	TestStartedAt     *time.Time                  `json:"test_started_at,omitempty"`
	TestCompletedAt   *time.Time                  `json:"test_completed_at,omitempty"`
	VariationResults  map[string]*VariationResult `json:"variation_results"`
	RecommendedWinner string                      `json:"recommended_winner,omitempty"`
	WinningTemplate   string                      `json:"winning_template,omitempty"`
	IsAutoSendWinner  bool                        `json:"is_auto_send_winner"`
}

TestResultsResponse represents the response for A/B test results

type TestTemplateRequest

type TestTemplateRequest struct {
	WorkspaceID    string       `json:"workspace_id"`
	TemplateID     string       `json:"template_id"`
	IntegrationID  string       `json:"integration_id"`
	SenderID       string       `json:"sender_id"`
	RecipientEmail string       `json:"recipient_email"`
	EmailOptions   EmailOptions `json:"email_options,omitempty"`
}

TestTemplateRequest represents a request to test a template

func (*TestTemplateRequest) Validate

func (r *TestTemplateRequest) Validate() error

type TestTemplateResponse

type TestTemplateResponse struct {
	Success bool   `json:"success"`
	Error   string `json:"error,omitempty"`
}

TestTemplateResponse represents the response from testing a template

type TestWinnerMetric

type TestWinnerMetric string

TestWinnerMetric defines the metric used to determine the winning A/B test variation

const (
	TestWinnerMetricOpenRate  TestWinnerMetric = "open_rate"
	TestWinnerMetricClickRate TestWinnerMetric = "click_rate"
)

type TimelineListRequest

type TimelineListRequest struct {
	WorkspaceID string
	Email       string
	Limit       int
	Cursor      *string
}

TimelineListRequest represents the request parameters for listing timeline entries

func (*TimelineListRequest) FromQuery

func (r *TimelineListRequest) FromQuery(query url.Values) error

FromQuery parses query parameters into a TimelineListRequest

func (*TimelineListRequest) Validate

func (r *TimelineListRequest) Validate() error

Validate validates the timeline list request

type TimelineListResponse

type TimelineListResponse struct {
	Timeline   []*ContactTimelineEntry `json:"timeline"`
	NextCursor *string                 `json:"next_cursor,omitempty"`
}

TimelineListResponse represents the response for listing timeline entries

type TimelineTriggerConfig

type TimelineTriggerConfig struct {
	EventKind       string           `json:"event_kind"`                  // Timeline event type to listen for
	ListID          *string          `json:"list_id,omitempty"`           // Required for list.* events
	SegmentID       *string          `json:"segment_id,omitempty"`        // Required for segment.* events
	CustomEventName *string          `json:"custom_event_name,omitempty"` // Required for custom_event
	UpdatedFields   []string         `json:"updated_fields,omitempty"`    // For contact.updated: only trigger on these field changes
	Conditions      *TreeNode        `json:"conditions"`                  // Reuse segments condition system
	Frequency       TriggerFrequency `json:"frequency"`
}

TimelineTriggerConfig defines the trigger configuration for an automation

func (*TimelineTriggerConfig) Validate

func (c *TimelineTriggerConfig) Validate() error

Validate validates the trigger configuration

type TransactionalChannel

type TransactionalChannel string

TransactionalChannel represents supported notification channels

const (
	// TransactionalChannelEmail for email notifications
	TransactionalChannelEmail TransactionalChannel = "email"
)

type TransactionalNotification

type TransactionalNotification struct {
	ID               string                         `json:"id"` // Unique identifier for the notification, also used for API triggering
	Name             string                         `json:"name"`
	Description      string                         `json:"description"`
	Channels         ChannelTemplates               `json:"channels"`
	TrackingSettings notifuse_mjml.TrackingSettings `json:"tracking_settings"`
	Metadata         MapOfAny                       `json:"metadata,omitempty"`
	IntegrationID    *string                        `json:"integration_id,omitempty"` // Set if notification is managed by an integration (e.g., Supabase)

	// System timestamps
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
	DeletedAt *time.Time `json:"deleted_at,omitempty"`
}

TransactionalNotification represents a transactional notification configuration

type TransactionalNotificationCreateParams

type TransactionalNotificationCreateParams struct {
	ID               string                         `json:"id" validate:"required"` // Unique identifier for API triggering
	Name             string                         `json:"name" validate:"required"`
	Description      string                         `json:"description"`
	Channels         ChannelTemplates               `json:"channels" validate:"required,min=1"`
	TrackingSettings notifuse_mjml.TrackingSettings `json:"tracking_settings"`
	Metadata         MapOfAny                       `json:"metadata,omitempty"`
}

TransactionalNotificationCreateParams contains the parameters for creating a new transactional notification

type TransactionalNotificationRepository

type TransactionalNotificationRepository interface {
	// Create adds a new transactional notification
	Create(ctx context.Context, workspace string, notification *TransactionalNotification) error

	// Update updates an existing transactional notification
	Update(ctx context.Context, workspace string, notification *TransactionalNotification) error

	// Get retrieves a transactional notification by ID
	Get(ctx context.Context, workspace, id string) (*TransactionalNotification, error)

	// List retrieves all transactional notifications with optional filtering
	List(ctx context.Context, workspace string, filter map[string]interface{}, limit, offset int) ([]*TransactionalNotification, int, error)

	// Delete soft-deletes a transactional notification
	Delete(ctx context.Context, workspace, id string) error
}

TransactionalNotificationRepository defines methods for transactional notification persistence

type TransactionalNotificationSendParams

type TransactionalNotificationSendParams struct {
	ID           string                 `json:"id" validate:"required"`      // ID of the notification to send
	ExternalID   *string                `json:"external_id,omitempty"`       // External ID for idempotency checks
	Contact      *Contact               `json:"contact" validate:"required"` // Contact to send the notification to
	Channels     []TransactionalChannel `json:"channels,omitempty"`          // Specific channels to send through (if empty, use all configured channels)
	Data         MapOfAny               `json:"data,omitempty"`              // Data to populate the template with
	Metadata     MapOfAny               `json:"metadata,omitempty"`          // Additional metadata for tracking
	EmailOptions EmailOptions           `json:"email_options,omitempty"`     // Email options for the notification
}

TransactionalNotificationSendParams contains the parameters for sending a transactional notification

type TransactionalNotificationService

type TransactionalNotificationService interface {
	// CreateNotification creates a new transactional notification
	CreateNotification(ctx context.Context, workspaceID string, params TransactionalNotificationCreateParams) (*TransactionalNotification, error)

	// UpdateNotification updates an existing transactional notification
	UpdateNotification(ctx context.Context, workspaceID, id string, params TransactionalNotificationUpdateParams) (*TransactionalNotification, error)

	// GetNotification retrieves a transactional notification by ID
	GetNotification(ctx context.Context, workspaceID, id string) (*TransactionalNotification, error)

	// ListNotifications retrieves all transactional notifications with optional filtering
	ListNotifications(ctx context.Context, workspaceID string, filter map[string]interface{}, limit, offset int) ([]*TransactionalNotification, int, error)

	// DeleteNotification soft-deletes a transactional notification
	DeleteNotification(ctx context.Context, workspaceID, id string) error

	// SendNotification sends a transactional notification to a contact
	SendNotification(ctx context.Context, workspaceID string, params TransactionalNotificationSendParams) (string, error)

	TestTemplate(ctx context.Context, workspaceID string, templateID string, integrationID string, senderID string, recipientEmail string, options EmailOptions) error
}

TransactionalNotificationService defines the interface for transactional notification operations

type TransactionalNotificationUpdateParams

type TransactionalNotificationUpdateParams struct {
	Name             string                         `json:"name,omitempty"`
	Description      string                         `json:"description,omitempty"`
	Channels         ChannelTemplates               `json:"channels,omitempty"`
	TrackingSettings notifuse_mjml.TrackingSettings `json:"tracking_settings,omitempty"`
	Metadata         MapOfAny                       `json:"metadata,omitempty"`
}

TransactionalNotificationUpdateParams contains the parameters for updating an existing transactional notification

type TreeNode

type TreeNode struct {
	Kind   string          `json:"kind"` // "branch" or "leaf"
	Branch *TreeNodeBranch `json:"branch,omitempty"`
	Leaf   *TreeNodeLeaf   `json:"leaf,omitempty"`
}

TreeNode represents a node in the segment tree structure It can be either a branch (AND/OR operator) or a leaf (actual condition)

func TreeNodeFromJSON

func TreeNodeFromJSON(jsonStr string) (*TreeNode, error)

TreeNodeFromJSON parses a JSON string into a TreeNode

func TreeNodeFromMapOfAny

func TreeNodeFromMapOfAny(data MapOfAny) (*TreeNode, error)

TreeNodeFromMapOfAny converts a MapOfAny to a TreeNode

func (*TreeNode) HasRelativeDates

func (t *TreeNode) HasRelativeDates() bool

HasRelativeDates checks if the tree contains any relative date filters that require daily recomputation (e.g., "in_the_last_days")

func (*TreeNode) ToMapOfAny

func (t *TreeNode) ToMapOfAny() (MapOfAny, error)

ToMapOfAny converts a TreeNode to MapOfAny (for backwards compatibility)

func (*TreeNode) Validate

func (t *TreeNode) Validate() error

Validate validates the tree structure

type TreeNodeBranch

type TreeNodeBranch struct {
	Operator string      `json:"operator"` // "and" or "or"
	Leaves   []*TreeNode `json:"leaves"`
}

TreeNodeBranch represents a logical operator (AND/OR) with child nodes

func (*TreeNodeBranch) Validate

func (b *TreeNodeBranch) Validate() error

Validate validates a branch node

type TreeNodeLeaf

type TreeNodeLeaf struct {
	Source           string                     `json:"source"` // "contacts", "contact_lists", "contact_timeline", "custom_events_goals"
	Contact          *ContactCondition          `json:"contact,omitempty"`
	ContactList      *ContactListCondition      `json:"contact_list,omitempty"`
	ContactTimeline  *ContactTimelineCondition  `json:"contact_timeline,omitempty"`
	CustomEventsGoal *CustomEventsGoalCondition `json:"custom_events_goal,omitempty"`
}

TreeNodeLeaf represents an actual condition on a data source

func (*TreeNodeLeaf) Validate

func (l *TreeNodeLeaf) Validate() error

Validate validates a leaf node

type TriggerFrequency

type TriggerFrequency string

TriggerFrequency defines how often an automation should trigger for a contact

const (
	TriggerFrequencyOnce      TriggerFrequency = "once"       // Only trigger on first occurrence
	TriggerFrequencyEveryTime TriggerFrequency = "every_time" // Trigger on each occurrence
)

func (TriggerFrequency) IsValid

func (f TriggerFrequency) IsValid() bool

IsValid checks if the trigger frequency is valid

type UTMParameters

type UTMParameters struct {
	Source   string `json:"source,omitempty"`
	Medium   string `json:"medium,omitempty"`
	Campaign string `json:"campaign,omitempty"`
	Term     string `json:"term,omitempty"`
	Content  string `json:"content,omitempty"`
}

UTMParameters contains UTM tracking parameters for the broadcast

func (*UTMParameters) Scan

func (u *UTMParameters) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (UTMParameters) Value

func (u UTMParameters) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type UnpublishBlogPostRequest

type UnpublishBlogPostRequest struct {
	ID string `json:"id"`
}

UnpublishBlogPostRequest defines the request to unpublish a blog post

func (*UnpublishBlogPostRequest) Validate

func (r *UnpublishBlogPostRequest) Validate() error

Validate validates the unpublish blog post request

type UnsubscribeFromListsRequest

type UnsubscribeFromListsRequest struct {
	WorkspaceID string   `json:"wid"`
	Email       string   `json:"email"`
	EmailHMAC   string   `json:"email_hmac"`
	ListIDs     []string `json:"lids"`
	MessageID   string   `json:"mid"`
}

func (*UnsubscribeFromListsRequest) FromURLParams

func (r *UnsubscribeFromListsRequest) FromURLParams(queryParams url.Values) (err error)

from url params

type UpdateAutomationRequest

type UpdateAutomationRequest struct {
	WorkspaceID string      `json:"workspace_id"`
	Automation  *Automation `json:"automation"`
}

UpdateAutomationRequest represents the request to update an automation

func (*UpdateAutomationRequest) Validate

func (r *UpdateAutomationRequest) Validate() error

Validate validates the update automation request

type UpdateBlogCategoryRequest

type UpdateBlogCategoryRequest struct {
	ID          string       `json:"id"`
	Name        string       `json:"name"`
	Slug        string       `json:"slug"`
	Description string       `json:"description,omitempty"`
	SEO         *SEOSettings `json:"seo,omitempty"`
}

UpdateBlogCategoryRequest defines the request to update a blog category

func (*UpdateBlogCategoryRequest) Validate

func (r *UpdateBlogCategoryRequest) Validate() error

Validate validates the update blog category request

type UpdateBlogPostRequest

type UpdateBlogPostRequest struct {
	ID                 string       `json:"id"`
	CategoryID         string       `json:"category_id"`
	Slug               string       `json:"slug"`
	Title              string       `json:"title"`
	TemplateID         string       `json:"template_id"`
	TemplateVersion    int          `json:"template_version"`
	Excerpt            string       `json:"excerpt,omitempty"`
	FeaturedImageURL   string       `json:"featured_image_url,omitempty"`
	Authors            []BlogAuthor `json:"authors"`
	ReadingTimeMinutes int          `json:"reading_time_minutes"`
	SEO                *SEOSettings `json:"seo,omitempty"`
}

UpdateBlogPostRequest defines the request to update a blog post

func (*UpdateBlogPostRequest) Validate

func (r *UpdateBlogPostRequest) Validate() error

Validate validates the update blog post request

type UpdateBlogThemeRequest

type UpdateBlogThemeRequest struct {
	Version int            `json:"version"`
	Files   BlogThemeFiles `json:"files"`
	Notes   *string        `json:"notes,omitempty"`
}

UpdateBlogThemeRequest defines the request to update a blog theme

func (*UpdateBlogThemeRequest) Validate

func (r *UpdateBlogThemeRequest) Validate() error

Validate validates the update blog theme request

type UpdateBroadcastRequest

type UpdateBroadcastRequest struct {
	WorkspaceID     string                `json:"workspace_id"`
	ID              string                `json:"id"`
	Name            string                `json:"name"`
	Audience        AudienceSettings      `json:"audience"`
	Schedule        ScheduleSettings      `json:"schedule"`
	TestSettings    BroadcastTestSettings `json:"test_settings"`
	TrackingEnabled bool                  `json:"tracking_enabled"`
	UTMParameters   *UTMParameters        `json:"utm_parameters,omitempty"`
	Metadata        MapOfAny              `json:"metadata,omitempty"`
}

UpdateBroadcastRequest defines the request to update an existing broadcast

func (*UpdateBroadcastRequest) Validate

func (r *UpdateBroadcastRequest) Validate(existingBroadcast *Broadcast) (*Broadcast, error)

Validate validates the update broadcast request

type UpdateContactListStatusRequest

type UpdateContactListStatusRequest struct {
	WorkspaceID string `json:"workspace_id"`
	Email       string `json:"email"`
	ListID      string `json:"list_id"`
	Status      string `json:"status"`
}

func (*UpdateContactListStatusRequest) Validate

func (r *UpdateContactListStatusRequest) Validate() (workspaceID string, list *ContactList, err error)

type UpdateContactListStatusResult

type UpdateContactListStatusResult struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
	Found   bool   `json:"found"` // Whether the contact was found in the list
}

UpdateContactListStatusResult represents the result of updating a contact list status

type UpdateIntegrationRequest

type UpdateIntegrationRequest struct {
	WorkspaceID       string                       `json:"workspace_id"`
	IntegrationID     string                       `json:"integration_id"`
	Name              string                       `json:"name"`
	Provider          EmailProvider                `json:"provider,omitempty"`           // For email integrations
	SupabaseSettings  *SupabaseIntegrationSettings `json:"supabase_settings,omitempty"`  // For Supabase integrations
	LLMProvider       *LLMProvider                 `json:"llm_provider,omitempty"`       // For LLM integrations
	FirecrawlSettings *FirecrawlSettings           `json:"firecrawl_settings,omitempty"` // For Firecrawl integrations
}

UpdateIntegrationRequest defines the request structure for updating an integration

func (*UpdateIntegrationRequest) Validate

func (r *UpdateIntegrationRequest) Validate(passphrase string) error

type UpdateListRequest

type UpdateListRequest struct {
	WorkspaceID         string             `json:"workspace_id"`
	ID                  string             `json:"id"`
	Name                string             `json:"name"`
	IsDoubleOptin       bool               `json:"is_double_optin"`
	IsPublic            bool               `json:"is_public"`
	Description         string             `json:"description,omitempty"`
	DoubleOptInTemplate *TemplateReference `json:"double_optin_template,omitempty"`
}

func (*UpdateListRequest) Validate

func (r *UpdateListRequest) Validate() (list *List, workspaceID string, err error)

type UpdateSegmentRequest

type UpdateSegmentRequest struct {
	WorkspaceID string    `json:"workspace_id"`
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Color       string    `json:"color"`
	Tree        *TreeNode `json:"tree"`
	Timezone    string    `json:"timezone"`
}

func (*UpdateSegmentRequest) Validate

func (r *UpdateSegmentRequest) Validate() (segment *Segment, workspaceID string, err error)

type UpdateTemplateBlockRequest

type UpdateTemplateBlockRequest struct {
	WorkspaceID string                   `json:"workspace_id"`
	ID          string                   `json:"id"`
	Name        string                   `json:"name"`
	Block       notifuse_mjml.EmailBlock `json:"block"`
}

UpdateTemplateBlockRequest defines the request structure for updating a template block

func (*UpdateTemplateBlockRequest) UnmarshalJSON

func (r *UpdateTemplateBlockRequest) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for UpdateTemplateBlockRequest

func (*UpdateTemplateBlockRequest) Validate

func (r *UpdateTemplateBlockRequest) Validate() (block *TemplateBlock, workspaceID string, err error)

Validate validates the update template block request

type UpdateTemplateRequest

type UpdateTemplateRequest struct {
	WorkspaceID     string         `json:"workspace_id"`
	ID              string         `json:"id"`
	Name            string         `json:"name"`
	Channel         string         `json:"channel"`
	Email           *EmailTemplate `json:"email,omitempty"`
	Web             *WebTemplate   `json:"web,omitempty"`
	Category        string         `json:"category"`
	TemplateMacroID *string        `json:"template_macro_id,omitempty"`
	TestData        MapOfAny       `json:"test_data,omitempty"`
	Settings        MapOfAny       `json:"settings,omitempty"`
}

func (*UpdateTemplateRequest) Validate

func (r *UpdateTemplateRequest) Validate() (template *Template, workspaceID string, err error)

type UpdateTransactionalRequest

type UpdateTransactionalRequest struct {
	WorkspaceID string                                `json:"workspace_id"`
	ID          string                                `json:"id"`
	Updates     TransactionalNotificationUpdateParams `json:"updates"`
}

UpdateTransactionalRequest represents a request to update a transactional notification

func (*UpdateTransactionalRequest) Validate

func (req *UpdateTransactionalRequest) Validate() error

Validate validates the update request

type UpdateWorkspaceRequest

type UpdateWorkspaceRequest struct {
	ID       string            `json:"id"`
	Name     string            `json:"name"`
	Settings WorkspaceSettings `json:"settings"`
}

func (*UpdateWorkspaceRequest) Validate

func (r *UpdateWorkspaceRequest) Validate(passphrase string) error

type UpsertContactOperation

type UpsertContactOperation struct {
	Email  string `json:"email"`
	Action string `json:"action"` // create or update or error
	Error  string `json:"error,omitempty"`
}

type UpsertContactRequest

type UpsertContactRequest struct {
	WorkspaceID string          `json:"workspace_id" valid:"required"`
	Contact     json.RawMessage `json:"contact" valid:"required"`
}

func (*UpsertContactRequest) Validate

func (r *UpsertContactRequest) Validate() (contact *Contact, workspaceID string, err error)

type UpsertCustomEventRequest

type UpsertCustomEventRequest struct {
	WorkspaceID   string                 `json:"workspace_id"`
	Email         string                 `json:"email"`
	EventName     string                 `json:"event_name"`
	ExternalID    string                 `json:"external_id"` // Required: unique external resource ID
	Properties    map[string]interface{} `json:"properties"`
	OccurredAt    *time.Time             `json:"occurred_at,omitempty"`    // Optional, defaults to now
	IntegrationID *string                `json:"integration_id,omitempty"` // Optional integration ID

	// Goal tracking fields
	GoalName  *string  `json:"goal_name,omitempty"`  // Optional goal name
	GoalType  *string  `json:"goal_type,omitempty"`  // purchase, subscription, lead, signup, booking, trial, other
	GoalValue *float64 `json:"goal_value,omitempty"` // Required for purchase/subscription, can be negative for refunds

	// Soft delete - set to a timestamp to delete, null to restore
	DeletedAt *time.Time `json:"deleted_at,omitempty"`
}

UpsertCustomEventRequest represents the API request to create or update a custom event Soft-delete by setting deleted_at, restore by setting deleted_at to null

func (*UpsertCustomEventRequest) Validate

func (r *UpsertCustomEventRequest) Validate() error

type User

type User struct {
	ID        string    `json:"id" db:"id"`
	Type      UserType  `json:"type" db:"type"`
	Email     string    `json:"email" db:"email"`
	Name      string    `json:"name,omitempty" db:"name"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

User represents a user in the system

type UserPermissions

type UserPermissions map[PermissionResource]ResourcePermissions

UserPermissions maps resources to their permission settings

func (*UserPermissions) Scan

func (up *UserPermissions) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (UserPermissions) Value

func (up UserPermissions) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type UserRepository

type UserRepository interface {
	// CreateUser creates a new user in the database
	CreateUser(ctx context.Context, user *User) error

	// GetUserByEmail retrieves a user by their email address
	GetUserByEmail(ctx context.Context, email string) (*User, error)

	// GetUserByID retrieves a user by their ID
	GetUserByID(ctx context.Context, id string) (*User, error)

	// CreateSession creates a new session for a user
	CreateSession(ctx context.Context, session *Session) error

	// GetSessionByID retrieves a session by its ID
	GetSessionByID(ctx context.Context, id string) (*Session, error)

	// GetSessionsByUserID retrieves all sessions for a user
	GetSessionsByUserID(ctx context.Context, userID string) ([]*Session, error)

	// UpdateSession updates an existing session
	UpdateSession(ctx context.Context, session *Session) error

	// DeleteSession deletes a session by its ID
	DeleteSession(ctx context.Context, id string) error

	// DeleteAllSessionsByUserID deletes all sessions for a user
	DeleteAllSessionsByUserID(ctx context.Context, userID string) error

	// Delete removes a user by their ID
	Delete(ctx context.Context, id string) error
}

type UserServiceInterface

type UserServiceInterface interface {
	SignIn(ctx context.Context, input SignInInput) (string, error)
	VerifyCode(ctx context.Context, input VerifyCodeInput) (*AuthResponse, error)
	RootSignin(ctx context.Context, input RootSigninInput) (*AuthResponse, error)
	VerifyUserSession(ctx context.Context, userID string, sessionID string) (*User, error)
	GetUserByID(ctx context.Context, userID string) (*User, error)
	GetUserByEmail(ctx context.Context, email string) (*User, error)
	Logout(ctx context.Context, userID string) error
}

UserServiceInterface defines the interface for user operations

type UserType

type UserType string
const (
	UserTypeUser   UserType = "user"
	UserTypeAPIKey UserType = "api_key"
)

type UserWorkspace

type UserWorkspace struct {
	UserID      string          `json:"user_id" db:"user_id"`
	WorkspaceID string          `json:"workspace_id" db:"workspace_id"`
	Role        string          `json:"role" db:"role"`
	Permissions UserPermissions `json:"permissions,omitempty" db:"permissions"`
	CreatedAt   time.Time       `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time       `json:"updated_at" db:"updated_at"`
}

UserWorkspace represents the relationship between a user and a workspace

func (*UserWorkspace) HasPermission

func (uw *UserWorkspace) HasPermission(resource PermissionResource, permissionType PermissionType) bool

HasPermission checks if the user has a specific permission for a resource

func (*UserWorkspace) SetPermissions

func (uw *UserWorkspace) SetPermissions(permissions UserPermissions)

SetPermissions replaces all permissions for the user

func (*UserWorkspace) Validate

func (uw *UserWorkspace) Validate() error

Validate performs validation on the user workspace fields

type UserWorkspaceWithEmail

type UserWorkspaceWithEmail struct {
	UserWorkspace
	Email               string     `json:"email" db:"email"`
	Type                UserType   `json:"type" db:"type"`
	InvitationExpiresAt *time.Time `json:"invitation_expires_at" db:"invitation_expires_at"`
	InvitationID        string     `json:"invitation_id,omitempty" db:"invitation_id"`
}

UserWorkspaceWithEmail extends UserWorkspace to include user email

type ValidationError

type ValidationError struct {
	Message string
}

ValidationError represents an error that occurs due to invalid input or parameters

func (ValidationError) Error

func (e ValidationError) Error() string

Error implements the error interface

type VariationMetrics

type VariationMetrics struct {
	Recipients   int `json:"recipients"`
	Delivered    int `json:"delivered"`
	Opens        int `json:"opens"`
	Clicks       int `json:"clicks"`
	Bounced      int `json:"bounced"`
	Complained   int `json:"complained"`
	Unsubscribed int `json:"unsubscribed"`
}

VariationMetrics contains performance metrics for a variation

func (*VariationMetrics) Scan

func (m *VariationMetrics) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (VariationMetrics) Value

func (m VariationMetrics) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

type VariationResult

type VariationResult struct {
	TemplateID   string  `json:"template_id"`
	TemplateName string  `json:"template_name"`
	Recipients   int     `json:"recipients"` // Total sent emails (used as denominator for rate calculations)
	Delivered    int     `json:"delivered"`  // Total delivered emails (ESP-dependent, may not be available)
	Opens        int     `json:"opens"`
	Clicks       int     `json:"clicks"`
	OpenRate     float64 `json:"open_rate"`  // Opens / Recipients
	ClickRate    float64 `json:"click_rate"` // Clicks / Recipients
}

VariationResult represents the results for a single A/B test variation

type VerifyCodeInput

type VerifyCodeInput struct {
	Email string `json:"email"`
	Code  string `json:"code"`
}

type WebTemplate

type WebTemplate struct {
	Content   MapOfAny `json:"content,omitempty"`    // Tiptap JSON (source of truth)
	HTML      string   `json:"html,omitempty"`       // Pre-rendered HTML for display
	PlainText string   `json:"plain_text,omitempty"` // Extracted text for search indexing
}

func (WebTemplate) MarshalJSON

func (w WebTemplate) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for WebTemplate

func (*WebTemplate) Scan

func (w *WebTemplate) Scan(val interface{}) error

func (*WebTemplate) UnmarshalJSON

func (w *WebTemplate) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for WebTemplate

func (*WebTemplate) Validate

func (w *WebTemplate) Validate(testData MapOfAny) error

func (WebTemplate) Value

func (w WebTemplate) Value() (driver.Value, error)

type WebhookDelivery

type WebhookDelivery struct {
	ID                 string                 `json:"id"`
	SubscriptionID     string                 `json:"subscription_id"`
	EventType          string                 `json:"event_type"`
	Payload            map[string]interface{} `json:"payload"`
	Status             string                 `json:"status"` // pending, delivering, delivered, failed
	Attempts           int                    `json:"attempts"`
	MaxAttempts        int                    `json:"max_attempts"`
	NextAttemptAt      time.Time              `json:"next_attempt_at"`
	LastAttemptAt      *time.Time             `json:"last_attempt_at,omitempty"`
	DeliveredAt        *time.Time             `json:"delivered_at,omitempty"`
	LastResponseStatus *int                   `json:"last_response_status,omitempty"`
	LastResponseBody   *string                `json:"last_response_body,omitempty"`
	LastError          *string                `json:"last_error,omitempty"`
	CreatedAt          time.Time              `json:"created_at"`
}

WebhookDelivery represents a pending or completed webhook delivery

type WebhookDeliveryRepository

type WebhookDeliveryRepository interface {
	GetPendingForWorkspace(ctx context.Context, workspaceID string, limit int) ([]*WebhookDelivery, error)
	ListAll(ctx context.Context, workspaceID string, subscriptionID *string, limit, offset int) ([]*WebhookDelivery, int, error)
	UpdateStatus(ctx context.Context, workspaceID, id string, status string, attempts int, responseStatus *int, responseBody, lastError *string) error
	MarkDelivered(ctx context.Context, workspaceID, id string, responseStatus int, responseBody string) error
	ScheduleRetry(ctx context.Context, workspaceID, id string, nextAttempt time.Time, attempts int, responseStatus *int, responseBody, lastError *string) error
	MarkFailed(ctx context.Context, workspaceID, id string, attempts int, lastError string, responseStatus *int, responseBody *string) error
	Create(ctx context.Context, workspaceID string, delivery *WebhookDelivery) error
	CleanupOldDeliveries(ctx context.Context, workspaceID string, retentionDays int) (int64, error)
}

WebhookDeliveryRepository defines the interface for webhook delivery data access

type WebhookDeliveryWithSubscription

type WebhookDeliveryWithSubscription struct {
	Delivery     *WebhookDelivery
	Subscription *WebhookSubscription
	WorkspaceID  string
}

WebhookDeliveryWithSubscription contains a delivery with its associated subscription

type WebhookEndpointStatus

type WebhookEndpointStatus struct {
	WebhookID string         `json:"webhook_id,omitempty"`
	URL       string         `json:"url"`
	EventType EmailEventType `json:"event_type"`
	Active    bool           `json:"active"`
}

WebhookEndpointStatus represents the status of a single webhook endpoint

type WebhookNodeConfig

type WebhookNodeConfig struct {
	URL    string  `json:"url"`
	Secret *string `json:"secret,omitempty"` // Optional: becomes Authorization: Bearer <secret>
}

WebhookNodeConfig configures a webhook node

func (WebhookNodeConfig) Validate

func (c WebhookNodeConfig) Validate() error

Validate validates the webhook node config

type WebhookProvider

type WebhookProvider interface {
	// RegisterWebhooks registers webhooks for the specified events
	RegisterWebhooks(ctx context.Context, workspaceID, integrationID string, baseURL string, eventTypes []EmailEventType, providerConfig *EmailProvider) (*WebhookRegistrationStatus, error)

	// GetWebhookStatus checks the current status of webhooks
	GetWebhookStatus(ctx context.Context, workspaceID, integrationID string, providerConfig *EmailProvider) (*WebhookRegistrationStatus, error)

	// UnregisterWebhooks removes all webhooks for this integration
	UnregisterWebhooks(ctx context.Context, workspaceID, integrationID string, providerConfig *EmailProvider) error
}

WebhookProvider defines a common interface for all email providers that support webhooks

type WebhookRegistrationConfig

type WebhookRegistrationConfig struct {
	IntegrationID string           `json:"integration_id"`
	EventTypes    []EmailEventType `json:"event_types"`
}

WebhookRegistrationConfig defines the configuration for registering webhooks

type WebhookRegistrationService

type WebhookRegistrationService interface {
	// RegisterWebhooks registers the webhook URLs with the email provider
	RegisterWebhooks(ctx context.Context, workspaceID string, config *WebhookRegistrationConfig) (*WebhookRegistrationStatus, error)

	// UnregisterWebhooks removes all webhook URLs associated with the integration
	UnregisterWebhooks(ctx context.Context, workspaceID string, integrationID string) error

	// GetWebhookStatus gets the current status of webhooks for the email provider
	GetWebhookStatus(ctx context.Context, workspaceID string, integrationID string) (*WebhookRegistrationStatus, error)
}

WebhookRegistrationService defines the interface for registering webhooks with email providers

type WebhookRegistrationStatus

type WebhookRegistrationStatus struct {
	EmailProviderKind EmailProviderKind       `json:"email_provider_kind"`
	IsRegistered      bool                    `json:"is_registered"`
	Endpoints         []WebhookEndpointStatus `json:"endpoints,omitempty"`
	Error             string                  `json:"error,omitempty"`
	ProviderDetails   map[string]interface{}  `json:"provider_details,omitempty"`
}

WebhookRegistrationStatus represents the current status of webhooks for a provider

type WebhookSource

type WebhookSource string

WebhookSource defines the source of the webhook event

const (
	// WebhookSourceSES indicates webhook from Amazon SES
	WebhookSourceSES WebhookSource = "ses"

	// WebhookSourcePostmark indicates webhook from Postmark
	WebhookSourcePostmark WebhookSource = "postmark"

	// WebhookSourceMailgun indicates webhook from Mailgun
	WebhookSourceMailgun WebhookSource = "mailgun"

	// WebhookSourceSparkPost indicates webhook from SparkPost
	WebhookSourceSparkPost WebhookSource = "sparkpost"

	// WebhookSourceMailjet indicates webhook from Mailjet
	WebhookSourceMailjet WebhookSource = "mailjet"

	// WebhookSourceSMTP indicates webhook from SMTP
	WebhookSourceSMTP WebhookSource = "smtp"

	// WebhookSourceSupabase indicates webhook from Supabase
	WebhookSourceSupabase WebhookSource = "supabase"
)

type WebhookSubscription

type WebhookSubscription struct {
	ID             string                      `json:"id"`
	Name           string                      `json:"name"`
	URL            string                      `json:"url"`
	Secret         string                      `json:"secret"`
	Settings       WebhookSubscriptionSettings `json:"settings"`
	Enabled        bool                        `json:"enabled"`
	LastDeliveryAt *time.Time                  `json:"last_delivery_at,omitempty"`
	CreatedAt      time.Time                   `json:"created_at"`
	UpdatedAt      time.Time                   `json:"updated_at"`
}

WebhookSubscription represents an outgoing webhook subscription configuration

func (WebhookSubscription) MarshalJSON

func (w WebhookSubscription) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling to flatten settings into top-level fields This maintains backward-compatible API responses while using nested internal structure

type WebhookSubscriptionRepository

type WebhookSubscriptionRepository interface {
	Create(ctx context.Context, workspaceID string, sub *WebhookSubscription) error
	GetByID(ctx context.Context, workspaceID, id string) (*WebhookSubscription, error)
	List(ctx context.Context, workspaceID string) ([]*WebhookSubscription, error)
	Update(ctx context.Context, workspaceID string, sub *WebhookSubscription) error
	Delete(ctx context.Context, workspaceID, id string) error
	UpdateLastDeliveryAt(ctx context.Context, workspaceID, id string, deliveredAt time.Time) error
}

WebhookSubscriptionRepository defines the interface for webhook subscription data access

type WebhookSubscriptionSettings

type WebhookSubscriptionSettings struct {
	EventTypes         []string            `json:"event_types"`
	CustomEventFilters *CustomEventFilters `json:"custom_event_filters,omitempty"`
}

WebhookSubscriptionSettings contains event subscription configuration

type Workspace

type Workspace struct {
	ID           string            `json:"id"`
	Name         string            `json:"name"`
	Settings     WorkspaceSettings `json:"settings"`
	Integrations Integrations      `json:"integrations"`
	CreatedAt    time.Time         `json:"created_at"`
	UpdatedAt    time.Time         `json:"updated_at"`
}

func ScanWorkspace

func ScanWorkspace(scanner interface {
	Scan(dest ...interface{}) error
}) (*Workspace, error)

ScanWorkspace scans a workspace from the database

func (*Workspace) AddIntegration

func (w *Workspace) AddIntegration(integration Integration)

AddIntegration adds a new integration to the workspace

func (*Workspace) AfterLoad

func (w *Workspace) AfterLoad(globalSecretKey string) error

func (*Workspace) BeforeSave

func (w *Workspace) BeforeSave(globalSecretKey string) error

func (*Workspace) GetEmailProvider

func (w *Workspace) GetEmailProvider(isMarketing bool) (*EmailProvider, error)

GetEmailProvider returns the email provider based on provider type

func (*Workspace) GetEmailProviderWithIntegrationID

func (w *Workspace) GetEmailProviderWithIntegrationID(isMarketing bool) (*EmailProvider, string, error)

GetEmailProviderWithIntegrationID returns both the email provider and integration ID based on provider type

func (*Workspace) GetIntegrationByID

func (w *Workspace) GetIntegrationByID(id string) *Integration

GetIntegrationByID finds an integration by ID in the workspace

func (*Workspace) GetIntegrationsByType

func (w *Workspace) GetIntegrationsByType(integrationType IntegrationType) []*Integration

GetIntegrationsByType returns all integrations of a specific type

func (*Workspace) MarshalJSON

func (w *Workspace) MarshalJSON() ([]byte, error)

func (*Workspace) RemoveIntegration

func (w *Workspace) RemoveIntegration(id string) bool

RemoveIntegration removes an integration by ID

func (*Workspace) Validate

func (w *Workspace) Validate(passphrase string) error

Validate performs validation on the workspace fields

type WorkspaceInvitation

type WorkspaceInvitation struct {
	ID          string          `json:"id"`
	WorkspaceID string          `json:"workspace_id"`
	InviterID   string          `json:"inviter_id"`
	Email       string          `json:"email"`
	Permissions UserPermissions `json:"permissions,omitempty"`
	ExpiresAt   time.Time       `json:"expires_at"`
	CreatedAt   time.Time       `json:"created_at"`
	UpdatedAt   time.Time       `json:"updated_at"`
}

WorkspaceInvitation represents an invitation to a workspace

type WorkspaceRepository

type WorkspaceRepository interface {
	Create(ctx context.Context, workspace *Workspace) error
	GetByID(ctx context.Context, id string) (*Workspace, error)
	GetWorkspaceByCustomDomain(ctx context.Context, hostname string) (*Workspace, error)
	List(ctx context.Context) ([]*Workspace, error)
	Update(ctx context.Context, workspace *Workspace) error
	Delete(ctx context.Context, id string) error

	// User workspace management
	AddUserToWorkspace(ctx context.Context, userWorkspace *UserWorkspace) error
	RemoveUserFromWorkspace(ctx context.Context, userID string, workspaceID string) error
	GetUserWorkspaces(ctx context.Context, userID string) ([]*UserWorkspace, error)
	GetWorkspaceUsersWithEmail(ctx context.Context, workspaceID string) ([]*UserWorkspaceWithEmail, error)
	GetUserWorkspace(ctx context.Context, userID string, workspaceID string) (*UserWorkspace, error)

	// User permission management
	UpdateUserWorkspacePermissions(ctx context.Context, userWorkspace *UserWorkspace) error

	// Workspace invitation management
	CreateInvitation(ctx context.Context, invitation *WorkspaceInvitation) error
	GetInvitationByID(ctx context.Context, id string) (*WorkspaceInvitation, error)
	GetInvitationByEmail(ctx context.Context, workspaceID, email string) (*WorkspaceInvitation, error)
	GetWorkspaceInvitations(ctx context.Context, workspaceID string) ([]*WorkspaceInvitation, error)
	DeleteInvitation(ctx context.Context, id string) error
	IsUserWorkspaceMember(ctx context.Context, userID, workspaceID string) (bool, error)

	// Database management
	GetConnection(ctx context.Context, workspaceID string) (*sql.DB, error)
	GetSystemConnection(ctx context.Context) (*sql.DB, error)
	CreateDatabase(ctx context.Context, workspaceID string) error
	DeleteDatabase(ctx context.Context, workspaceID string) error

	// Transaction management
	WithWorkspaceTransaction(ctx context.Context, workspaceID string, fn func(*sql.Tx) error) error
}

type WorkspaceServiceInterface

type WorkspaceServiceInterface interface {
	CreateWorkspace(ctx context.Context, id, name, websiteURL, logoURL, coverURL, timezone string, fileManager FileManagerSettings) (*Workspace, error)
	GetWorkspace(ctx context.Context, id string) (*Workspace, error)
	ListWorkspaces(ctx context.Context) ([]*Workspace, error)
	UpdateWorkspace(ctx context.Context, id, name string, settings WorkspaceSettings) (*Workspace, error)
	DeleteWorkspace(ctx context.Context, id string) error
	GetWorkspaceMembersWithEmail(ctx context.Context, id string) ([]*UserWorkspaceWithEmail, error)
	InviteMember(ctx context.Context, workspaceID, email string, permissions UserPermissions) (*WorkspaceInvitation, string, error)
	AddUserToWorkspace(ctx context.Context, workspaceID string, userID string, role string, permissions UserPermissions) error
	RemoveUserFromWorkspace(ctx context.Context, workspaceID string, userID string) error
	TransferOwnership(ctx context.Context, workspaceID string, newOwnerID string, currentOwnerID string) error
	CreateAPIKey(ctx context.Context, workspaceID string, emailPrefix string) (string, string, error)
	RemoveMember(ctx context.Context, workspaceID string, userIDToRemove string) error

	// Invitation management
	GetInvitationByID(ctx context.Context, invitationID string) (*WorkspaceInvitation, error)
	AcceptInvitation(ctx context.Context, invitationID, workspaceID, email string) (*AuthResponse, error)
	DeleteInvitation(ctx context.Context, invitationID string) error

	// Integration management
	CreateIntegration(ctx context.Context, req CreateIntegrationRequest) (string, error)
	UpdateIntegration(ctx context.Context, req UpdateIntegrationRequest) error
	DeleteIntegration(ctx context.Context, workspaceID, integrationID string) error

	// Permission management
	SetUserPermissions(ctx context.Context, workspaceID, userID string, permissions UserPermissions) error
}

WorkspaceServiceInterface defines the interface for workspace operations

type WorkspaceSettings

type WorkspaceSettings struct {
	WebsiteURL                   string              `json:"website_url,omitempty"`
	LogoURL                      string              `json:"logo_url,omitempty"`
	CoverURL                     string              `json:"cover_url,omitempty"`
	Timezone                     string              `json:"timezone"`
	FileManager                  FileManagerSettings `json:"file_manager,omitempty"`
	TransactionalEmailProviderID string              `json:"transactional_email_provider_id,omitempty"`
	MarketingEmailProviderID     string              `json:"marketing_email_provider_id,omitempty"`
	EncryptedSecretKey           string              `json:"encrypted_secret_key,omitempty"`
	EmailTrackingEnabled         bool                `json:"email_tracking_enabled"`
	TemplateBlocks               []TemplateBlock     `json:"template_blocks,omitempty"`
	CustomEndpointURL            *string             `json:"custom_endpoint_url,omitempty"`
	CustomFieldLabels            map[string]string   `json:"custom_field_labels,omitempty"`
	BlogEnabled                  bool                `json:"blog_enabled"`            // Enable blog feature at workspace level
	BlogSettings                 *BlogSettings       `json:"blog_settings,omitempty"` // Blog styling and SEO settings

	// decoded secret key, not stored in the database
	SecretKey string `json:"-"`
}

WorkspaceSettings contains configurable workspace settings

func (*WorkspaceSettings) Scan

func (b *WorkspaceSettings) Scan(value interface{}) error

Scan implements the sql.Scanner interface for database deserialization

func (*WorkspaceSettings) Validate

func (ws *WorkspaceSettings) Validate(passphrase string) error

Validate validates workspace settings

func (*WorkspaceSettings) ValidateCustomFieldLabels

func (ws *WorkspaceSettings) ValidateCustomFieldLabels() error

ValidateCustomFieldLabels validates custom field label mappings

func (WorkspaceSettings) Value

func (b WorkspaceSettings) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL