Changeset 0.9.0 (#50)
This commit is contained in:
296
server/store/interfaces.go
Normal file
296
server/store/interfaces.go
Normal file
@@ -0,0 +1,296 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
)
|
||||
|
||||
// =========================================
|
||||
// STORES — Data Access Layer
|
||||
// =========================================
|
||||
// Every database operation goes through these interfaces.
|
||||
// Handlers never touch SQL directly. This makes the DB
|
||||
// portable (Postgres today, SQLite/MySQL later) and
|
||||
// handlers testable with in-memory implementations.
|
||||
// =========================================
|
||||
|
||||
// Stores bundles all store interfaces for dependency injection.
|
||||
type Stores struct {
|
||||
Providers ProviderStore
|
||||
Catalog CatalogStore
|
||||
Personas PersonaStore
|
||||
Policies PolicyStore
|
||||
UserSettings UserModelSettingsStore
|
||||
Users UserStore
|
||||
Teams TeamStore
|
||||
Channels ChannelStore
|
||||
Messages MessageStore
|
||||
Audit AuditStore
|
||||
Notes NoteStore
|
||||
GlobalConfig GlobalConfigStore
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// PROVIDER STORE
|
||||
// =========================================
|
||||
|
||||
type ProviderStore interface {
|
||||
Create(ctx context.Context, cfg *models.ProviderConfig) error
|
||||
GetByID(ctx context.Context, id string) (*models.ProviderConfig, error)
|
||||
Update(ctx context.Context, id string, patch models.ProviderConfigPatch) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
|
||||
// Scoped queries
|
||||
ListGlobal(ctx context.Context) ([]models.ProviderConfig, error)
|
||||
ListForTeam(ctx context.Context, teamID string) ([]models.ProviderConfig, error)
|
||||
ListForUser(ctx context.Context, userID string) ([]models.ProviderConfig, error) // personal scope
|
||||
ListAccessible(ctx context.Context, userID string) ([]models.ProviderConfig, error) // all user can access
|
||||
|
||||
// Access check
|
||||
UserCanAccess(ctx context.Context, userID, configID string) (bool, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CATALOG STORE
|
||||
// =========================================
|
||||
|
||||
type CatalogStore interface {
|
||||
// Sync from provider API
|
||||
UpsertFromSync(ctx context.Context, providerConfigID string, entries []CatalogSyncEntry) (added, updated int, err error)
|
||||
|
||||
// Queries
|
||||
GetByID(ctx context.Context, id string) (*models.CatalogEntry, error)
|
||||
GetByModelID(ctx context.Context, providerConfigID, modelID string) (*models.CatalogEntry, error)
|
||||
GetByModelIDAny(ctx context.Context, modelID string) (*models.CatalogEntry, error) // any provider, most recently synced
|
||||
ListVisible(ctx context.Context) ([]models.CatalogEntry, error)
|
||||
ListEnabledForProvider(ctx context.Context, providerConfigID string) ([]models.CatalogEntry, error)
|
||||
ListForProvider(ctx context.Context, providerConfigID string) ([]models.CatalogEntry, error)
|
||||
ListAll(ctx context.Context) ([]models.CatalogEntry, error) // admin view
|
||||
|
||||
// Visibility management
|
||||
SetVisibility(ctx context.Context, id string, visibility string) error
|
||||
BulkSetVisibility(ctx context.Context, providerConfigID string, visibility string) error
|
||||
BulkSetVisibilityAll(ctx context.Context, visibility string) error
|
||||
|
||||
// Delete
|
||||
Delete(ctx context.Context, id string) error
|
||||
DeleteForProvider(ctx context.Context, providerConfigID string) error
|
||||
}
|
||||
|
||||
// CatalogSyncEntry is the input format from provider FetchModels.
|
||||
type CatalogSyncEntry struct {
|
||||
ModelID string
|
||||
DisplayName string
|
||||
Capabilities models.ModelCapabilities
|
||||
Pricing *models.ModelPricing
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// PERSONA STORE
|
||||
// =========================================
|
||||
|
||||
type PersonaStore interface {
|
||||
Create(ctx context.Context, p *models.Persona) error
|
||||
GetByID(ctx context.Context, id string) (*models.Persona, error)
|
||||
Update(ctx context.Context, id string, patch models.PersonaPatch) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
|
||||
// Scoped queries
|
||||
ListForUser(ctx context.Context, userID string) ([]models.Persona, error) // all visible to user
|
||||
ListForTeam(ctx context.Context, teamID string) ([]models.Persona, error)
|
||||
ListGlobal(ctx context.Context) ([]models.Persona, error)
|
||||
ListPersonal(ctx context.Context, userID string) ([]models.Persona, error) // user's own
|
||||
|
||||
// Grants
|
||||
SetGrants(ctx context.Context, personaID string, grants []models.Grant) error
|
||||
GetGrants(ctx context.Context, personaID string) ([]models.Grant, error)
|
||||
GetToolGrants(ctx context.Context, personaID string) ([]string, error)
|
||||
|
||||
// Access check
|
||||
UserCanAccess(ctx context.Context, userID, personaID string) (bool, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// POLICY STORE
|
||||
// =========================================
|
||||
|
||||
type PolicyStore interface {
|
||||
Get(ctx context.Context, key string) (string, error)
|
||||
GetBool(ctx context.Context, key string) (bool, error)
|
||||
Set(ctx context.Context, key, value string, updatedBy string) error
|
||||
GetAll(ctx context.Context) (map[string]string, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// USER MODEL SETTINGS STORE
|
||||
// =========================================
|
||||
|
||||
type UserModelSettingsStore interface {
|
||||
GetForUser(ctx context.Context, userID string) ([]models.UserModelSetting, error)
|
||||
GetHiddenModelIDs(ctx context.Context, userID string) (map[string]bool, error)
|
||||
Set(ctx context.Context, userID, modelID string, patch models.UserModelSettingPatch) error
|
||||
BulkSetHidden(ctx context.Context, userID string, modelIDs []string, hidden bool) error
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// USER STORE
|
||||
// =========================================
|
||||
|
||||
type UserStore interface {
|
||||
Create(ctx context.Context, u *models.User) error
|
||||
GetByID(ctx context.Context, id string) (*models.User, error)
|
||||
GetByUsername(ctx context.Context, username string) (*models.User, error)
|
||||
GetByEmail(ctx context.Context, email string) (*models.User, error)
|
||||
GetByLogin(ctx context.Context, login string) (*models.User, error) // username or email
|
||||
Update(ctx context.Context, id string, fields map[string]interface{}) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
List(ctx context.Context, opts ListOptions) ([]models.User, int, error)
|
||||
UpdateLastLogin(ctx context.Context, id string) error
|
||||
SetActive(ctx context.Context, id string, active bool) error
|
||||
|
||||
// Refresh tokens
|
||||
CreateRefreshToken(ctx context.Context, userID, tokenHash string, expiresAt time.Time) error
|
||||
GetRefreshToken(ctx context.Context, tokenHash string) (userID string, err error)
|
||||
RevokeRefreshToken(ctx context.Context, tokenHash string) error
|
||||
RevokeAllRefreshTokens(ctx context.Context, userID string) error
|
||||
CleanExpiredTokens(ctx context.Context) error
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// TEAM STORE
|
||||
// =========================================
|
||||
|
||||
type TeamStore interface {
|
||||
Create(ctx context.Context, t *models.Team) error
|
||||
GetByID(ctx context.Context, id string) (*models.Team, error)
|
||||
Update(ctx context.Context, id string, fields map[string]interface{}) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
List(ctx context.Context) ([]models.Team, error)
|
||||
|
||||
// Members
|
||||
AddMember(ctx context.Context, teamID, userID, role string) error
|
||||
RemoveMember(ctx context.Context, teamID, userID string) error
|
||||
UpdateMemberRole(ctx context.Context, teamID, userID, role string) error
|
||||
ListMembers(ctx context.Context, teamID string) ([]models.TeamMember, error)
|
||||
GetMember(ctx context.Context, teamID, userID string) (*models.TeamMember, error)
|
||||
GetUserTeamIDs(ctx context.Context, userID string) ([]string, error)
|
||||
IsTeamAdmin(ctx context.Context, teamID, userID string) (bool, error)
|
||||
IsMember(ctx context.Context, teamID, userID string) (bool, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CHANNEL STORE
|
||||
// =========================================
|
||||
|
||||
type ChannelStore interface {
|
||||
Create(ctx context.Context, ch *models.Channel) error
|
||||
GetByID(ctx context.Context, id string) (*models.Channel, error)
|
||||
Update(ctx context.Context, id string, fields map[string]interface{}) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
ListForUser(ctx context.Context, userID string, opts ListOptions) ([]models.Channel, int, error)
|
||||
Search(ctx context.Context, userID, query string, opts ListOptions) ([]models.Channel, int, error)
|
||||
|
||||
// Cursor management (conversation forking)
|
||||
GetCursor(ctx context.Context, channelID, userID string) (*models.ChannelCursor, error)
|
||||
SetCursor(ctx context.Context, channelID, userID, leafID string) error
|
||||
|
||||
// Channel models
|
||||
SetModel(ctx context.Context, cm *models.ChannelModel) error
|
||||
GetModels(ctx context.Context, channelID string) ([]models.ChannelModel, error)
|
||||
|
||||
// Ownership check
|
||||
UserOwns(ctx context.Context, channelID, userID string) (bool, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// MESSAGE STORE
|
||||
// =========================================
|
||||
|
||||
type MessageStore interface {
|
||||
Create(ctx context.Context, m *models.Message) error
|
||||
GetByID(ctx context.Context, id string) (*models.Message, error)
|
||||
Update(ctx context.Context, id string, fields map[string]interface{}) error
|
||||
Delete(ctx context.Context, id string) error // soft delete
|
||||
ListForChannel(ctx context.Context, channelID string, opts ListOptions) ([]models.Message, error)
|
||||
|
||||
// Tree operations
|
||||
GetChildren(ctx context.Context, parentID string) ([]models.Message, error)
|
||||
GetSiblings(ctx context.Context, messageID string) ([]models.Message, error)
|
||||
GetPathToRoot(ctx context.Context, messageID string) ([]models.Message, error)
|
||||
GetNextSiblingIndex(ctx context.Context, parentID string) (int, error)
|
||||
|
||||
// Count
|
||||
CountForChannel(ctx context.Context, channelID string) (int, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// AUDIT STORE
|
||||
// =========================================
|
||||
|
||||
type AuditStore interface {
|
||||
Log(ctx context.Context, entry *models.AuditEntry) error
|
||||
List(ctx context.Context, opts AuditListOptions) ([]models.AuditEntry, int, error)
|
||||
}
|
||||
|
||||
type AuditListOptions struct {
|
||||
ListOptions
|
||||
ActorID string
|
||||
Action string
|
||||
ResourceType string
|
||||
ResourceID string
|
||||
Since *time.Time
|
||||
Until *time.Time
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// NOTE STORE
|
||||
// =========================================
|
||||
|
||||
type NoteStore interface {
|
||||
Create(ctx context.Context, n *models.Note) error
|
||||
GetByID(ctx context.Context, id string) (*models.Note, error)
|
||||
Update(ctx context.Context, id string, fields map[string]interface{}) error
|
||||
Delete(ctx context.Context, id string) error
|
||||
ListForUser(ctx context.Context, userID string, opts NoteListOptions) ([]models.Note, int, error)
|
||||
Search(ctx context.Context, userID, query string, opts ListOptions) ([]models.Note, int, error)
|
||||
BulkDelete(ctx context.Context, ids []string, userID string) (int, error)
|
||||
}
|
||||
|
||||
type NoteListOptions struct {
|
||||
ListOptions
|
||||
FolderPath string
|
||||
Tag string
|
||||
TeamID string
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// GLOBAL CONFIG STORE
|
||||
// =========================================
|
||||
|
||||
type GlobalConfigStore interface {
|
||||
Get(ctx context.Context, key string) (models.JSONMap, error)
|
||||
Set(ctx context.Context, key string, value models.JSONMap, updatedBy string) error
|
||||
GetAll(ctx context.Context) (map[string]models.JSONMap, error)
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// SHARED TYPES
|
||||
// =========================================
|
||||
|
||||
// ListOptions provides standard pagination/sort for list queries.
|
||||
type ListOptions struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Sort string // column name
|
||||
Order string // "asc" or "desc"
|
||||
}
|
||||
|
||||
// DefaultListOptions returns sensible defaults.
|
||||
func DefaultListOptions() ListOptions {
|
||||
return ListOptions{
|
||||
Limit: 50,
|
||||
Order: "desc",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user