Documentation
¶
Overview ¶
Package kc provides store interfaces for hexagonal architecture.
Each interface defines the contract that other packages depend on, allowing concrete implementations to be swapped (e.g., in-memory vs. SQLite vs. mock). Compile-time verification ensures the concrete types satisfy these interfaces.
Package kc — manager.go: Manager constructors only.
Anchor 6 PR 6.15 collapsed manager.go to the constructor surface. The Manager struct + sentinel errors + KiteSessionData alias moved to kc/manager_struct.go; Config moved to kc/config.go; KiteConnect moved to kc/kite_connect.go; truncKey moved to kc/internal/util/ (exported as util.Trunc at v0.1.1). The remaining pointers (// X lives in Y) are listed at the bottom of the file as a roadmap for new contributors.
Index ¶
- Constants
- Variables
- func ClientHintFromRequest(r *http.Request) string
- func DetectClientHint(userAgent, oauthClientName, mcpClientInfoName string) string
- func IsKiteTokenExpired(storedAt time.Time) bool
- func ToDomainSession(email string, entry *KiteTokenEntry) domain.Session
- type AdminAlertsRegistrarDeps
- type AdminMFRegistrarDeps
- type AdminNativeAlertsRegistrarDeps
- type AdminRiskRegistrarDeps
- type AdminTickerRegistrarDeps
- type AdminUserRegistrarDeps
- type AlertService
- func (as *AlertService) AlertDB() *alerts.DB
- func (as *AlertService) AlertEvaluator() *alerts.Evaluator
- func (as *AlertService) AlertStore() *alerts.Store
- func (as *AlertService) OwnsAlertDB() bool
- func (as *AlertService) PnLService() *alerts.PnLSnapshotService
- func (as *AlertService) SetPnLService(svc *alerts.PnLSnapshotService)
- func (as *AlertService) TelegramNotifier() *alerts.TelegramNotifier
- func (as *AlertService) TrailingStopManager() *alerts.TrailingStopManager
- type AlertServiceConfig
- type AlertStoreInterface
- type AppConfigProvider
- type AuditReader
- type AuditStoreInterface
- type AuditStoreProvider
- type AuditStreamer
- type AuditWriter
- type BillingStoreInterface
- type BillingStoreProvider
- type BrokerResolverProvider
- type BrokerServices
- func (b *BrokerServices) ForceInstrumentsUpdate() error
- func (b *BrokerServices) GetInstrumentsStats() instruments.UpdateStats
- func (b *BrokerServices) InstrumentsManager() InstrumentManagerInterface
- func (b *BrokerServices) InstrumentsManagerConcrete() *instruments.Manager
- func (b *BrokerServices) KiteClientFactory() KiteClientFactory
- func (b *BrokerServices) PaperEngine() PaperEngineInterface
- func (b *BrokerServices) PaperEngineConcrete() *papertrading.PaperEngine
- func (b *BrokerServices) RiskGuard() *riskguard.Guard
- func (b *BrokerServices) SetKiteClientFactory(f KiteClientFactory)
- func (b *BrokerServices) SetPaperEngine(e *papertrading.PaperEngine)
- func (b *BrokerServices) SetRiskGuard(guard *riskguard.Guard)
- func (b *BrokerServices) TickerService() TickerServiceInterface
- func (b *BrokerServices) TickerServiceConcrete() *ticker.Service
- func (b *BrokerServices) UpdateInstrumentsConfig(config *instruments.UpdateConfig)
- type BrowserOpener
- type CleanupHook
- type ClientHintResolver
- type CommandBusProvider
- type Config
- type CredentialService
- func (cs *CredentialService) BackfillRegistryFromCredentials()
- func (cs *CredentialService) GetAPIKeyForEmail(email string) string
- func (cs *CredentialService) GetAPISecretForEmail(email string) string
- func (cs *CredentialService) GetAccessTokenForEmail(email string) string
- func (cs *CredentialService) HasCachedToken(email string) bool
- func (cs *CredentialService) HasCredentials(email string) bool
- func (cs *CredentialService) HasGlobalCredentials() bool
- func (cs *CredentialService) HasPreAuth() bool
- func (cs *CredentialService) HasUserCredentials(email string) bool
- func (cs *CredentialService) IsTokenValid(email string) bool
- func (cs *CredentialService) QualifiesForTrading(email string) bool
- func (cs *CredentialService) ResolveCredentials(email string) (apiKey, apiSecret string, err error)
- type CredentialServiceConfig
- type CredentialStoreInterface
- type CredentialStoreProvider
- type EventDispatcherProvider
- type EventingService
- type FamilyService
- func (f *FamilyService) AdminEmailFn() func(string) string
- func (f *FamilyService) CanInvite(adminEmail string) (bool, int, int)
- func (f *FamilyService) ListMembers(adminEmail string) []*users.User
- func (f *FamilyService) MaxUsers(adminEmail string) int
- func (f *FamilyService) MemberCount(adminEmail string) int
- func (f *FamilyService) RemoveMember(adminEmail, memberEmail string) error
- type FamilyUserStore
- type FillWatcher
- type FillWatcherBroker
- type FillWatcherBrokerResolver
- type FillWatcherConfig
- type IdentityService
- type InstrumentManagerInterface
- type KiteClientFactory
- type KiteConnect
- type KiteCredentialEntry
- type KiteCredentialStore
- func (s *KiteCredentialStore) Count() int
- func (s *KiteCredentialStore) Delete(email string)
- func (s *KiteCredentialStore) Get(email string) (*KiteCredentialEntry, bool)
- func (s *KiteCredentialStore) GetSecretByAPIKey(apiKey string) (apiSecret string, ok bool)
- func (s *KiteCredentialStore) ListAll() []KiteCredentialSummary
- func (s *KiteCredentialStore) ListAllRaw() []RawCredentialEntry
- func (s *KiteCredentialStore) LoadFromDB() error
- func (s *KiteCredentialStore) OnTokenInvalidate(fn func(email string))
- func (s *KiteCredentialStore) Set(email string, entry *KiteCredentialEntry)
- func (s *KiteCredentialStore) SetDB(db *alerts.DB)
- func (s *KiteCredentialStore) SetLogger(logger *slog.Logger)
- type KiteCredentialSummary
- type KiteSessionData
- type KiteTokenEntry
- type KiteTokenStore
- func (s *KiteTokenStore) Count() int
- func (s *KiteTokenStore) Delete(email string)
- func (s *KiteTokenStore) Get(email string) (*KiteTokenEntry, bool)
- func (s *KiteTokenStore) ListAll() []KiteTokenSummary
- func (s *KiteTokenStore) LoadFromDB() error
- func (s *KiteTokenStore) OnChange(cb TokenChangeCallback)
- func (s *KiteTokenStore) Set(email string, entry *KiteTokenEntry)
- func (s *KiteTokenStore) SetDB(db *alerts.DB)
- func (s *KiteTokenStore) SetLogger(logger *slog.Logger)
- type KiteTokenSummary
- type MCPServerProvider
- type MCPSession
- type ManagedSessionService
- type Manager
- func (m *Manager) APIKey() string
- func (m *Manager) AdminSecretPath() string
- func (m *Manager) AlertDB() *alerts.DB
- func (m *Manager) AlertStore() AlertStoreInterface
- func (m *Manager) AlertStoreConcrete() *alerts.Store
- func (m *Manager) AuditStore() AuditStoreInterface
- func (m *Manager) AuditStoreConcrete() *audit.Store
- func (m *Manager) BillingStore() BillingStoreInterface
- func (m *Manager) BillingStoreConcrete() *billing.Store
- func (m *Manager) Brokers() *BrokerServices
- func (m *Manager) CleanupExpiredSessions() int
- func (m *Manager) ClearSession(sessionID string)
- func (m *Manager) ClearSessionData(sessionID string) error
- func (m *Manager) CommandBus() *cqrs.InMemoryBus
- func (m *Manager) CompleteSession(mcpSessionID, kiteRequestToken string) error
- func (m *Manager) CompleteSessionAndRotate(mcpSessionID, kiteRequestToken string) (string, error)
- func (m *Manager) CredentialStore() CredentialStoreInterface
- func (m *Manager) CredentialStoreConcrete() *KiteCredentialStore
- func (m *Manager) DevMode() bool
- func (m *Manager) EventDispatcher() *domain.EventDispatcher
- func (m *Manager) EventStoreConcrete() *eventsourcing.EventStore
- func (m *Manager) Eventing() *EventingService
- func (m *Manager) ExternalURL() string
- func (m *Manager) ForceInstrumentsUpdate() error
- func (m *Manager) GenerateSession() string
- func (m *Manager) GetAPIKeyForEmail(email string) string
- func (m *Manager) GetAPISecretForEmail(email string) string
- func (m *Manager) GetAccessTokenForEmail(email string) string
- func (m *Manager) GetActiveSessionCount() int
- func (m *Manager) GetBrokerForEmail(email string) (broker.Client, error)
- func (m *Manager) GetInstrumentsStats() instruments.UpdateStats
- func (m *Manager) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
- func (m *Manager) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
- func (m *Manager) GetSession(mcpSessionID string) (*KiteSessionData, error)
- func (m *Manager) HandleKiteCallback() func(w http.ResponseWriter, r *http.Request)
- func (m *Manager) HasBrokerFactory() bool
- func (m *Manager) HasCachedToken(email string) bool
- func (m *Manager) HasGlobalCredentials() bool
- func (m *Manager) HasMetrics() bool
- func (m *Manager) HasPreAuth() bool
- func (m *Manager) HasUserCredentials(email string) bool
- func (m *Manager) IncrementDailyMetric(key string)
- func (m *Manager) IncrementMetric(key string)
- func (m *Manager) InstrumentsManager() InstrumentManagerInterface
- func (m *Manager) InstrumentsManagerConcrete() *instruments.Manager
- func (m *Manager) InvitationStore() *users.InvitationStore
- func (m *Manager) IsLocalMode() bool
- func (m *Manager) IsTokenValid(email string) bool
- func (m *Manager) KiteClientFactory() KiteClientFactory
- func (m *Manager) MCPServer() any
- func (m *Manager) OpenBrowser(rawURL string) error
- func (m *Manager) PaperEngine() PaperEngineInterface
- func (m *Manager) PaperEngineConcrete() *papertrading.PaperEngine
- func (m *Manager) PnLService() *alerts.PnLSnapshotService
- func (m *Manager) QualifiesForTrading(email string) bool
- func (m *Manager) QueryBus() *cqrs.InMemoryBus
- func (m *Manager) RegistryStore() RegistryStoreInterface
- func (m *Manager) RegistryStoreConcrete() *registry.Store
- func (m *Manager) RiskGuard() *riskguard.Guard
- func (m *Manager) Scheduling() *SchedulingService
- func (m *Manager) SessionLifecycle() *SessionLifecycleService
- func (m *Manager) SessionLoginURL(mcpSessionID string) (string, error)
- func (m *Manager) SessionRegistry() *SessionRegistry
- func (m *Manager) SetAuditStore(store *audit.Store)
- func (m *Manager) SetBillingStore(store *billing.Store)
- func (m *Manager) SetEventDispatcher(d *domain.EventDispatcher)
- func (m *Manager) SetEventStore(s *eventsourcing.EventStore)
- func (m *Manager) SetFamilyService(fs *FamilyService)
- func (m *Manager) SetInvitationStore(store *users.InvitationStore)
- func (m *Manager) SetKiteClientFactory(f KiteClientFactory)
- func (m *Manager) SetMCPServer(srv any)
- func (m *Manager) SetPaperEngine(e *papertrading.PaperEngine)
- func (m *Manager) SetPnLService(svc *alerts.PnLSnapshotService)
- func (m *Manager) SetRiskGuard(guard *riskguard.Guard)
- func (m *Manager) Shutdown()
- func (m *Manager) StopCleanupRoutine()
- func (m *Manager) Stores() *StoreRegistry
- func (m *Manager) TelegramNotifier() *alerts.TelegramNotifier
- func (m *Manager) TelegramStore() TelegramStoreInterface
- func (m *Manager) TickerService() TickerServiceInterface
- func (m *Manager) TickerServiceConcrete() *ticker.Service
- func (m *Manager) TokenStore() TokenStoreInterface
- func (m *Manager) TokenStoreConcrete() *KiteTokenStore
- func (m *Manager) TrackDailyUser(userID string)
- func (m *Manager) TrailingStopManager() *alerts.TrailingStopManager
- func (m *Manager) UpdateInstrumentsConfig(config *instruments.UpdateConfig)
- func (m *Manager) UserStore() UserStoreInterface
- func (m *Manager) UserStoreConcrete() *users.Store
- func (m *Manager) WatchlistStore() WatchlistStoreInterface
- func (m *Manager) WatchlistStoreConcrete() *watchlist.Store
- type ManagerLifecycle
- type MetricsRecorder
- type OAuthBridgeRegistrarDeps
- type Option
- func WithAccessToken(token string) Option
- func WithAdminSecretPath(path string) Option
- func WithAlertDB(db *alerts.DB) Option
- func WithAlertDBPath(path string) Option
- func WithAppMode(mode string) Option
- func WithAuditStore(s *audit.Store) Option
- func WithBillingStore(s *billing.Store) Option
- func WithBotFactory(factory alerts.BotFactory) Option
- func WithConfig(cfg Config) Option
- func WithContext(ctx context.Context) Option
- func WithDevMode(enabled bool) Option
- func WithEncryptionSecret(secret string) Option
- func WithExternalURL(url string) Option
- func WithInstrumentsConfig(cfg *instruments.UpdateConfig) Option
- func WithInstrumentsManager(m *instruments.Manager) Option
- func WithInstrumentsSkipFetch(skip bool) Option
- func WithInvitationStore(s *users.InvitationStore) Option
- func WithKiteCredentials(apiKey, apiSecret string) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMetrics(m *metrics.Manager) Option
- func WithRiskGuard(g *riskguard.Guard) Option
- func WithSessionSigner(s *SessionSigner) Option
- func WithTelegramBotToken(token string) Option
- type OrderService
- func (os *OrderService) CancelOrder(email, orderID, variety string) (broker.OrderResponse, error)
- func (os *OrderService) GetOrders(email string) ([]broker.Order, error)
- func (os *OrderService) GetTrades(email string) ([]broker.Trade, error)
- func (os *OrderService) InitUseCases(riskGuard *riskguard.Guard, dispatcher *domain.EventDispatcher, ...)
- func (os *OrderService) ModifyOrder(email, orderID string, params broker.OrderParams) (broker.OrderResponse, error)
- func (os *OrderService) PlaceOrder(email string, params broker.OrderParams) (broker.OrderResponse, error)
- func (os *OrderService) PropagateDispatcher(d *domain.EventDispatcher)
- type PaperEngineInterface
- type PaperEngineProvider
- type PortfolioService
- func (ps *PortfolioService) GetHoldings(email string) ([]broker.Holding, error)
- func (ps *PortfolioService) GetMargins(email string) (broker.Margins, error)
- func (ps *PortfolioService) GetPositions(email string) (broker.Positions, error)
- func (ps *PortfolioService) GetProfile(email string) (broker.Profile, error)
- type QueryBusProvider
- type RawCredentialEntry
- type RegistryReader
- type RegistryStoreInterface
- type RegistryStoreProvider
- type RegistryWriter
- type RiskGuardProvider
- type SchedulingService
- func (s *SchedulingService) CleanupExpiredSessions() int
- func (s *SchedulingService) HasMetrics() bool
- func (s *SchedulingService) IncrementDailyMetric(key string)
- func (s *SchedulingService) IncrementMetric(key string)
- func (s *SchedulingService) StopCleanupRoutine()
- func (s *SchedulingService) TrackDailyUser(userID string)
- type SessionDB
- type SessionIdManagerShim
- type SessionLifecycleService
- func (s *SessionLifecycleService) ClearSession(sessionID string)
- func (s *SessionLifecycleService) ClearSessionData(sessionID string) error
- func (s *SessionLifecycleService) CompleteSession(mcpSessionID, kiteRequestToken string) error
- func (s *SessionLifecycleService) CompleteSessionAndRotate(mcpSessionID, kiteRequestToken string) (string, error)
- func (s *SessionLifecycleService) GenerateSession() string
- func (s *SessionLifecycleService) GetActiveSessionCount() int
- func (s *SessionLifecycleService) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
- func (s *SessionLifecycleService) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
- func (s *SessionLifecycleService) GetSession(mcpSessionID string) (*KiteSessionData, error)
- func (s *SessionLifecycleService) SessionLoginURL(mcpSessionID string) (string, error)
- type SessionLoadEntry
- type SessionRegistry
- func (sm *SessionRegistry) AddCleanupHook(hook CleanupHook)
- func (sm *SessionRegistry) CleanupExpiredSessions() int
- func (sm *SessionRegistry) Generate() string
- func (sm *SessionRegistry) GenerateWithData(data any) string
- func (sm *SessionRegistry) GenerateWithDataAndHint(data any, clientHint string) string
- func (sm *SessionRegistry) GetOrCreateSessionData(sessionID string, createDataFn func() any) (data any, isNew bool, err error)
- func (sm *SessionRegistry) GetSession(sessionID string) (*MCPSession, error)
- func (sm *SessionRegistry) GetSessionData(sessionID string) (any, error)
- func (sm *SessionRegistry) GetSessionDuration() time.Duration
- func (sm *SessionRegistry) ListActiveSessions() []*MCPSession
- func (sm *SessionRegistry) LoadFromDB() error
- func (sm *SessionRegistry) SetDB(db SessionDB)
- func (sm *SessionRegistry) SetSessionDuration(duration time.Duration)
- func (sm *SessionRegistry) StartCleanupRoutine(ctx context.Context)
- func (sm *SessionRegistry) StopCleanupRoutine()
- func (sm *SessionRegistry) Terminate(sessionID string) (isNotAllowed bool, err error)
- func (sm *SessionRegistry) TerminateByEmail(email string) int
- func (sm *SessionRegistry) UpdateSessionData(sessionID string, data any) error
- func (sm *SessionRegistry) UpdateSessionField(sessionID string, mutator func(data any)) error
- func (sm *SessionRegistry) Validate(sessionID string) (isTerminated bool, err error)
- type SessionService
- func (ss *SessionService) CleanupExpiredSessions() int
- func (ss *SessionService) ClearSession(sessionID string)
- func (ss *SessionService) ClearSessionData(sessionID string) error
- func (ss *SessionService) CompleteSession(mcpSessionID, kiteRequestToken string) error
- func (ss *SessionService) CompleteSessionAndRotate(mcpSessionID, kiteRequestToken string) (string, error)
- func (ss *SessionService) GenerateSession() string
- func (ss *SessionService) GetActiveSessionCount() int
- func (ss *SessionService) GetBrokerForEmail(email string) (broker.Client, error)
- func (ss *SessionService) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
- func (ss *SessionService) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
- func (ss *SessionService) GetSession(mcpSessionID string) (*KiteSessionData, error)
- func (ss *SessionService) HasBrokerFactory() bool
- func (ss *SessionService) InitializeSessionManager()
- func (ss *SessionService) SessionLoginURL(mcpSessionID string) (string, error)
- func (ss *SessionService) SessionManager() *SessionRegistry
- func (ss *SessionService) SetAuditStore(store AuditStoreInterface)
- func (ss *SessionService) SetBrokerFactory(f broker.Factory)
- func (ss *SessionService) SetEventDispatcher(d *domain.EventDispatcher)
- func (ss *SessionService) SetSessionManager(sm *SessionRegistry)
- func (ss *SessionService) StopCleanupRoutine()
- type SessionServiceConfig
- type SessionSigner
- func (s *SessionSigner) SetSignatureExpiry(duration time.Duration)
- func (s *SessionSigner) SignRedirectParams(sessionID string) (string, error)
- func (s *SessionSigner) SignSessionID(sessionID string) string
- func (s *SessionSigner) ValidateSessionID(sessionID string) error
- func (s *SessionSigner) VerifyRedirectParams(redirectParams string) (string, error)
- func (s *SessionSigner) VerifySessionID(signedParam string) (string, error)
- type StoreAccessor
- type StoreRegistry
- func (s *StoreRegistry) AlertDB() *alerts.DB
- func (s *StoreRegistry) AlertStore() AlertStoreInterface
- func (s *StoreRegistry) AlertStoreConcrete() *alerts.Store
- func (s *StoreRegistry) AuditStore() AuditStoreInterface
- func (s *StoreRegistry) AuditStoreConcrete() *audit.Store
- func (s *StoreRegistry) BillingStore() BillingStoreInterface
- func (s *StoreRegistry) BillingStoreConcrete() *billing.Store
- func (s *StoreRegistry) CredentialStore() CredentialStoreInterface
- func (s *StoreRegistry) CredentialStoreConcrete() *KiteCredentialStore
- func (s *StoreRegistry) InvitationStore() *users.InvitationStore
- func (s *StoreRegistry) RegistryStore() RegistryStoreInterface
- func (s *StoreRegistry) RegistryStoreConcrete() *registry.Store
- func (s *StoreRegistry) SetAuditStore(store *audit.Store)
- func (s *StoreRegistry) SetBillingStore(store *billing.Store)
- func (s *StoreRegistry) SetInvitationStore(store *users.InvitationStore)
- func (s *StoreRegistry) TelegramStore() TelegramStoreInterface
- func (s *StoreRegistry) TokenStore() TokenStoreInterface
- func (s *StoreRegistry) TokenStoreConcrete() *KiteTokenStore
- func (s *StoreRegistry) UserStore() UserStoreInterface
- func (s *StoreRegistry) UserStoreConcrete() *users.Store
- func (s *StoreRegistry) WatchlistStore() WatchlistStoreInterface
- func (s *StoreRegistry) WatchlistStoreConcrete() *watchlist.Store
- type TelegramStoreInterface
- type TelegramStoreProvider
- type TemplateData
- type TickerServiceInterface
- type TickerServiceProvider
- type TokenChangeCallback
- type TokenStoreInterface
- type TokenStoreProvider
- type UserAuthChecker
- type UserReader
- type UserStoreInterface
- type UserStoreProvider
- type UserWriter
- type WatchlistStoreInterface
- type WatchlistStoreProvider
Constants ¶
const ( HintClaudeDesktop = "claude-desktop" HintClaudeCode = "claude-code" HintClaudeWeb = "claude-web" HintCursor = "cursor" HintChatGPT = "chatgpt" HintVSCode = "vscode" HintMCPRemote = "mcp-remote" HintUnknown = "unknown" )
Known normalized hints. Keep this list in sync with the docstring on MCPSession.ClientHint and with any UI that filters/sums by hint.
const ( // Default session configuration DefaultSessionDuration = 12 * time.Hour DefaultCleanupInterval = 30 * time.Minute )
const ( // Default expiry for signed session parameters (30 minutes) DefaultSignatureExpiry = 30 * time.Minute // Maximum allowed clock skew for signature validation MaxClockSkew = 5 * time.Minute )
Variables ¶
var ( ErrSessionNotFound = errors.New("MCP session not found or Kite session not associated, try to login again") ErrInvalidSessionID = errors.New("invalid MCP session ID, please try logging in again") )
var ( ErrInvalidSignature = errors.New("invalid session signature") ErrTamperedSession = errors.New("session parameter has been tampered with") ErrExpiredSignature = errors.New("session signature has expired") ErrInvalidFormat = errors.New("invalid session parameter format") )
var ErrEmptySecretKey = errors.New("secret key cannot be empty")
ErrEmptySecretKey is returned when an empty secret key is provided.
var KolkataLocation = isttz.Location
KolkataLocation is the Asia/Kolkata timezone used throughout for IST operations. Delegates to kc/isttz which is a leaf package importable from anywhere.
Functions ¶
func ClientHintFromRequest ¶
ClientHintFromRequest extracts a normalized client hint from an HTTP request. Returns an empty string when the request is nil (e.g. when called from the mcp-go idle sweeper path), letting the caller fall back to its own default behavior.
When r is non-nil, this function always returns a non-empty hint (the normalized string "unknown" if no headers match).
func DetectClientHint ¶
DetectClientHint returns a normalized hint based on the three signals available at session creation time. See the package comment above for priority order.
Behavior:
- Tries userAgent first. If it matches a known pattern, that wins.
- Falls through to oauthClientName, then mcpClientInfoName.
- When nothing matches (or all inputs are empty), returns HintUnknown.
The function is deliberately permissive — it returns a value for every input, including empty strings, rather than signalling errors. Sessions without an identifiable client are reported as "unknown" rather than blocking the session from being created.
func IsKiteTokenExpired ¶
IsKiteTokenExpired checks if a Kite token stored at the given time has likely expired. Kite tokens expire daily around 6 AM IST.
Retained as the free-standing helper for callers that only have a storedAt timestamp (no email/token fields). For callers with a full KiteTokenEntry, prefer ToDomainSession(email, entry).IsExpired().
func ToDomainSession ¶
func ToDomainSession(email string, entry *KiteTokenEntry) domain.Session
ToDomainSession converts a KiteTokenEntry (+ email) into the rich domain Session entity. Converter boundary between the kc infrastructure type and the domain entity — kc retains zero knowledge of domain method bodies.
Types ¶
type AdminAlertsRegistrarDeps ¶
type AdminAlertsRegistrarDeps struct {
AlertStore *alerts.Store
InstrumentsGetter func() *instruments.Manager // for adminBatchInstrumentResolver
DispatcherGetter func() *domain.EventDispatcher
EventStoreGetter func() *eventsourcing.EventStore
}
type AdminMFRegistrarDeps ¶
type AdminMFRegistrarDeps struct {
SessionSvc *SessionService
DispatcherGetter func() *domain.EventDispatcher
EventStoreGetter func() *eventsourcing.EventStore
}
type AdminNativeAlertsRegistrarDeps ¶
type AdminNativeAlertsRegistrarDeps struct {
SessionSvc *SessionService
DispatcherGetter func() *domain.EventDispatcher
EventStoreGetter func() *eventsourcing.EventStore
}
AdminNativeAlertsRegistrarDeps holds the dependencies for native-alert admin commands (Place/Modify/Delete; 3 commands).
type AdminRiskRegistrarDeps ¶
type AdminRiskRegistrarDeps struct {
RiskGuardGetter func() *riskguard.Guard // required at command-dispatch time
}
type AdminTickerRegistrarDeps ¶
type AdminTickerRegistrarDeps struct {
TickerServiceGetter func() *ticker.Service // required at command-dispatch time
}
type AdminUserRegistrarDeps ¶
type AdminUserRegistrarDeps struct {
UserStore *users.Store
RiskGuardGetter func() *riskguard.Guard // may return nil; handler nil-safes
SessionManager *SessionRegistry // may be nil at very-minimal fixtures
DispatcherGetter func() *domain.EventDispatcher
}
AdminUserRegistrarDeps holds the dependencies for the user-lifecycle admin command handlers (suspend/activate/change-role). All deps default to closure-getters per the Tier 2.2 lesson (preserve laziness semantics at fixture-incomplete tests; eager dereference at registration time can change panic-reachability profiles).
type AlertService ¶
type AlertService struct {
// contains filtered or unexported fields
}
AlertService owns alert lifecycle: CRUD, evaluation, trailing stops, Telegram notifications, P&L snapshots, AND alert-DB lifecycle. Extracted from Manager as part of Clean Architecture / SOLID refactoring (Tier B Step 3 — alert subsystem bundle).
Tier B Step 3 absorbed the 6 raw alert fields that previously lived on Manager directly: alertStore, alertEvaluator, trailingStopMgr, telegramNotifier, alertDB, ownsAlertDB. AlertService is now the single source of truth for these; Manager keeps only a *AlertService pointer plus thin delegator methods on the Manager surface for backward compatibility with the ~60 call sites that read these fields.
Field-write protocol during Manager.NewWithOptions:
newEmptyManager constructs an empty AlertService up front. The init* phases (initAlertSystem, initPersistence, initTelegramNotifier, initAlertEvaluator, initTrailingStop) write into m.AlertSvc.<field> directly using same-package field access. After initFocusedServices the service is fully populated; consumer code reads via the accessor methods on either *AlertService or *Manager.
Lifecycle invariant preserved verbatim: Manager.Shutdown closes the alert DB iff ownsAlertDB == true (manager opened it via OpenDB rather than receiving it from cfg.AlertDB).
func NewAlertService ¶
func NewAlertService(cfg AlertServiceConfig) *AlertService
NewAlertService creates an AlertService from a pre-built dependency bundle. Retained for backward compatibility with the test sites in service_test.go.
func NewEmptyAlertService ¶ added in v0.1.4
func NewEmptyAlertService() *AlertService
NewEmptyAlertService allocates an AlertService with all fields zero. Used by newEmptyManager so the init* phases can populate fields in-place via same-package field access. Mirror of Step 2's OrderService pattern where the service is constructed before dependencies are wired.
func (*AlertService) AlertDB ¶ added in v0.1.4
func (as *AlertService) AlertDB() *alerts.DB
AlertDB returns the optional SQLite database used for persistence (nil when persistence is disabled or no DB path was configured).
func (*AlertService) AlertEvaluator ¶
func (as *AlertService) AlertEvaluator() *alerts.Evaluator
AlertEvaluator returns the tick-to-alert matcher.
func (*AlertService) AlertStore ¶
func (as *AlertService) AlertStore() *alerts.Store
AlertStore returns the per-user alert store (alert CRUD).
func (*AlertService) OwnsAlertDB ¶ added in v0.1.4
func (as *AlertService) OwnsAlertDB() bool
OwnsAlertDB reports whether this manager opened the alert DB itself (and therefore must Close it on shutdown). Returns false when the DB was supplied externally via Config.AlertDB.
func (*AlertService) PnLService ¶
func (as *AlertService) PnLService() *alerts.PnLSnapshotService
PnLService returns the P&L snapshot service (nil if not initialized).
func (*AlertService) SetPnLService ¶
func (as *AlertService) SetPnLService(svc *alerts.PnLSnapshotService)
SetPnLService sets the P&L snapshot service (called from app layer after initialization).
func (*AlertService) TelegramNotifier ¶
func (as *AlertService) TelegramNotifier() *alerts.TelegramNotifier
TelegramNotifier returns the Telegram alert sender (nil if not configured).
func (*AlertService) TrailingStopManager ¶
func (as *AlertService) TrailingStopManager() *alerts.TrailingStopManager
TrailingStopManager returns the trailing stop-loss manager.
type AlertServiceConfig ¶
type AlertServiceConfig struct {
AlertStore *alerts.Store
AlertEvaluator *alerts.Evaluator
TrailingStopMgr *alerts.TrailingStopManager
TelegramNotifier *alerts.TelegramNotifier
}
AlertServiceConfig holds dependencies for creating an AlertService via the legacy NewAlertService path. Retained for the two tests in service_test.go that construct an AlertService directly; production wiring uses NewEmptyAlertService + same-package field writes during the manager init phases.
type AlertStoreInterface ¶
type AlertStoreInterface = alerts.AlertStoreInterface
AlertStoreInterface is the per-user price-alert interface. Anchor 5 PR 5.2 relocated the canonical declaration to kc/alerts/store_interface.go (its owning package); this alias preserves the legacy `kc.AlertStoreInterface` reference path so the 11+ pre-existing reverse-dep call sites build unchanged. Type aliases are not new types — `kc.AlertStoreInterface` and `alerts.AlertStoreInterface` are interchangeable at every call site, including the compile-time satisfaction check below (`_ AlertStoreInterface = (*alerts.Store)(nil)`).
Wave B-2 PR 5.3 will rewrite kc/ports/alert.go to reference `alerts.AlertStoreInterface` directly so it can drop its kc-parent import; this alias remains as the long-tail backward-compatibility shim until call sites migrate.
type AppConfigProvider ¶
type AppConfigProvider interface {
// IsLocalMode returns true when running in STDIO mode.
IsLocalMode() bool
// DevMode returns true when the server runs with a mock broker.
DevMode() bool
// ExternalURL returns the configured external URL.
ExternalURL() string
// AdminSecretPath returns the configured admin secret path.
AdminSecretPath() string
// APIKey returns the global Kite API key.
APIKey() string
}
AppConfigProvider provides application-level configuration.
type AuditReader ¶
type AuditReader interface {
// List retrieves tool call records for a given email with filtering/pagination.
List(email string, opts audit.ListOptions) ([]*audit.ToolCall, int, error)
// ListOrders returns tool calls with order IDs for the given email.
ListOrders(email string, since time.Time) ([]*audit.ToolCall, error)
// GetOrderAttribution returns the decision trace for a given order.
GetOrderAttribution(email, orderID string) ([]*audit.ToolCall, error)
// GetStats returns aggregate stats for a given email since the given time.
// Optional category and errorsOnly filters scope the results.
GetStats(email string, since time.Time, category string, errorsOnly bool) (*audit.Stats, error)
// GetToolCounts returns tool_name -> count for the given email.
// Optional category and errorsOnly filters scope the results.
GetToolCounts(email string, since time.Time, category string, errorsOnly bool) (map[string]int, error)
// GetToolMetrics returns per-tool aggregate metrics since the given time.
GetToolMetrics(since time.Time) ([]audit.ToolMetric, error)
// GetGlobalStats returns aggregate stats across all users.
GetGlobalStats(since time.Time) (*audit.Stats, error)
// GetTopErrorUsers returns the top N users with the most errors since the given time.
GetTopErrorUsers(since time.Time, limit int) ([]audit.UserErrorCount, error)
// VerifyChain walks the hash chain and checks integrity.
VerifyChain() (*audit.ChainVerification, error)
}
AuditReader provides read and query operations for audit records.
type AuditStoreInterface ¶
type AuditStoreInterface interface {
AuditWriter
AuditReader
AuditStreamer
}
AuditStoreInterface defines operations for recording and querying MCP tool call audit records. Composed from focused sub-interfaces.
type AuditStoreProvider ¶
type AuditStoreProvider interface {
AuditStore() AuditStoreInterface
}
AuditStoreProvider exposes the audit trail store. Returns nil if disabled.
type AuditStreamer ¶
type AuditStreamer interface {
// AddActivityListener registers a listener for real-time activity streaming.
AddActivityListener(id string) chan *audit.ToolCall
// RemoveActivityListener unregisters and closes a listener.
RemoveActivityListener(id string)
}
AuditStreamer provides real-time activity streaming via listeners.
type AuditWriter ¶
type AuditWriter interface {
// EnqueueCtx adds a tool call to the async write buffer with a
// request context for trace correlation. SOLID 99→100 cleanup
// retired the legacy non-ctx Enqueue shim; consumers must thread
// ctx (or context.Background() for service-ctx callbacks).
EnqueueCtx(ctx context.Context, entry *audit.ToolCall)
// Record inserts a tool call synchronously.
Record(entry *audit.ToolCall) error
// DeleteOlderThan removes tool_calls older than the given time.
DeleteOlderThan(before time.Time) (int64, error)
}
AuditWriter provides write operations for audit records.
type BillingStoreInterface ¶
type BillingStoreInterface interface {
// GetTier returns the current billing tier for an email.
GetTier(email string) billing.Tier
// SetSubscription creates or updates a subscription.
SetSubscription(sub *billing.Subscription) error
// GetSubscription returns the subscription for an email, or nil.
GetSubscription(email string) *billing.Subscription
// GetEmailByCustomerID returns the email for a Stripe customer ID.
GetEmailByCustomerID(customerID string) string
// IsEventProcessed returns true if a webhook event has been handled.
IsEventProcessed(eventID string) bool
// MarkEventProcessed records that an event has been processed.
MarkEventProcessed(eventID, eventType string) error
// GetTierForUser returns the tier checking both direct subscription and admin linkage.
GetTierForUser(email string, adminEmailFn func(string) string) billing.Tier
}
BillingStoreInterface defines operations for managing user billing subscriptions and tier enforcement.
type BillingStoreProvider ¶
type BillingStoreProvider interface {
BillingStore() BillingStoreInterface
}
BillingStoreProvider exposes the billing store. Returns nil if disabled.
type BrokerResolverProvider ¶
type BrokerResolverProvider interface {
GetBrokerForEmail(email string) (broker.Client, error)
HasBrokerFactory() bool
}
BrokerResolverProvider exposes the broker-resolution surface that use cases and HTTP handlers need without forcing callers to reach for the full *SessionService. Anchor 6 PR 6.4 (per .research/anchor- 6-pr-6-4-broker-resolver-redesign.md commit a2a11db) narrowed the interface from a single SessionSvc() *SessionService method to the two methods consumers actually use:
- GetBrokerForEmail (4 callsites: mcp/ext_apps.go, kc/manager_commands_admin.go, app/wire.go via the FillWatcherResolverFromBroker constructor, plus in-package CQRS use-case constructors via this interface)
- HasBrokerFactory (1 callsite: app/http.go's auth-gate guard)
The narrower interface is satisfied by both *kc.SessionService (its existing methods) AND *kc.Manager (via the passthrough methods declared in kc/manager_accessors.go below). This dual- satisfaction lets PR 6.4 delete the Manager.SessionSvc() accessor while preserving the use-case-level BrokerResolver contract that kc/usecases/ports.go declares (one-method narrower port).
type BrokerServices ¶
type BrokerServices struct {
// contains filtered or unexported fields
}
BrokerServices groups broker-adjacent factories and subsystems: the Kite client factory, instruments manager, ticker service, paper trading engine, and risk guard. These previously lived as loose accessors on Manager.
Tier 1.1 (Path A.28 — kc-manager decomp design Tier-1.1): the back-pointer to *Manager has been replaced with closures over the underlying fields. Each method captures exactly the getter/setter pair it needs at construction time. Two consequences:
- The closures read the *current* field value at call time (the Manager-mutation-after-construction pattern still works), preserving observable behaviour identical to the prior `b.m.X` access.
- The struct no longer references *Manager at all, eliminating the cyclic-pointer architecture that the kc/ports invariant (assertions.go: "only ports imports kc, keeping the graph acyclic") would otherwise extend by example.
Empirically: 0 consumer signature changes outside this file. All external callers reach broker concerns via Manager-level delegators (m.RiskGuard, m.TickerService, etc.) which still exist below at lines covering "Manager-level delegators (moved from manager.go)". The delegators now invoke b.<method>() instead of b.m.<field>; same observable result.
func (*BrokerServices) ForceInstrumentsUpdate ¶
func (b *BrokerServices) ForceInstrumentsUpdate() error
ForceInstrumentsUpdate forces an immediate instruments update.
func (*BrokerServices) GetInstrumentsStats ¶
func (b *BrokerServices) GetInstrumentsStats() instruments.UpdateStats
GetInstrumentsStats returns current instruments update statistics.
func (*BrokerServices) InstrumentsManager ¶
func (b *BrokerServices) InstrumentsManager() InstrumentManagerInterface
InstrumentsManager returns the instruments manager.
func (*BrokerServices) InstrumentsManagerConcrete ¶
func (b *BrokerServices) InstrumentsManagerConcrete() *instruments.Manager
InstrumentsManagerConcrete returns the concrete instruments manager.
func (*BrokerServices) KiteClientFactory ¶
func (b *BrokerServices) KiteClientFactory() KiteClientFactory
KiteClientFactory returns the factory used to create zerodha.KiteSDK instances.
func (*BrokerServices) PaperEngine ¶
func (b *BrokerServices) PaperEngine() PaperEngineInterface
PaperEngine returns the paper trading engine, or nil if not configured.
func (*BrokerServices) PaperEngineConcrete ¶
func (b *BrokerServices) PaperEngineConcrete() *papertrading.PaperEngine
PaperEngineConcrete returns the concrete paper engine.
func (*BrokerServices) RiskGuard ¶
func (b *BrokerServices) RiskGuard() *riskguard.Guard
RiskGuard returns the riskguard instance, or nil if not configured.
func (*BrokerServices) SetKiteClientFactory ¶
func (b *BrokerServices) SetKiteClientFactory(f KiteClientFactory)
SetKiteClientFactory overrides the default factory. Intended for tests.
func (*BrokerServices) SetPaperEngine ¶
func (b *BrokerServices) SetPaperEngine(e *papertrading.PaperEngine)
SetPaperEngine sets the paper trading engine.
func (*BrokerServices) SetRiskGuard ¶
func (b *BrokerServices) SetRiskGuard(guard *riskguard.Guard)
SetRiskGuard sets the riskguard for financial safety controls.
func (*BrokerServices) TickerService ¶
func (b *BrokerServices) TickerService() TickerServiceInterface
TickerService returns the per-user WebSocket ticker service.
func (*BrokerServices) TickerServiceConcrete ¶
func (b *BrokerServices) TickerServiceConcrete() *ticker.Service
TickerServiceConcrete returns the concrete ticker service.
func (*BrokerServices) UpdateInstrumentsConfig ¶
func (b *BrokerServices) UpdateInstrumentsConfig(config *instruments.UpdateConfig)
UpdateInstrumentsConfig updates the instruments manager configuration.
type BrowserOpener ¶
BrowserOpener exposes the local-mode browser-open helper. Phase 3a Batch 2 narrow port for setup_tools.go (auto-open Kite login URL + dashboard URL on local STDIO runs). Hosted Fly.io callers depend on this being a no-op or returning an error — production safety.
type CleanupHook ¶
type CleanupHook func(session *MCPSession)
CleanupHook is called when a session is terminated or expires
type ClientHintResolver ¶
type ClientHintResolver struct {
// contains filtered or unexported fields
}
ClientHintResolver is a SessionIdManagerResolver that derives a ClientHint from each incoming HTTP request and records it on the MCPSession the library is about to generate.
func NewClientHintResolver ¶
func NewClientHintResolver(registry *SessionRegistry) *ClientHintResolver
NewClientHintResolver constructs a resolver backed by the given registry.
func (*ClientHintResolver) ResolveSessionIdManager ¶
func (r *ClientHintResolver) ResolveSessionIdManager(req *http.Request) SessionIdManagerShim
ResolveSessionIdManager is the mcp-go hook. It inspects the request to determine the client hint, then returns a request-scoped wrapper around the underlying SessionRegistry.
Nil r is handled — the mcp-go idle-TTL sweeper passes a nil request, in which case we return the bare registry (Generate-path will produce an empty hint, which renders as "Unknown").
type CommandBusProvider ¶
type CommandBusProvider interface {
CommandBus() *cqrs.InMemoryBus
}
CommandBusProvider exposes the CQRS command bus for write dispatches. Handlers depend on this narrow port rather than pulling the full *Manager to reach CommandBus() — closes the last composition-root leak for write-side bus consumers.
type Config ¶
type Config struct {
APIKey string // required
APISecret string // required
AccessToken string // optional: pre-set access token to bypass browser login
Logger *slog.Logger // required
InstrumentsConfig *instruments.UpdateConfig // optional - defaults to instruments.DefaultUpdateConfig()
InstrumentsManager *instruments.Manager // optional - if provided, skips creating new instruments manager
SessionSigner *SessionSigner // optional - if nil, creates new session signer
Metrics *metrics.Manager // optional - for tracking user metrics
TelegramBotToken string // optional - for Telegram price alert notifications
AlertDBPath string // optional - SQLite path for alert persistence
AppMode string // optional - "stdio", "http", "sse"
ExternalURL string // optional - e.g. "https://kite-mcp-server.fly.dev"
AdminSecretPath string // optional - admin endpoint secret for ops dashboard URL
EncryptionSecret string // optional - secret for encrypting credentials at rest (typically OAUTH_JWT_SECRET)
DevMode bool // optional - use mock broker, no real Kite login required
// InstrumentsSkipFetch causes the auto-created instruments manager to
// skip the HTTP prefetch of api.kite.trade/instruments.json and load an
// empty instrument map instead. Intended for tests that exercise the
// full wiring (initializeServices) but do not need live instrument data
// — isolates the test suite from external-API rate limits / outages.
// Ignored when InstrumentsManager is already provided.
InstrumentsSkipFetch bool
// BotFactory is an optional per-Manager Telegram bot factory. When
// non-nil, alerts.NewTelegramNotifierWithFactory is used to construct
// the notifier — bypassing the kc/alerts package-level newBotFunc
// global. Tests pass a fake-server-backed factory here to avoid the
// global-mutex OverrideNewBotFunc pattern, unblocking t.Parallel.
// Production wiring leaves this nil so the default tgbotapi.NewBotAPI
// path is used.
BotFactory alerts.BotFactory
// AlertDB is an optional pre-opened SQLite database. When non-nil,
// initPersistence uses this DB directly instead of calling
// alerts.OpenDB(AlertDBPath). This is the inversion seam that lets
// app/wire.go open the DB once and construct DB-backed stores
// (audit, riskguard, billing, invitation) BEFORE kc.NewWithOptions —
// breaking the cycle where those stores were post-wired via SetX
// setters from the manager's own AlertDB() accessor. AlertDBPath is
// ignored when this is non-nil (the manager does not close a DB it
// did not open).
AlertDB *alerts.DB
// AuditStore, RiskGuard, BillingStore, InvitationStore are optional
// pre-constructed stores. When non-nil, the manager populates the
// matching field directly during init, replacing the post-construction
// SetX setter pattern (which is retained as deprecated shims for
// backward compatibility with the ~70+ test sites that still use it).
//
// Production wiring (app/wire.go) uses these in combination with
// AlertDB to break the construction cycle. Tests that don't need
// these stores can leave them nil and the manager runs without them
// (matching legacy behaviour).
AuditStore *audit.Store
RiskGuard *riskguard.Guard
BillingStore *billing.Store
InvitationStore *users.InvitationStore
}
Config holds configuration for creating a new kc Manager.
Anchor 6 PR 6.15 relocated the canonical declaration from kc/manager.go to its own file so manager.go can stay focused on the constructors only. No behaviour change — pure file move.
type CredentialService ¶
type CredentialService struct {
// contains filtered or unexported fields
}
CredentialService owns credential resolution: per-user vs global credentials, API key lookup, and registry backfill. Extracted from Manager as part of Clean Architecture / SOLID refactoring.
Dependencies are interface types (Dependency Inversion Principle), enabling mock injection for testing.
func NewCredentialService ¶
func NewCredentialService(cfg CredentialServiceConfig) *CredentialService
NewCredentialService creates a new CredentialService with the given dependencies.
func (*CredentialService) BackfillRegistryFromCredentials ¶
func (cs *CredentialService) BackfillRegistryFromCredentials()
BackfillRegistryFromCredentials syncs existing credentials into the registry. This handles pre-registry self-provisioned keys that were stored before the registry existed.
func (*CredentialService) GetAPIKeyForEmail ¶
func (cs *CredentialService) GetAPIKeyForEmail(email string) string
GetAPIKeyForEmail returns the API key: per-user if registered, otherwise global. Thin delegate to domain.CredentialResolution.APIKey.
func (*CredentialService) GetAPISecretForEmail ¶
func (cs *CredentialService) GetAPISecretForEmail(email string) string
GetAPISecretForEmail returns the API secret: per-user if registered, otherwise global. Thin delegate to domain.CredentialResolution.APISecret.
func (*CredentialService) GetAccessTokenForEmail ¶
func (cs *CredentialService) GetAccessTokenForEmail(email string) string
GetAccessTokenForEmail returns the cached access token for a given email.
func (*CredentialService) HasCachedToken ¶
func (cs *CredentialService) HasCachedToken(email string) bool
HasCachedToken returns true if there's a cached Kite token for the given email.
func (*CredentialService) HasCredentials ¶
func (cs *CredentialService) HasCredentials(email string) bool
HasCredentials returns true if credentials can be resolved for the email (either per-user or global). Delegates to domain.CredentialResolution.IsResolved.
func (*CredentialService) HasGlobalCredentials ¶
func (cs *CredentialService) HasGlobalCredentials() bool
HasGlobalCredentials returns true if global API key/secret are configured (from env vars).
func (*CredentialService) HasPreAuth ¶
func (cs *CredentialService) HasPreAuth() bool
HasPreAuth returns true if the service has a pre-set access token.
func (*CredentialService) HasUserCredentials ¶
func (cs *CredentialService) HasUserCredentials(email string) bool
HasUserCredentials returns true if per-user Kite credentials exist for the given email.
func (*CredentialService) IsTokenValid ¶
func (cs *CredentialService) IsTokenValid(email string) bool
IsTokenValid returns true if the user has a cached Kite token that has not expired. Delegates to domain.Session.IsExpired via the ToDomainSession converter so the 06:00 IST refresh rule lives on the rich entity rather than being re-derived here.
func (*CredentialService) QualifiesForTrading ¶
func (cs *CredentialService) QualifiesForTrading(email string) bool
QualifiesForTrading is the canonical "can this user place orders right now" rule. Combines credential availability + session authenticity via the domain aggregate; no service-layer logic. Single source of truth so every call site (place_order, modify_order, GTT, etc.) gets identical answers.
func (*CredentialService) ResolveCredentials ¶
func (cs *CredentialService) ResolveCredentials(email string) (apiKey, apiSecret string, err error)
ResolveCredentials returns the (apiKey, apiSecret) for a user. Per-user credentials take priority; global credentials are the fallback.
Thin orchestrator: delegates the rule to domain.ResolveCredentials so the per-user-vs-global decision lives on a value object that any layer can consult independently.
type CredentialServiceConfig ¶
type CredentialServiceConfig struct {
APIKey string
APISecret string
AccessToken string
CredentialStore CredentialStoreInterface
TokenStore TokenStoreInterface
RegistryStore RegistryStoreInterface
Logger *slog.Logger
}
CredentialServiceConfig holds dependencies for creating a CredentialService.
type CredentialStoreInterface ¶
type CredentialStoreInterface interface {
// Get retrieves stored credentials for the given email.
Get(email string) (*KiteCredentialEntry, bool)
// Set stores credentials for the given email.
Set(email string, entry *KiteCredentialEntry)
// Delete removes credentials for the given email.
Delete(email string)
// ListAll returns a redacted summary of all stored credentials.
ListAll() []KiteCredentialSummary
// ListAllRaw returns all credentials unredacted (for internal operations).
ListAllRaw() []RawCredentialEntry
// GetSecretByAPIKey finds the API secret for a given API key.
GetSecretByAPIKey(apiKey string) (apiSecret string, ok bool)
// Count returns the number of stored credential entries.
Count() int
}
CredentialStoreInterface defines operations for storing per-user Kite developer app credentials (API key + secret).
type CredentialStoreProvider ¶
type CredentialStoreProvider interface {
CredentialStore() CredentialStoreInterface
}
CredentialStoreProvider exposes the per-email Kite credential store.
type EventDispatcherProvider ¶
type EventDispatcherProvider interface {
EventDispatcher() *domain.EventDispatcher
}
EventDispatcherProvider exposes the domain event dispatcher. Returns nil when event-sourcing is disabled (no AlertDB / no event store wiring). Authored to unblock Phase 3a Batch 5 — ext_apps.go + admin_risk_tools.go reach manager.EventDispatcher() directly; this provider lets them go through ToolHandlerDeps.Events instead.
type EventingService ¶
type EventingService struct {
// contains filtered or unexported fields
}
EventingService groups the domain event dispatcher and append-only event store. Both are optional infrastructure: Manager holds the concrete values and this service mediates access so use-case code can depend on a narrow surface rather than the whole Manager.
Tier 1.2 (Path A.28 follow-up to Tier 1.1's broker_services elimination): the back-pointer to *Manager has been replaced with closures over the underlying fields. Each closure dereferences the source-of-truth Manager field at call time (not at construction time), preserving observable behaviour identical to the prior `e.m.X` access. Critical for SetDispatcher: the propagated subscribers (projector, sessionSvc, trailingStopMgr, 8 Wave-D use-case fields) are nil at newEventingService() time and only populated later by initProjector / initFocusedServices / initTrailingStop / initOrderUseCases. Closures capture by-reference so they read the latest value when SetDispatcher runs.
func (*EventingService) Dispatcher ¶
func (e *EventingService) Dispatcher() *domain.EventDispatcher
Dispatcher returns the domain event dispatcher, or nil if not configured.
func (*EventingService) SetDispatcher ¶
func (e *EventingService) SetDispatcher(d *domain.EventDispatcher)
SetDispatcher sets the domain event dispatcher and subscribes the read-side projector so order/alert/position events flow into the live aggregate maps. Also wires the dispatcher into the session service so new MCP sessions emit SessionCreatedEvent, and into the trailing-stop manager so successful triggers emit TrailingStopTriggeredEvent.
Wave D Slice D2/D3: also propagates the new dispatcher into the startup-once order/GTT use cases the Manager holds. Without this propagation, the use cases would have captured a nil dispatcher at initOrderUseCases time (because production wires the dispatcher AFTER kc.NewWithOptions returns) and silently drop OrderPlaced / OrderModified / OrderCancelled / GTTPlaced / GTTModified / GTTDeleted events — breaking the audit-log persister + read-side projector.
All Set* propagation calls are nil-safe: the use case's setter accepts nil to disable event dispatch, and the Manager-side fields are nil until initOrderUseCases runs (so the early-init path before registerCQRSHandlers is also safe).
func (*EventingService) SetStore ¶
func (e *EventingService) SetStore(s *eventsourcing.EventStore)
SetStore sets the domain audit log.
func (*EventingService) Store ¶
func (e *EventingService) Store() *eventsourcing.EventStore
Store returns the domain audit log (append-only event store), or nil.
type FamilyService ¶
type FamilyService struct {
// contains filtered or unexported fields
}
FamilyService handles family billing operations — invite, remove, list, tier resolution. Extracts family logic from Manager to reduce god-object coupling.
func NewFamilyService ¶
func NewFamilyService(us FamilyUserStore, bs BillingStoreInterface, is *users.InvitationStore) *FamilyService
NewFamilyService creates a family service with the required stores.
func (*FamilyService) AdminEmailFn ¶
func (f *FamilyService) AdminEmailFn() func(string) string
AdminEmailFn returns a function that resolves a user's admin email for tier inheritance.
func (*FamilyService) CanInvite ¶
func (f *FamilyService) CanInvite(adminEmail string) (bool, int, int)
CanInvite checks if the admin has room for one more family member. Delegates the rule to domain.Family — the service is now a thin orchestrator that fetches counts and lifts them into the aggregate.
Returns (canInvite, currentCount, maxCount). On any error constructing the aggregate (shouldn't happen for valid emails / non-negative counts) returns (false, current, max) so the caller sees a "no" answer rather than a misleading "yes".
func (*FamilyService) ListMembers ¶
func (f *FamilyService) ListMembers(adminEmail string) []*users.User
ListMembers returns all users linked to this admin.
func (*FamilyService) MaxUsers ¶
func (f *FamilyService) MaxUsers(adminEmail string) int
MaxUsers returns the max family members for this admin's plan.
func (*FamilyService) MemberCount ¶
func (f *FamilyService) MemberCount(adminEmail string) int
MemberCount returns how many family members are linked to this admin.
func (*FamilyService) RemoveMember ¶
func (f *FamilyService) RemoveMember(adminEmail, memberEmail string) error
RemoveMember unlinks a family member from the admin.
type FamilyUserStore ¶
type FamilyUserStore interface {
Get(email string) (*users.User, bool)
ListByAdminEmail(adminEmail string) []*users.User
SetAdminEmail(email, adminEmail string) error
}
FamilyUserStore is the narrow interface FamilyService needs from user store. ISP: only Get + ListByAdminEmail + SetAdminEmail.
type FillWatcher ¶
type FillWatcher struct {
// contains filtered or unexported fields
}
FillWatcher polls the broker for order completion and dispatches OrderFilledEvent. Safe for concurrent Watch calls — each invocation spawns its own goroutine, and the dispatcher is itself concurrency- safe. See fill_watcher_test.go for the contract.
func NewFillWatcher ¶
func NewFillWatcher(cfg FillWatcherConfig) *FillWatcher
NewFillWatcher constructs a FillWatcher from config. Callers must separately invoke Start() to wire the OrderPlacedEvent subscription, or drive Watch() directly for tight control in tests.
If Resolver is nil but Broker is non-nil, the broker is wrapped in a static resolver (useful for tests). Either form requires Dispatcher and Logger.
func (*FillWatcher) Start ¶
func (w *FillWatcher) Start()
Start subscribes the watcher to domain.OrderPlacedEvent so every placed order automatically spawns a poll goroutine. Idempotent only across distinct Dispatchers — subscribing twice to the same dispatcher will produce two goroutines per event.
func (*FillWatcher) Stop ¶
func (w *FillWatcher) Stop()
Stop signals every in-flight pollLoop goroutine to exit promptly. Idempotent — safe to call from both lifecycle.Shutdown and direct test cleanup. After Stop returns, callers should Wait() to confirm goroutines have actually exited (channel close is async).
Stop does NOT unsubscribe from the dispatcher; callers wanting full teardown should drop the dispatcher reference (or use a fresh dispatcher per server instance).
func (*FillWatcher) Wait ¶
func (w *FillWatcher) Wait(timeout time.Duration)
Wait blocks until every in-flight poll goroutine has exited, or the timeout fires (whichever comes first). Primary use is test synchronisation — production code should not call this.
func (*FillWatcher) Watch ¶
func (w *FillWatcher) Watch(placed domain.OrderPlacedEvent)
Watch spawns a goroutine that polls the broker for the given order. Returns immediately — callers that need to synchronise should use Wait().
The ticker is created on the caller goroutine (before we spawn the poll loop) so tests using testutil.FakeClock have a happens-before guarantee that the first Advance() will find a registered ticker. If the ticker were created inside the goroutine, a race between test-thread Advance and goroutine NewTicker would silently drop the first tick.
type FillWatcherBroker ¶
FillWatcherBroker is the narrow broker surface the watcher depends on. Satisfied by broker.Client (which embeds broker.OrderManager). Tests use a hand-rolled fake instead of the full broker/mock — the GetOrderHistory-only dependency is intentional.
type FillWatcherBrokerResolver ¶
type FillWatcherBrokerResolver interface {
GetBrokerForEmail(email string) (FillWatcherBroker, error)
}
FillWatcherBrokerResolver resolves a FillWatcherBroker by email. In production this is satisfied by SessionService.GetBrokerForEmail — see app/wire.go for the adapter. Tests can return a fake broker directly without resolving through the session service.
func FillWatcherResolverFromBroker ¶
func FillWatcherResolverFromBroker(r BrokerResolverProvider) FillWatcherBrokerResolver
FillWatcherResolverFromBroker returns a FillWatcherBrokerResolver backed by anything that satisfies BrokerResolverProvider. The caller (app/wire.go) passes *kc.Manager directly post-PR-6.4; pre-PR callers passed *kc.SessionService via the now-deleted FillWatcherResolverFromSessionSvc constructor.
type FillWatcherConfig ¶
type FillWatcherConfig struct {
Broker FillWatcherBroker
Resolver FillWatcherBrokerResolver
Dispatcher *domain.EventDispatcher
Logger *slog.Logger
Clock clockport.Clock // nil => clockport.RealClock{}
PollInterval time.Duration // default: 5 * time.Second
MaxDuration time.Duration // default: 60 * time.Second
}
FillWatcherConfig is the constructor payload. All fields are required except PollInterval/MaxDuration, which default to 5s and 60s.
Exactly one of Broker or Resolver must be set. Broker wraps a single static broker in a resolver for tests; production callers pass a real per-email Resolver.
type IdentityService ¶ added in v0.1.5
type IdentityService struct {
Credential *CredentialService
Session *SessionService
ManagedSession *ManagedSessionService
Signer *SessionSigner
Lifecycle *SessionLifecycleService
}
IdentityService bundles the identity / authentication / session-lifecycle services that previously lived as 5 separate fields directly on Manager.
Tier B Step 4 (2026-05-16) — identity bundle. Manager 43 → 38 fields.
Membership decision (per .research/tier-b-steps-4-5-preflight-2026-05-16.md §2.2):
- Credential — per-user OAuth credential resolution
- Session — MCP session lifecycle (login → token → session)
- ManagedSession — thin facade over SessionManager (active count, terminate)
- Signer — HMAC session signing (crypto bundle, cohesive w/ identity)
- Lifecycle — thin Manager-shaped facade exposing get/create/clear/ complete via delegation to Session
NOT in scope (stay outside IdentityService):
- SessionManager (*SessionRegistry) — has 4 external direct-readers (kite-mcp-bootstrap / kite-mcp-usecases); kept as a Manager field so those call sites are not forced to migrate yet (Option A per preflight §2.4). Identity.Session and Identity.ManagedSession both hold a pointer to the same registry, set during initFocusedServices.
- tokenStore / credentialStore / registryStore / userStore — owned by StoreRegistry per Phase 3a design. Identity reaches them via interface ports threaded through Session/Credential configs.
- encryptionKey — cross-cutting concern (also used by users.Store TOTP); stays on Manager per Step 3 footnote.
Pattern: matches the Step 2 OrderService + Step 3 AlertService precedent — an empty service is allocated up front in newEmptyManager, then the init* phases populate the fields in-place via same-package field access. After initFocusedServices the bundle is fully populated; consumers reach the individual services via m.Identity.<Field> (e.g. m.Identity.Session).
type InstrumentManagerInterface ¶
type InstrumentManagerInterface = instruments.InstrumentManagerInterface
InstrumentManagerInterface is the instrument-metadata lookup interface. Anchor 5 PR 5.4 relocated the canonical declaration to kc/instruments/manager_interface.go (its owning package); this alias preserves the legacy `kc.InstrumentManagerInterface` reference path so the 10+ pre-existing reverse-dep call sites build unchanged. Type aliases are not new types — `kc.InstrumentManagerInterface` and `instruments.InstrumentManagerInterface` are interchangeable at every call site, including the compile-time satisfaction check below (`_ InstrumentManagerInterface = (*instruments.Manager)(nil)`).
Wave B-2 PR 5.5 will rewrite kc/ports/instrument.go to reference `instruments.InstrumentManagerInterface` directly so it can drop its kc-parent import; this alias remains as the long-tail backward- compatibility shim until call sites migrate.
type KiteClientFactory ¶
type KiteClientFactory = zerodha.KiteClientFactory
KiteClientFactory creates Kite API clients. Inject a mock in tests by returning any zerodha.KiteSDK implementation (e.g. zerodha.MockKiteSDK) that replays canned responses without touching HTTP.
This factory is used by background services (briefing, pnl snapshots, telegram bot) that run outside MCP tool handlers and therefore don't have access to a session-pinned broker. The return type is the broker-owned zerodha.KiteSDK interface, NOT the raw SDK *kiteconnect.Client — the concrete kiteconnect.New call site is confined to broker/zerodha (the single-seam guarantee that the hexagonal-100 claim always promised).
F4 consolidation (Phase B/D close-out): canonical declaration moved to broker/zerodha (commit-this). kc.KiteClientFactory is now a Go type alias preserving the historical name + import path while pointing at the single source of truth. kc/telegram.KiteClientFactory got the same alias treatment. kc/alerts.KiteClientFactory stays as a narrow 1-method subset (intentional ISP narrowness — briefing only needs NewClientWithToken).
type KiteConnect ¶
type KiteConnect struct {
// Client is the authenticated Kite SDK. Exported because 23+ tool handlers access it directly.
Client zerodha.KiteSDK
}
KiteConnect wraps the Kite Connect client.
The Client field holds a zerodha.KiteSDK (interface) rather than a concrete *kiteconnect.Client so background services and tool handlers both consume the same hexagonal port — the broker-owned interface collapses the former two SDK construction sites (kc/kite_client.go and broker/zerodha/sdk_adapter.go) into one, and lets tests swap in zerodha.MockKiteSDK without touching HTTP.
Anchor 6 PR 6.15 relocated this from kc/manager.go to keep manager.go focused on the constructor surface only.
func NewKiteConnect ¶
func NewKiteConnect(apiKey string, factory ...KiteClientFactory) *KiteConnect
NewKiteConnect creates a new KiteConnect instance. All SDK instantiation routes through the KiteClientFactory interface.
type KiteCredentialEntry ¶
type KiteCredentialEntry struct {
APIKey string
APISecret string
AppID string // AppID = API key for Kite developer apps
StoredAt time.Time
}
KiteCredentialEntry stores a user's Kite developer app credentials.
type KiteCredentialStore ¶
type KiteCredentialStore struct {
// contains filtered or unexported fields
}
KiteCredentialStore is a thread-safe in-memory map of email -> Kite developer credentials. Optionally backed by SQLite for persistence via SetDB.
func NewKiteCredentialStore ¶
func NewKiteCredentialStore() *KiteCredentialStore
NewKiteCredentialStore creates a new credential store.
func (*KiteCredentialStore) Count ¶
func (s *KiteCredentialStore) Count() int
Count returns the number of stored credential entries.
func (*KiteCredentialStore) Delete ¶
func (s *KiteCredentialStore) Delete(email string)
Delete removes credentials for the given email.
func (*KiteCredentialStore) Get ¶
func (s *KiteCredentialStore) Get(email string) (*KiteCredentialEntry, bool)
Get retrieves stored credentials for the given email. Returns a copy to prevent callers from mutating shared state.
func (*KiteCredentialStore) GetSecretByAPIKey ¶
func (s *KiteCredentialStore) GetSecretByAPIKey(apiKey string) (apiSecret string, ok bool)
GetSecretByAPIKey finds the API secret for a given API key by scanning all stored credentials. Used when the client_id (= API key) is known but the email is not yet resolved.
func (*KiteCredentialStore) ListAll ¶
func (s *KiteCredentialStore) ListAll() []KiteCredentialSummary
ListAll returns a redacted summary of all stored credentials.
func (*KiteCredentialStore) ListAllRaw ¶
func (s *KiteCredentialStore) ListAllRaw() []RawCredentialEntry
ListAllRaw returns all credentials unredacted. Used internally for registry backfill.
func (*KiteCredentialStore) LoadFromDB ¶
func (s *KiteCredentialStore) LoadFromDB() error
LoadFromDB populates the in-memory store from the database.
func (*KiteCredentialStore) OnTokenInvalidate ¶
func (s *KiteCredentialStore) OnTokenInvalidate(fn func(email string))
OnTokenInvalidate registers a callback that is invoked when a user's API key changes, so the stale cached Kite token (issued for the old app) can be deleted.
func (*KiteCredentialStore) Set ¶
func (s *KiteCredentialStore) Set(email string, entry *KiteCredentialEntry)
Set stores credentials for the given email.
func (*KiteCredentialStore) SetDB ¶
func (s *KiteCredentialStore) SetDB(db *alerts.DB)
SetDB enables write-through persistence to the given SQLite database.
func (*KiteCredentialStore) SetLogger ¶
func (s *KiteCredentialStore) SetLogger(logger *slog.Logger)
SetLogger sets the logger for DB error reporting.
type KiteCredentialSummary ¶
type KiteCredentialSummary struct {
Email string `json:"email"`
APIKey string `json:"api_key"`
APISecretHint string `json:"api_secret_hint"`
StoredAt time.Time `json:"stored_at"`
}
KiteCredentialSummary is a redacted view of a credential entry (API secret masked).
type KiteSessionData ¶
type KiteSessionData = domain.KiteSessionData
KiteSessionData is the transient runtime state of an authenticated MCP session. Anchor 5 PR 5.6 relocated the canonical declaration to kc/domain/session.go (its proper bounded-context home — see anchor-5-prs-design.md). This alias preserves the legacy kc.KiteSessionData reference path so the 56-file reverse-dep set continues to compile via existing imports.
The PR also collapsed the kc.KiteConnect wrapper indirection: the Kite field is now zerodha.KiteSDK (interface) directly, not *KiteConnect (one-field struct holding the same SDK). All callsites migrated from `.Kite.Client.METHOD(...)` to `.Kite.METHOD(...)`. The kc.KiteConnect type + NewKiteConnect helper remain available (see kc/kite_connect.go) for the few callers that still need a *KiteConnect pointer; the field type change is a deliberate decoupling so kc/domain can host KiteSessionData without depending on the kc parent package.
type KiteTokenEntry ¶
KiteTokenEntry stores a Kite access token and metadata for a user.
type KiteTokenStore ¶
type KiteTokenStore struct {
// contains filtered or unexported fields
}
KiteTokenStore is a thread-safe in-memory map of email -> Kite access token. Used to cache tokens so users only need to login once per day. Optionally backed by SQLite for persistence via SetDB.
func NewKiteTokenStore ¶
func NewKiteTokenStore() *KiteTokenStore
NewKiteTokenStore creates a new token store.
func (*KiteTokenStore) Count ¶
func (s *KiteTokenStore) Count() int
Count returns the number of stored tokens.
func (*KiteTokenStore) Delete ¶
func (s *KiteTokenStore) Delete(email string)
Delete removes a token for the given email.
func (*KiteTokenStore) Get ¶
func (s *KiteTokenStore) Get(email string) (*KiteTokenEntry, bool)
Get retrieves a stored token for the given email. Returns a copy to prevent callers from mutating shared state.
func (*KiteTokenStore) ListAll ¶
func (s *KiteTokenStore) ListAll() []KiteTokenSummary
ListAll returns a redacted summary of all cached tokens.
func (*KiteTokenStore) LoadFromDB ¶
func (s *KiteTokenStore) LoadFromDB() error
LoadFromDB populates the in-memory store from the database.
func (*KiteTokenStore) OnChange ¶
func (s *KiteTokenStore) OnChange(cb TokenChangeCallback)
OnChange registers a callback that fires when a token is stored or updated.
func (*KiteTokenStore) Set ¶
func (s *KiteTokenStore) Set(email string, entry *KiteTokenEntry)
Set stores a token for the given email and notifies observers. The entry is copied before storing to prevent the caller from mutating shared state.
func (*KiteTokenStore) SetDB ¶
func (s *KiteTokenStore) SetDB(db *alerts.DB)
SetDB enables write-through persistence to the given SQLite database.
func (*KiteTokenStore) SetLogger ¶
func (s *KiteTokenStore) SetLogger(logger *slog.Logger)
SetLogger sets the logger for DB error reporting.
type KiteTokenSummary ¶
type KiteTokenSummary struct {
Email string `json:"email"`
UserID string `json:"user_id"`
UserName string `json:"user_name"`
StoredAt time.Time `json:"stored_at"`
}
KiteTokenSummary is a redacted view of a token entry (no AccessToken exposed).
type MCPServerProvider ¶
type MCPServerProvider interface {
MCPServer() any
}
MCPServerProvider exposes the stored MCP server reference. Returns nil before the server has been attached.
type MCPSession ¶
type MCPSession struct {
ID string
Terminated bool
CreatedAt time.Time
ExpiresAt time.Time
Data any // Contains KiteSessionData
// ClientHint is a free-form description of the MCP surface that created
// the session (e.g. the raw User-Agent from the bearer-issuance HTTP
// request, or a constant like "claude-code" / "claude-desktop"). Empty
// when the registry was called through a code path that has no HTTP
// request context (SessionIdManager.Generate(), SSE/stdio transports).
// Rendered as "Unknown" by list_mcp_sessions when empty.
ClientHint string
}
type ManagedSessionService ¶
type ManagedSessionService struct {
// contains filtered or unexported fields
}
ManagedSessionService wraps session operations for cleaner access. Extracted from Manager to reduce god-object coupling.
func NewManagedSessionService ¶
func NewManagedSessionService(reg *SessionRegistry) *ManagedSessionService
NewManagedSessionService creates a new ManagedSessionService.
func (*ManagedSessionService) ActiveCount ¶
func (s *ManagedSessionService) ActiveCount() int
ActiveCount returns the number of non-terminated, non-expired sessions.
func (*ManagedSessionService) Registry ¶
func (s *ManagedSessionService) Registry() *SessionRegistry
Registry returns the underlying SessionRegistry.
func (*ManagedSessionService) TerminateByEmail ¶
func (s *ManagedSessionService) TerminateByEmail(email string) int
TerminateByEmail terminates all active sessions belonging to the given email.
type Manager ¶
type Manager struct {
Logger *slog.Logger
// Focused service objects (Clean Architecture)
Identity *IdentityService // identity bundle: Credential / Session / ManagedSession / Signer / Lifecycle (Tier B Step 4)
PortfolioSvc *PortfolioService // portfolio queries (holdings, positions, margins, profile)
OrderSvc *OrderService // order placement, modification, cancellation
AlertSvc *AlertService // alert lifecycle (CRUD, evaluation, trailing stops, Telegram, P&L)
FamilyService *FamilyService // family billing (invite, remove, list, tier resolution)
Instruments *instruments.Manager
SessionManager *SessionRegistry
// contains filtered or unexported fields
}
func New
deprecated
New creates a new kc Manager with the given configuration.
Deprecated: prefer NewWithOptions(ctx, opts...) which uses the functional-options pattern consistent with the rest of the codebase (testutil/kcfixture, kc/ticker/config.go, kc/scheduler/provider.go). This function is retained as a thin backward-compat shim because 40+ test files across app/, mcp/, and kc/ops/ call it directly with literal kc.Config{…} structs; forcing all of them to migrate at once would ripple through three scopes owned by other active agents.
New is equivalent to NewWithOptions(context.Background(), WithConfig(cfg)). It validates cfg.Logger is non-nil (matching pre-shim behaviour) before delegating — preserving the error class "logger is required" so existing tests that rely on that exact error message keep passing.
func NewManager
deprecated
NewManager creates a new manager with default configuration.
Deprecated: Use New(Config{APIKey: apiKey, APISecret: apiSecret, Logger: logger}) instead. NOTE: Still used by kc/manager_test.go (TestNewManager). Remove once tests are migrated to New().
func NewWithOptions ¶
NewWithOptions creates a new kc Manager from a base context plus a list of functional options. Primary constructor for the Manager — backward-compat paths flow through New(Config) above.
The body is a thin orchestrator over the init* helpers in kc/manager_init.go. Each helper is documented at its declaration site; the order below is load-bearing — downstream phases read state that earlier phases wrote. Do not reorder without re-reading the helper docs.
ctx is currently stashed on the options payload for future use (cancellable init, tracing spans, deadline propagation); no init phase consumes it yet, but the plumbing is in place so that flip does not later become a breaking change.
func (*Manager) AdminSecretPath ¶
AdminSecretPath returns the configured admin secret path.
func (*Manager) AlertDB ¶
func (m *Manager) AlertDB() *alerts.DB
AlertDB returns the optional SQLite database used for persistence.
func (*Manager) AlertStore ¶
func (m *Manager) AlertStore() AlertStoreInterface
AlertStore returns the per-user alert store.
func (*Manager) AlertStoreConcrete ¶
func (m *Manager) AlertStoreConcrete() *alerts.Store
AlertStoreConcrete returns the concrete alert store.
func (*Manager) AuditStore ¶
func (m *Manager) AuditStore() AuditStoreInterface
AuditStore returns the audit trail store, or nil if not configured.
func (*Manager) AuditStoreConcrete ¶
func (m *Manager) AuditStoreConcrete() *audit.Store
AuditStoreConcrete returns the concrete audit store.
func (*Manager) BillingStore ¶
func (m *Manager) BillingStore() BillingStoreInterface
BillingStore returns the billing store, or nil if not configured.
func (*Manager) BillingStoreConcrete ¶
func (m *Manager) BillingStoreConcrete() *billing.Store
BillingStoreConcrete returns the concrete billing store.
func (*Manager) Brokers ¶
func (m *Manager) Brokers() *BrokerServices
Brokers returns the broker services group.
func (*Manager) CleanupExpiredSessions ¶
CleanupExpiredSessions manually triggers cleanup of expired MCP sessions.
func (*Manager) ClearSession ¶
ClearSession terminates a session, triggering cleanup hooks.
func (*Manager) ClearSessionData ¶
ClearSessionData clears the session data without terminating the session.
func (*Manager) CommandBus ¶
func (m *Manager) CommandBus() *cqrs.InMemoryBus
CommandBus returns the CQRS command bus for write-side dispatches.
func (*Manager) CompleteSession ¶
CompleteSession completes Kite authentication using the request token. Back-compat shim — new callers should use CompleteSessionAndRotate to receive the post-auth rotated session ID (OWASP A07 defence).
func (*Manager) CompleteSessionAndRotate ¶
CompleteSessionAndRotate completes Kite authentication and rotates the session ID. See SessionService.CompleteSessionAndRotate for semantics.
func (*Manager) CredentialStore ¶
func (m *Manager) CredentialStore() CredentialStoreInterface
CredentialStore returns the per-email Kite credential store.
func (*Manager) CredentialStoreConcrete ¶
func (m *Manager) CredentialStoreConcrete() *KiteCredentialStore
CredentialStoreConcrete returns the concrete credential store.
func (*Manager) DevMode ¶
DevMode returns true if the server is running in development mode with mock broker.
func (*Manager) EventDispatcher ¶
func (m *Manager) EventDispatcher() *domain.EventDispatcher
EventDispatcher returns the domain event dispatcher, or nil if not configured.
func (*Manager) EventStoreConcrete ¶
func (m *Manager) EventStoreConcrete() *eventsourcing.EventStore
EventStoreConcrete returns the domain audit log, or nil if not configured.
func (*Manager) Eventing ¶
func (m *Manager) Eventing() *EventingService
Eventing returns the eventing service.
func (*Manager) ExternalURL ¶
ExternalURL returns the configured external URL (e.g. "https://kite-mcp-server.fly.dev").
func (*Manager) ForceInstrumentsUpdate ¶
ForceInstrumentsUpdate forces an immediate instruments update.
func (*Manager) GenerateSession ¶
GenerateSession creates a new MCP session and returns its ID.
func (*Manager) GetAPIKeyForEmail ¶
GetAPIKeyForEmail returns the API key for a user (per-user or global fallback).
func (*Manager) GetAPISecretForEmail ¶
GetAPISecretForEmail returns the API secret for a user (per-user or global fallback).
func (*Manager) GetAccessTokenForEmail ¶
GetAccessTokenForEmail returns the cached access token for the given email.
func (*Manager) GetActiveSessionCount ¶
GetActiveSessionCount returns the number of active sessions.
func (*Manager) GetBrokerForEmail ¶
GetBrokerForEmail resolves the broker.Client for the given email by delegating to the underlying SessionService. Anchor 6 PR 6.4 (per .research/anchor-6-pr-6-4-broker-resolver-redesign.md commit a2a11db): added so *Manager satisfies the narrowed BrokerResolverProvider interface (kc/manager_interfaces.go:95-114) directly, without exposing the *SessionService wrapper. Replaces the prior `manager.SessionSvc().GetBrokerForEmail(email)` two-hop at all 4 cross-package call sites.
func (*Manager) GetInstrumentsStats ¶
func (m *Manager) GetInstrumentsStats() instruments.UpdateStats
GetInstrumentsStats returns current instruments update statistics.
func (*Manager) GetOrCreateSession ¶
func (m *Manager) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
GetOrCreateSession retrieves an existing Kite session or creates a new one.
func (*Manager) GetOrCreateSessionWithEmail ¶
func (m *Manager) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
GetOrCreateSessionWithEmail retrieves or creates a Kite session with email context.
func (*Manager) GetSession ¶
func (m *Manager) GetSession(mcpSessionID string) (*KiteSessionData, error)
GetSession retrieves an existing Kite session by MCP session ID.
func (*Manager) HandleKiteCallback ¶
func (m *Manager) HandleKiteCallback() func(w http.ResponseWriter, r *http.Request)
HandleKiteCallback returns an HTTP handler for Kite authentication callbacks. Kept as a Manager method for backward compatibility with existing callers in app/http.go and the test suite.
func (*Manager) HasBrokerFactory ¶
HasBrokerFactory reports whether the underlying SessionService has an explicit broker.Factory wired. Anchor 6 PR 6.4: added so *Manager satisfies BrokerResolverProvider directly. Replaces the prior `manager.SessionSvc().HasBrokerFactory()` two-hop at the app/http.go:720 call site.
func (*Manager) HasCachedToken ¶
HasCachedToken returns true if there's a cached Kite token for the given email.
func (*Manager) HasGlobalCredentials ¶
HasGlobalCredentials returns true if global API key/secret are configured.
func (*Manager) HasMetrics ¶
HasMetrics returns true if metrics manager is available.
func (*Manager) HasPreAuth ¶
HasPreAuth returns true if the manager has a pre-set access token.
func (*Manager) HasUserCredentials ¶
HasUserCredentials returns true if per-user Kite credentials exist for the given email.
func (*Manager) IncrementDailyMetric ¶
IncrementDailyMetric increments a daily metric counter by 1.
func (*Manager) IncrementMetric ¶
IncrementMetric increments a metric counter by 1.
func (*Manager) InstrumentsManager ¶
func (m *Manager) InstrumentsManager() InstrumentManagerInterface
InstrumentsManager returns the instruments manager.
func (*Manager) InstrumentsManagerConcrete ¶
func (m *Manager) InstrumentsManagerConcrete() *instruments.Manager
InstrumentsManagerConcrete returns the concrete instruments manager.
func (*Manager) InvitationStore ¶
func (m *Manager) InvitationStore() *users.InvitationStore
InvitationStore returns the invitation store, or nil if not configured.
func (*Manager) IsLocalMode ¶
IsLocalMode returns true when running in STDIO mode (local process, not remote HTTP).
func (*Manager) IsTokenValid ¶
IsTokenValid returns true if the user has a cached Kite token that has not expired.
func (*Manager) KiteClientFactory ¶
func (m *Manager) KiteClientFactory() KiteClientFactory
KiteClientFactory returns the factory used to create zerodha.KiteSDK instances.
func (*Manager) OpenBrowser ¶
OpenBrowser opens the given URL in the user's default browser. Only works in local/STDIO mode where the server runs on the user's machine.
func (*Manager) PaperEngine ¶
func (m *Manager) PaperEngine() PaperEngineInterface
PaperEngine returns the paper trading engine, or nil if not configured.
func (*Manager) PaperEngineConcrete ¶
func (m *Manager) PaperEngineConcrete() *papertrading.PaperEngine
PaperEngineConcrete returns the concrete paper engine.
func (*Manager) PnLService ¶
func (m *Manager) PnLService() *alerts.PnLSnapshotService
PnLService returns the P&L snapshot service (nil if not initialized).
func (*Manager) QualifiesForTrading ¶
QualifiesForTrading delegates to CredentialSvc.QualifiesForTrading. Returns true iff the user has resolvable credentials AND a non-expired cached Kite token.
func (*Manager) QueryBus ¶
func (m *Manager) QueryBus() *cqrs.InMemoryBus
QueryBus returns the CQRS query bus for read-side dispatches.
func (*Manager) RegistryStore ¶
func (m *Manager) RegistryStore() RegistryStoreInterface
RegistryStore returns the key registry store.
func (*Manager) RegistryStoreConcrete ¶
func (m *Manager) RegistryStoreConcrete() *registry.Store
RegistryStoreConcrete returns the concrete registry store.
func (*Manager) RiskGuard ¶
func (m *Manager) RiskGuard() *riskguard.Guard
RiskGuard returns the riskguard instance, or nil if not configured.
func (*Manager) Scheduling ¶
func (m *Manager) Scheduling() *SchedulingService
Scheduling returns the scheduling service.
func (*Manager) SessionLifecycle ¶
func (m *Manager) SessionLifecycle() *SessionLifecycleService
SessionLifecycle returns the session lifecycle facade.
func (*Manager) SessionLoginURL ¶
SessionLoginURL returns the Kite login URL for the given session.
func (*Manager) SessionRegistry ¶ added in v0.1.2
func (m *Manager) SessionRegistry() *SessionRegistry
SessionRegistry returns the concrete session registry. Added so that *Manager satisfies ports.SessionRegistryProvider — the Provider port that Phase 3 sub-git brief 3 (kite-mcp-tools-ops) consumes via ToolHandlerDeps in kite-mcp-tools-common, replacing the two residual `manager.SessionManager` field-access call sites in mcp/misc/session_admin_tools.go (admin operations like ListActiveSessions, TerminateByEmail).
The field `SessionManager *SessionRegistry` (manager_struct.go:91) remains the canonical home — this method is a thin one-line passthrough so that the abstract Provider-port surface is satisfied without breaking direct-field consumers (which the B4 work established as the preferred internal access pattern).
Identifier discipline: the method name `SessionRegistry` is distinct from the field name `SessionManager`, so no Go method/field collision.
func (*Manager) SetAuditStore ¶
func (m *Manager) SetAuditStore(store *audit.Store)
SetAuditStore wires the audit store.
func (*Manager) SetBillingStore ¶
func (m *Manager) SetBillingStore(store *billing.Store)
SetBillingStore sets the billing store.
func (*Manager) SetEventDispatcher ¶
func (m *Manager) SetEventDispatcher(d *domain.EventDispatcher)
SetEventDispatcher sets the domain event dispatcher.
func (*Manager) SetEventStore ¶
func (m *Manager) SetEventStore(s *eventsourcing.EventStore)
SetEventStore sets the domain audit log.
func (*Manager) SetFamilyService ¶
func (m *Manager) SetFamilyService(fs *FamilyService)
SetFamilyService sets the family billing service. Anchor 6 PR 6.12: the FamilyService accessor method was deleted in favour of direct field access (m.FamilyService — capitalised), but the setter is retained because:
- It encapsulates the assignment for the Fx-graph wiring path in app/providers/family.go (the family setter-after-construct pattern that wire.go's lifecycle requires).
- Multiple test fixtures (app/app_edge_test.go, mcp/admin_tools_test.go, mcp/helpers_test.go) seed the family service via this setter; preserving it keeps the test surface stable.
- It does NOT conflict with the field — methods and fields with the same name DO clash, but only when both the getter method and field share the name. Setter `SetFamilyService` is a distinct identifier from the field `FamilyService`, so no conflict.
func (*Manager) SetInvitationStore ¶
func (m *Manager) SetInvitationStore(store *users.InvitationStore)
SetInvitationStore sets the invitation store.
func (*Manager) SetKiteClientFactory ¶
func (m *Manager) SetKiteClientFactory(f KiteClientFactory)
SetKiteClientFactory overrides the default factory. Intended for tests.
func (*Manager) SetMCPServer ¶
SetMCPServer stores a reference to the MCP server for elicitation support.
func (*Manager) SetPaperEngine ¶
func (m *Manager) SetPaperEngine(e *papertrading.PaperEngine)
SetPaperEngine sets the paper trading engine.
func (*Manager) SetPnLService ¶
func (m *Manager) SetPnLService(svc *alerts.PnLSnapshotService)
SetPnLService sets the P&L snapshot service.
func (*Manager) SetRiskGuard ¶
func (m *Manager) SetRiskGuard(guard *riskguard.Guard)
SetRiskGuard sets the riskguard for financial safety controls.
func (*Manager) Shutdown ¶
func (m *Manager) Shutdown()
Shutdown gracefully shuts down the manager and all its components.
func (*Manager) StopCleanupRoutine ¶
func (m *Manager) StopCleanupRoutine()
StopCleanupRoutine stops the background cleanup routine.
func (*Manager) Stores ¶
func (m *Manager) Stores() *StoreRegistry
Stores returns the store registry.
func (*Manager) TelegramNotifier ¶
func (m *Manager) TelegramNotifier() *alerts.TelegramNotifier
TelegramNotifier returns the Telegram alert sender (nil if not configured).
func (*Manager) TelegramStore ¶
func (m *Manager) TelegramStore() TelegramStoreInterface
TelegramStore returns the per-user Telegram chat ID store.
func (*Manager) TickerService ¶
func (m *Manager) TickerService() TickerServiceInterface
TickerService returns the per-user WebSocket ticker service.
func (*Manager) TickerServiceConcrete ¶
func (m *Manager) TickerServiceConcrete() *ticker.Service
TickerServiceConcrete returns the concrete ticker service.
func (*Manager) TokenStore ¶
func (m *Manager) TokenStore() TokenStoreInterface
TokenStore returns the per-email token store.
func (*Manager) TokenStoreConcrete ¶
func (m *Manager) TokenStoreConcrete() *KiteTokenStore
TokenStoreConcrete returns the concrete token store.
func (*Manager) TrackDailyUser ¶
TrackDailyUser records a unique user interaction for today's counter.
func (*Manager) TrailingStopManager ¶
func (m *Manager) TrailingStopManager() *alerts.TrailingStopManager
TrailingStopManager returns the trailing stop-loss manager.
func (*Manager) UpdateInstrumentsConfig ¶
func (m *Manager) UpdateInstrumentsConfig(config *instruments.UpdateConfig)
UpdateInstrumentsConfig updates the instruments manager configuration.
func (*Manager) UserStore ¶
func (m *Manager) UserStore() UserStoreInterface
UserStore returns the user identity store.
func (*Manager) UserStoreConcrete ¶
func (m *Manager) UserStoreConcrete() *users.Store
UserStoreConcrete returns the concrete user store.
func (*Manager) WatchlistStore ¶
func (m *Manager) WatchlistStore() WatchlistStoreInterface
WatchlistStore returns the per-user watchlist store.
func (*Manager) WatchlistStoreConcrete ¶
func (m *Manager) WatchlistStoreConcrete() *watchlist.Store
WatchlistStoreConcrete returns the concrete watchlist store.
type ManagerLifecycle ¶
type ManagerLifecycle interface {
// Shutdown gracefully shuts down the manager and all its components.
Shutdown()
// OpenBrowser opens a URL in the user's default browser (local mode only).
OpenBrowser(rawURL string) error
// CleanupExpiredSessions manually triggers cleanup of expired sessions.
CleanupExpiredSessions() int
// StopCleanupRoutine stops the background cleanup routine.
StopCleanupRoutine()
}
ManagerLifecycle manages the lifecycle of the Manager and its sub-components.
type MetricsRecorder ¶
type MetricsRecorder interface {
// HasMetrics returns true if metrics manager is available.
HasMetrics() bool
// IncrementMetric increments a metric counter by 1.
IncrementMetric(key string)
// TrackDailyUser records a unique user interaction.
TrackDailyUser(userID string)
// IncrementDailyMetric increments a daily metric counter.
IncrementDailyMetric(key string)
}
MetricsRecorder records operational metrics.
type OAuthBridgeRegistrarDeps ¶
type OAuthBridgeRegistrarDeps struct {
UserStore *users.Store
TokenStore *KiteTokenStore
CredentialStore *KiteCredentialStore
RegistryStore *registry.Store
AlertDBGetter func() *alerts.DB // lazy access for OAuth client store; nil-safe
}
OAuthBridgeRegistrarDeps holds the store dependencies needed to register the OAuth-bridge command handlers. The package-level registrar consumes this struct so it can be shared across multiple bus instances (production Manager + the local-bus mirror in app/adapters_local_bus.go style follow-ups, if any).
Note: AlertDB is provided as a getter closure (not a *alerts.DB value directly) because the OAuth-client-store handler reaches it lazily — only when a SaveOAuthClient/DeleteOAuthClient command arrives. The closure preserves the original "evaluate at command-dispatch time" semantics; constructing the deps eagerly with a *alerts.DB would dereference Manager.AlertDB() at registration time and panic on test fixtures that don't initialize the stores facade.
type Option ¶
type Option func(*options)
Option mutates the Manager construction payload. Returned from the With* helpers; consumed by NewWithOptions (and, as a backward-compat shim, by the deprecated New(Config)).
Design notes:
All options are additive. Later options win when they overlap (e.g. WithConfig followed by WithLogger overrides Config.Logger with the explicit logger). This matches how the rest of the codebase uses functional options (testutil/kcfixture, kc/ticker/config.go, kc/scheduler/provider.go) — predictable last-wins rather than first-wins or accumulator.
The receiver is *options (not options) so helpers that need to inspect prior state to refine a field can read what earlier options wrote. Not used today; kept for future flexibility.
Error-returning options are not supported. Any validation that COULD fail (credential parsing, logger nil-check, context cancellation) is deferred to NewWithOptions' body so the Option surface stays as pure data. This matches functional-option convention in Go — errors flow through the constructor, not through each setter.
func WithAccessToken ¶
WithAccessToken sets a pre-authenticated Kite access token. Used by local-dev and single-user deployments to skip the browser login; on the hosted multi-user deployment this is always empty and tokens are acquired per-user via the OAuth flow.
func WithAdminSecretPath ¶
WithAdminSecretPath sets the admin endpoint's secret path segment so /admin/<secret>/ops can be generated by the dashboard link helpers. Empty disables the admin link emission.
func WithAlertDB ¶
func WithAlertDB(db *alerts.DB) Option
WithAlertDB threads a pre-opened *alerts.DB through Manager construction. When supplied, initPersistence skips the alerts.OpenDB(AlertDBPath) call and uses the externally-opened DB directly. This is the inversion seam for the AlertDB construction cycle: app/wire.go opens the DB once, constructs DB-backed stores (audit/riskguard/billing/invitation) via the matching With* options, then passes them all to NewWithOptions in one hop — eliminating the post-construction SetX setters that previously required kcManager.AlertDB() to be readable BEFORE the manager finished initialising.
Lifetime: the manager does NOT close a DB it did not open. Callers that pass a DB via WithAlertDB own the DB lifecycle and are responsible for closing it during graceful shutdown. The app/lifecycle.go LifecycleManager handles this for app/wire.go.
func WithAlertDBPath ¶
WithAlertDBPath enables SQLite persistence for alerts, tokens, credentials, watchlists, users, registry, sessions, and the domain event store. When empty the server runs in-memory only; persistence is all-or-nothing because every store shares the same DB handle.
func WithAppMode ¶
WithAppMode sets the transport mode — "stdio" (default, local), "http", or "sse". Drives IsLocalMode() which gates OpenBrowser and other local-only behaviours.
func WithAuditStore ¶
func WithAuditStore(s *audit.Store) Option
WithAuditStore threads a pre-constructed audit.Store through Manager construction, eliminating the post-init kcManager.SetAuditStore call site in app/wire.go. The legacy SetAuditStore setter is retained as a deprecated shim so the ~5+ test sites that mutate the manager after construction continue to work unchanged.
func WithBillingStore ¶
func WithBillingStore(s *billing.Store) Option
WithBillingStore threads a pre-constructed billing.Store through Manager construction. Same deprecation contract as WithAuditStore.
func WithBotFactory ¶
func WithBotFactory(factory alerts.BotFactory) Option
WithBotFactory installs a per-Manager Telegram bot factory. When supplied, the manager constructs its TelegramNotifier via the factory instead of consulting the kc/alerts package-level newBotFunc global — this is the t.Parallel-safe entry point for tests that need a fake Telegram server. Production wiring omits this so the default tgbotapi.NewBotAPI path is used.
func WithConfig ¶
WithConfig installs an entire Config struct in one hop. The primary backward-compat path: the deprecated New(cfg) shim delegates to NewWithOptions(ctx, WithConfig(cfg)), so every existing caller (app/wire.go, testutil/kcfixture, 40+ test files under app/, mcp/, kc/ops/) keeps compiling unchanged. New code should prefer the granular setters below unless it already holds a full Config from another source (e.g. env-parsing).
func WithContext ¶
WithContext attaches the caller's context to the Manager build. Today the context is not threaded into the init phases (each phase is synchronous and fast), but it is captured so future reshaping — cancellable init, tracing spans, deadline propagation — has the plumbing already in place. Defaults to context.Background() when NewWithOptions is called without this option.
func WithDevMode ¶
WithDevMode toggles the mock-broker path. When true, the Manager constructs a broker/mock client and skips real Kite login; used by the devmode test suite and local dev without Kite credentials.
func WithEncryptionSecret ¶
WithEncryptionSecret supplies the secret used to derive the credential-encryption key (via HKDF in alerts.EnsureEncryptionSalt). Typically the same value as OAUTH_JWT_SECRET so operators manage one secret, not two. Empty disables credential encryption at rest — safe for dev, fatal for production (caller enforces).
func WithExternalURL ¶
WithExternalURL sets the server's externally-reachable URL (e.g. "https://kite-mcp-server.fly.dev"). Used to construct dashboard links and OAuth redirect URIs.
func WithInstrumentsConfig ¶
func WithInstrumentsConfig(cfg *instruments.UpdateConfig) Option
WithInstrumentsConfig overrides the default instruments update configuration (refresh interval, timeout, TestData seed). Ignored when WithInstrumentsManager is also applied.
func WithInstrumentsManager ¶
func WithInstrumentsManager(m *instruments.Manager) Option
WithInstrumentsManager installs a pre-built instruments manager so the Manager skips construction of a new one. Primary use: tests that share a seeded manager across multiple Manager instances for speed.
func WithInstrumentsSkipFetch ¶
WithInstrumentsSkipFetch sets the test-isolation seam so the auto-created instruments manager skips the HTTP fetch of api.kite.trade/instruments.json and loads an empty instrument map instead. Ignored when WithInstrumentsManager is applied.
func WithInvitationStore ¶
func WithInvitationStore(s *users.InvitationStore) Option
WithInvitationStore threads a pre-constructed users.InvitationStore through Manager construction. Same deprecation contract as WithAuditStore.
func WithKiteCredentials ¶
WithKiteCredentials installs the Kite API key + secret pair. These two always travel together (the Kite OAuth flow needs both) so a combined setter avoids the "set key, forget secret" error class. AccessToken (optional pre-set token bypass) has its own setter because it is semantically distinct: key+secret are app identity, AccessToken is user-session identity.
func WithLogger ¶
WithLogger sets the structured logger. Required — NewWithOptions returns an error when the assembled options have a nil Logger, matching the legacy New(cfg) contract.
func WithMetrics ¶
func WithMetrics(m *metrics.Manager) Option
WithMetrics attaches the metrics manager used for per-user tracking and Prometheus-style counters. Optional; Manager runs without metrics when this is nil.
func WithRiskGuard ¶
func WithRiskGuard(g *riskguard.Guard) Option
WithRiskGuard threads a pre-constructed riskguard.Guard through Manager construction. Same deprecation contract as WithAuditStore.
func WithSessionSigner ¶
func WithSessionSigner(s *SessionSigner) Option
WithSessionSigner installs a pre-built HMAC session signer. When omitted the Manager generates a fresh signer at construction. Used by tests that need signature stability across multiple Manager instances.
func WithTelegramBotToken ¶
WithTelegramBotToken configures the Telegram bot used for alert notifications. Empty token disables Telegram — the notifier simply is not constructed.
type OrderService ¶
type OrderService struct {
// Wave D Phase 1 Slice D2: order-write use cases.
PlaceOrderUC *usecases.PlaceOrderUseCase
ModifyOrderUC *usecases.ModifyOrderUseCase
CancelOrderUC *usecases.CancelOrderUseCase
// Slice D3: GTT (Good Till Triggered) write use cases.
PlaceGTTUC *usecases.PlaceGTTUseCase
ModifyGTTUC *usecases.ModifyGTTUseCase
DeleteGTTUC *usecases.DeleteGTTUseCase
// Slice D4: position-exit write use cases.
ClosePositionUC *usecases.ClosePositionUseCase
CloseAllPositionsUC *usecases.CloseAllPositionsUseCase
// Slice D5: margin-query read use cases.
GetOrderMarginsUC *usecases.GetOrderMarginsUseCase
GetBasketMarginsUC *usecases.GetBasketMarginsUseCase
GetOrderChargesUC *usecases.GetOrderChargesUseCase
// Slice D6: widget-query read use cases (the 2 hoistable ones).
// GetOrdersForWidgetUC + GetActivityForWidgetUC stay per-dispatch
// per their ctx-bound audit-store override contract.
GetPortfolioForWidgetUC *usecases.GetPortfolioForWidgetUseCase
GetAlertsForWidgetUC *usecases.GetAlertsForWidgetUseCase
// contains filtered or unexported fields
}
OrderService owns order placement, modification, and cancellation. It resolves a broker.Client per user and delegates to the broker interface. Extracted from Manager as part of Clean Architecture / SOLID refactoring.
Tier B Step 2 (2026-05-16): absorbed the 13 Wave D Phase 1 use-case fields that previously lived on Manager (placeOrderUC, modifyOrderUC, cancelOrderUC, placeGTTUC, modifyGTTUC, deleteGTTUC, closePositionUC, closeAllPositionsUC, getOrderMarginsUC, getBasketMarginsUC, getOrderChargesUC, getPortfolioForWidgetUC, getAlertsForWidgetUC). Manager goes 63 → 50 fields by this move. The constructor signature stays narrow (sessionSvc + logger); the additional 13 UCs are wired in a separate InitUseCases() call from Manager.initOrderUseCases after riskGuard / eventDispatcher / eventStore / instruments are available. This two-phase init matches the existing Wave D pattern.
func NewOrderService ¶
func NewOrderService(sessionSvc *SessionService, logger *slog.Logger) *OrderService
NewOrderService creates a new OrderService.
func (*OrderService) CancelOrder ¶
func (os *OrderService) CancelOrder(email, orderID, variety string) (broker.OrderResponse, error)
CancelOrder cancels an existing pending order.
func (*OrderService) GetOrders ¶
func (os *OrderService) GetOrders(email string) ([]broker.Order, error)
GetOrders returns all orders for the user's current trading day.
func (*OrderService) GetTrades ¶
func (os *OrderService) GetTrades(email string) ([]broker.Trade, error)
GetTrades returns all executed trades for the user's current trading day.
func (*OrderService) InitUseCases ¶ added in v0.1.3
func (os *OrderService) InitUseCases( riskGuard *riskguard.Guard, dispatcher *domain.EventDispatcher, eventStore usecases.EventAppender, lotSizeLookup usecases.LotSizeLookup, alertStore usecases.WidgetAlertStore, )
InitUseCases wires the 13 absorbed Wave D use cases into OrderService. Called from Manager.initOrderUseCases after riskGuard / eventDispatcher / eventStore / instruments are available (post initFocusedServices and pre registerCQRSHandlers). All parameters are nil-tolerant per the pre-existing Wave D contract — riskGuard may be nil (DEV_MODE or no SQLite), dispatcher is nil at this point (production wires after kc.NewWithOptions; tests usually don't wire one), eventStore may be nil, instruments may be nil in test fixtures.
The construction sequence mirrors the prior manager_use_cases.go initOrderUseCases body verbatim. No behavior change.
func (*OrderService) ModifyOrder ¶
func (os *OrderService) ModifyOrder(email, orderID string, params broker.OrderParams) (broker.OrderResponse, error)
ModifyOrder modifies an existing pending order.
func (*OrderService) PlaceOrder ¶
func (os *OrderService) PlaceOrder(email string, params broker.OrderParams) (broker.OrderResponse, error)
PlaceOrder places a new order for the user.
func (*OrderService) PropagateDispatcher ¶ added in v0.1.3
func (os *OrderService) PropagateDispatcher(d *domain.EventDispatcher)
PropagateDispatcher fans the dispatcher into the 8 dispatch-aware use cases. Called by EventingService.SetDispatcher when production (app/wire.go) wires the real dispatcher AFTER kc.NewWithOptions has returned. Each call is nil-safe per the use case's SetEventDispatcher contract; the inner UC field-nil check guards against the pre- InitUseCases path.
type PaperEngineInterface ¶
type PaperEngineInterface interface {
// IsEnabled returns whether paper trading is enabled for the given email.
IsEnabled(email string) bool
// Enable activates paper trading with the specified initial cash.
Enable(email string, initialCash float64) error
// Disable deactivates paper trading.
Disable(email string) error
// Reset clears all paper trading data and resets cash.
Reset(email string) error
// Status returns a summary of the paper trading account.
Status(email string) (map[string]any, error)
// PlaceOrder places a paper order. Returns a Kite-compatible response map.
PlaceOrder(email string, params map[string]any) (map[string]any, error)
// ModifyOrder modifies an open paper order.
ModifyOrder(email, orderID string, params map[string]any) (map[string]any, error)
// CancelOrder cancels an open paper order.
CancelOrder(email, orderID string) (map[string]any, error)
// GetOrders returns all paper orders in Kite API format.
GetOrders(email string) (any, error)
// GetPositions returns all paper positions in Kite API format.
GetPositions(email string) (any, error)
// GetHoldings returns all paper holdings in Kite API format.
GetHoldings(email string) (any, error)
// GetMargins returns paper margin info in Kite API format.
GetMargins(email string) (any, error)
}
PaperEngineInterface defines operations for virtual portfolio trading, allowing users to practice without real money.
type PaperEngineProvider ¶
type PaperEngineProvider interface {
PaperEngine() PaperEngineInterface
}
PaperEngineProvider exposes the paper trading engine. Returns nil if disabled.
type PortfolioService ¶
type PortfolioService struct {
// contains filtered or unexported fields
}
PortfolioService owns portfolio queries: holdings, positions, margins, profile. It resolves a broker.Client per user and delegates to the broker interface. Extracted from Manager as part of Clean Architecture / SOLID refactoring.
func NewPortfolioService ¶
func NewPortfolioService(sessionSvc *SessionService, logger *slog.Logger) *PortfolioService
NewPortfolioService creates a new PortfolioService.
func (*PortfolioService) GetHoldings ¶
func (ps *PortfolioService) GetHoldings(email string) ([]broker.Holding, error)
GetHoldings returns the user's stock holdings.
func (*PortfolioService) GetMargins ¶
func (ps *PortfolioService) GetMargins(email string) (broker.Margins, error)
GetMargins returns the user's account margins.
func (*PortfolioService) GetPositions ¶
func (ps *PortfolioService) GetPositions(email string) (broker.Positions, error)
GetPositions returns the user's current positions.
func (*PortfolioService) GetProfile ¶
func (ps *PortfolioService) GetProfile(email string) (broker.Profile, error)
GetProfile returns the user's profile information.
type QueryBusProvider ¶
type QueryBusProvider interface {
QueryBus() *cqrs.InMemoryBus
}
QueryBusProvider exposes the CQRS query bus for read dispatches. Paired with CommandBusProvider; most tool handlers will depend on both because the same closure often issues a command then a confirming query.
type RawCredentialEntry ¶
RawCredentialEntry is an unredacted credential entry used for internal operations like backfill.
type RegistryReader ¶
type RegistryReader interface {
// Get retrieves a registration by ID.
Get(id string) (*registry.AppRegistration, bool)
// GetByAPIKey finds an active registration by API key.
GetByAPIKey(apiKey string) (*registry.AppRegistration, bool)
// GetByAPIKeyAnyStatus finds a registration by API key regardless of status.
GetByAPIKeyAnyStatus(apiKey string) (*registry.AppRegistration, bool)
// GetByEmail finds the most recently updated active registration for an email.
GetByEmail(email string) (*registry.AppRegistration, bool)
// List returns a redacted summary of all registered apps.
List() []registry.AppRegistrationSummary
// Count returns the number of registry entries.
Count() int
// HasEntries returns true if the registry has any entries.
HasEntries() bool
}
RegistryReader provides read-only access to registry data.
type RegistryStoreInterface ¶
type RegistryStoreInterface interface {
RegistryReader
RegistryWriter
}
RegistryStoreInterface defines operations for the Kite app key registry, used for zero-config onboarding where admins pre-register API credentials. Composed from focused sub-interfaces.
type RegistryStoreProvider ¶
type RegistryStoreProvider interface {
RegistryStore() RegistryStoreInterface
}
RegistryStoreProvider exposes the key registry store.
type RegistryWriter ¶
type RegistryWriter interface {
// Register adds a new app registration.
Register(reg *registry.AppRegistration) error
// Update modifies a registration's mutable fields.
Update(id string, assignedTo, label, status string) error
// UpdateLastUsedAt records the most recent token exchange for an API key.
UpdateLastUsedAt(apiKey string)
// MarkStatus sets the status of a registration found by API key.
MarkStatus(apiKey, status string)
// Delete removes a registration by ID.
Delete(id string) error
}
RegistryWriter provides write operations on registry data.
type RiskGuardProvider ¶
type RiskGuardProvider interface {
RiskGuard() *riskguard.Guard
}
RiskGuardProvider exposes the risk guard. Returns nil if disabled.
type SchedulingService ¶
type SchedulingService struct {
// contains filtered or unexported fields
}
SchedulingService groups background scheduling and cleanup concerns: session cleanup routines, the Kite session cleanup hook, and operational metrics recording (which drives internal daily/cleanup routines on the metrics manager). Manager holds a *SchedulingService field and exposes thin delegators so existing callers continue to work.
Tier 1.3 (Path A.28 — final facade back-pointer elimination, follows Tier 1.1 brokers + Tier 1.2 eventing): the back-pointer to *Manager has been replaced with closures over the underlying fields. Each closure dereferences the source-of-truth Manager field at call time, preserving observable behaviour identical to the prior `s.m.X` access.
initialize() needs the closure-with-write-back variant for sessionManager because the registry is constructed inside the service then handed back to Manager as the source of truth. Read-only closures (Logger, SessionSvc, metrics) follow the same closure-by-reference idiom that landed in Tier 1.1 + 1.2.
func (*SchedulingService) CleanupExpiredSessions ¶
func (s *SchedulingService) CleanupExpiredSessions() int
CleanupExpiredSessions manually triggers cleanup of expired MCP sessions.
func (*SchedulingService) HasMetrics ¶
func (s *SchedulingService) HasMetrics() bool
HasMetrics returns true if a metrics manager is available.
func (*SchedulingService) IncrementDailyMetric ¶
func (s *SchedulingService) IncrementDailyMetric(key string)
IncrementDailyMetric increments a daily metric counter by 1.
func (*SchedulingService) IncrementMetric ¶
func (s *SchedulingService) IncrementMetric(key string)
IncrementMetric increments a metric counter by 1.
func (*SchedulingService) StopCleanupRoutine ¶
func (s *SchedulingService) StopCleanupRoutine()
StopCleanupRoutine stops the background cleanup routine.
func (*SchedulingService) TrackDailyUser ¶
func (s *SchedulingService) TrackDailyUser(userID string)
TrackDailyUser records a unique user interaction for today's counter.
type SessionDB ¶
type SessionDB interface {
SaveSession(sessionID, email string, createdAt, expiresAt time.Time, terminated bool) error
LoadSessions() ([]*SessionLoadEntry, error)
DeleteSession(sessionID string) error
}
SessionDB is an optional persistence backend for MCP sessions. Implemented by an adapter that wraps alerts.DB to avoid circular imports.
type SessionIdManagerShim ¶
type SessionIdManagerShim interface {
Generate() string
Validate(sessionID string) (isTerminated bool, err error)
Terminate(sessionID string) (isNotAllowed bool, err error)
}
SessionIdManagerShim mirrors mcp-go's SessionIdManager interface without importing the mcp-go server package (which would create an import cycle between kc and mcp-go). The app-level wire code in app/http.go casts this shim to the library's interface; they're structurally identical.
type SessionLifecycleService ¶
type SessionLifecycleService struct {
// contains filtered or unexported fields
}
SessionLifecycleService is a thin facade over SessionService that groups MCP-session lifecycle delegators (get/create/clear/complete). Manager keeps the old method names as delegators into this facade for backward compatibility with existing call sites.
func (*SessionLifecycleService) ClearSession ¶
func (s *SessionLifecycleService) ClearSession(sessionID string)
ClearSession terminates a session, triggering cleanup hooks.
func (*SessionLifecycleService) ClearSessionData ¶
func (s *SessionLifecycleService) ClearSessionData(sessionID string) error
ClearSessionData clears the session data without terminating the session.
func (*SessionLifecycleService) CompleteSession ¶
func (s *SessionLifecycleService) CompleteSession(mcpSessionID, kiteRequestToken string) error
CompleteSession completes Kite authentication using the request token. Back-compat wrapper around CompleteSessionAndRotate.
func (*SessionLifecycleService) CompleteSessionAndRotate ¶
func (s *SessionLifecycleService) CompleteSessionAndRotate(mcpSessionID, kiteRequestToken string) (string, error)
CompleteSessionAndRotate completes Kite authentication AND rotates the MCP session ID for OWASP A07 (Session Fixation) defence. Returns the post-rotation session ID.
func (*SessionLifecycleService) GenerateSession ¶
func (s *SessionLifecycleService) GenerateSession() string
GenerateSession creates a new MCP session and returns its ID.
func (*SessionLifecycleService) GetActiveSessionCount ¶
func (s *SessionLifecycleService) GetActiveSessionCount() int
GetActiveSessionCount returns the number of active sessions.
func (*SessionLifecycleService) GetOrCreateSession ¶
func (s *SessionLifecycleService) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
GetOrCreateSession retrieves an existing Kite session or creates a new one.
func (*SessionLifecycleService) GetOrCreateSessionWithEmail ¶
func (s *SessionLifecycleService) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
GetOrCreateSessionWithEmail retrieves or creates a Kite session with email context.
func (*SessionLifecycleService) GetSession ¶
func (s *SessionLifecycleService) GetSession(mcpSessionID string) (*KiteSessionData, error)
GetSession retrieves an existing Kite session by MCP session ID.
func (*SessionLifecycleService) SessionLoginURL ¶
func (s *SessionLifecycleService) SessionLoginURL(mcpSessionID string) (string, error)
SessionLoginURL returns the Kite login URL for the given session.
type SessionLoadEntry ¶
type SessionLoadEntry struct {
SessionID string
Email string
CreatedAt time.Time
ExpiresAt time.Time
Terminated bool
}
SessionLoadEntry represents a session loaded from the database.
type SessionRegistry ¶
type SessionRegistry struct {
// contains filtered or unexported fields
}
func NewSessionRegistry ¶
func NewSessionRegistry(logger *slog.Logger) *SessionRegistry
NewSessionRegistry creates a new registry that manages MCP sessions and their associated Kite data
func NewSessionRegistryWithDuration ¶
func NewSessionRegistryWithDuration(duration time.Duration, logger *slog.Logger) *SessionRegistry
NewSessionRegistryWithDuration creates a new session registry with custom duration
func (*SessionRegistry) AddCleanupHook ¶
func (sm *SessionRegistry) AddCleanupHook(hook CleanupHook)
AddCleanupHook adds a cleanup function for the Kite session to be called when MCP sessions are terminated
func (*SessionRegistry) CleanupExpiredSessions ¶
func (sm *SessionRegistry) CleanupExpiredSessions() int
CleanupExpiredSessions removes expired MCP sessions from memory and their associated Kite data
func (*SessionRegistry) Generate ¶
func (sm *SessionRegistry) Generate() string
Generate creates a new MCP session ID and stores it in memory
func (*SessionRegistry) GenerateWithData ¶
func (sm *SessionRegistry) GenerateWithData(data any) string
GenerateWithData creates a new MCP session ID with associated Kite data and stores it in memory. ClientHint is left empty. Callers with access to the originating HTTP request should use GenerateWithDataAndHint instead.
func (*SessionRegistry) GenerateWithDataAndHint ¶
func (sm *SessionRegistry) GenerateWithDataAndHint(data any, clientHint string) string
GenerateWithDataAndHint creates a new MCP session ID with associated Kite data and a free-form client hint (typically the User-Agent of the HTTP request that caused the session to be issued). The hint is best-effort — empty is acceptable and renders as "Unknown" to consumers.
func (*SessionRegistry) GetOrCreateSessionData ¶
func (sm *SessionRegistry) GetOrCreateSessionData(sessionID string, createDataFn func() any) (data any, isNew bool, err error)
GetOrCreateSessionData atomically validates session and retrieves/creates data to eliminate TOCTOU races
func (*SessionRegistry) GetSession ¶
func (sm *SessionRegistry) GetSession(sessionID string) (*MCPSession, error)
GetSession retrieves a MCP session by ID (helper method)
func (*SessionRegistry) GetSessionData ¶
func (sm *SessionRegistry) GetSessionData(sessionID string) (any, error)
GetSessionData retrieves the Kite data for a MCP session
func (*SessionRegistry) GetSessionDuration ¶
func (sm *SessionRegistry) GetSessionDuration() time.Duration
GetSessionDuration returns the configured MCP session duration
func (*SessionRegistry) ListActiveSessions ¶
func (sm *SessionRegistry) ListActiveSessions() []*MCPSession
ListActiveSessions returns all non-terminated MCP sessions (helper method)
func (*SessionRegistry) LoadFromDB ¶
func (sm *SessionRegistry) LoadFromDB() error
LoadFromDB populates the in-memory session registry from the database. Expired and terminated sessions are skipped (and deleted from DB). Valid sessions are restored with Data set to &KiteSessionData{Email: email}.
func (*SessionRegistry) SetDB ¶
func (sm *SessionRegistry) SetDB(db SessionDB)
SetDB enables write-through persistence to the given session database.
func (*SessionRegistry) SetSessionDuration ¶
func (sm *SessionRegistry) SetSessionDuration(duration time.Duration)
SetSessionDuration updates the MCP session duration for new sessions
func (*SessionRegistry) StartCleanupRoutine ¶
func (sm *SessionRegistry) StartCleanupRoutine(ctx context.Context)
StartCleanupRoutine starts background cleanup goroutines for expired MCP sessions
func (*SessionRegistry) StopCleanupRoutine ¶
func (sm *SessionRegistry) StopCleanupRoutine()
StopCleanupRoutine stops background cleanup goroutines for MCP sessions and waits for the cleanupRoutine goroutine to exit before returning. Safe to call multiple times — the sync.Once guard absorbs double-close of the internal cancel context. Waiting (rather than returning after a signal) lets goleak-style sentinels observe the goroutine has actually terminated.
func (*SessionRegistry) Terminate ¶
func (sm *SessionRegistry) Terminate(sessionID string) (isNotAllowed bool, err error)
Terminate marks a MCP session ID as terminated and cleans up associated Kite session
func (*SessionRegistry) TerminateByEmail ¶
func (sm *SessionRegistry) TerminateByEmail(email string) int
TerminateByEmail terminates all active sessions belonging to the given email. Used when offboarding a user to revoke all their sessions.
func (*SessionRegistry) UpdateSessionData ¶
func (sm *SessionRegistry) UpdateSessionData(sessionID string, data any) error
UpdateSessionData updates the Kite data for an existing MCP session
func (*SessionRegistry) UpdateSessionField ¶
func (sm *SessionRegistry) UpdateSessionField(sessionID string, mutator func(data any)) error
UpdateSessionField updates a field within the session data under the registry lock. The mutator function is called with the session's Data pointer while holding the write lock, ensuring no concurrent reads or writes can race on session fields.
func (*SessionRegistry) Validate ¶
func (sm *SessionRegistry) Validate(sessionID string) (isTerminated bool, err error)
Validate checks if a MCP session ID is valid and not terminated. Uses a read lock for the common (non-expired) path and only upgrades to a write lock when the session needs to be marked as terminated.
type SessionService ¶
type SessionService struct {
CredentialSvc *CredentialService
// contains filtered or unexported fields
}
SessionService owns MCP session lifecycle: creation, retrieval, validation, login URL generation, and session completion. Extracted from Manager as part of Clean Architecture / SOLID refactoring.
Dependencies use interface types (Dependency Inversion Principle), enabling mock injection for testing.
func NewSessionService ¶
func NewSessionService(cfg SessionServiceConfig) *SessionService
NewSessionService creates a new SessionService. The SessionRegistry is created internally; use SetDB to wire persistence.
func (*SessionService) CleanupExpiredSessions ¶
func (ss *SessionService) CleanupExpiredSessions() int
CleanupExpiredSessions manually triggers cleanup of expired MCP sessions.
func (*SessionService) ClearSession ¶
func (ss *SessionService) ClearSession(sessionID string)
ClearSession terminates a session, triggering cleanup hooks.
func (*SessionService) ClearSessionData ¶
func (ss *SessionService) ClearSessionData(sessionID string) error
ClearSessionData clears the session data without terminating the session.
func (*SessionService) CompleteSession ¶
func (ss *SessionService) CompleteSession(mcpSessionID, kiteRequestToken string) error
CompleteSession completes Kite authentication using the request token.
Back-compat shim around CompleteSessionAndRotate. New callers should use CompleteSessionAndRotate directly to receive the post-auth rotated session ID — that's the OWASP A07 (session fixation) defence. This wrapper discards the new ID and returns only the error so the pre-G99 `error`-only signature continues to compile.
In-tree callers (the HTTP callback handler in kc/callback_handler.go) have been migrated; the handful of test fixtures that still call this method don't care about the rotated ID.
func (*SessionService) CompleteSessionAndRotate ¶
func (ss *SessionService) CompleteSessionAndRotate(mcpSessionID, kiteRequestToken string) (string, error)
CompleteSessionAndRotate completes Kite authentication AND rotates the MCP session ID — OWASP A07 (Session Fixation) defence.
The flow:
- Validate the supplied (possibly attacker-influenced) session ID.
- Exchange Kite request token for the access token.
- Generate a fresh session ID via SessionRegistry.Generate (which uses crypto/rand-backed UUIDv4 — same RNG as the original session-issuance path).
- Migrate the Kite session data (token, email, user id) onto the new ID.
- Terminate the old ID so Validate() rejects it.
The new ID is returned to the caller, which is responsible for surfacing it back to the legitimate MCP client (e.g. via a signed cookie on the callback response, or a server-side mapping keyed by the user's email).
On any pre-rotation failure the OLD session is left untouched — nothing was authenticated, nothing to invalidate. Callers seeing a non-nil error should NOT treat the old ID as terminated.
func (*SessionService) GenerateSession ¶
func (ss *SessionService) GenerateSession() string
GenerateSession creates a new MCP session with Kite data and returns the session ID.
func (*SessionService) GetActiveSessionCount ¶
func (ss *SessionService) GetActiveSessionCount() int
GetActiveSessionCount returns the number of active sessions.
func (*SessionService) GetBrokerForEmail ¶
func (ss *SessionService) GetBrokerForEmail(email string) (broker.Client, error)
GetBrokerForEmail resolves a broker.Client for the given email. It first checks for an active session with a broker (preserves custom base URI and avoids creating redundant clients). In DevMode, returns a mock broker. Otherwise, falls back to creating a new client from cached credentials.
func (*SessionService) GetOrCreateSession ¶
func (ss *SessionService) GetOrCreateSession(mcpSessionID string) (*KiteSessionData, bool, error)
GetOrCreateSession retrieves an existing Kite session or creates a new one atomically. For email-aware session creation (Fly.io with OAuth), use GetOrCreateSessionWithEmail.
func (*SessionService) GetOrCreateSessionWithEmail ¶
func (ss *SessionService) GetOrCreateSessionWithEmail(mcpSessionID, email string) (*KiteSessionData, bool, error)
GetOrCreateSessionWithEmail retrieves or creates a Kite session with email context. If email is provided and a cached Kite token exists for that email, it is auto-applied.
func (*SessionService) GetSession ¶
func (ss *SessionService) GetSession(mcpSessionID string) (*KiteSessionData, error)
GetSession retrieves an existing Kite session by MCP session ID.
func (*SessionService) HasBrokerFactory ¶
func (ss *SessionService) HasBrokerFactory() bool
HasBrokerFactory reports whether an explicit broker.Factory is wired. Used by /healthz?probe=deep to surface mis-wired deployments where session creation would fail later under load. A nil factory is fine in DevMode (the session lifecycle falls through to a lazy default); production deployments should always wire one.
func (*SessionService) InitializeSessionManager ¶
func (ss *SessionService) InitializeSessionManager()
InitializeSessionManager creates and configures the session registry with cleanup hooks.
func (*SessionService) SessionLoginURL ¶
func (ss *SessionService) SessionLoginURL(mcpSessionID string) (string, error)
SessionLoginURL returns the Kite login URL for the given session. Returns an error in DEV_MODE since there is no real Kite client to generate a login URL.
func (*SessionService) SessionManager ¶
func (ss *SessionService) SessionManager() *SessionRegistry
SessionManager returns the underlying SessionRegistry.
func (*SessionService) SetAuditStore ¶
func (ss *SessionService) SetAuditStore(store AuditStoreInterface)
SetAuditStore wires the audit store for synthetic session events.
func (*SessionService) SetBrokerFactory ¶
func (ss *SessionService) SetBrokerFactory(f broker.Factory)
SetBrokerFactory overrides the broker factory used by GetBrokerForEmail. Intended for tests that need to inject a mock broker.Factory.
func (*SessionService) SetEventDispatcher ¶
func (ss *SessionService) SetEventDispatcher(d *domain.EventDispatcher)
SetEventDispatcher wires the domain event dispatcher so the service can emit SessionCreatedEvent on every new MCP session. Optional — a nil dispatcher disables the side-effect (existing behavior). Called from the Manager after its dispatcher is built.
func (*SessionService) SetSessionManager ¶
func (ss *SessionService) SetSessionManager(sm *SessionRegistry)
SetSessionManager allows injecting an already-configured SessionRegistry (used by Manager).
func (*SessionService) StopCleanupRoutine ¶
func (ss *SessionService) StopCleanupRoutine()
StopCleanupRoutine stops the background cleanup routine.
type SessionServiceConfig ¶
type SessionServiceConfig struct {
CredentialSvc *CredentialService
TokenStore TokenStoreInterface
SessionSigner *SessionSigner
AuditStore AuditStoreInterface
Logger *slog.Logger
Metrics metricsTracker
DevMode bool
BrokerFactory broker.Factory // optional: defaults to Zerodha factory if nil
}
SessionServiceConfig holds dependencies for creating a SessionService.
type SessionSigner ¶
type SessionSigner struct {
// contains filtered or unexported fields
}
SessionSigner handles HMAC signing and verification of session parameters
func NewSessionSigner ¶
func NewSessionSigner() (*SessionSigner, error)
NewSessionSigner creates a new session signer with a random secret key
func NewSessionSignerWithKey ¶
func NewSessionSignerWithKey(secretKey []byte) (*SessionSigner, error)
NewSessionSignerWithKey creates a new session signer with a provided secret key
func (*SessionSigner) SetSignatureExpiry ¶
func (s *SessionSigner) SetSignatureExpiry(duration time.Duration)
SetSignatureExpiry sets the expiry duration for signed session parameters
func (*SessionSigner) SignRedirectParams ¶
func (s *SessionSigner) SignRedirectParams(sessionID string) (string, error)
SignRedirectParams creates a signed redirect parameter string for Kite authentication
func (*SessionSigner) SignSessionID ¶
func (s *SessionSigner) SignSessionID(sessionID string) string
SignSessionID creates a signed session parameter with timestamp and HMAC signature
func (*SessionSigner) ValidateSessionID ¶
func (s *SessionSigner) ValidateSessionID(sessionID string) error
ValidateSessionID performs basic validation on a session ID format
func (*SessionSigner) VerifyRedirectParams ¶
func (s *SessionSigner) VerifyRedirectParams(redirectParams string) (string, error)
VerifyRedirectParams verifies signed redirect parameters and extracts the session ID
func (*SessionSigner) VerifySessionID ¶
func (s *SessionSigner) VerifySessionID(signedParam string) (string, error)
VerifySessionID verifies a signed session parameter and extracts the session ID
type StoreAccessor ¶
type StoreAccessor interface {
TokenStoreProvider
CredentialStoreProvider
TelegramStoreProvider
WatchlistStoreProvider
UserStoreProvider
RegistryStoreProvider
AuditStoreProvider
BillingStoreProvider
TickerServiceProvider
PaperEngineProvider
// AlertStore() + AlertDB() + InstrumentsManager() inlined here
// (Phase B/D F1 close): the previous AlertStoreProvider /
// AlertDBProvider / InstrumentsManagerProvider single-method
// aliases were deleted in favor of ports.AlertPort + ports.
// InstrumentPort at consumer sites. StoreAccessor lives in package
// kc and cannot embed kc/ports types without creating a cycle
// (kc/ports already imports kc), so each accessor is inlined here
// directly. *kc.Manager satisfies the corresponding ports via its
// existing method implementations — see kc/ports/alert.go:25,
// kc/ports/instrument.go:32, and kc/ports/assertions.go.
AlertStore() AlertStoreInterface
AlertDB() *alerts.DB
InstrumentsManager() InstrumentManagerInterface
RiskGuardProvider
MCPServerProvider
}
StoreAccessor is the aggregate composition of every Manager-implemented store-provider interface, retained for consumers that legitimately need broad access (e.g. the Manager itself, admin tooling, and registration code). New code should depend on the narrowest port (kc/ports) or provider it needs instead of the aggregate.
Note: TelegramNotifier, TrailingStopManager, and PnLService are intentionally excluded — those three accessors live on AlertService (obtain them via m.AlertSvc().TelegramNotifier() etc.) and are not exposed on Manager itself after the Round 3 decomposition. Consumers that need them depend on ports.AlertPort directly (which mirrors AlertService's surface), not on StoreAccessor.
type StoreRegistry ¶
type StoreRegistry struct {
// contains filtered or unexported fields
}
StoreRegistry groups all persistence store accessors that Manager previously exposed directly. Manager retains a *StoreRegistry field and thin delegator methods (defined below) forward to it for backward compatibility with the 73 files that already depend on the Manager-level accessors.
Concrete vs interface-typed accessor pairing -------------------------------------------- Each store has two accessors: an interface-typed one (e.g., TokenStore() → TokenStoreInterface) and a *Concrete()-suffixed sibling (e.g., TokenStoreConcrete() → *KiteTokenStore). The interface-typed pair is the canonical "consumer" surface — application logic that depends on a store should accept the narrowest interface that lets it work, per ISP and the hexagonal port discipline.
The *Concrete() siblings are an architectural escape hatch retained **for construction-site use only** — composition-root files that pass concrete pointer types into adapter struct literals or service constructors that legitimately need access to fields/methods not on the interface surface. Examples: app/app.go's kiteExchangerAdapter (needs *KiteTokenStore for direct cache access on a CQRS-bypass-ok read path), app/wire.go's briefingTokenAdapter, kc/ops/handler.go (UI handler that needs *registry.Store for List() shape — wider than RegistryReader.List() can express). Phase 3a kc/-side migration documented this status; the *Concrete() methods are not "leaks" to be retired — they are an architectural exception, symmetric with the mcp/-consumer side's admin_baseline_tool.go / admin_cache_info_tool.go AuditStoreConcrete uses for forensics-only methods (UserOrderStats / StatsCacheHitRate).
Phase 3a-complete state at this commit:
- Consumer surfaces (mcp/, kc/telegram, kc/manager_use_cases.go's read paths) route through interface-typed accessors.
- Construction-site surfaces (app/app.go, app/wire.go, kc/ops/handler.go, and kc-internal manager_queries_escapes.go's audit fallback) use *Concrete() siblings explicitly because they need concrete-type access for adapter constructions.
Future deletion of the *Concrete() siblings would require either (a) widening every store interface to absorb every concrete-only method (UserOrderStats, StatsCacheHitRate, etc.) — anti-Go-idiom, surface bloat, fails ISP, or (b) restructuring the construction-site adapters to take interface fields and threading the concrete-method calls through their own adapter ports — substantial app/wire.go churn that ADR 0006 §"What was rejected" explicitly excluded for ROI reasons. Both options are anti-rec'd; the current state is the calibrated end-state.
func (*StoreRegistry) AlertDB ¶
func (s *StoreRegistry) AlertDB() *alerts.DB
AlertDB returns the optional SQLite database used for persistence.
func (*StoreRegistry) AlertStore ¶
func (s *StoreRegistry) AlertStore() AlertStoreInterface
AlertStore returns the per-user alert store.
func (*StoreRegistry) AlertStoreConcrete ¶
func (s *StoreRegistry) AlertStoreConcrete() *alerts.Store
AlertStoreConcrete returns the concrete alert store.
func (*StoreRegistry) AuditStore ¶
func (s *StoreRegistry) AuditStore() AuditStoreInterface
AuditStore returns the audit trail store, or nil if not configured.
func (*StoreRegistry) AuditStoreConcrete ¶
func (s *StoreRegistry) AuditStoreConcrete() *audit.Store
AuditStoreConcrete returns the concrete audit store.
func (*StoreRegistry) BillingStore ¶
func (s *StoreRegistry) BillingStore() BillingStoreInterface
BillingStore returns the billing store, or nil if not configured.
func (*StoreRegistry) BillingStoreConcrete ¶
func (s *StoreRegistry) BillingStoreConcrete() *billing.Store
BillingStoreConcrete returns the concrete billing store.
func (*StoreRegistry) CredentialStore ¶
func (s *StoreRegistry) CredentialStore() CredentialStoreInterface
CredentialStore returns the per-email Kite credential store.
func (*StoreRegistry) CredentialStoreConcrete ¶
func (s *StoreRegistry) CredentialStoreConcrete() *KiteCredentialStore
CredentialStoreConcrete returns the concrete credential store.
func (*StoreRegistry) InvitationStore ¶
func (s *StoreRegistry) InvitationStore() *users.InvitationStore
InvitationStore returns the invitation store, or nil if not configured.
func (*StoreRegistry) RegistryStore ¶
func (s *StoreRegistry) RegistryStore() RegistryStoreInterface
RegistryStore returns the key registry store.
func (*StoreRegistry) RegistryStoreConcrete ¶
func (s *StoreRegistry) RegistryStoreConcrete() *registry.Store
RegistryStoreConcrete returns the concrete registry store.
func (*StoreRegistry) SetAuditStore ¶
func (s *StoreRegistry) SetAuditStore(store *audit.Store)
SetAuditStore wires the audit store.
func (*StoreRegistry) SetBillingStore ¶
func (s *StoreRegistry) SetBillingStore(store *billing.Store)
SetBillingStore sets the billing store.
func (*StoreRegistry) SetInvitationStore ¶
func (s *StoreRegistry) SetInvitationStore(store *users.InvitationStore)
SetInvitationStore sets the invitation store.
func (*StoreRegistry) TelegramStore ¶
func (s *StoreRegistry) TelegramStore() TelegramStoreInterface
TelegramStore returns the per-user Telegram chat ID store.
func (*StoreRegistry) TokenStore ¶
func (s *StoreRegistry) TokenStore() TokenStoreInterface
TokenStore returns the per-email Kite token store.
func (*StoreRegistry) TokenStoreConcrete ¶
func (s *StoreRegistry) TokenStoreConcrete() *KiteTokenStore
TokenStoreConcrete returns the concrete token store (for internal wiring).
func (*StoreRegistry) UserStore ¶
func (s *StoreRegistry) UserStore() UserStoreInterface
UserStore returns the user identity store.
func (*StoreRegistry) UserStoreConcrete ¶
func (s *StoreRegistry) UserStoreConcrete() *users.Store
UserStoreConcrete returns the concrete user store.
func (*StoreRegistry) WatchlistStore ¶
func (s *StoreRegistry) WatchlistStore() WatchlistStoreInterface
WatchlistStore returns the per-user watchlist store.
func (*StoreRegistry) WatchlistStoreConcrete ¶
func (s *StoreRegistry) WatchlistStoreConcrete() *watchlist.Store
WatchlistStoreConcrete returns the concrete watchlist store.
type TelegramStoreInterface ¶
type TelegramStoreInterface interface {
// SetTelegramChatID sets the Telegram chat ID for a user.
SetTelegramChatID(email string, chatID int64)
// GetTelegramChatID returns the Telegram chat ID for a user.
GetTelegramChatID(email string) (int64, bool)
// GetEmailByChatID performs a reverse lookup from chat ID to email.
GetEmailByChatID(chatID int64) (string, bool)
// ListAllTelegram returns all Telegram chat ID mappings.
ListAllTelegram() map[string]int64
}
TelegramStoreInterface defines operations for managing per-user Telegram chat ID mappings. Separated from AlertStoreInterface per Single Responsibility.
type TelegramStoreProvider ¶
type TelegramStoreProvider interface {
TelegramStore() TelegramStoreInterface
}
TelegramStoreProvider exposes the per-user Telegram chat ID store.
type TemplateData ¶
type TemplateData struct {
Title string
RedirectURL string // optional: used by login_success.html for auto-redirect
}
TemplateData holds data for template rendering on callback success.
type TickerServiceInterface ¶
type TickerServiceInterface interface {
// Start creates and starts a WebSocket ticker for the given user.
Start(email, apiKey, accessToken string) error
// Stop stops the ticker for the given user.
Stop(email string) error
// UpdateToken stops and restarts a ticker with a fresh token.
UpdateToken(email, apiKey, accessToken string) error
// Subscribe subscribes the user's ticker to instrument tokens.
Subscribe(email string, tokens []uint32, mode brokerticker.Mode) error
// Unsubscribe removes instrument tokens from the user's ticker.
Unsubscribe(email string, tokens []uint32) error
// GetStatus returns the current status of a user's ticker.
GetStatus(email string) (*ticker.Status, error)
// IsRunning returns true if a ticker is active for the given email.
IsRunning(email string) bool
// ListAll returns a summary of all active ticker connections.
ListAll() []ticker.UserTickerInfo
// Shutdown stops all running tickers.
Shutdown()
}
TickerServiceInterface defines operations for managing per-user WebSocket ticker connections for real-time market data.
type TickerServiceProvider ¶
type TickerServiceProvider interface {
TickerService() TickerServiceInterface
}
TickerServiceProvider exposes the per-user WebSocket ticker service.
type TokenChangeCallback ¶
type TokenChangeCallback func(email string, entry *KiteTokenEntry)
TokenChangeCallback is invoked when a token is stored or updated.
type TokenStoreInterface ¶
type TokenStoreInterface interface {
// Get retrieves a stored token for the given email.
Get(email string) (*KiteTokenEntry, bool)
// Set stores a token for the given email and notifies observers.
Set(email string, entry *KiteTokenEntry)
// Delete removes a token for the given email.
Delete(email string)
// OnChange registers a callback that fires when a token is stored or updated.
OnChange(cb TokenChangeCallback)
// ListAll returns a redacted summary of all cached tokens.
ListAll() []KiteTokenSummary
// Count returns the number of stored tokens.
Count() int
}
TokenStoreInterface defines operations for caching per-user Kite access tokens so users only need to login once per day.
type TokenStoreProvider ¶
type TokenStoreProvider interface {
TokenStore() TokenStoreInterface
}
TokenStoreProvider exposes the per-email Kite token store.
type UserAuthChecker ¶
type UserAuthChecker interface {
// IsAdmin returns true if the email belongs to an active admin.
IsAdmin(email string) bool
// HasPassword returns true if the user has a non-empty password hash.
HasPassword(email string) bool
// VerifyPassword checks plaintext password against stored hash.
VerifyPassword(email, password string) (bool, error)
}
UserAuthChecker provides authentication and authorization checks.
type UserReader ¶
type UserReader interface {
// Get retrieves a user by email.
Get(email string) (*users.User, bool)
// GetByEmail is an alias for Get.
GetByEmail(email string) (*users.User, bool)
// Exists returns true if a user with the given email exists.
Exists(email string) bool
// GetStatus returns the user's status (empty if not found).
GetStatus(email string) string
// GetRole returns the user's role (empty if not found).
GetRole(email string) string
// List returns all users as a slice.
List() []*users.User
// Count returns the number of registered users.
Count() int
// ListByAdminEmail returns all users linked to this admin.
ListByAdminEmail(adminEmail string) []*users.User
// EnsureUser creates a user if they don't exist, returning the user.
EnsureUser(email, kiteUID, displayName, onboardedBy string) *users.User
// EnsureAdmin creates or upgrades a user to admin role.
EnsureAdmin(email string)
}
UserReader provides read-only access to user data.
type UserStoreInterface ¶
type UserStoreInterface interface {
UserReader
UserWriter
UserAuthChecker
}
UserStoreInterface defines operations for user registration, authentication, and role-based access control. Composed from focused sub-interfaces.
type UserStoreProvider ¶
type UserStoreProvider interface {
UserStore() UserStoreInterface
}
UserStoreProvider exposes the user identity store.
type UserWriter ¶
type UserWriter interface {
// Create inserts a new user. Returns error if user already exists.
Create(u *users.User) error
// Delete removes a user from the store.
Delete(email string)
// UpdateLastLogin records the current time as the user's last login.
UpdateLastLogin(email string)
// UpdateRole changes the user's role.
UpdateRole(email, role string) error
// UpdateStatus changes the user's status.
UpdateStatus(email, status string) error
// UpdateKiteUID sets the Kite user ID for a user.
UpdateKiteUID(email, kiteUID string)
// SetAdminEmail links a user to their admin for family billing.
SetAdminEmail(email, adminEmail string) error
// SetPasswordHash stores a bcrypt password hash for the given user.
SetPasswordHash(email, hash string) error
}
UserWriter provides write operations on user data.
type WatchlistStoreInterface ¶
type WatchlistStoreInterface interface {
// CreateWatchlist creates a new named watchlist for the user.
CreateWatchlist(email, name string) (string, error)
// DeleteWatchlist removes a watchlist and all its items.
DeleteWatchlist(email, watchlistID string) error
// DeleteByEmail removes all watchlists for the given email.
DeleteByEmail(email string)
// ListWatchlists returns all watchlists for the given email.
ListWatchlists(email string) []*watchlist.Watchlist
// ItemCount returns the number of items in a watchlist.
ItemCount(watchlistID string) int
// AddItem adds an instrument to a watchlist.
AddItem(email, watchlistID string, item *watchlist.WatchlistItem) error
// RemoveItem removes an instrument from a watchlist by item ID.
RemoveItem(email, watchlistID, itemID string) error
// GetItems returns copies of all items in a watchlist.
GetItems(watchlistID string) []*watchlist.WatchlistItem
// GetAllItems returns all items across all watchlists for a user.
GetAllItems(email string) []*watchlist.WatchlistItem
// FindWatchlistByName returns the watchlist with the given name for the user.
FindWatchlistByName(email, name string) *watchlist.Watchlist
// FindItemBySymbol finds an item by exchange:tradingsymbol in a watchlist.
FindItemBySymbol(watchlistID, exchange, tradingsymbol string) *watchlist.WatchlistItem
}
WatchlistStoreInterface defines operations for managing named instrument watchlists per user.
type WatchlistStoreProvider ¶
type WatchlistStoreProvider interface {
WatchlistStore() WatchlistStoreInterface
}
WatchlistStoreProvider exposes the per-user watchlist store.
Source Files
¶
- alert_service.go
- broker_services.go
- callback_handler.go
- client_hint_detect.go
- client_hint_resolver.go
- config.go
- config_manager.go
- credential_service.go
- credential_store.go
- eventing_service.go
- expiry.go
- family_service.go
- fill_watcher.go
- identity_service.go
- interfaces.go
- kite_client.go
- kite_connect.go
- manager.go
- manager_accessors.go
- manager_commands_account.go
- manager_commands_admin.go
- manager_commands_admin_alerts.go
- manager_commands_admin_mf.go
- manager_commands_admin_native_alerts.go
- manager_commands_admin_risk.go
- manager_commands_admin_ticker.go
- manager_commands_admin_user.go
- manager_commands_exit.go
- manager_commands_oauth.go
- manager_commands_orders.go
- manager_commands_setup.go
- manager_cqrs_register.go
- manager_init.go
- manager_init_alerts.go
- manager_init_persistence.go
- manager_init_services.go
- manager_init_stores.go
- manager_interfaces.go
- manager_lifecycle.go
- manager_orders_fallback.go
- manager_queries_escapes.go
- manager_queries_remaining.go
- manager_struct.go
- manager_use_cases.go
- options.go
- order_service.go
- portfolio_service.go
- reconstitution.go
- scheduling_service.go
- session.go
- session_lifecycle_service.go
- session_service.go
- session_signing.go
- session_svc.go
- store_registry.go
- timezone.go
- token_store.go
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
util
Package util holds small helper functions internal to the kite-mcp-kc module.
|
Package util holds small helper functions internal to the kite-mcp-kc module. |
|
shared
Package shared holds the kc/ops sub-package's foundation types — pure DTOs (OverviewData, SessionInfo, TickerData, AlertData) and the LogBuffer / TeeHandler observability primitives — extracted from kc/ops/ to enable the planned Anchor 3 fan-out (PRs 3.2 admin, 3.3 user) per .research/anchor-1-and-3-pr-design.md.
|
Package shared holds the kc/ops sub-package's foundation types — pure DTOs (OverviewData, SessionInfo, TickerData, AlertData) and the LogBuffer / TeeHandler observability primitives — extracted from kc/ops/ to enable the planned Anchor 3 fan-out (PRs 3.2 admin, 3.3 user) per .research/anchor-1-and-3-pr-design.md. |
|
Package ports holds the bounded-context interfaces (hexagonal ports) that Manager satisfies.
|
Package ports holds the bounded-context interfaces (hexagonal ports) that Manager satisfies. |