feat: enforce account usage limits
CI and Deploy / test (push) Successful in 2m39s
CI and Deploy / deploy (push) Successful in 55s

This commit is contained in:
cesnimda
2026-07-30 23:14:42 +02:00
parent 9cd2e5c2e3
commit 158970fa01
7 changed files with 74 additions and 16 deletions
@@ -4,6 +4,7 @@ using JobTrackerApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace JobTrackerApi.Controllers;
@@ -17,12 +18,14 @@ public sealed class AiWorkspaceController : ControllerBase
private readonly UserManager<ApplicationUser> _users;
private readonly IAiWorkspaceService _workspace;
private readonly IConfiguration _config;
private readonly JobTrackerApi.Data.JobTrackerContext? _db;
public AiWorkspaceController(UserManager<ApplicationUser> users, IAiWorkspaceService workspace, IConfiguration config)
public AiWorkspaceController(UserManager<ApplicationUser> users, IAiWorkspaceService workspace, IConfiguration config, JobTrackerApi.Data.JobTrackerContext? db = null)
{
_users = users;
_workspace = workspace;
_config = config;
_db = db;
}
public sealed record GenerateRequest(string Module, string? Mode, string? ExtraContext);
@@ -38,6 +41,15 @@ public sealed class AiWorkspaceController : ControllerBase
if (user is null) return Unauthorized();
if (string.IsNullOrWhiteSpace(request?.Module)) return BadRequest("Choose an AI module.");
if (_db is not null)
{
var roles = await _users.GetRolesAsync(user);
var limit = AccountPlans.ForRoles(roles).MonthlyAiCalls;
var monthStart = new DateTimeOffset(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1, 0, 0, 0, TimeSpan.Zero);
var used = await _db.AiInteractions.CountAsync(x => x.OwnerUserId == user.Id && x.CreatedAtUtc >= monthStart, ct);
if (used >= limit) return StatusCode(StatusCodes.Status429TooManyRequests, $"Monthly AI limit reached ({limit} generations). Upgrade your plan or try again next month.");
}
try
{
var interaction = await _workspace.GenerateAsync(