models

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// ServerSecurityModePermissive allows any user whose sender domain matches
	// allowed_domains to use this server, regardless of domain ownership.
	ServerSecurityModePermissive = "permissive"

	// ServerSecurityModeStrict requires the user to have verified ownership of
	// the sender domain (via TXT record) before the server is available to them.
	ServerSecurityModeStrict = "strict"
)
View Source
const (
	EncryptionNone     = "none"     // Plain text (port 25)
	EncryptionSTARTTLS = "starttls" // Upgrade via STARTTLS (port 587)
	EncryptionSSL      = "ssl"      // Implicit TLS (port 465)
)

Encryption modes for SMTP connections.

View Source
const (
	SMTPStatusEnabled  = "enabled"  // Valid and available for sending
	SMTPStatusDisabled = "disabled" // Manually disabled by user
	SMTPStatusInvalid  = "invalid"  // Validation failed (bad credentials, connection error)
)

SMTP server status values.

Variables

This section is empty.

Functions

This section is empty.

Types

type ABTestVariant

type ABTestVariant struct {
	Name            string `json:"name"`
	Subject         string `json:"subject"`
	TemplateID      *uint  `json:"template_id,omitempty"`
	SplitPercentage int    `json:"split_percentage"`
}

ABTestVariant represents a single variant in an A/B test campaign.

type ABTestVariants

type ABTestVariants []ABTestVariant

ABTestVariants is a JSON array of A/B test variants stored as TEXT.

func (*ABTestVariants) Scan

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

func (ABTestVariants) Value

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

type APIKey

type APIKey struct {
	ID          uint           `json:"id" gorm:"primaryKey"`
	UserID      uint           `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint          `json:"workspace_id,omitempty" gorm:"index"`
	Name        string         `json:"name" gorm:"not null"`
	KeyHash     string         `json:"-" gorm:"not null"`
	KeyPrefix   string         `json:"key_prefix" gorm:"not null"`
	CreatedAt   time.Time      `json:"created_at"`
	ExpiresAt   *time.Time     `json:"expires_at"`
	LastUsedAt  *time.Time     `json:"last_used_at"`
	Revoked     bool           `json:"revoked" gorm:"default:false"`
	AllowedIPs  pq.StringArray `json:"allowed_ips" gorm:"type:text[]"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

func (*APIKey) IsExpired

func (k *APIKey) IsExpired() bool

func (*APIKey) IsValid

func (k *APIKey) IsValid() bool

type Attachment

type Attachment struct {
	Filename    string `json:"filename"`
	Content     string `json:"content,omitempty"`
	ContentType string `json:"content_type"`
	// StorageKey is set when the attachment content is stored in blob storage
	// (S3 or filesystem). When present, Content may be empty and the actual
	// bytes should be fetched from the blob store using this key.
	StorageKey string `json:"storage_key,omitempty"`
}

Attachment represents a file attachment in an email.

type Bounce

type Bounce struct {
	ID          uint       `json:"id" gorm:"primaryKey"`
	UserID      uint       `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint      `json:"workspace_id,omitempty" gorm:"index"`
	EmailID     uint       `json:"email_id" gorm:"index;not null"`
	Recipient   string     `json:"recipient" gorm:"not null"`
	Type        BounceType `json:"type" gorm:"not null"`
	Reason      string     `json:"reason"`
	CreatedAt   time.Time  `json:"created_at"`

	User  User  `json:"-" gorm:"foreignKey:UserID"`
	Email Email `json:"-" gorm:"foreignKey:EmailID"`
}

type BounceType

type BounceType string
const (
	BounceTypeHard      BounceType = "hard"
	BounceTypeSoft      BounceType = "soft"
	BounceTypeComplaint BounceType = "complaint"
)

type Campaign

type Campaign struct {
	ID                uint           `json:"id" gorm:"primaryKey"`
	UserID            uint           `json:"user_id" gorm:"index;not null"`
	WorkspaceID       *uint          `json:"workspace_id,omitempty" gorm:"index"`
	Name              string         `json:"name" gorm:"not null"`
	Subject           string         `json:"subject" gorm:"not null"`
	FromEmail         string         `json:"from_email" gorm:"not null"`
	FromName          string         `json:"from_name"`
	TemplateID        uint           `json:"template_id" gorm:"index;not null"`
	TemplateVersionID *uint          `json:"template_version_id,omitempty" gorm:"index"`
	Language          string         `json:"language" gorm:"default:'en'"`
	TemplateData      TemplateData   `json:"template_data,omitempty" gorm:"type:text"`
	Status            CampaignStatus `json:"status" gorm:"type:varchar(20);default:'draft';not null;index"`
	ListID            uint           `json:"list_id" gorm:"index;not null"`
	SendRate          int            `json:"send_rate" gorm:"default:0"`
	SendAtLocalTime   bool           `json:"send_at_local_time" gorm:"default:false"`
	ABTestEnabled     bool           `json:"ab_test_enabled" gorm:"default:false"`
	ABTestVariants    ABTestVariants `json:"ab_test_variants,omitempty" gorm:"type:text"`
	ABTestWinner      string         `json:"ab_test_winner,omitempty"`
	ScheduledAt       *time.Time     `json:"scheduled_at,omitempty"`
	StartedAt         *time.Time     `json:"started_at,omitempty"`
	CompletedAt       *time.Time     `json:"completed_at,omitempty"`
	CreatedAt         time.Time      `json:"created_at"`
	UpdatedAt         *time.Time     `json:"updated_at,omitempty"`
	DeletedAt         gorm.DeletedAt `json:"-" gorm:"index"`
	// Snapshot captures the aggregated stats at soft-delete time so analytics
	// for past sends survive after CampaignMessage rows are purged.
	Snapshot TemplateData `json:"snapshot,omitempty" gorm:"type:text"`
	User     User         `json:"-" gorm:"foreignKey:UserID"`
}

type CampaignMessage

type CampaignMessage struct {
	ID             uint                  `json:"id" gorm:"primaryKey"`
	CampaignID     uint                  `json:"campaign_id" gorm:"uniqueIndex:idx_campaign_sub;not null;index"`
	SubscriberID   uint                  `json:"subscriber_id" gorm:"uniqueIndex:idx_campaign_sub;not null;index"`
	EmailID        *uint                 `json:"email_id,omitempty" gorm:"index"`
	Status         CampaignMessageStatus `json:"status" gorm:"type:varchar(20);default:'pending';not null;index"`
	ErrorMessage   string                `json:"error_message,omitempty"`
	Variant        string                `json:"variant,omitempty" gorm:"size:50"`
	SentAt         *time.Time            `json:"sent_at,omitempty"`
	OpenedAt       *time.Time            `json:"opened_at,omitempty"`
	ClickedAt      *time.Time            `json:"clicked_at,omitempty"`
	BouncedAt      *time.Time            `json:"bounced_at,omitempty"`
	UnsubscribedAt *time.Time            `json:"unsubscribed_at,omitempty"`
	CreatedAt      time.Time             `json:"created_at"`

	Campaign   Campaign   `json:"-" gorm:"foreignKey:CampaignID"`
	Subscriber Subscriber `json:"-" gorm:"foreignKey:SubscriberID"`
}

type CampaignMessageStatus

type CampaignMessageStatus string
const (
	CampaignMsgPending CampaignMessageStatus = "pending"
	CampaignMsgQueued  CampaignMessageStatus = "queued"
	CampaignMsgSent    CampaignMessageStatus = "sent"
	CampaignMsgFailed  CampaignMessageStatus = "failed"
	CampaignMsgSkipped CampaignMessageStatus = "skipped"
)

type CampaignStatus

type CampaignStatus string
const (
	CampaignStatusDraft     CampaignStatus = "draft"
	CampaignStatusScheduled CampaignStatus = "scheduled"
	CampaignStatusSending   CampaignStatus = "sending"
	CampaignStatusSent      CampaignStatus = "sent"
	CampaignStatusPaused    CampaignStatus = "paused"
	CampaignStatusCancelled CampaignStatus = "cancelled"
)

type Contact

type Contact struct {
	ID          uint       `json:"id" gorm:"primaryKey"`
	UserID      uint       `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint      `json:"workspace_id,omitempty" gorm:"index"`
	Email       string     `json:"email" gorm:"not null"`
	Name        string     `json:"name" gorm:"default:''"`
	SentCount   int64      `json:"sent_count" gorm:"default:0;not null"`
	FailCount   int64      `json:"fail_count" gorm:"default:0;not null"`
	LastSentAt  *time.Time `json:"last_sent_at"`
	CreatedAt   time.Time  `json:"created_at"`
}

type ContactList

type ContactList struct {
	ID          uint       `json:"id" gorm:"primaryKey"`
	UserID      uint       `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint      `json:"workspace_id,omitempty" gorm:"index"`
	Name        string     `json:"name" gorm:"not null"`
	Description string     `json:"description"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   *time.Time `json:"updated_at"`

	User    User                `json:"-" gorm:"foreignKey:UserID"`
	Members []ContactListMember `json:"-" gorm:"foreignKey:ListID"`
}

type ContactListMember

type ContactListMember struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	ListID    uint      `json:"list_id" gorm:"uniqueIndex:idx_list_email;not null"`
	Email     string    `json:"email" gorm:"uniqueIndex:idx_list_email;not null"`
	Name      string    `json:"name"`
	Data      string    `json:"data" gorm:"type:text"` // JSON metadata
	CreatedAt time.Time `json:"created_at"`

	List ContactList `json:"-" gorm:"foreignKey:ListID"`
}

type CustomFields

type CustomFields map[string]interface{}

CustomFields is a JSON map stored as TEXT in the database.

func (*CustomFields) Scan

func (cf *CustomFields) Scan(value interface{}) error

func (CustomFields) Value

func (cf CustomFields) Value() (driver.Value, error)

type Domain

type Domain struct {
	ID                uint      `json:"id" gorm:"primaryKey"`
	UserID            uint      `json:"user_id" gorm:"index;not null"`
	WorkspaceID       *uint     `json:"workspace_id,omitempty" gorm:"index"`
	Domain            string    `json:"domain" gorm:"not null"`
	OwnershipVerified bool      `json:"ownership_verified" gorm:"default:false"`
	SPFVerified       bool      `json:"spf_verified" gorm:"default:false"`
	DKIMVerified      bool      `json:"dkim_verified" gorm:"default:false"`
	DMARCVerified     bool      `json:"dmarc_verified" gorm:"default:false"`
	VerificationToken string    `json:"verification_token" gorm:"not null"`
	CreatedAt         time.Time `json:"created_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

func (*Domain) IsFullyVerified

func (d *Domain) IsFullyVerified() bool

IsFullyVerified returns true when ownership is confirmed and all DNS checks pass.

func (*Domain) IsOwnershipVerified

func (d *Domain) IsOwnershipVerified() bool

IsOwnershipVerified returns true when domain ownership has been confirmed via TXT record.

type Email

type Email struct {
	ID                  uint           `json:"id" gorm:"primaryKey"`
	UUID                string         `json:"uuid" gorm:"type:uuid;default:gen_random_uuid();uniqueIndex;not null"`
	UserID              uint           `json:"user_id" gorm:"index;not null"`
	WorkspaceID         *uint          `json:"workspace_id,omitempty" gorm:"index"`
	APIKeyID            *uint          `json:"api_key_id" gorm:"index"`
	Sender              string         `json:"sender" gorm:"not null"`
	Recipients          pq.StringArray `json:"recipients" gorm:"type:text[];not null"`
	Subject             string         `json:"subject" gorm:"not null"`
	TemplateName        string         `json:"template_name,omitempty"`
	HTMLBody            string         `json:"html_body"`
	TextBody            string         `json:"text_body"`
	AttachmentsJSON     string         `json:"attachments_json,omitempty" gorm:"type:text"`
	HeadersJSON         string         `json:"headers_json,omitempty" gorm:"type:text"`
	ListUnsubscribeURL  string         `json:"list_unsubscribe_url,omitempty" gorm:"type:text"`
	ListUnsubscribePost bool           `json:"list_unsubscribe_post,omitempty"`
	Status              EmailStatus    `json:"status" gorm:"default:pending;not null"`
	ErrorMessage        string         `json:"error_message"`
	RetryCount          int            `json:"retry_count" gorm:"default:0;not null"`
	CreatedAt           time.Time      `json:"created_at"`
	SentAt              *time.Time     `json:"sent_at"`
	ScheduledAt         *time.Time     `json:"scheduled_at"`
	Provider            string         `json:"provider,omitempty" gorm:"index;size:32"`

	SMTPHostname string `json:"smtp_hostname,omitempty"`

	User   User   `json:"-" gorm:"foreignKey:UserID"`
	APIKey APIKey `json:"-" gorm:"foreignKey:APIKeyID"`
}

type EmailStatus

type EmailStatus string
const (
	EmailStatusPending    EmailStatus = "pending"
	EmailStatusQueued     EmailStatus = "queued"
	EmailStatusProcessing EmailStatus = "processing"
	EmailStatusSent       EmailStatus = "sent"
	EmailStatusFailed     EmailStatus = "failed"
	EmailStatusSuppressed EmailStatus = "suppressed"
	EmailStatusScheduled  EmailStatus = "scheduled"
)

type Event

type Event struct {
	ID          uint          `json:"id" gorm:"primaryKey"`
	Category    EventCategory `json:"category" gorm:"index;not null"`
	Type        string        `json:"type" gorm:"index;not null"`
	WorkspaceID *uint         `json:"workspace_id,omitempty" gorm:"index"`
	ActorID     *uint         `json:"actor_id" gorm:"index"`
	ActorName   string        `json:"actor_name"`
	ClientIP    string        `json:"client_ip,omitempty" gorm:"size:45"`
	Message     string        `json:"message" gorm:"not null"`
	Metadata    string        `json:"metadata" gorm:"type:text"`
	CreatedAt   time.Time     `json:"created_at" gorm:"index"`
}

type EventCategory

type EventCategory string
const (
	EventCategoryUser   EventCategory = "user"
	EventCategoryEmail  EventCategory = "email"
	EventCategorySystem EventCategory = "system"
	EventCategoryAudit  EventCategory = "audit"
)

type FilterRule

type FilterRule struct {
	Field    string `json:"field"`
	Operator string `json:"operator"`
	Value    any    `json:"value"`
}

type FilterRules

type FilterRules []FilterRule

func (*FilterRules) Scan

func (fr *FilterRules) Scan(value interface{}) error

func (FilterRules) Value

func (fr FilterRules) Value() (driver.Value, error)

type InboundAttachmentMeta added in v0.6.0

type InboundAttachmentMeta struct {
	Filename    string `json:"filename"`
	ContentType string `json:"content_type"`
	Size        int64  `json:"size"`
	StorageKey  string `json:"storage_key,omitempty"`
	// Content is only populated when no blob store is configured (dev fallback).
	Content string `json:"content,omitempty"`
}

InboundAttachmentMeta describes one inbound attachment stored in blob storage. Serialized into InboundEmail.AttachmentsJSON.

type InboundEmail added in v0.6.0

type InboundEmail struct {
	ID              uint               `json:"id" gorm:"primaryKey"`
	UUID            string             `json:"uuid" gorm:"type:uuid;default:gen_random_uuid();uniqueIndex;not null"`
	UserID          uint               `json:"user_id" gorm:"index;not null"`
	WorkspaceID     *uint              `json:"workspace_id,omitempty" gorm:"index"`
	DomainID        uint               `json:"domain_id" gorm:"index;not null"`
	MessageID       string             `json:"message_id" gorm:"index"`
	Sender          string             `json:"sender" gorm:"not null"`
	Recipients      pq.StringArray     `json:"recipients" gorm:"type:text[];not null"`
	Subject         string             `json:"subject"`
	TextBody        string             `json:"text_body" gorm:"type:text"`
	HTMLBody        string             `json:"html_body" gorm:"type:text"`
	AttachmentsJSON string             `json:"attachments_json,omitempty" gorm:"type:text"`
	HeadersJSON     string             `json:"headers_json,omitempty" gorm:"type:text"`
	RawStorageKey   string             `json:"raw_storage_key,omitempty"`
	DedupHash       string             `json:"-" gorm:"index"`
	Size            int64              `json:"size"`
	SpamScore       *float64           `json:"spam_score,omitempty"`
	Status          InboundEmailStatus `json:"status" gorm:"default:received;not null"`
	Source          InboundSource      `json:"source" gorm:"not null"`
	ErrorMessage    string             `json:"error_message,omitempty"`
	RetryCount      int                `json:"retry_count" gorm:"default:0;not null"`
	ReceivedAt      time.Time          `json:"received_at" gorm:"not null"`
	ForwardedAt     *time.Time         `json:"forwarded_at,omitempty"`
	CreatedAt       time.Time          `json:"created_at"`

	User   User   `json:"-" gorm:"foreignKey:UserID"`
	Domain Domain `json:"-" gorm:"foreignKey:DomainID"`
}

type InboundEmailStatus added in v0.6.0

type InboundEmailStatus string
const (
	InboundStatusReceived  InboundEmailStatus = "received"
	InboundStatusForwarded InboundEmailStatus = "forwarded"
	InboundStatusFailed    InboundEmailStatus = "failed"
	InboundStatusRejected  InboundEmailStatus = "rejected"
)

type InboundSource added in v0.6.0

type InboundSource string
const (
	InboundSourceSMTP    InboundSource = "smtp"
	InboundSourceWebhook InboundSource = "webhook"
)

type InvitationStatus

type InvitationStatus string
const (
	InvitationStatusPending  InvitationStatus = "pending"
	InvitationStatusAccepted InvitationStatus = "accepted"
	InvitationStatusDeclined InvitationStatus = "declined"
)

type Language

type Language struct {
	ID          uint      `json:"id" gorm:"primaryKey"`
	UserID      uint      `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint     `json:"workspace_id,omitempty" gorm:"index"`
	Code        string    `json:"code" gorm:"not null;size:10"`
	Name        string    `json:"name" gorm:"not null"`
	IsDefault   bool      `json:"is_default" gorm:"default:false"`
	CreatedAt   time.Time `json:"created_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

type OAuthAccount

type OAuthAccount struct {
	ID             uint       `json:"id" gorm:"primaryKey"`
	UserID         uint       `json:"user_id" gorm:"uniqueIndex:idx_user_provider;not null"`
	ProviderID     uint       `json:"provider_id" gorm:"uniqueIndex:idx_user_provider;not null"`
	ProviderUserID string     `json:"provider_user_id" gorm:"uniqueIndex:idx_provider_ext_id;not null"`
	Email          string     `json:"email"`
	Name           string     `json:"name"`
	AvatarURL      string     `json:"avatar_url"`
	AccessToken    string     `json:"-" gorm:"type:text"`
	RefreshToken   string     `json:"-" gorm:"type:text"`
	TokenExpiresAt *time.Time `json:"-"`
	CreatedAt      time.Time  `json:"created_at"`
	UpdatedAt      time.Time  `json:"updated_at"`

	User     User          `json:"-" gorm:"foreignKey:UserID"`
	Provider OAuthProvider `json:"-" gorm:"foreignKey:ProviderID"`
}

OAuthAccount links an external OAuth identity to a local user.

type OAuthProvider

type OAuthProvider struct {
	ID             uint              `json:"id" gorm:"primaryKey"`
	WorkspaceID    *uint             `json:"workspace_id,omitempty" gorm:"index"`
	Name           string            `json:"name" gorm:"not null"`
	Slug           string            `json:"slug" gorm:"uniqueIndex;not null"`
	Type           OAuthProviderType `json:"type" gorm:"not null"`
	ClientID       string            `json:"-" gorm:"not null"`
	ClientSecret   string            `json:"-" gorm:"not null"`
	Issuer         string            `json:"issuer"`
	AuthURL        string            `json:"auth_url"`
	TokenURL       string            `json:"token_url"`
	UserInfoURL    string            `json:"userinfo_url"`
	Scopes         string            `json:"scopes" gorm:"default:'openid email profile'"`
	Enabled        bool              `json:"enabled" gorm:"default:true;not null"`
	Hidden         bool              `json:"hidden" gorm:"default:false;not null"`
	AutoRegister   bool              `json:"auto_register" gorm:"default:true"`
	AllowedDomains string            `json:"allowed_domains"`
	CreatedAt      time.Time         `json:"created_at"`
	UpdatedAt      time.Time         `json:"updated_at"`
}

OAuthProvider stores configuration for an OAuth/OIDC identity provider.

type OAuthProviderType

type OAuthProviderType string
const (
	OAuthProviderGoogle OAuthProviderType = "google"
	OAuthProviderOIDC   OAuthProviderType = "oidc"
)

type Plan

type Plan struct {
	ID                    uint      `json:"id" gorm:"primaryKey"`
	Name                  string    `json:"name" gorm:"uniqueIndex;not null"`
	Description           string    `json:"description"`
	IsDefault             bool      `json:"is_default" gorm:"default:false"`
	IsActive              bool      `json:"is_active" gorm:"default:true"`
	DailyRateLimit        int       `json:"daily_rate_limit" gorm:"default:0"`
	HourlyRateLimit       int       `json:"hourly_rate_limit" gorm:"default:0"`
	MaxAttachmentSizeMB   int       `json:"max_attachment_size_mb" gorm:"default:0"`
	MaxBatchSize          int       `json:"max_batch_size" gorm:"default:0"`
	MaxAPIKeys            int       `json:"max_api_keys" gorm:"default:0"`
	MaxDomains            int       `json:"max_domains" gorm:"default:0"`
	MaxSMTPServers        int       `json:"max_smtp_servers" gorm:"default:0"`
	MaxWorkspaces         int       `json:"max_workspaces" gorm:"default:0"`
	EmailLogRetentionDays int       `json:"email_log_retention_days" gorm:"default:0"`
	CreatedAt             time.Time `json:"created_at"`
	UpdatedAt             time.Time `json:"updated_at"`
}

Plan defines a usage package that can be assigned to workspaces. Each plan specifies rate limits, resource quotas, and retention policies. A value of 0 for any limit field means unlimited.

type SMTPServer

type SMTPServer struct {
	ID              uint           `json:"id" gorm:"primaryKey"`
	UserID          uint           `json:"user_id" gorm:"index;not null"`
	WorkspaceID     *uint          `json:"workspace_id,omitempty" gorm:"index"`
	Host            string         `json:"host" gorm:"not null"`
	Port            int            `json:"port" gorm:"not null"`
	Username        string         `json:"username"`
	Password        string         `json:"-"`
	Encryption      string         `json:"encryption" gorm:"default:none;not null"`
	MaxRetries      int            `json:"max_retries" gorm:"default:0;not null"`
	AllowedEmails   pq.StringArray `json:"allowed_emails" gorm:"type:text[]"`
	Status          string         `json:"status" gorm:"default:enabled;not null"`
	ValidationError string         `json:"validation_error" gorm:"type:text"`
	ValidatedAt     *time.Time     `json:"validated_at"`
	CreatedAt       time.Time      `json:"created_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

func (*SMTPServer) AfterFind

func (s *SMTPServer) AfterFind(tx *gorm.DB) error

AfterFind decrypts the password after reading from the database.

func (*SMTPServer) BeforeSave

func (s *SMTPServer) BeforeSave(tx *gorm.DB) error

BeforeSave encrypts the password before writing to the database. Uses AES-256-GCM if POSTA_ENCRYPTION_KEY is set, otherwise base64.

func (*SMTPServer) IsEnabled

func (s *SMTPServer) IsEnabled() bool

IsEnabled returns true when the server can be used for delivery.

type Server

type Server struct {
	ID              uint           `json:"id" gorm:"primaryKey"`
	Name            string         `json:"name" gorm:"not null"`
	Host            string         `json:"host" gorm:"not null"`
	Port            int            `json:"port" gorm:"not null"`
	Username        string         `json:"username"`
	Password        string         `json:"-"`
	Encryption      string         `json:"encryption" gorm:"default:none;not null"`
	MaxRetries      int            `json:"max_retries" gorm:"default:0;not null"`
	Status          string         `json:"status" gorm:"default:enabled;not null"`
	AllowedDomains  pq.StringArray `json:"allowed_domains" gorm:"type:text[]"`
	SecurityMode    string         `json:"security_mode" gorm:"default:permissive;not null"`
	SentCount       int64          `json:"sent_count" gorm:"default:0;not null"`
	FailedCount     int64          `json:"failed_count" gorm:"default:0;not null"`
	ValidationError string         `json:"validation_error" gorm:"type:text"`
	ValidatedAt     *time.Time     `json:"validated_at"`
	CreatedAt       time.Time      `json:"created_at"`
	UpdatedAt       time.Time      `json:"updated_at"`
}

Server represents a shared SMTP server managed by platform administrators. Unlike per-user SMTPServer records, a Server is available across multiple user accounts based on the sender domain.

func (*Server) AfterFind

func (s *Server) AfterFind(tx *gorm.DB) error

AfterFind decrypts the password after reading from the database.

func (*Server) BeforeSave

func (s *Server) BeforeSave(tx *gorm.DB) error

BeforeSave encrypts the password before writing to the database. Uses AES-256-GCM if POSTA_ENCRYPTION_KEY is set, otherwise base64.

func (*Server) IsEnabled

func (s *Server) IsEnabled() bool

IsEnabled returns true when the server can be used for delivery.

func (*Server) ToSMTPServer

func (s *Server) ToSMTPServer() *SMTPServer

ToSMTPServer converts this shared Server into the SMTPServer format used by the SMTP sender, so existing send logic can be reused without modification.

type Session

type Session struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	UserID    uint      `json:"user_id" gorm:"index;not null"`
	JTI       string    `json:"jti" gorm:"uniqueIndex;not null;size:36"` // JWT ID (UUID)
	IPAddress string    `json:"ip_address"`
	UserAgent string    `json:"user_agent"`
	Revoked   bool      `json:"revoked" gorm:"default:false;not null"`
	CreatedAt time.Time `json:"created_at"`
	ExpiresAt time.Time `json:"expires_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

Session tracks an active JWT session for a user.

func (*Session) IsActive

func (s *Session) IsActive() bool

IsActive returns true if the session is neither revoked nor expired.

func (*Session) IsExpired

func (s *Session) IsExpired() bool

IsExpired returns true if the session has passed its expiry time.

type Setting

type Setting struct {
	ID        uint      `json:"id" gorm:"primaryKey"`
	Key       string    `json:"key" gorm:"uniqueIndex;not null"`
	Value     string    `json:"value" gorm:"type:text"`
	Type      string    `json:"type" gorm:"default:string;not null"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Setting represents a platform-wide configuration entry managed by admins. Settings are stored as key-value pairs with a type hint for the frontend.

type StyleSheet

type StyleSheet struct {
	ID          uint       `json:"id" gorm:"primaryKey"`
	UserID      uint       `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint      `json:"workspace_id,omitempty" gorm:"index"`
	Name        string     `json:"name" gorm:"not null"`
	CSS         string     `json:"css"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   *time.Time `json:"updated_at,omitempty"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

type Subscriber

type Subscriber struct {
	ID             uint             `json:"id" gorm:"primaryKey"`
	UserID         uint             `json:"user_id" gorm:"uniqueIndex:idx_sub_scope_email;not null"`
	WorkspaceID    *uint            `json:"workspace_id,omitempty" gorm:"uniqueIndex:idx_sub_scope_email;index"`
	Email          string           `json:"email" gorm:"uniqueIndex:idx_sub_scope_email;not null"`
	Name           string           `json:"name" gorm:"default:''"`
	Status         SubscriberStatus `json:"status" gorm:"type:varchar(20);default:'subscribed';not null;index"`
	CustomFields   CustomFields     `json:"custom_fields" gorm:"type:text"`
	Timezone       string           `json:"timezone" gorm:"size:50;default:''"`
	Language       string           `json:"language" gorm:"size:10;default:''"`
	SubscribedAt   *time.Time       `json:"subscribed_at"`
	UnsubscribedAt *time.Time       `json:"unsubscribed_at"`
	CreatedAt      time.Time        `json:"created_at"`
	UpdatedAt      *time.Time       `json:"updated_at"`
	User           User             `json:"-" gorm:"foreignKey:UserID"`
}

type SubscriberList

type SubscriberList struct {
	ID          uint               `json:"id" gorm:"primaryKey"`
	UserID      uint               `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint              `json:"workspace_id,omitempty" gorm:"index"`
	Name        string             `json:"name" gorm:"not null"`
	Description string             `json:"description"`
	Type        SubscriberListType `json:"type" gorm:"type:varchar(10);default:'static';not null"`
	FilterRules FilterRules        `json:"filter_rules,omitempty" gorm:"type:text"`
	CreatedAt   time.Time          `json:"created_at"`
	UpdatedAt   *time.Time         `json:"updated_at"`
	User        User               `json:"-" gorm:"foreignKey:UserID"`
}

type SubscriberListMember

type SubscriberListMember struct {
	ID           uint      `json:"id" gorm:"primaryKey"`
	ListID       uint      `json:"list_id" gorm:"uniqueIndex:idx_sublist_sub;not null"`
	SubscriberID uint      `json:"subscriber_id" gorm:"uniqueIndex:idx_sublist_sub;not null;index"`
	CreatedAt    time.Time `json:"created_at"`

	List       SubscriberList `json:"-" gorm:"foreignKey:ListID"`
	Subscriber Subscriber     `json:"-" gorm:"foreignKey:SubscriberID"`
}

type SubscriberListType

type SubscriberListType string
const (
	SubscriberListTypeStatic  SubscriberListType = "static"
	SubscriberListTypeDynamic SubscriberListType = "dynamic"
)

type SubscriberListUnsubscribe added in v0.6.0

type SubscriberListUnsubscribe struct {
	ID             uint      `json:"id" gorm:"primaryKey"`
	ListID         uint      `json:"list_id" gorm:"uniqueIndex:idx_listunsub_sub;not null"`
	SubscriberID   uint      `json:"subscriber_id" gorm:"uniqueIndex:idx_listunsub_sub;not null;index"`
	Reason         string    `json:"reason" gorm:"size:64"`
	UnsubscribedAt time.Time `json:"unsubscribed_at"`

	List       SubscriberList `json:"-" gorm:"foreignKey:ListID"`
	Subscriber Subscriber     `json:"-" gorm:"foreignKey:SubscriberID"`
}

SubscriberListUnsubscribe records that a specific subscriber has opted out

type SubscriberStatus

type SubscriberStatus string
const (
	SubscriberStatusSubscribed   SubscriberStatus = "subscribed"
	SubscriberStatusUnsubscribed SubscriberStatus = "unsubscribed"
	SubscriberStatusBounced      SubscriberStatus = "bounced"
	SubscriberStatusComplained   SubscriberStatus = "complained"
)

type Suppression

type Suppression struct {
	ID          uint      `json:"id" gorm:"primaryKey"`
	UserID      uint      `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint     `json:"workspace_id,omitempty" gorm:"index"`
	Email       string    `json:"email" gorm:"not null"`
	Reason      string    `json:"reason"`
	CreatedAt   time.Time `json:"created_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

type Template

type Template struct {
	ID              uint       `json:"id" gorm:"primaryKey"`
	UserID          uint       `json:"user_id" gorm:"index;not null"`
	WorkspaceID     *uint      `json:"workspace_id,omitempty" gorm:"index"`
	Name            string     `json:"name" gorm:"not null"`
	DefaultLanguage string     `json:"default_language" gorm:"default:en;not null"`
	ActiveVersionID *uint      `json:"active_version_id,omitempty" gorm:"uniqueIndex"`
	Description     string     `json:"description"`
	SampleData      string     `json:"sample_data"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       *time.Time `json:"updated_at,omitempty"`

	User          User             `json:"-" gorm:"foreignKey:UserID"`
	ActiveVersion *TemplateVersion `json:"active_version,omitempty" gorm:"foreignKey:ActiveVersionID;constraint:false"`
}

type TemplateData

type TemplateData map[string]interface{}

TemplateData is a JSON map for template variable substitution.

func (*TemplateData) Scan

func (td *TemplateData) Scan(value interface{}) error

func (TemplateData) Value

func (td TemplateData) Value() (driver.Value, error)

type TemplateLocalization

type TemplateLocalization struct {
	ID              uint       `json:"id" gorm:"primaryKey"`
	VersionID       uint       `json:"version_id" gorm:"uniqueIndex:idx_version_language;not null"`
	Language        string     `json:"language" gorm:"uniqueIndex:idx_version_language;not null;size:10"`
	SubjectTemplate string     `json:"subject_template" gorm:"not null"`
	HTMLTemplate    string     `json:"html_template"`
	TextTemplate    string     `json:"text_template"`
	BuilderJSON     string     `json:"builder_json,omitempty" gorm:"type:text"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       *time.Time `json:"updated_at,omitempty"`

	Version TemplateVersion `json:"-" gorm:"foreignKey:VersionID;constraint:OnDelete:CASCADE"`
}

type TemplateVersion

type TemplateVersion struct {
	ID           uint      `json:"id" gorm:"primaryKey"`
	TemplateID   uint      `json:"template_id" gorm:"index;not null"`
	Version      int       `json:"version" gorm:"not null"`
	StyleSheetID *uint     `json:"stylesheet_id,omitempty" gorm:"index"`
	SampleData   string    `json:"sample_data"`
	CreatedAt    time.Time `json:"created_at"`

	StyleSheet    *StyleSheet            `json:"stylesheet,omitempty" gorm:"foreignKey:StyleSheetID;constraint:OnDelete:SET NULL"`
	Localizations []TemplateLocalization `json:"localizations,omitempty" gorm:"foreignKey:VersionID"`
}
type TrackedLink struct {
	ID          uint      `json:"id" gorm:"primaryKey"`
	CampaignID  uint      `json:"campaign_id" gorm:"index;not null"`
	OriginalURL string    `json:"original_url" gorm:"type:text;not null"`
	Hash        string    `json:"hash" gorm:"uniqueIndex;not null"`
	ClickCount  int64     `json:"click_count" gorm:"default:0;not null"`
	CreatedAt   time.Time `json:"created_at"`

	Campaign Campaign `json:"-" gorm:"foreignKey:CampaignID"`
}

TrackedLink stores rewritten links for click tracking.

type TrackingEvent

type TrackingEvent struct {
	ID                uint              `json:"id" gorm:"primaryKey"`
	CampaignMessageID uint              `json:"campaign_message_id" gorm:"index;not null"`
	EventType         TrackingEventType `json:"event_type" gorm:"type:varchar(20);not null;index"`
	TrackedLinkID     *uint             `json:"tracked_link_id,omitempty" gorm:"index"`
	IP                string            `json:"ip" gorm:"size:45"`
	UserAgent         string            `json:"user_agent" gorm:"type:text"`
	CreatedAt         time.Time         `json:"created_at" gorm:"index"`

	CampaignMessage CampaignMessage `json:"-" gorm:"foreignKey:CampaignMessageID"`
	TrackedLink     *TrackedLink    `json:"-" gorm:"foreignKey:TrackedLinkID"`
}

TrackingEvent records individual open/click/unsubscribe events.

type TrackingEventType

type TrackingEventType string
const (
	TrackingEventOpen        TrackingEventType = "open"
	TrackingEventClick       TrackingEventType = "click"
	TrackingEventUnsubscribe TrackingEventType = "unsubscribe"
)

type User

type User struct {
	ID                    uint       `json:"id" gorm:"primaryKey"`
	Name                  string     `json:"name" gorm:"not null;default:''"`
	Email                 string     `json:"email" gorm:"uniqueIndex;not null"`
	PasswordHash          string     `json:"-" gorm:"not null"`
	Role                  UserRole   `json:"role" gorm:"default:user;not null"`
	TwoFactorSecret       string     `json:"-" gorm:"type:text"`
	TwoFactorEnabled      bool       `json:"two_factor_enabled" gorm:"default:false"`
	Active                bool       `json:"active" gorm:"default:true;not null"`
	RequireVerifiedDomain bool       `json:"require_verified_domain" gorm:"default:false"`
	AuthMethod            string     `json:"auth_method" gorm:"default:'password';not null"`
	AvatarURL             string     `json:"avatar_url"`
	PlanID                *uint      `json:"plan_id" gorm:"index"`
	ScheduledDeletionAt   *time.Time `json:"scheduled_deletion_at"`
	EmailVerifiedAt       *time.Time `json:"email_verified_at"`
	CreatedAt             time.Time  `json:"created_at"`
	LastLoginAt           *time.Time `json:"last_login_at"`

	Plan Plan `json:"-" gorm:"foreignKey:PlanID"`
}

func (*User) IsAdmin

func (u *User) IsAdmin() bool

type UserEmailVerification added in v0.6.0

type UserEmailVerification struct {
	ID        uint       `gorm:"primaryKey"`
	UserID    uint       `gorm:"index;not null"`
	TokenHash string     `gorm:"uniqueIndex;size:64;not null"`
	ExpiresAt time.Time  `gorm:"not null"`
	UsedAt    *time.Time `gorm:""`
	CreatedAt time.Time  `gorm:"not null"`
}

type UserRole

type UserRole string
const (
	UserRoleAdmin UserRole = "admin"
	UserRoleUser  UserRole = "user"
)

type UserSetting

type UserSetting struct {
	ID                 uint      `json:"id" gorm:"primaryKey"`
	UserID             uint      `json:"user_id" gorm:"uniqueIndex;not null"`
	Timezone           string    `json:"timezone" gorm:"default:UTC"`
	DefaultSenderName  string    `json:"default_sender_name"`
	DefaultSenderEmail string    `json:"default_sender_email"`
	EmailNotifications bool      `json:"email_notifications" gorm:"default:true"`
	NotificationEmail  string    `json:"notification_email"`
	WebhookRetryCount  int       `json:"webhook_retry_count" gorm:"default:3"`
	DefaultTemplateID  *uint     `json:"default_template_id"`
	APIKeyExpiryDays   int       `json:"api_key_expiry_days" gorm:"default:90"`
	BounceAutoSuppress bool      `json:"bounce_auto_suppress" gorm:"default:true"`
	DefaultLanguage    string    `json:"default_language" gorm:"size:10;default:'en'"`
	DailyReport        bool      `json:"daily_report" gorm:"default:false"`
	CreatedAt          time.Time `json:"created_at"`
	UpdatedAt          time.Time `json:"updated_at"`
}

UserSetting stores per-user preferences. Each user has at most one row.

type Webhook

type Webhook struct {
	ID          uint           `json:"id" gorm:"primaryKey"`
	UserID      uint           `json:"user_id" gorm:"index;not null"`
	WorkspaceID *uint          `json:"workspace_id,omitempty" gorm:"index"`
	URL         string         `json:"url" gorm:"not null"`
	Events      pq.StringArray `json:"events" gorm:"type:text[];not null"`
	Filters     pq.StringArray `json:"filters" gorm:"type:text[]"`
	Secret      string         `json:"secret,omitempty" gorm:"type:varchar(64);not null;default:''"`
	CreatedAt   time.Time      `json:"created_at"`

	User User `json:"-" gorm:"foreignKey:UserID"`
}

type WebhookDelivery

type WebhookDelivery struct {
	ID             uint                  `json:"id" gorm:"primaryKey"`
	WebhookID      uint                  `json:"webhook_id" gorm:"index;not null"`
	UserID         uint                  `json:"user_id" gorm:"index;not null"`
	WorkspaceID    *uint                 `json:"workspace_id,omitempty" gorm:"index"`
	Event          string                `json:"event" gorm:"not null"`
	Status         WebhookDeliveryStatus `json:"status" gorm:"type:varchar(16);not null;index"`
	HTTPStatusCode int                   `json:"http_status_code"`
	ErrorMessage   string                `json:"error_message,omitempty"`
	Attempt        int                   `json:"attempt" gorm:"not null;default:1"`
	CreatedAt      time.Time             `json:"created_at"`

	Webhook Webhook `json:"-" gorm:"foreignKey:WebhookID"`
	User    User    `json:"-" gorm:"foreignKey:UserID"`
}

WebhookDelivery records the result of delivering a webhook notification.

type WebhookDeliveryStatus

type WebhookDeliveryStatus string

WebhookDeliveryStatus represents the outcome of a webhook delivery attempt.

const (
	WebhookDeliverySuccess WebhookDeliveryStatus = "success"
	WebhookDeliveryFailed  WebhookDeliveryStatus = "failed"
)

type Workspace

type Workspace struct {
	ID              uint      `json:"id" gorm:"primaryKey"`
	Name            string    `json:"name" gorm:"not null"`
	Slug            string    `json:"slug" gorm:"uniqueIndex;not null"`
	Description     string    `json:"description"`
	OwnerID         uint      `json:"owner_id" gorm:"index;not null"`
	PlanID          *uint     `json:"plan_id" gorm:"index"`
	DefaultLanguage string    `json:"default_language" gorm:"size:10;default:'en'"`
	CreatedAt       time.Time `json:"created_at"`
	UpdatedAt       time.Time `json:"updated_at"`

	Owner   User              `json:"-" gorm:"foreignKey:OwnerID"`
	Plan    Plan              `json:"-" gorm:"foreignKey:PlanID"`
	Members []WorkspaceMember `json:"-" gorm:"foreignKey:WorkspaceID"`
}

type WorkspaceInvitation

type WorkspaceInvitation struct {
	ID          uint             `json:"id" gorm:"primaryKey"`
	WorkspaceID uint             `json:"workspace_id" gorm:"index;not null"`
	Email       string           `json:"email" gorm:"not null"`
	Role        WorkspaceRole    `json:"role" gorm:"not null;default:viewer"`
	Token       string           `json:"-" gorm:"uniqueIndex;not null"`
	Status      InvitationStatus `json:"status" gorm:"not null;default:pending"`
	InvitedBy   uint             `json:"invited_by" gorm:"not null"`
	ExpiresAt   time.Time        `json:"expires_at" gorm:"not null"`
	CreatedAt   time.Time        `json:"created_at"`

	Workspace Workspace `json:"-" gorm:"foreignKey:WorkspaceID"`
	Inviter   User      `json:"-" gorm:"foreignKey:InvitedBy"`
}

type WorkspaceMember

type WorkspaceMember struct {
	ID          uint          `json:"id" gorm:"primaryKey"`
	WorkspaceID uint          `json:"workspace_id" gorm:"uniqueIndex:idx_workspace_user;not null"`
	UserID      uint          `json:"user_id" gorm:"uniqueIndex:idx_workspace_user;not null"`
	Role        WorkspaceRole `json:"role" gorm:"not null;default:viewer"`
	CreatedAt   time.Time     `json:"created_at"`

	Workspace Workspace `json:"-" gorm:"foreignKey:WorkspaceID"`
	User      User      `json:"-" gorm:"foreignKey:UserID"`
}

type WorkspaceRole

type WorkspaceRole string
const (
	WorkspaceRoleOwner  WorkspaceRole = "owner"
	WorkspaceRoleAdmin  WorkspaceRole = "admin"
	WorkspaceRoleEditor WorkspaceRole = "editor"
	WorkspaceRoleViewer WorkspaceRole = "viewer"
)

func (WorkspaceRole) CanEdit

func (r WorkspaceRole) CanEdit() bool

CanEdit returns true if the role can create/modify resources.

func (WorkspaceRole) CanManageMembers

func (r WorkspaceRole) CanManageMembers() bool

CanManageMembers returns true if the role can invite/remove members.

func (WorkspaceRole) CanView

func (r WorkspaceRole) CanView() bool

CanView returns true if the role has any access.

func (WorkspaceRole) IsOwner

func (r WorkspaceRole) IsOwner() bool

IsOwner returns true if the role is owner.

type WorkspaceSSOConfig

type WorkspaceSSOConfig struct {
	ID             uint      `json:"id" gorm:"primaryKey"`
	WorkspaceID    uint      `json:"workspace_id" gorm:"uniqueIndex;not null"`
	ProviderID     uint      `json:"provider_id" gorm:"not null"`
	EnforceSSO     bool      `json:"enforce_sso" gorm:"default:false"`
	AutoProvision  bool      `json:"auto_provision" gorm:"default:true"`
	AllowedDomains string    `json:"allowed_domains"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`

	Workspace Workspace     `json:"-" gorm:"foreignKey:WorkspaceID"`
	Provider  OAuthProvider `json:"-" gorm:"foreignKey:ProviderID"`
}

WorkspaceSSOConfig controls SSO enforcement for a workspace.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL