budget

package
v0.1.53 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PeriodHourlySeconds int64 = 3600
	PeriodDailySeconds  int64 = 86400
	PeriodWeeklySeconds int64 = 604800
	// PeriodMonthlySeconds is a sentinel key for calendar-month windows, not a literal 30-day duration.
	PeriodMonthlySeconds int64 = 2592000
)
View Source
const (
	// SourceConfig marks budgets seeded from static configuration.
	SourceConfig = "config"
	// SourceManual marks budgets created or changed through admin APIs.
	SourceManual = "manual"
)

Variables

View Source
var ErrNotFound = errors.New("budget not found")
View Source
var ErrUnavailable = errors.New("budget service is unavailable")

ErrUnavailable indicates a budget service was used without an initialized store.

Functions

func NormalizeUserPath

func NormalizeUserPath(raw string) (string, error)

func PeriodBounds

func PeriodBounds(now time.Time, seconds int64, settings Settings) (time.Time, time.Time)

func PeriodLabel

func PeriodLabel(seconds int64) string

func PeriodSeconds

func PeriodSeconds(period string) (int64, bool)

func ValidateSettings

func ValidateSettings(settings Settings) error

Types

type Budget

type Budget struct {
	UserPath      string     `json:"user_path" bson:"user_path"`
	PeriodSeconds int64      `json:"period_seconds" bson:"period_seconds"`
	Amount        float64    `json:"amount" bson:"amount"`
	Source        string     `json:"source,omitempty" bson:"source,omitempty"`
	LastResetAt   *time.Time `json:"last_reset_at,omitempty" bson:"last_reset_at,omitempty"`
	CreatedAt     time.Time  `json:"created_at" bson:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at" bson:"updated_at"`
}

Budget stores one spend limit for one user path and reset period.

func NormalizeBudget

func NormalizeBudget(b Budget) (Budget, error)

type CheckResult

type CheckResult struct {
	Budget      Budget    `json:"budget"`
	PeriodStart time.Time `json:"period_start"`
	PeriodEnd   time.Time `json:"period_end"`
	Spent       float64   `json:"spent"`
	HasUsage    bool      `json:"has_usage"`
	Remaining   float64   `json:"remaining"`
}

CheckResult describes one evaluated budget limit.

func (CheckResult) PeriodRatio

func (r CheckResult) PeriodRatio(now time.Time) float64

PeriodRatio returns the elapsed fraction of the budget period at now, clamped to [0, 1].

func (CheckResult) UsageRatio

func (r CheckResult) UsageRatio() float64

UsageRatio returns spent/amount for the period, or 0 when the budget amount is not positive. It is deliberately not clamped: values above 1 indicate an exceeded budget.

type ExceededError

type ExceededError struct {
	Result CheckResult
}

ExceededError indicates a budget has already been exhausted.

func (*ExceededError) Error

func (e *ExceededError) Error() string

type MongoDBStore

type MongoDBStore struct {
	// contains filtered or unexported fields
}

func NewMongoDBStore

func NewMongoDBStore(ctx context.Context, database *mongo.Database) (*MongoDBStore, error)

func (*MongoDBStore) Close

func (s *MongoDBStore) Close() error

func (*MongoDBStore) DeleteBudget

func (s *MongoDBStore) DeleteBudget(ctx context.Context, userPath string, periodSeconds int64) error

func (*MongoDBStore) GetSettings

func (s *MongoDBStore) GetSettings(ctx context.Context) (Settings, error)

func (*MongoDBStore) ListBudgets

func (s *MongoDBStore) ListBudgets(ctx context.Context) ([]Budget, error)

func (*MongoDBStore) ReplaceConfigBudgets

func (s *MongoDBStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error

func (*MongoDBStore) ResetAllBudgets

func (s *MongoDBStore) ResetAllBudgets(ctx context.Context, at time.Time) error

func (*MongoDBStore) ResetBudget

func (s *MongoDBStore) ResetBudget(ctx context.Context, userPath string, periodSeconds int64, at time.Time) error

func (*MongoDBStore) SaveSettings

func (s *MongoDBStore) SaveSettings(ctx context.Context, settings Settings) (Settings, error)

func (*MongoDBStore) SumUsageCost

func (s *MongoDBStore) SumUsageCost(ctx context.Context, userPath string, start, end time.Time) (float64, bool, error)

func (*MongoDBStore) UpsertBudgets

func (s *MongoDBStore) UpsertBudgets(ctx context.Context, budgets []Budget) error

type PostgreSQLStore

type PostgreSQLStore struct {
	// contains filtered or unexported fields
}

func NewPostgreSQLStore

func NewPostgreSQLStore(ctx context.Context, pool *pgxpool.Pool) (*PostgreSQLStore, error)

func (*PostgreSQLStore) Close

func (s *PostgreSQLStore) Close() error

func (*PostgreSQLStore) DeleteBudget

func (s *PostgreSQLStore) DeleteBudget(ctx context.Context, userPath string, periodSeconds int64) error

func (*PostgreSQLStore) GetSettings

func (s *PostgreSQLStore) GetSettings(ctx context.Context) (Settings, error)

func (*PostgreSQLStore) ListBudgets

func (s *PostgreSQLStore) ListBudgets(ctx context.Context) ([]Budget, error)

func (*PostgreSQLStore) ReplaceConfigBudgets

func (s *PostgreSQLStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error

func (*PostgreSQLStore) ResetAllBudgets

func (s *PostgreSQLStore) ResetAllBudgets(ctx context.Context, at time.Time) error

func (*PostgreSQLStore) ResetBudget

func (s *PostgreSQLStore) ResetBudget(ctx context.Context, userPath string, periodSeconds int64, at time.Time) error

func (*PostgreSQLStore) SaveSettings

func (s *PostgreSQLStore) SaveSettings(ctx context.Context, settings Settings) (Settings, error)

func (*PostgreSQLStore) SumUsageCost

func (s *PostgreSQLStore) SumUsageCost(ctx context.Context, userPath string, start, end time.Time) (float64, bool, error)

func (*PostgreSQLStore) UpsertBudgets

func (s *PostgreSQLStore) UpsertBudgets(ctx context.Context, budgets []Budget) error

type Result

type Result struct {
	Service *Service
	Store   Store
	Storage storage.Storage
	// contains filtered or unexported fields
}

func New

func New(ctx context.Context, cfg *config.Config) (*Result, error)

func NewWithSharedStorage

func NewWithSharedStorage(ctx context.Context, cfg *config.Config, shared storage.Storage) (*Result, error)

func (*Result) Close

func (r *Result) Close() error

type SQLiteStore

type SQLiteStore struct {
	// contains filtered or unexported fields
}

func NewSQLiteStore

func NewSQLiteStore(db *sql.DB) (*SQLiteStore, error)

func (*SQLiteStore) Close

func (s *SQLiteStore) Close() error

func (*SQLiteStore) DeleteBudget

func (s *SQLiteStore) DeleteBudget(ctx context.Context, userPath string, periodSeconds int64) error

func (*SQLiteStore) GetSettings

func (s *SQLiteStore) GetSettings(ctx context.Context) (Settings, error)

func (*SQLiteStore) ListBudgets

func (s *SQLiteStore) ListBudgets(ctx context.Context) ([]Budget, error)

func (*SQLiteStore) ReplaceConfigBudgets

func (s *SQLiteStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error

func (*SQLiteStore) ResetAllBudgets

func (s *SQLiteStore) ResetAllBudgets(ctx context.Context, at time.Time) error

func (*SQLiteStore) ResetBudget

func (s *SQLiteStore) ResetBudget(ctx context.Context, userPath string, periodSeconds int64, at time.Time) error

func (*SQLiteStore) SaveSettings

func (s *SQLiteStore) SaveSettings(ctx context.Context, settings Settings) (Settings, error)

func (*SQLiteStore) SumUsageCost

func (s *SQLiteStore) SumUsageCost(ctx context.Context, userPath string, start, end time.Time) (float64, bool, error)

func (*SQLiteStore) UpsertBudgets

func (s *SQLiteStore) UpsertBudgets(ctx context.Context, budgets []Budget) error

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(ctx context.Context, store Store) (*Service, error)

func (*Service) Budgets

func (s *Service) Budgets() []Budget

func (*Service) Check

func (s *Service) Check(ctx context.Context, userPath string, now time.Time) error

func (*Service) CheckWithResults

func (s *Service) CheckWithResults(ctx context.Context, userPath string, now time.Time) ([]CheckResult, error)

func (*Service) DeleteBudget

func (s *Service) DeleteBudget(ctx context.Context, userPath string, periodSeconds int64) error

func (*Service) Refresh

func (s *Service) Refresh(ctx context.Context) error

func (*Service) ReplaceConfigBudgets

func (s *Service) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error

func (*Service) ResetAll

func (s *Service) ResetAll(ctx context.Context, at time.Time) error

func (*Service) ResetBudget

func (s *Service) ResetBudget(ctx context.Context, userPath string, periodSeconds int64, at time.Time) error

func (*Service) SaveSettings

func (s *Service) SaveSettings(ctx context.Context, settings Settings) (Settings, error)

func (*Service) Settings

func (s *Service) Settings() Settings

func (*Service) Statuses

func (s *Service) Statuses(ctx context.Context, now time.Time) ([]CheckResult, error)

func (*Service) StatusesForPath

func (s *Service) StatusesForPath(ctx context.Context, userPath string, now time.Time) ([]CheckResult, error)

StatusesForPath evaluates every budget covering userPath without enforcing limits. Unlike CheckWithResults it never stops at an exhausted budget, so callers get the full status picture even when several budgets are exceeded.

func (*Service) UpsertBudgets

func (s *Service) UpsertBudgets(ctx context.Context, budgets []Budget) error

type Settings

type Settings struct {
	DailyResetHour     int       `json:"daily_reset_hour" bson:"daily_reset_hour"`
	DailyResetMinute   int       `json:"daily_reset_minute" bson:"daily_reset_minute"`
	WeeklyResetWeekday int       `json:"weekly_reset_weekday" bson:"weekly_reset_weekday"`
	WeeklyResetHour    int       `json:"weekly_reset_hour" bson:"weekly_reset_hour"`
	WeeklyResetMinute  int       `json:"weekly_reset_minute" bson:"weekly_reset_minute"`
	MonthlyResetDay    int       `json:"monthly_reset_day" bson:"monthly_reset_day"`
	MonthlyResetHour   int       `json:"monthly_reset_hour" bson:"monthly_reset_hour"`
	MonthlyResetMinute int       `json:"monthly_reset_minute" bson:"monthly_reset_minute"`
	UpdatedAt          time.Time `json:"updated_at" bson:"updated_at"`
}

Settings controls the calendar anchors used to find the active budget period. Values are interpreted in UTC.

func DefaultSettings

func DefaultSettings() Settings

DefaultSettings returns the reset anchors used when no DB setting exists.

type Store

type Store interface {
	ListBudgets(ctx context.Context) ([]Budget, error)
	UpsertBudgets(ctx context.Context, budgets []Budget) error
	DeleteBudget(ctx context.Context, userPath string, periodSeconds int64) error
	ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
	GetSettings(ctx context.Context) (Settings, error)
	SaveSettings(ctx context.Context, settings Settings) (Settings, error)
	ResetBudget(ctx context.Context, userPath string, periodSeconds int64, at time.Time) error
	ResetAllBudgets(ctx context.Context, at time.Time) error
	SumUsageCost(ctx context.Context, userPath string, start, end time.Time) (float64, bool, error)
	Close() error
}

Store persists budget definitions, reset settings, and spend lookups.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL