// Package demos : cœur métier — cycle de vie des démos client déployées // dans le cluster (une démo = un namespace isolé, TTL 30 jours). package demos import "time" // Paramètres capacité / durée de vie. const ( TTL = 30 * 24 * time.Hour // durée de vie d'une démo MaxConcurrentDemos = 5 // capacité cible PoolSizePerService = 5 // slots par service externe poolé ) // Services externes gérés par pool pré-provisionné (non auto-créables par API). // TomTom n'y figure pas : ses clés sont créées à la volée par le worker. const ( ServiceTelegram = "telegram" ServiceNowPayments = "nowpayments" ) // PooledServices : services nécessitant un slot de pool par démo. var PooledServices = []string{ServiceTelegram, ServiceNowPayments} // Status : état d'une démo. type Status string const ( StatusPending Status = "pending" // créée, pas encore prise par le worker StatusProvisioning Status = "provisioning" // worker en train de déployer StatusReady Status = "ready" // démo accessible StatusExpiring Status = "expiring" // teardown en cours StatusExpired Status = "expired" // détruite / TTL atteint StatusFailed Status = "failed" // échec de provisioning ) func (s Status) Valid() bool { switch s { case StatusPending, StatusProvisioning, StatusReady, StatusExpiring, StatusExpired, StatusFailed: return true } return false } // Active indique si la démo occupe des ressources (compte dans la capacité). func (s Status) Active() bool { switch s { case StatusPending, StatusProvisioning, StatusReady, StatusExpiring: return true } return false } // Extendable : on ne prolonge que des démos encore vivantes. func (s Status) Extendable() bool { switch s { case StatusProvisioning, StatusReady: return true } return false } // Demo : modèle GORM d'une démo. type Demo struct { ID string `gorm:"type:uuid;primaryKey" json:"id"` Username string `gorm:"type:varchar(64);index" json:"username,omitempty"` LeadID string `gorm:"type:varchar(36);index" json:"lead_id,omitempty"` Status Status `gorm:"size:20;not null;index" json:"status"` Namespace string `gorm:"size:63;uniqueIndex" json:"namespace"` URL string `gorm:"size:255" json:"url"` TypeAbo string `gorm:"type:varchar(35)" json:"type_abonnement"` CreatedAt time.Time `json:"created_at"` ExpiresAt time.Time `json:"expires_at"` } func (Demo) TableName() string { return "demos" } // ResourceStatus : état d'un slot de pool. type ResourceStatus string const ( ResourceFree ResourceStatus = "free" ResourceBorrowed ResourceStatus = "borrowed" ) // ExternalResource : slot pré-provisionné (table external_pool). // On stocke une *référence* au secret (SecretRef), jamais le secret en clair. type ExternalResource struct { ID uint `gorm:"primaryKey" json:"id"` Service string `gorm:"size:20;not null;index:idx_service_status" json:"service"` Label string `gorm:"size:120" json:"label"` // ex. "@omnex_demo_bot_1" SecretRef string `gorm:"size:200;not null" json:"-"` // clé dans le secret manager Status ResourceStatus `gorm:"size:20;not null;index:idx_service_status" json:"status"` DemoID string `gorm:"type:varchar(36);index" json:"demo_id,omitempty"` // FK optionnelle (vide si libre) } func (ExternalResource) TableName() string { return "external_pool" }