package entities import ( "database/sql/driver" "encoding/json" "errors" "time" "github.com/google/uuid" "gorm.io/gorm" ) type NotificationPriority string type NotificationDeliveryStatus string type NotificationChannel string type NotificationProvider string const ( NotificationPriorityLow NotificationPriority = "low" NotificationPriorityNormal NotificationPriority = "normal" NotificationPriorityHigh NotificationPriority = "high" NotificationDeliveryStatusPending NotificationDeliveryStatus = "pending" NotificationDeliveryStatusSent NotificationDeliveryStatus = "sent" NotificationDeliveryStatusDelivered NotificationDeliveryStatus = "delivered" NotificationDeliveryStatusFailed NotificationDeliveryStatus = "failed" NotificationChannelPush NotificationChannel = "push" NotificationChannelWebsocket NotificationChannel = "websocket" NotificationChannelEmail NotificationChannel = "email" NotificationProviderFirebase NotificationProvider = "firebase" ) // NotificationData is a JSON-serializable map for extra notification payload. type NotificationData map[string]interface{} func (d NotificationData) Value() (driver.Value, error) { if d == nil { return nil, nil } return json.Marshal(d) } func (d *NotificationData) Scan(value interface{}) error { if value == nil { *d = nil return nil } bytes, ok := value.([]byte) if !ok { return errors.New("type assertion to []byte failed") } return json.Unmarshal(bytes, d) } // Notification is the master notification record. type Notification struct { ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"` Title string `gorm:"not null;size:255" json:"title"` Body string `gorm:"type:text" json:"body"` Type string `gorm:"size:100" json:"type"` Category string `gorm:"size:100" json:"category"` Priority NotificationPriority `gorm:"size:50;default:'normal'" json:"priority"` ImageURL string `gorm:"size:512" json:"image_url"` ActionURL string `gorm:"size:512" json:"action_url"` NotifiableType string `gorm:"size:100" json:"notifiable_type"` NotifiableID *uuid.UUID `gorm:"type:uuid" json:"notifiable_id"` Data NotificationData `gorm:"type:jsonb" json:"data"` ScheduledAt *time.Time `gorm:"type:timestamptz" json:"scheduled_at"` SentAt *time.Time `gorm:"type:timestamptz" json:"sent_at"` ExpiredAt *time.Time `gorm:"type:timestamptz" json:"expired_at"` CreatedBy *uuid.UUID `gorm:"type:uuid" json:"created_by"` CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"` Creator *User `gorm:"foreignKey:CreatedBy" json:"creator,omitempty"` Receivers []*NotificationReceiver `gorm:"foreignKey:NotificationID" json:"receivers,omitempty"` } func (n *Notification) BeforeCreate(tx *gorm.DB) error { if n.ID == uuid.Nil { n.ID = uuid.New() } return nil } func (Notification) TableName() string { return "notifications" } // NotificationReceiver links a notification to a specific user. type NotificationReceiver struct { ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"` NotificationID uuid.UUID `gorm:"type:uuid;not null;index" json:"notification_id"` UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"` IsRead bool `gorm:"default:false" json:"is_read"` ReadAt *time.Time `gorm:"type:timestamptz" json:"read_at"` IsDeleted bool `gorm:"default:false" json:"is_deleted"` DeletedAt *time.Time `gorm:"type:timestamptz" json:"deleted_at"` CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"` Notification *Notification `gorm:"foreignKey:NotificationID" json:"notification,omitempty"` User *User `gorm:"foreignKey:UserID" json:"user,omitempty"` Deliveries []*NotificationDelivery `gorm:"foreignKey:NotificationReceiverID" json:"deliveries,omitempty"` } func (n *NotificationReceiver) BeforeCreate(tx *gorm.DB) error { if n.ID == uuid.Nil { n.ID = uuid.New() } return nil } func (NotificationReceiver) TableName() string { return "notification_receivers" } // NotificationDelivery tracks per-device delivery attempts. type NotificationDelivery struct { ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"` NotificationReceiverID uuid.UUID `gorm:"type:uuid;not null;index" json:"notification_receiver_id"` UserDeviceID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_device_id"` Channel NotificationChannel `gorm:"size:50;default:'push'" json:"channel"` DeliveryStatus NotificationDeliveryStatus `gorm:"size:50;default:'pending'" json:"delivery_status"` Provider NotificationProvider `gorm:"size:50" json:"provider"` ProviderMessageID string `gorm:"size:255" json:"provider_message_id"` SentAt *time.Time `gorm:"type:timestamptz" json:"sent_at"` DeliveredAt *time.Time `gorm:"type:timestamptz" json:"delivered_at"` FailedAt *time.Time `gorm:"type:timestamptz" json:"failed_at"` FailureReason string `gorm:"type:text" json:"failure_reason"` RetryCount int `gorm:"default:0" json:"retry_count"` CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"` NotificationReceiver *NotificationReceiver `gorm:"foreignKey:NotificationReceiverID" json:"notification_receiver,omitempty"` UserDevice *UserDevice `gorm:"foreignKey:UserDeviceID" json:"user_device,omitempty"` } func (n *NotificationDelivery) BeforeCreate(tx *gorm.DB) error { if n.ID == uuid.Nil { n.ID = uuid.New() } return nil } func (NotificationDelivery) TableName() string { return "notification_deliveries" }