version-0.1 (#1)

Squash and merge of version-0.1

Co-authored-by: James Wampler <james@wamp.dev>
Co-committed-by: James Wampler <james@wamp.dev>
This commit was merged in pull request #1.
This commit is contained in:
2026-07-01 13:30:07 -07:00
committed by wamplerj
parent 8ff071c69b
commit 6887d09f9c
989 changed files with 76379 additions and 18042 deletions

39
src/api/MicCheck.Api/Features/FeatureService.cs Normal file → Executable file
View File

@@ -13,13 +13,14 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web
public async Task<IReadOnlyList<Feature>> ListByProjectAsync(int projectId, CancellationToken ct = default)
{
return await db.Features
.Include(f => f.Tags)
.Where(f => f.ProjectId == projectId)
.ToListAsync(ct);
}
public async Task<Feature?> FindByIdAsync(int id, CancellationToken ct = default)
{
return await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct);
return await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == id, ct);
}
public async Task<Feature> CreateAsync(
@@ -80,7 +81,7 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web
public async Task<Feature> UpdateAsync(
int id, string name, string? description, CancellationToken ct = default)
{
var feature = await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct)
var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == id, ct)
?? throw new KeyNotFoundException($"Feature {id} not found.");
var before = new { feature.Name, feature.Description };
@@ -101,6 +102,40 @@ public class FeatureService(MicCheckDbContext db, AuditService auditService, Web
return feature;
}
public async Task<Feature> AssignTagAsync(int featureId, int tagId, CancellationToken ct = default)
{
var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == featureId, ct)
?? throw new KeyNotFoundException($"Feature {featureId} not found.");
var tag = await db.Tags.FirstOrDefaultAsync(t => t.Id == tagId, ct)
?? throw new KeyNotFoundException($"Tag {tagId} not found.");
if (tag.ProjectId != feature.ProjectId)
throw new DomainException("Tag does not belong to the feature's project.");
if (feature.Tags.All(t => t.Id != tagId))
{
feature.Tags.Add(tag);
await db.SaveChangesAsync(ct);
}
return feature;
}
public async Task<Feature> RemoveTagAsync(int featureId, int tagId, CancellationToken ct = default)
{
var feature = await db.Features.Include(f => f.Tags).FirstOrDefaultAsync(f => f.Id == featureId, ct)
?? throw new KeyNotFoundException($"Feature {featureId} not found.");
var tag = feature.Tags.FirstOrDefault(t => t.Id == tagId);
if (tag is not null)
{
feature.Tags.Remove(tag);
await db.SaveChangesAsync(ct);
}
return feature;
}
public async Task DeleteAsync(int id, CancellationToken ct = default)
{
var feature = await db.Features.FirstOrDefaultAsync(f => f.Id == id, ct);