package outbox import "time" const ( StatePending = "pending" StateProcessing = "processing" StateRetry = "retry" StateDead = "dead" StateDelivered = "delivered" ) // Message is a Sense-internal delivery record. PayloadJSON is deliberately // excluded from management APIs and is not a cross-product contract. type Message struct { ID string `gorm:"size:36;primaryKey" json:"id"` InternalType string `gorm:"size:64;not null;index" json:"internalType"` BusinessRef string `gorm:"size:128;not null;index" json:"businessRef"` IdempotencyKey string `gorm:"size:191;not null;uniqueIndex" json:"idempotencyKey"` PayloadJSON string `gorm:"column:payload;type:jsonb;not null" json:"-"` State string `gorm:"size:24;not null;index" json:"state"` AttemptCount int `gorm:"not null;default:0" json:"attemptCount"` MaxAttempts int `gorm:"not null;default:12" json:"maxAttempts"` AvailableAt time.Time `gorm:"not null;index" json:"availableAt"` LeaseOwner string `gorm:"size:128;not null;default:''" json:"leaseOwner,omitempty"` LeaseUntil *time.Time `gorm:"index" json:"leaseUntil,omitempty"` LastError string `gorm:"size:512;not null;default:''" json:"lastError,omitempty"` DeliveredAt *time.Time `json:"deliveredAt,omitempty"` Version int64 `gorm:"not null;default:1" json:"version"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } func (Message) TableName() string { return "sense_outbox_messages" } // DeliveryRecord is permanent idempotency evidence. It is never deleted by // queue cleanup and prevents a delivered key from being processed again. type DeliveryRecord struct { IdempotencyKey string `gorm:"size:191;primaryKey" json:"idempotencyKey"` MessageID string `gorm:"size:36;not null;uniqueIndex" json:"messageId"` DeliveredAt time.Time `gorm:"not null" json:"deliveredAt"` CreatedAt time.Time `json:"createdAt"` } func (DeliveryRecord) TableName() string { return "sense_outbox_deliveries" } type Attempt struct { ID uint `gorm:"primaryKey;autoIncrement" json:"id"` MessageID string `gorm:"size:36;not null;index" json:"messageId"` Number int `gorm:"not null" json:"number"` Outcome string `gorm:"size:32;not null" json:"outcome"` Detail string `gorm:"size:512;not null;default:''" json:"detail"` Worker string `gorm:"size:128;not null;default:''" json:"worker,omitempty"` ActorUserID int `gorm:"not null;default:0" json:"actorUserId,omitempty"` CreatedAt time.Time `json:"createdAt"` } func (Attempt) TableName() string { return "sense_outbox_attempts" }