// Package leads : gestion des prospects (feature "leads" du back-office). package leads import ( "sync" "time" "github.com/google/uuid" ) type Status string const ( StatusNew Status = "new" StatusContacted Status = "contacted" StatusDemo Status = "demo" StatusWon Status = "won" StatusLost Status = "lost" ) func (s Status) Valid() bool { switch s { case StatusNew, StatusContacted, StatusDemo, StatusWon, StatusLost: return true } return false } // Lead : prospect. Modèle GORM. type Lead struct { ID string `gorm:"type:uuid;primaryKey" json:"id"` Telegram string `gorm:"size:120;not null" json:"telegram"` Message *string `gorm:"size:2000" json:"message"` Status Status `gorm:"size:20;not null;index" json:"status"` CreatedAt time.Time `json:"created_at"` } // TableName force le nom de table. func (Lead) TableName() string { return "leads" } // Store : persistance des leads. Impl mémoire ici, Postgres plus tard. type Store interface { Create(l Lead) (Lead, error) List() ([]Lead, error) Get(id string) (Lead, bool) SetStatus(id string, s Status) (Lead, bool) } // MemStore : implémentation en mémoire (dev/tests). type MemStore struct { mu sync.RWMutex items map[string]Lead } func NewMemStore() *MemStore { return &MemStore{items: make(map[string]Lead)} } func (m *MemStore) Create(l Lead) (Lead, error) { m.mu.Lock() defer m.mu.Unlock() l.ID = uuid.NewString() l.Status = StatusNew l.CreatedAt = time.Now().UTC() m.items[l.ID] = l return l, nil } func (m *MemStore) List() ([]Lead, error) { m.mu.RLock() defer m.mu.RUnlock() out := make([]Lead, 0, len(m.items)) for _, l := range m.items { out = append(out, l) } return out, nil } func (m *MemStore) Get(id string) (Lead, bool) { m.mu.RLock() defer m.mu.RUnlock() l, ok := m.items[id] return l, ok } func (m *MemStore) SetStatus(id string, s Status) (Lead, bool) { m.mu.Lock() defer m.mu.Unlock() l, ok := m.items[id] if !ok { return Lead{}, false } l.Status = s m.items[id] = l return l, true }