// Package store is a stand-in for the real Postgres-backed tenant store. // The skeleton ships an in-memory implementation pre-seeded with one tenant // (acme) so portal middleware has something to resolve in local dev. // Replace with a pgx-backed implementation in the M4.1 follow-up PR. package store import ( "context" "errors" "sync" "time" ) var ErrNotFound = errors.New("tenant not found") type Tenant struct { ID string `json:"id"` Slug string `json:"slug"` Name string `json:"name"` Status string `json:"status"` // active | trial | frozen | archived | demo Plan string `json:"plan"` // starter | professional | enterprise Products []string `json:"products"` CreatedAt time.Time `json:"created_at"` } type Memory struct { mu sync.RWMutex bySlug map[string]*Tenant byID map[string]*Tenant } func NewMemory() *Memory { m := &Memory{ bySlug: make(map[string]*Tenant), byID: make(map[string]*Tenant), } seed := &Tenant{ ID: "00000000-0000-0000-0000-000000000001", Slug: "acme", Name: "Acme Inc.", Status: "active", Plan: "professional", Products: []string{"certifai", "compliance"}, CreatedAt: time.Now().UTC(), } m.bySlug[seed.Slug] = seed m.byID[seed.ID] = seed return m } func (m *Memory) BySlug(_ context.Context, slug string) (*Tenant, error) { m.mu.RLock() defer m.mu.RUnlock() t, ok := m.bySlug[slug] if !ok { return nil, ErrNotFound } cp := *t return &cp, nil } func (m *Memory) ByID(_ context.Context, id string) (*Tenant, error) { m.mu.RLock() defer m.mu.RUnlock() t, ok := m.byID[id] if !ok { return nil, ErrNotFound } cp := *t return &cp, nil }