veza/veza-backend-api/internal/models/chat_message.go
senke d3e3ba9b33 feat(chat): Redis rate limiter, persistent presence, PostgreSQL full-text search
- Rewrite chat rate limiter with Redis sliding window (sorted sets) and
  automatic in-memory fallback when Redis is unavailable
- Add ChatPresenceService with Redis-backed online/offline/heartbeat
  tracking (2min TTL), integrated into Hub register/unregister
- Add migration 113: tsvector column with GIN index and auto-update
  trigger on messages table for full-text search
- Update Search repository method to use ts_rank ordering instead of ILIKE
- Wire Redis client into chat WebSocket setup in router.go
- Add comprehensive tests: rate limiter, presence, 100-user concurrent benchmark
2026-02-22 21:17:51 +01:00

30 lines
1.4 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
)
type ChatMessage struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
ConversationID uuid.UUID `gorm:"column:room_id;type:uuid;not null" json:"conversation_id"`
SenderID uuid.UUID `gorm:"type:uuid;not null" json:"sender_id"`
Content string `gorm:"type:text;not null" json:"content"`
MessageType string `gorm:"type:varchar(50);not null" json:"message_type"` // text, image, audio, etc.
ParentMessageID *uuid.UUID `gorm:"type:uuid" json:"parent_message_id,omitempty"`
ReplyToID *uuid.UUID `gorm:"type:uuid" json:"reply_to_id,omitempty"`
IsPinned bool `gorm:"default:false;not null" json:"is_pinned"`
IsEdited bool `gorm:"default:false;not null" json:"is_edited"`
IsDeleted bool `gorm:"default:false;not null" json:"is_deleted"`
EditedAt *time.Time `json:"edited_at,omitempty"`
Status string `gorm:"type:varchar(50);not null" json:"status"` // sent, delivered, read
Metadata []byte `gorm:"type:jsonb" json:"metadata,omitempty"` // JSONB for additional data
ContentTsv *string `gorm:"type:tsvector;->" json:"-"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
func (ChatMessage) TableName() string {
return "messages" // Rust uses 'messages' table
}