M1: audit log (Governance) + edit-distance metric
SharedKernel: - IAuditLog/AuditEvent — append-only audit contract any module writes through. - EditDistance (Levenshtein + normalized) — the north-star metric, available from day one; consumed at edit-and-approve in M5. Governance module (references SharedKernel only): - AuditEntry entity; internal GovernanceDbContext (schema "governance") + InitialGovernance migration; AuditLog implements IAuditLog. - GET /api/governance/audit — owner-only (ViewAuditLog), returns recent entries. Wiring (via the SharedKernel IAuditLog interface — no module references Governance): - OrgBoard records team.created, task.created, task.moved, task.assigned. - Identity records invitation.created, member.joined. Verified: build green; ArchitectureTests 8/8 (Governance references only SharedKernel; audit flows through the shared interface); IntegrationTests 20/20 — board flow now asserts task.created/task.moved appear in the audit log, plus EditDistance unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,27 +1,32 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using TeamUp.Modules.Governance.Auditing;
|
||||
using TeamUp.Modules.Governance.Endpoints;
|
||||
using TeamUp.Modules.Governance.Persistence;
|
||||
using TeamUp.SharedKernel.Auditing;
|
||||
using TeamUp.SharedKernel.Modularity;
|
||||
using TeamUp.SharedKernel.Persistence;
|
||||
|
||||
namespace TeamUp.Modules.Governance;
|
||||
|
||||
/// <summary>Autonomy dial, the action gate, the review inbox, the audit log (M5).</summary>
|
||||
/// <summary>Autonomy dial, the action gate, the review inbox, the audit log (M5). M1 ships the audit log.</summary>
|
||||
public sealed class GovernanceModule : IModule
|
||||
{
|
||||
public string Name => "governance";
|
||||
|
||||
public void Register(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
// Skeleton: no services yet. M5 introduces the action gate, ReviewItem context,
|
||||
// edit-distance capture, and the immutable audit log here.
|
||||
var connectionString = configuration.GetConnectionString("Postgres")
|
||||
?? throw new InvalidOperationException("Missing connection string 'ConnectionStrings:Postgres'.");
|
||||
|
||||
services.AddDbContext<GovernanceDbContext>(options => options.UseNpgsql(connectionString));
|
||||
services.AddScoped<IModuleDbContext>(sp => sp.GetRequiredService<GovernanceDbContext>());
|
||||
services.AddScoped<IAuditLog, AuditLog>();
|
||||
services.TryAddSingleton(TimeProvider.System);
|
||||
}
|
||||
|
||||
public void MapEndpoints(IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapGroup($"/api/{Name}")
|
||||
.WithTags("Governance")
|
||||
.MapGet("/ping", () => TypedResults.Ok(new ModulePing(Name)));
|
||||
}
|
||||
public void MapEndpoints(IEndpointRouteBuilder endpoints) => GovernanceEndpoints.Map(endpoints);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user