Documentation
¶
Overview ¶
Package server provides the HTTP API for the online calibration subsystem. It exposes endpoints for ingesting calibration events, retrieving per-team thresholds, and deleting team data. All protected routes require a Bearer token supplied at construction time.
Package server defines the server-side interfaces and types for the online calibration subsystem. Implementations of these interfaces handle event persistence, profile materialisation, and cross-org signal computation.
Index ¶
- type APIServer
- type EventStore
- type SQLiteStore
- func (s *SQLiteStore) AppendEvents(ctx context.Context, teamID string, events []calibration.Event) error
- func (s *SQLiteStore) Close() error
- func (s *SQLiteStore) DeleteTeamData(ctx context.Context, teamID string) error
- func (s *SQLiteStore) GetGlobalStats(ctx context.Context, ruleIDs []string) (map[string]calibration.CrossOrgSignal, error)
- func (s *SQLiteStore) GetTeamProfile(ctx context.Context, teamID string, ruleIDs []string) ([]calibration.RuleProfile, error)
- func (s *SQLiteStore) UpdateProfileFromFeedback(ctx context.Context, teamID string, fb calibration.FeedbackPayload) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIServer ¶
type APIServer struct {
// contains filtered or unexported fields
}
APIServer is an HTTP server that exposes the calibration API. It wraps an EventStore for persistence and a chi.Router for routing. APIServer implements http.Handler so it can be passed directly to http.ListenAndServe or used in httptest.NewServer.
func NewAPIServer ¶
func NewAPIServer(store EventStore, apiKey string) *APIServer
NewAPIServer constructs and wires an APIServer with the given EventStore and API key. The API key is used by authMiddleware to validate Bearer tokens on all protected routes.
Routes:
GET /v1/health – unauthenticated liveness probe
POST /v1/events/batch – ingest a batch of calibration events
GET /v1/calibration/{teamID} – retrieve per-team thresholds + cross-org signals
DELETE /v1/teams/{teamID}/data – erase all data for a team (GDPR)
type EventStore ¶
type EventStore interface {
// AppendEvents stores a batch of events for the given team. Events are
// appended in the order provided; the store must not reorder them.
// Returns an error if any event in the batch cannot be persisted — in that
// case the implementation should treat the batch atomically (all-or-nothing)
// where the underlying storage supports it.
AppendEvents(ctx context.Context, teamID string, events []calibration.Event) error
// GetTeamProfile returns the materialised calibration profile for each of
// the requested ruleIDs belonging to teamID. Rules that have no profile yet
// are omitted from the result slice rather than returned as zero values.
GetTeamProfile(ctx context.Context, teamID string, ruleIDs []string) ([]calibration.RuleProfile, error)
// GetGlobalStats returns anonymised cross-org calibration signals for each
// of the requested ruleIDs. The returned map is keyed by rule ID. Rules
// that have no cross-org data are omitted from the map.
GetGlobalStats(ctx context.Context, ruleIDs []string) (map[string]calibration.CrossOrgSignal, error)
// UpdateProfileFromFeedback incrementally updates the materialised
// RuleProfile for the rule identified in fb.RuleID, belonging to teamID.
// Implementations should apply the feedback without requiring a full replay
// of all events, enabling low-latency profile updates on the hot path.
UpdateProfileFromFeedback(ctx context.Context, teamID string, fb calibration.FeedbackPayload) error
// DeleteTeamData removes all events and materialised profiles associated
// with teamID. This method exists to satisfy GDPR right-to-erasure
// obligations and must purge data completely from the backing store.
DeleteTeamData(ctx context.Context, teamID string) error
// Close releases any resources held by the store (connections, file
// handles, background goroutines, etc.). After Close returns, no other
// methods may be called.
Close() error
}
EventStore persists calibration events and materialized profiles.
All methods accept a context so that callers can enforce deadlines and propagate cancellation. Implementations must be safe for concurrent use.
type SQLiteStore ¶
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore is a file-backed implementation of EventStore using SQLite. It persists calibration events and materialised per-team rule profiles. All public methods are safe for concurrent use; SQLite WAL mode allows concurrent readers alongside a single writer.
func NewSQLiteStore ¶
func NewSQLiteStore(path string) (*SQLiteStore, error)
NewSQLiteStore opens (or creates) a SQLite database at path and runs schema migrations. WAL journal mode and a 5-second busy timeout are enabled so that concurrent writers do not immediately return SQLITE_BUSY errors.
The caller is responsible for calling Close when done.
func (*SQLiteStore) AppendEvents ¶
func (s *SQLiteStore) AppendEvents(ctx context.Context, teamID string, events []calibration.Event) error
AppendEvents stores a batch of calibration events for teamID atomically. All events in the batch are inserted within a single transaction; if any insertion fails the entire batch is rolled back and an error is returned.
func (*SQLiteStore) Close ¶
func (s *SQLiteStore) Close() error
Close releases the underlying database connection. No further method calls may be made on s after Close returns.
func (*SQLiteStore) DeleteTeamData ¶
func (s *SQLiteStore) DeleteTeamData(ctx context.Context, teamID string) error
DeleteTeamData removes all events and materialised profiles associated with teamID. It satisfies GDPR right-to-erasure obligations by purging data from both the events and team_rule_profiles tables.
func (*SQLiteStore) GetGlobalStats ¶
func (s *SQLiteStore) GetGlobalStats(ctx context.Context, ruleIDs []string) (map[string]calibration.CrossOrgSignal, error)
GetGlobalStats returns anonymised cross-org calibration signals for each rule in ruleIDs. This method is a placeholder for a future task; it currently returns nil, nil for all inputs.
func (*SQLiteStore) GetTeamProfile ¶
func (s *SQLiteStore) GetTeamProfile(ctx context.Context, teamID string, ruleIDs []string) ([]calibration.RuleProfile, error)
GetTeamProfile returns the materialised calibration profile for each rule in ruleIDs that has at least one feedback event recorded for teamID. Rules with no profile are omitted from the result slice rather than returned as zero values. Derived fields are recomputed via RuleProfile.Recalculate before the profiles are returned.
Returns nil, nil when ruleIDs is empty.
func (*SQLiteStore) UpdateProfileFromFeedback ¶
func (s *SQLiteStore) UpdateProfileFromFeedback(ctx context.Context, teamID string, fb calibration.FeedbackPayload) error
UpdateProfileFromFeedback applies a single feedback verdict to the materialised team_rule_profiles row for fb.RuleID and teamID. It uses an UPSERT so the first feedback for a rule creates the row and subsequent feedbacks increment the appropriate counter.
Derived fields (NoiseRate, ConfCalibration, SuppressBelow) are NOT stored in the database; they are computed in-memory by RuleProfile.Recalculate when the profile is read back via GetTeamProfile.