From 27497e31a93ee9f9655f336dc33a2129b52cb5e1 Mon Sep 17 00:00:00 2001 From: James Wampler Date: Sun, 5 Jul 2026 22:00:13 -0700 Subject: [PATCH] Move FeatureUsage code into MicCheck.Api.Features.Usage namespace Groups usage-tracking (metrics, background flush, query service, controller, entity) under its own namespace/folder, updates all consumers and the EF migration snapshot's CLR type strings to match. --- .../Data/Configurations/FeatureUsageDailyConfiguration.cs | 2 +- src/api/MicCheck.Api/Data/MicCheckDbContext.cs | 1 + src/api/MicCheck.Api/Features/FeatureEvaluationService.cs | 1 + .../Features/{ => Usage}/FeatureUsageBucketKey.cs | 2 +- .../Features/{ => Usage}/FeatureUsageController.cs | 2 +- .../MicCheck.Api/Features/{ => Usage}/FeatureUsageDaily.cs | 2 +- .../{ => Usage}/FeatureUsageFlushBackgroundService.cs | 2 +- .../MicCheck.Api/Features/{ => Usage}/FeatureUsageMetrics.cs | 2 +- .../Features/{ => Usage}/FeatureUsageQueryService.cs | 2 +- .../Features/{ => Usage}/FeatureUsageResponses.cs | 2 +- .../20260617194113_AddFeatureUsageDaily.Designer.cs | 2 +- .../MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs | 2 +- src/api/MicCheck.Api/Program.cs | 1 + .../Features/FeatureEvaluationServiceTests.cs | 1 + .../Features/FlagsApiIntegrationTests.cs | 1 + .../Features/{ => Usage}/FeatureUsageControllerTests.cs | 4 ++-- .../Features/{ => Usage}/FeatureUsageMetricsTests.cs | 4 ++-- .../Features/{ => Usage}/FeatureUsageQueryServiceTests.cs | 4 ++-- .../Identities/IdentitiesControllerTests.cs | 1 + 19 files changed, 22 insertions(+), 16 deletions(-) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageBucketKey.cs (75%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageController.cs (96%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageDaily.cs (89%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageFlushBackgroundService.cs (98%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageMetrics.cs (97%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageQueryService.cs (97%) rename src/api/MicCheck.Api/Features/{ => Usage}/FeatureUsageResponses.cs (89%) rename tests/api/MicCheck.Api.Tests.Unit/Features/{ => Usage}/FeatureUsageControllerTests.cs (97%) rename tests/api/MicCheck.Api.Tests.Unit/Features/{ => Usage}/FeatureUsageMetricsTests.cs (96%) rename tests/api/MicCheck.Api.Tests.Unit/Features/{ => Usage}/FeatureUsageQueryServiceTests.cs (98%) diff --git a/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs b/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs index 087ca85..e9aafbe 100644 --- a/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs +++ b/src/api/MicCheck.Api/Data/Configurations/FeatureUsageDailyConfiguration.cs @@ -1,4 +1,4 @@ -using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/api/MicCheck.Api/Data/MicCheckDbContext.cs b/src/api/MicCheck.Api/Data/MicCheckDbContext.cs index 9e10b97..c4f0b9b 100755 --- a/src/api/MicCheck.Api/Data/MicCheckDbContext.cs +++ b/src/api/MicCheck.Api/Data/MicCheckDbContext.cs @@ -2,6 +2,7 @@ using MicCheck.Api.Common.Security.ApiKeys; using MicCheck.Api.Audit; using MicCheck.Api.Common.Security.Authorization; using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Organizations; using MicCheck.Api.Projects; diff --git a/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs b/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs index dd8666e..1e5e595 100755 --- a/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs +++ b/src/api/MicCheck.Api/Features/FeatureEvaluationService.cs @@ -1,4 +1,5 @@ using MicCheck.Api.Data; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Segments; using Microsoft.EntityFrameworkCore; diff --git a/src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageBucketKey.cs similarity index 75% rename from src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageBucketKey.cs index 370437d..5fbf11c 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageBucketKey.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageBucketKey.cs @@ -1,3 +1,3 @@ -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; public record struct FeatureUsageBucketKey(int EnvironmentId, int FeatureId, string FeatureName, DateOnly UsageDate); diff --git a/src/api/MicCheck.Api/Features/FeatureUsageController.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageController.cs similarity index 96% rename from src/api/MicCheck.Api/Features/FeatureUsageController.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageController.cs index 09bbc95..7430eeb 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageController.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Microsoft.Extensions.Caching.Memory; -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; [ApiController] [Route("api/v1/environment/{environmentId}/usage")] diff --git a/src/api/MicCheck.Api/Features/FeatureUsageDaily.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageDaily.cs similarity index 89% rename from src/api/MicCheck.Api/Features/FeatureUsageDaily.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageDaily.cs index 30ed719..5507b81 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageDaily.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageDaily.cs @@ -1,4 +1,4 @@ -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; public class FeatureUsageDaily { diff --git a/src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageFlushBackgroundService.cs similarity index 98% rename from src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageFlushBackgroundService.cs index f69a807..6b14e85 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageFlushBackgroundService.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageFlushBackgroundService.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using MicCheck.Api.Data; using Microsoft.EntityFrameworkCore; -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; [ExcludeFromCodeCoverage(Justification = "Timer-driven BackgroundService that issues raw SQL through a DI-scoped concrete MicCheckDbContext; exercising it cleanly requires a live DB, which CLAUDE.md disallows (no WebApplicationFactory/InMemory). DrainAccumulated's bucketing logic is covered by FeatureUsageMetricsTests.")] public class FeatureUsageFlushBackgroundService( diff --git a/src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageMetrics.cs similarity index 97% rename from src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageMetrics.cs index fd44b4b..2ab2a51 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageMetrics.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageMetrics.cs @@ -1,7 +1,7 @@ using System.Collections.Concurrent; using System.Diagnostics.Metrics; -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; public class FeatureUsageMetrics : IDisposable { diff --git a/src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageQueryService.cs similarity index 97% rename from src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageQueryService.cs index f2608ed..e8f3429 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageQueryService.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageQueryService.cs @@ -1,7 +1,7 @@ using MicCheck.Api.Data; using Microsoft.EntityFrameworkCore; -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; public class FeatureUsageQueryService(IMicCheckDbContext db) { diff --git a/src/api/MicCheck.Api/Features/FeatureUsageResponses.cs b/src/api/MicCheck.Api/Features/Usage/FeatureUsageResponses.cs similarity index 89% rename from src/api/MicCheck.Api/Features/FeatureUsageResponses.cs rename to src/api/MicCheck.Api/Features/Usage/FeatureUsageResponses.cs index 201d8b5..61833fc 100644 --- a/src/api/MicCheck.Api/Features/FeatureUsageResponses.cs +++ b/src/api/MicCheck.Api/Features/Usage/FeatureUsageResponses.cs @@ -1,4 +1,4 @@ -namespace MicCheck.Api.Features; +namespace MicCheck.Api.Features.Usage; public record TopFeatureUsage(int FeatureId, string FeatureName, long Count); diff --git a/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs index 1632da8..1994b03 100644 --- a/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs +++ b/src/api/MicCheck.Api/Migrations/20260617194113_AddFeatureUsageDaily.Designer.cs @@ -305,7 +305,7 @@ namespace MicCheck.Api.Migrations b.ToTable("FeatureStates"); }); - modelBuilder.Entity("MicCheck.Api.Features.FeatureUsageDaily", b => + modelBuilder.Entity("MicCheck.Api.Features.Usage.FeatureUsageDaily", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs b/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs index f1e18f0..6e18fbe 100755 --- a/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs +++ b/src/api/MicCheck.Api/Migrations/MicCheckDbContextModelSnapshot.cs @@ -302,7 +302,7 @@ namespace MicCheck.Api.Migrations b.ToTable("FeatureStates"); }); - modelBuilder.Entity("MicCheck.Api.Features.FeatureUsageDaily", b => + modelBuilder.Entity("MicCheck.Api.Features.Usage.FeatureUsageDaily", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/api/MicCheck.Api/Program.cs b/src/api/MicCheck.Api/Program.cs index 714ceb6..cec1604 100755 --- a/src/api/MicCheck.Api/Program.cs +++ b/src/api/MicCheck.Api/Program.cs @@ -8,6 +8,7 @@ using MicCheck.Api.Common.Validation; using MicCheck.Api.Data; using MicCheck.Api.Environments; using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Organizations; using MicCheck.Api.Projects; diff --git a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureEvaluationServiceTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureEvaluationServiceTests.cs index 86073e5..f757f83 100755 --- a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureEvaluationServiceTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureEvaluationServiceTests.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Metrics; using MicCheck.Api.Data; using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Segments; using MicCheck.Api.Tests.Unit.TestSupport; diff --git a/tests/api/MicCheck.Api.Tests.Unit/Features/FlagsApiIntegrationTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Features/FlagsApiIntegrationTests.cs index 689f31d..b1a4261 100755 --- a/tests/api/MicCheck.Api.Tests.Unit/Features/FlagsApiIntegrationTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Features/FlagsApiIntegrationTests.cs @@ -2,6 +2,7 @@ using System.Security.Claims; using MicCheck.Api.Data; using MicCheck.Api.Environments; using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Projects; using MicCheck.Api.Segments; diff --git a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageControllerTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageControllerTests.cs similarity index 97% rename from tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageControllerTests.cs rename to tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageControllerTests.cs index 051f809..df57bcf 100644 --- a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageControllerTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageControllerTests.cs @@ -1,12 +1,12 @@ using MicCheck.Api.Data; -using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Tests.Unit.TestSupport; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Moq; using NUnit.Framework; -namespace MicCheck.Api.Tests.Unit.Features; +namespace MicCheck.Api.Tests.Unit.Features.Usage; [TestFixture] public class FeatureUsageControllerTests diff --git a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageMetricsTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageMetricsTests.cs similarity index 96% rename from tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageMetricsTests.cs rename to tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageMetricsTests.cs index 8d95b06..3dcc650 100644 --- a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageMetricsTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageMetricsTests.cs @@ -1,9 +1,9 @@ using System.Diagnostics.Metrics; -using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using Moq; using NUnit.Framework; -namespace MicCheck.Api.Tests.Unit.Features; +namespace MicCheck.Api.Tests.Unit.Features.Usage; [TestFixture] public class FeatureUsageMetricsTests diff --git a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageQueryServiceTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageQueryServiceTests.cs similarity index 98% rename from tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageQueryServiceTests.cs rename to tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageQueryServiceTests.cs index 966bbf0..ce75b41 100644 --- a/tests/api/MicCheck.Api.Tests.Unit/Features/FeatureUsageQueryServiceTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Features/Usage/FeatureUsageQueryServiceTests.cs @@ -1,10 +1,10 @@ using MicCheck.Api.Data; -using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Tests.Unit.TestSupport; using Moq; using NUnit.Framework; -namespace MicCheck.Api.Tests.Unit.Features; +namespace MicCheck.Api.Tests.Unit.Features.Usage; [TestFixture] public class FeatureUsageQueryServiceTests diff --git a/tests/api/MicCheck.Api.Tests.Unit/Identities/IdentitiesControllerTests.cs b/tests/api/MicCheck.Api.Tests.Unit/Identities/IdentitiesControllerTests.cs index 7b66443..25c7833 100644 --- a/tests/api/MicCheck.Api.Tests.Unit/Identities/IdentitiesControllerTests.cs +++ b/tests/api/MicCheck.Api.Tests.Unit/Identities/IdentitiesControllerTests.cs @@ -2,6 +2,7 @@ using System.Security.Claims; using MicCheck.Api.Data; using MicCheck.Api.Environments; using MicCheck.Api.Features; +using MicCheck.Api.Features.Usage; using MicCheck.Api.Identities; using MicCheck.Api.Projects; using MicCheck.Api.Segments;