Remove FluentValidation dependency; replace with plain IModelValidator/ValidationResult pattern (ported from BuyEngine's Guard/validation approach), wired via a ModelValidationActionFilter
Move FeatureUsage code into MicCheck.Api.Features.Usage namespace
Convert logic-free data classes to records per CLAUDE.md (WebhookEvent, FeatureStateResult, ProjectPermissionRequirement, AuditLog, Tag, FeatureUsageDaily)
Extract IAuditService interface, drop virtual-method mock seam on AuditService
Split Program.cs DI registrations into per-namespace DependencyRegistration classes
Test plan
dotnet build (API + tests) clean
dotnet test MicCheck.Api.Tests.Unit — 646/646 passing
Replace AbstractValidator-based request validators with a small
IModelValidator<T>/ValidationResult pattern (ported from BuyEngine's
Common namespace), wired into the MVC pipeline via a
ModelValidationActionFilter so controllers and response shape are
unaffected. Also copy over the Guard precondition helper.
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.
WebhookEvent, FeatureStateResult, ProjectPermissionRequirement, AuditLog,
Tag, and FeatureUsageDaily are plain data holders with no behavior, so
switch them to records. EF-mapped entities with identity semantics
(User, Organization, Project, Feature, Segment, etc.) stay classes,
since record value-equality and deep ToString fight EF's change tracker.
Also restore `virtual` on AuditService.RecordAsync/LogAsync, which had
been dropped and broke Mock<AuditService>-based test setups.
Consumers now depend on IAuditService instead of the concrete class,
so tests mock the interface (Mock<IAuditService>()) rather than
subclassing AuditService via virtual methods.
Each root namespace (Audit, Common, Data, Environments, Features/Usage,
Identities, Organizations, Projects, Segments, Users, Webhooks) gets its
own static DependencyRegistration class exposing an Add<Name>Services
extension method, so Program.cs just wires them together instead of
listing every registration inline.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Test plan