wip: doctor/cli/docs/api to vector db consolidation; api hardening for descriptions, tenant, and scopes; migrations and conversions of all DALs to EF v10

This commit is contained in:
master
2026-02-23 15:30:50 +02:00
parent bd8fee6ed8
commit e746577380
1424 changed files with 81225 additions and 25251 deletions

View File

@@ -2,8 +2,10 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using StellaOps.Notifier.WebService.Constants;
using StellaOps.Notifier.WebService.Contracts;
using StellaOps.Notifier.WebService.Extensions;
using StellaOps.Auth.ServerIntegration.Tenancy;
using StellaOps.Notifier.Worker.Dispatch;
using StellaOps.Notifier.Worker.Storage;
using StellaOps.Notifier.Worker.Templates;
@@ -26,7 +28,9 @@ public static class NotifyApiEndpoints
{
var group = app.MapGroup("/api/v2/notify")
.WithTags("Notify")
.WithOpenApi();
.WithOpenApi()
.RequireAuthorization(NotifierPolicies.NotifyViewer)
.RequireTenant();
// Rules CRUD
MapRulesEndpoints(group);
@@ -57,7 +61,8 @@ public static class NotifyApiEndpoints
var response = rules.Select(MapRuleToResponse).ToList();
return Results.Ok(response);
});
})
.WithDescription("Returns all alert routing rules for the tenant. Rules define which events trigger notifications, which channels receive them, and any throttle or digest settings applied.");
group.MapGet("/rules/{ruleId}", async (
HttpContext context,
@@ -78,7 +83,8 @@ public static class NotifyApiEndpoints
}
return Results.Ok(MapRuleToResponse(rule));
});
})
.WithDescription("Retrieves a single alert routing rule by its identifier. Returns match criteria, actions, throttle settings, and audit metadata.");
group.MapPost("/rules", async (
HttpContext context,
@@ -108,7 +114,9 @@ public static class NotifyApiEndpoints
}, cancellationToken);
return Results.Created($"/api/v2/notify/rules/{rule.RuleId}", MapRuleToResponse(rule));
});
})
.WithDescription("Creates a new alert routing rule. The rule specifies event match criteria (kinds, namespaces, severities) and the notification actions to execute. An audit entry is written on creation.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapPut("/rules/{ruleId}", async (
HttpContext context,
@@ -145,7 +153,9 @@ public static class NotifyApiEndpoints
}, cancellationToken);
return Results.Ok(MapRuleToResponse(updated));
});
})
.WithDescription("Updates an existing alert routing rule. Only the provided fields are changed; match criteria, actions, throttle settings, and labels are merged. An audit entry is written on update.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapDelete("/rules/{ruleId}", async (
HttpContext context,
@@ -176,7 +186,9 @@ public static class NotifyApiEndpoints
}, cancellationToken);
return Results.NoContent();
});
})
.WithDescription("Permanently removes an alert routing rule. Future events will no longer be matched against this rule. An audit entry is written on deletion.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
}
private static void MapTemplatesEndpoints(RouteGroupBuilder group)
@@ -214,7 +226,8 @@ public static class NotifyApiEndpoints
var response = templates.Select(MapTemplateToResponse).ToList();
return Results.Ok(response);
});
})
.WithDescription("Lists all notification templates for the tenant, with optional filtering by key prefix, channel type, and locale. Templates define the rendered message body used by notification rules.");
group.MapGet("/templates/{templateId}", async (
HttpContext context,
@@ -235,7 +248,8 @@ public static class NotifyApiEndpoints
}
return Results.Ok(MapTemplateToResponse(template));
});
})
.WithDescription("Retrieves a single notification template by its identifier. Returns the template body, channel type, locale, render mode, and audit metadata.");
group.MapPost("/templates", async (
HttpContext context,
@@ -294,7 +308,9 @@ public static class NotifyApiEndpoints
return result.IsNew
? Results.Created($"/api/v2/notify/templates/{request.TemplateId}", MapTemplateToResponse(created!))
: Results.Ok(MapTemplateToResponse(created!));
});
})
.WithDescription("Creates or updates a notification template. The template body supports Scriban syntax with access to event payload fields. Validation is performed before persisting; an error is returned for invalid syntax.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapDelete("/templates/{templateId}", async (
HttpContext context,
@@ -317,7 +333,9 @@ public static class NotifyApiEndpoints
}
return Results.NoContent();
});
})
.WithDescription("Permanently removes a notification template. Rules referencing this template will fall back to channel defaults on the next delivery. An audit entry is written on deletion.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapPost("/templates/preview", async (
HttpContext context,
@@ -393,7 +411,9 @@ public static class NotifyApiEndpoints
Format = rendered.Format.ToString(),
Warnings = warnings
});
});
})
.WithDescription("Renders a template against a sample event payload without sending any notification. Accepts either an existing templateId or an inline templateBody. Returns the rendered body, subject, and any template warnings.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapPost("/templates/validate", (
HttpContext context,
@@ -413,7 +433,8 @@ public static class NotifyApiEndpoints
errors = result.Errors,
warnings = result.Warnings
});
});
})
.WithDescription("Validates a template body for syntax correctness without persisting it. Returns isValid, a list of errors, and any non-fatal warnings.");
}
private static void MapIncidentsEndpoints(RouteGroupBuilder group)
@@ -465,7 +486,8 @@ public static class NotifyApiEndpoints
TotalCount = incidents.Count,
NextCursor = queryResult.ContinuationToken
});
});
})
.WithDescription("Returns a paginated list of notification incidents for the tenant, grouped by event ID. Supports filtering by status, event kind prefix, time range, and cursor-based pagination.");
group.MapPost("/incidents/{incidentId}/ack", async (
HttpContext context,
@@ -489,7 +511,9 @@ public static class NotifyApiEndpoints
}, cancellationToken);
return Results.NoContent();
});
})
.WithDescription("Acknowledges an incident, recording the actor and an optional comment in the audit log. Does not stop an active escalation; use the escalation stop endpoint for that.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
group.MapPost("/incidents/{incidentId}/resolve", async (
HttpContext context,
@@ -514,7 +538,9 @@ public static class NotifyApiEndpoints
}, cancellationToken);
return Results.NoContent();
});
})
.WithDescription("Marks an incident as resolved, recording the actor, resolution reason, and optional comment in the audit log. Subsequent notifications for this event kind will continue to be processed normally.")
.RequireAuthorization(NotifierPolicies.NotifyOperator);
}
#region Helpers