package bossraid import ( "errors" "time" "gorm.io/gorm" ) // ErrStatusConflict indicates that a room's status was already changed by another request. var ErrStatusConflict = errors.New("방 상태가 이미 변경되었습니다") type RoomStatus string const ( StatusWaiting RoomStatus = "waiting" StatusInProgress RoomStatus = "in_progress" StatusCompleted RoomStatus = "completed" StatusFailed RoomStatus = "failed" StatusRewardFailed RoomStatus = "reward_failed" ) // BossRoom represents a boss raid session room. type BossRoom struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"createdAt" gorm:"index"` UpdatedAt time.Time `json:"updatedAt"` DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` SessionName string `json:"sessionName" gorm:"type:varchar(100);uniqueIndex;not null"` BossID int `json:"bossId" gorm:"index;not null"` Status RoomStatus `json:"status" gorm:"type:varchar(20);index;default:waiting;not null"` MaxPlayers int `json:"maxPlayers" gorm:"default:3;not null"` // Players is stored as a JSON text column for simplicity. // TODO: For better query performance, consider migrating to a junction table // (boss_room_players with room_id + username columns). Players string `json:"players" gorm:"type:text"` // JSON array of usernames StartedAt *time.Time `json:"startedAt,omitempty"` CompletedAt *time.Time `json:"completedAt,omitempty"` } // SlotStatus represents the status of a dedicated server room slot. type SlotStatus string const ( SlotIdle SlotStatus = "idle" SlotWaiting SlotStatus = "waiting" SlotInProgress SlotStatus = "in_progress" ) // DedicatedServer represents a server group (e.g., "Dedi1"). // Multiple containers (replicas) share the same server group name. type DedicatedServer struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` ServerName string `json:"serverName" gorm:"type:varchar(100);uniqueIndex;not null"` MaxRooms int `json:"maxRooms" gorm:"default:10;not null"` } // RoomSlot represents a room slot on a dedicated server. // Each slot has a stable session name that the Fusion NetworkRunner uses. // InstanceID tracks which container process currently owns this slot. type RoomSlot struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` DedicatedServerID uint `json:"dedicatedServerId" gorm:"index;uniqueIndex:idx_server_slot;not null"` SlotIndex int `json:"slotIndex" gorm:"uniqueIndex:idx_server_slot;not null"` SessionName string `json:"sessionName" gorm:"type:varchar(100);uniqueIndex;not null"` Status SlotStatus `json:"status" gorm:"type:varchar(20);index;default:idle;not null"` BossRoomID *uint `json:"bossRoomId" gorm:"index"` InstanceID string `json:"instanceId" gorm:"type:varchar(100);index"` LastHeartbeat *time.Time `json:"lastHeartbeat"` } // RewardFailure records a failed reward grant for later retry. // A record is "pending" when ResolvedAt is nil and RetryCount < maxRetries (10). type RewardFailure struct { ID uint `json:"id" gorm:"primaryKey"` CreatedAt time.Time `json:"createdAt" gorm:"index"` SessionName string `json:"sessionName" gorm:"type:varchar(100);index;not null"` Username string `json:"username" gorm:"type:varchar(100);index;not null"` TokenAmount uint64 `json:"tokenAmount" gorm:"not null"` Assets string `json:"assets" gorm:"type:text"` Experience int `json:"experience" gorm:"default:0;not null"` Error string `json:"error" gorm:"type:text"` RetryCount int `json:"retryCount" gorm:"default:0;not null"` LastTxID string `json:"lastTxId" gorm:"type:varchar(100)"` // 마지막 시도한 블록체인 트랜잭션 ID (이중 지급 방지용) ResolvedAt *time.Time `json:"resolvedAt" gorm:"index"` }