package automation import ( "database/sql/driver" "encoding/json" "fmt" "time" "github.com/gochat/gochat/internal/model" ) // =========================== // JSON types for conditions and actions // =========================== // Condition represents a single filter condition in an automation rule. // Reference: Chatwoot automation_rule conditions — {attribute, filter_operator, values, query_operator} type Condition struct { Attribute string `json:"attribute"` FilterOperator string `json:"filter_operator"` Values []string `json:"values"` QueryOperator string `json:"query_operator"` // "and" or "or" } // Conditions is a slice of Condition that implements GORM's JSON-valued column type. type Conditions []Condition func (c Conditions) Value() (driver.Value, error) { if c == nil { return json.Marshal([]Condition{}) } return json.Marshal(c) } func (c *Conditions) Scan(value interface{}) error { if value == nil { *c = Conditions{} return nil } bytes, ok := value.([]byte) if !ok { return fmt.Errorf("failed to unmarshal Conditions value: %v", value) } return json.Unmarshal(bytes, c) } // Action represents a single action to execute when an automation rule matches. // Reference: Chatwoot automation_rule actions — {action_name, action_params} type Action struct { ActionName string `json:"action_name"` ActionParams map[string]interface{} `json:"action_params"` } // Actions is a slice of Action that implements GORM's JSON-valued column type. type Actions []Action func (a Actions) Value() (driver.Value, error) { if a == nil { return json.Marshal([]Action{}) } return json.Marshal(a) } func (a *Actions) Scan(value interface{}) error { if value == nil { *a = Actions{} return nil } bytes, ok := value.([]byte) if !ok { return fmt.Errorf("failed to unmarshal Actions value: %v", value) } return json.Unmarshal(bytes, a) } // =========================== // AutomationRule model // =========================== // AutomationRule represents an automation rule that triggers actions on events. // Reference: Chatwoot AutomationRule — account_id, event_name, conditions, actions, active, name, description type AutomationRule struct { model.Base AccountID uint `gorm:"index;not null" json:"account_id"` EventName string `gorm:"size:100;index;not null" json:"event_name"` // e.g. "conversation_created", "message_created" Name string `gorm:"size:255;not null" json:"name"` Description string `gorm:"type:text" json:"description,omitempty"` Conditions Conditions `gorm:"type:jsonb;default:'[]'" json:"conditions"` Actions Actions `gorm:"type:jsonb;default:'[]'" json:"actions"` Active bool `gorm:"not null" json:"active"` ActiveAt *time.Time `gorm:"index" json:"active_at,omitempty"` InactiveAt *time.Time `gorm:"index" json:"inactive_at,omitempty"` } func (AutomationRule) TableName() string { return "automation_rules" } // =========================== // Macro model // =========================== // MacroVisibility defines the visibility level of a macro. // Reference: Chatwoot Macro visibility — 0=personal, 1=global type MacroVisibility int const ( MacroVisibilityPersonal MacroVisibility = 0 MacroVisibilityGlobal MacroVisibility = 1 ) // Macro represents a user-defined macro that executes a set of actions on a conversation. // Reference: Chatwoot Macro — account_id, name, actions, visibility, created_by_id, updated_by_id type Macro struct { model.Base AccountID uint `gorm:"index;not null" json:"account_id"` Name string `gorm:"size:255;not null" json:"name"` Actions Actions `gorm:"type:jsonb;default:'[]'" json:"actions"` Visibility MacroVisibility `gorm:"default:0" json:"visibility"` // 0=personal, 1=global Active bool `gorm:"not null" json:"active"` // enable/disable macro execution CreatedByID uint `gorm:"index;not null" json:"created_by_id"` UpdatedByID uint `gorm:"index;not null" json:"updated_by_id"` } func (Macro) TableName() string { return "macros" } // =========================== // CsatSurveyResponse model // =========================== // CsatSurveyResponse captures customer satisfaction feedback after a conversation is resolved. // Reference: Chatwoot CsatSurveyResponse — rating, feedback_message, conversation_id, account_id, assigned_agent_id type CsatSurveyResponse struct { model.Base AccountID uint `gorm:"index;not null" json:"account_id"` ConversationID uint `gorm:"index;not null" json:"conversation_id"` ContactID uint `gorm:"index" json:"contact_id"` MessageID *uint `gorm:"uniqueIndex" json:"message_id,omitempty"` AssignedAgentID *uint `gorm:"index" json:"assigned_agent_id,omitempty"` Rating int `gorm:"not null" json:"rating"` // 1-5 scale FeedbackMessage string `gorm:"type:text" json:"feedback_message,omitempty"` CsatReviewNotes string `gorm:"type:text" json:"csat_review_notes,omitempty"` ReviewNotesUpdatedByID *uint `gorm:"index" json:"review_notes_updated_by_id,omitempty"` ReviewNotesUpdatedAt *time.Time `json:"review_notes_updated_at,omitempty"` } func (CsatSurveyResponse) TableName() string { return "csat_survey_responses" } // =========================== // AutomationExecution model // =========================== // AutomationExecution records an automation rule execution event for audit trail. // Reference: Chatwoot does not explicitly store automation execution logs — // gochat adds this for debugging, monitoring, and compliance. type AutomationExecution struct { model.Base AccountID uint `gorm:"index;not null" json:"account_id"` RuleID uint `gorm:"index;not null" json:"rule_id"` ConversationID uint `gorm:"index;not null" json:"conversation_id"` Status string `gorm:"size:50;not null" json:"status"` // success, partial, failed ActionsExecuted int `gorm:"default:0" json:"actions_executed"` ActionsFailed int `gorm:"default:0" json:"actions_failed"` ErrorMessage string `gorm:"type:text" json:"error_message,omitempty"` } func (AutomationExecution) TableName() string { return "automation_executions" }