feat(stamdata): extract policy-question text into Stamdata
CI / frontend (push) Failing after 1m21s
CI / storybook-a11y (push) Failing after 5m27s
CI / backend (push) Successful in 1m35s
CI / codeql (csharp) (push) Failing after 1m50s
CI / codeql (javascript-typescript) (push) Failing after 1m30s
CI / api-client-drift (push) Successful in 2m1s
CI / e2e (push) Failing after 3h14m48s

Move the geldigheidsvragen wording out of DiplomaRules into
Stamdata.PolicyQuestions (business-editable text, config-as-code); DiplomaRules
keeps only the rule of which questions apply. Extend StamdataValidationTests
(no blank id/wording, distinct ids in the manual set) and update ADR-0004.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-21 07:46:38 +02:00
co-authored by Claude Opus 4.8
parent a7f737e18c
commit c459fa0a60
4 changed files with 71 additions and 32 deletions
@@ -19,44 +19,20 @@ public static class DiplomaRules
/// <summary>Professions a user may declare for a manual (unlisted) diploma.</summary>
public static IReadOnlyList<string> ManualProfessions() => Professions.All();
// --- Policy questions (geldigheidsvragen) ---
private static readonly PolicyQuestion NlTaalEngelstalig = new(
"nl-taalvaardigheid",
"Uw opleiding was Engelstalig. Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
QuestionType.JaNee);
private static readonly PolicyQuestion NlTaalManual = new(
"nl-taalvaardigheid",
"Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
QuestionType.JaNee);
private static readonly PolicyQuestion DiplomaErkend = new(
"diploma-erkend",
"Is uw diploma erkend door de Nederlandse overheid (bijv. via Nuffic)?",
QuestionType.JaNee);
private static readonly PolicyQuestion Toelichting = new(
"toelichting",
"Geef een korte toelichting op uw diploma en opleiding.",
QuestionType.Tekst);
/// <summary>
/// RULE: an English-language diploma requires proof of Dutch proficiency (B2).
/// Add a question here to apply it to a (set of) diploma(s) — a single backend
/// change, no frontend change.
/// RULE: an English-language diploma requires proof of Dutch proficiency (B2). Which
/// question applies is the rule; its wording is stamdata in <see cref="PolicyQuestions"/>.
/// </summary>
public static IReadOnlyList<PolicyQuestion> QuestionsFor(Diploma d)
{
var questions = new List<PolicyQuestion>();
if (d.Engelstalig)
questions.Add(NlTaalEngelstalig);
questions.Add(PolicyQuestions.NlTaalEngelstalig);
return questions;
}
/// <summary>
/// RULE: a manual diploma is unverified, so the strictest (maximal) set applies.
/// </summary>
public static IReadOnlyList<PolicyQuestion> ManualQuestions() =>
new[] { NlTaalManual, DiplomaErkend, Toelichting };
public static IReadOnlyList<PolicyQuestion> ManualQuestions() => PolicyQuestions.ManualSet;
}
@@ -0,0 +1,45 @@
using BigRegister.Domain.Diplomas;
namespace BigRegister.Stamdata;
/// <summary>
/// BUSINESS-EDITABLE STAMDATA (config-as-code). The geldigheidsvragen (policy questions)
/// shown for a diploma, and their exact wording. This is the text the business tunes.
///
/// Change it by editing this file and opening a PR — NOT via a production database. The
/// compiler catches shape/type mistakes; <c>StamdataValidationTests</c> catches the rest
/// (blank ids/wording, duplicate ids). See ADR-0004.
///
/// This is DATA, not logic: WHICH questions apply to which diploma (English → B2, manual →
/// maximal set) is a rule and stays in <c>DiplomaRules</c>.
/// </summary>
public static class PolicyQuestions
{
public static readonly PolicyQuestion NlTaalEngelstalig = new(
"nl-taalvaardigheid",
"Uw opleiding was Engelstalig. Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
QuestionType.JaNee);
public static readonly PolicyQuestion NlTaalManual = new(
"nl-taalvaardigheid",
"Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
QuestionType.JaNee);
public static readonly PolicyQuestion DiplomaErkend = new(
"diploma-erkend",
"Is uw diploma erkend door de Nederlandse overheid (bijv. via Nuffic)?",
QuestionType.JaNee);
public static readonly PolicyQuestion Toelichting = new(
"toelichting",
"Geef een korte toelichting op uw diploma en opleiding.",
QuestionType.Tekst);
/// <summary>The maximal set applied to an unverified (manual) diploma.</summary>
public static readonly IReadOnlyList<PolicyQuestion> ManualSet =
new[] { NlTaalManual, DiplomaErkend, Toelichting };
/// <summary>Every question defined here — used by the stamdata validation gate.</summary>
public static readonly IReadOnlyList<PolicyQuestion> All =
new[] { NlTaalEngelstalig, NlTaalManual, DiplomaErkend, Toelichting };
}
@@ -38,4 +38,21 @@ public class StamdataValidationTests
Assert.NotEmpty(professions);
Assert.Equal(professions.Count, professions.Distinct().Count());
}
[Fact]
public void Every_policy_question_has_an_id_and_wording()
{
Assert.All(PolicyQuestions.All, q =>
{
Assert.False(string.IsNullOrWhiteSpace(q.Id), "A policy question has a blank id.");
Assert.False(string.IsNullOrWhiteSpace(q.Vraag), $"Policy question '{q.Id}' has blank wording.");
});
}
[Fact]
public void Manual_question_set_has_distinct_ids() // no field is asked twice
{
var ids = PolicyQuestions.ManualSet.Select(q => q.Id).ToList();
Assert.Equal(ids.Count, ids.Distinct().Count());
}
}