package budget import ( "context" "time" ) // BudgetStorage is the persistence seam behind DBBudget: one budget row per // user, with an atomic Add that rolls the 7-day window over transparently. Mort // backs this with GORM/MySQL (the skill_budgets table); Memory() is the // zero-dependency default; contrib/store adds a durable SQLite one. type BudgetStorage interface { // Initialize runs any schema setup. Safe to call repeatedly. Initialize(ctx context.Context) error // Get returns the user's current budget row, or (nil, nil) if none exists. Get(ctx context.Context, userID string) (*SkillBudget, error) // Add increments seconds_used + runs_count atomically, rolling the window // over when WindowStart is older than 7 days (reset to now, fresh count). // Creates the row if absent. Add(ctx context.Context, userID string, secondsUsed float64, now time.Time) error } // SkillBudget is one user's rolling-window usage row. type SkillBudget struct { UserID string WindowStart time.Time SecondsUsed float64 RunsCount int UpdatedAt time.Time } // budgetWindow is the rolling window length the storage rolls over at. const budgetWindow = 7 * 24 * time.Hour