feat(stamdata): admin stamdata maintenance editor (beheer)
Realizes ADR-0004's "future low-code editor that commits a PR": an
admin-only stamdata maintenance editor built on the stamdata-as-code
foundation.
Backend: `professions` moves from a hardcoded C# dictionary to an embedded
`professions.json` data-file (typed as `ProfessionMapping`) with valid-time
(geldigVan/geldigTot, half-open). A generic, reflection-driven
StamdataCatalog/StamdataTable/StamdataFile describes every table so one
endpoint pair + one grid editor serve all of them; add a table in one line.
Two read-only, admin-gated endpoints (GET /stamdata, GET /stamdata/{table}
?peildatum=) — no runtime write path. Generic build gate
`Every_catalog_table_is_valid` (keys non-blank, no overlapping validity,
well-formed windows).
Frontend: new `beheer` context (route beheer/stamdata, capabilityGuard
'stamdata:edit'). A schema-driven grid editor edits rows locally; download()
emits {table}.json for the admin to commit as a reviewed PR (no mutation
command — the CI build + StamdataValidationTests stay the authority).
Full gate GREEN both sides; gen:api leaves no drift; new stamdata story
passes axe. See WP-29 + ADR-0004.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using BigRegister.Api.Contracts;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
|
||||
namespace BigRegister.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The stamdata maintenance reads (ADR-0004): admin-only, generic (schema + rows), and the
|
||||
/// valid-time peildatum filter. The editor consumes these; the edit itself lands as a PR.
|
||||
/// </summary>
|
||||
public class StamdataEndpointTests(TestWebApplicationFactory factory) : IClassFixture<TestWebApplicationFactory>
|
||||
{
|
||||
private readonly HttpClient _client = factory.CreateClient();
|
||||
|
||||
private HttpRequestMessage Req(HttpMethod method, string path, string? role = null)
|
||||
{
|
||||
var req = new HttpRequestMessage(method, path);
|
||||
if (role is not null) req.Headers.Add("X-Role", role);
|
||||
return req;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Stamdata_reads_are_admin_only()
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.Forbidden, (await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata"))).StatusCode);
|
||||
Assert.Equal(HttpStatusCode.Forbidden, (await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions", role: "drafter"))).StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Table_list_exposes_the_reflected_schema()
|
||||
{
|
||||
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata", role: "admin"));
|
||||
res.EnsureSuccessStatusCode();
|
||||
var tables = (await res.Content.ReadFromJsonAsync<List<StamdataTableSummaryDto>>())!;
|
||||
var professions = tables.Single(t => t.Id == "professions");
|
||||
Assert.True(professions.Temporal);
|
||||
Assert.True(professions.Columns[0].IsKey);
|
||||
Assert.Equal("program", professions.Columns[0].Name);
|
||||
Assert.Contains(professions.Columns, c => c.Name == "geldigVan" && c.Type == "date");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Table_returns_all_rows_without_a_peildatum()
|
||||
{
|
||||
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions", role: "admin"));
|
||||
res.EnsureSuccessStatusCode();
|
||||
var table = (await res.Content.ReadFromJsonAsync<StamdataTableDto>())!;
|
||||
Assert.Equal(5, table.Rows.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Peildatum_before_the_seed_windows_hides_every_row()
|
||||
{
|
||||
// Seed mappings start 2000-01-01; a 1999 peildatum yields none (valid-time filter works).
|
||||
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions?peildatum=1999-01-01", role: "admin"));
|
||||
res.EnsureSuccessStatusCode();
|
||||
var table = (await res.Content.ReadFromJsonAsync<StamdataTableDto>())!;
|
||||
Assert.Empty(table.Rows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Unknown_table_is_404()
|
||||
{
|
||||
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/nope", role: "admin"));
|
||||
Assert.Equal(HttpStatusCode.NotFound, res.StatusCode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user