feat(zgw): finish WP-52 OpenZaak Notificaties (NRC) webhook slice
CI / frontend (push) Successful in 2m33s
CI / backend (push) Successful in 1m45s
CI / storybook-a11y (push) Successful in 7m47s
CI / e2e (push) Successful in 4m3s
CI / semgrep (push) Successful in 1m7s
CI / api-client-drift (push) Successful in 2m3s

Endpoint/DTO/options landed already in c4dd846; this closes the loop with
NotificatieTests.cs (accept/reject/missing-header, asserting the AuthzAuditStore
row), missing appsettings.json keys (also backfills DrcBaseUrl/
InformatieobjecttypeUrls, stale since WP-51), and the webhook + abonnement
provisioning docs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-30 08:07:50 +02:00
co-authored by Claude Sonnet 5
parent f356dc7329
commit bea04549dd
7 changed files with 243 additions and 84 deletions
+96 -68
View File
@@ -25393,7 +25393,7 @@
},
{
"name": "LanguageSwitcherComponent",
"id": "component-LanguageSwitcherComponent-942989669741812f8407b6b1ae4bd8ccca1ac8ff40c07616b2e38206df378a56517aedd9150eb2a5d8ad443e68566a798d0f4aaebfd1ca5e14f610a15776a5b5",
"id": "component-LanguageSwitcherComponent-02fced34bf97cdd33a71176c9bd80a3a43f4ef9ace7bd6dff503daf3b39f3355d829a6d990a5e62dd7f518515b3e68ec68c2dcfbeefb92bb19b8b15620e753dc",
"file": "src/app/shared/layout/language-switcher/language-switcher.component.ts",
"encapsulation": [],
"entryComponents": [],
@@ -25419,7 +25419,7 @@
"indexKey": "",
"optional": false,
"description": "<p>Override the detected locale (stories/tests); the app detects it from the base href.</p>\n",
"line": 63,
"line": 71,
"rawdescription": "\nOverride the detected locale (stories/tests); the app detects it from the base href.",
"required": false
}
@@ -25435,7 +25435,7 @@
"indexKey": "",
"optional": false,
"description": "",
"line": 65,
"line": 73,
"modifierKind": [
123,
148
@@ -25450,21 +25450,21 @@
"indexKey": "",
"optional": false,
"description": "",
"line": 81,
"line": 96,
"modifierKind": [
124
]
},
{
"name": "links",
"defaultValue": "computed(() =>\n localeLinks(\n this.loc.pathname,\n this.activeLocale() ?? this.detected,\n this.loc.search,\n this.loc.hash,\n ),\n )",
"defaultValue": "computed(() => {\n this.nav(); // recompute on every completed navigation — loc.pathname is read fresh below\n return localeLinks(\n this.loc.pathname,\n this.activeLocale() ?? this.detected,\n this.loc.search,\n this.loc.hash,\n );\n })",
"deprecated": false,
"deprecationMessage": "",
"type": "unknown",
"indexKey": "",
"optional": false,
"description": "",
"line": 71,
"line": 85,
"modifierKind": [
124
]
@@ -25478,12 +25478,26 @@
"indexKey": "",
"optional": false,
"description": "",
"line": 66,
"line": 74,
"modifierKind": [
123,
148
]
},
{
"name": "nav",
"defaultValue": "toSignal(\n this.router?.events.pipe(filter((e) => e instanceof NavigationEnd)) ?? EMPTY,\n { initialValue: null },\n )",
"deprecated": false,
"deprecationMessage": "",
"type": "unknown",
"indexKey": "",
"optional": false,
"description": "",
"line": 80,
"modifierKind": [
123
]
},
{
"name": "navLabel",
"defaultValue": "$localize`:@@lang.navLabel:Taal / Language`",
@@ -25493,10 +25507,24 @@
"indexKey": "",
"optional": false,
"description": "",
"line": 80,
"line": 95,
"modifierKind": [
124
]
},
{
"name": "router",
"defaultValue": "inject(Router, { optional: true })",
"deprecated": false,
"deprecationMessage": "",
"type": "unknown",
"indexKey": "",
"optional": false,
"description": "",
"line": 79,
"modifierKind": [
123
]
}
],
"methodsClass": [],
@@ -25506,10 +25534,10 @@
"hostListeners": [],
"standalone": false,
"imports": [],
"description": "<p>Organism: CIBG &quot;Taal instellen&quot; language switcher. A <code>&lt;nav&gt;</code> region (screenreader heading +\naria-label) with one link per locale — the endonym, tagged with its <code>lang</code>/<code>hreflang</code>, the\nactive one marked <code>aria-current</code> and rendered as text (not a link).</p>\n<p>Compile-time $localize means each locale is a separate bundle under <code>/&lt;locale&gt;/</code>, so switching\nis a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\nis read from the baked <code>&lt;base href&gt;</code> (<code>/en/</code> → en, else nl) — the deployment truth, independent\nof the app-config <code>LOCALE_ID</code>. Only functional where both locale bundles are served (the\nlocalized build, e.g. <code>npm run serve:i18n</code>), not under plain <code>ng serve</code> (nl-only at <code>/</code>).</p>\n",
"rawdescription": "\n\nOrganism: CIBG \"Taal instellen\" language switcher. A `<nav>` region (screenreader heading +\naria-label) with one link per locale — the endonym, tagged with its `lang`/`hreflang`, the\nactive one marked `aria-current` and rendered as text (not a link).\n\nCompile-time $localize means each locale is a separate bundle under `/<locale>/`, so switching\nis a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\nis read from the baked `<base href>` (`/en/` → en, else nl) — the deployment truth, independent\nof the app-config `LOCALE_ID`. Only functional where both locale bundles are served (the\nlocalized build, e.g. `npm run serve:i18n`), not under plain `ng serve` (nl-only at `/`).\n",
"description": "<p>Organism: CIBG &quot;Taal instellen&quot; language switcher. A <code>&lt;nav&gt;</code> region (screenreader heading +\naria-label) with one link per locale — the endonym, tagged with its <code>lang</code>/<code>hreflang</code>, the\nactive one marked <code>aria-current</code> and rendered as text (not a link).</p>\n<p>Compile-time $localize means each locale is a separate bundle under <code>/&lt;locale&gt;/</code>, so switching\nis a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\nis read from the baked <code>&lt;base href&gt;</code> (<code>/en/</code> → en, else nl) — the deployment truth, independent\nof the app-config <code>LOCALE_ID</code>. Only functional where both locale bundles are served (the\nlocalized build, e.g. <code>npm run serve:i18n</code>), not under plain <code>ng serve</code> (nl-only at <code>/</code>).</p>\n<p>The shell (and this switcher within it) is a persistent parent — only the routed child\nswaps — so <code>location.pathname</code> must be re-read on every completed navigation (same\n<code>toSignal(router.events...)</code> idiom as <code>site-header.component.ts</code>&#39;s breadcrumb <code>url</code>), or the\ntarget link freezes at whichever route was active when the switcher was first constructed.</p>\n",
"rawdescription": "\n\nOrganism: CIBG \"Taal instellen\" language switcher. A `<nav>` region (screenreader heading +\naria-label) with one link per locale — the endonym, tagged with its `lang`/`hreflang`, the\nactive one marked `aria-current` and rendered as text (not a link).\n\nCompile-time $localize means each locale is a separate bundle under `/<locale>/`, so switching\nis a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\nis read from the baked `<base href>` (`/en/` → en, else nl) — the deployment truth, independent\nof the app-config `LOCALE_ID`. Only functional where both locale bundles are served (the\nlocalized build, e.g. `npm run serve:i18n`), not under plain `ng serve` (nl-only at `/`).\n\nThe shell (and this switcher within it) is a persistent parent — only the routed child\nswaps — so `location.pathname` must be re-read on every completed navigation (same\n`toSignal(router.events...)` idiom as `site-header.component.ts`'s breadcrumb `url`), or the\ntarget link freezes at whichever route was active when the switcher was first constructed.\n",
"type": "component",
"sourceCode": "import { Component, computed, input } from '@angular/core';\nimport { Locale, localeLinks } from './locale-links';\n\n// CIBG-GAP EXTENSION: \"Taal instellen\" (designsystem.cibg.nl/componenten/taal-instellen) — no\n// vendored Huisstijl class ships for it, so this is a small hand-rolled surface built from the\n// token bridge. See cibg-gaps.mdx.\n/**\n * Organism: CIBG \"Taal instellen\" language switcher. A `<nav>` region (screenreader heading +\n * aria-label) with one link per locale — the endonym, tagged with its `lang`/`hreflang`, the\n * active one marked `aria-current` and rendered as text (not a link).\n *\n * Compile-time $localize means each locale is a separate bundle under `/<locale>/`, so switching\n * is a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\n * is read from the baked `<base href>` (`/en/` → en, else nl) — the deployment truth, independent\n * of the app-config `LOCALE_ID`. Only functional where both locale bundles are served (the\n * localized build, e.g. `npm run serve:i18n`), not under plain `ng serve` (nl-only at `/`).\n */\n@Component({\n selector: 'app-language-switcher',\n styles: [\n `\n nav {\n display: flex;\n justify-content: flex-end;\n gap: var(--rhc-space-max-md);\n padding: var(--rhc-space-max-sm) var(--rhc-space-max-2xl);\n font-size: var(--rhc-text-font-size-sm);\n }\n a {\n color: var(--rhc-color-hemelblauw-700);\n }\n [aria-current] {\n font-weight: var(--rhc-text-font-weight-semi-bold);\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n }\n `,\n ],\n template: `\n <nav [attr.aria-label]=\"navLabel\">\n <h2 class=\"sr-only\">{{ heading }}</h2>\n @for (l of links(); track l.locale) {\n @if (l.active) {\n <span [attr.lang]=\"l.locale\" aria-current=\"true\">{{ l.label }}</span>\n } @else {\n <a [attr.lang]=\"l.locale\" [attr.hreflang]=\"l.locale\" [href]=\"l.href\">{{ l.label }}</a>\n }\n }\n </nav>\n `,\n})\nexport class LanguageSwitcherComponent {\n /** Override the detected locale (stories/tests); the app detects it from the base href. */\n activeLocale = input<Locale | undefined>(undefined);\n\n private readonly detected: Locale = /\\/en\\//.test(document.baseURI) ? 'en' : 'nl';\n private readonly loc =\n typeof location !== 'undefined'\n ? location\n : ({ pathname: '/', search: '', hash: '' } as Location);\n\n protected links = computed(() =>\n localeLinks(\n this.loc.pathname,\n this.activeLocale() ?? this.detected,\n this.loc.search,\n this.loc.hash,\n ),\n );\n\n protected navLabel = $localize`:@@lang.navLabel:Taal / Language`;\n protected heading = $localize`:@@lang.heading:Kies een taal`;\n}\n",
"sourceCode": "import { Component, computed, inject, input } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { EMPTY, filter } from 'rxjs';\nimport { Locale, localeLinks } from './locale-links';\n\n// CIBG-GAP EXTENSION: \"Taal instellen\" (designsystem.cibg.nl/componenten/taal-instellen) — no\n// vendored Huisstijl class ships for it, so this is a small hand-rolled surface built from the\n// token bridge. See cibg-gaps.mdx.\n/**\n * Organism: CIBG \"Taal instellen\" language switcher. A `<nav>` region (screenreader heading +\n * aria-label) with one link per locale — the endonym, tagged with its `lang`/`hreflang`, the\n * active one marked `aria-current` and rendered as text (not a link).\n *\n * Compile-time $localize means each locale is a separate bundle under `/<locale>/`, so switching\n * is a plain full-page navigation to the sibling bundle (not a runtime toggle). The active locale\n * is read from the baked `<base href>` (`/en/` → en, else nl) — the deployment truth, independent\n * of the app-config `LOCALE_ID`. Only functional where both locale bundles are served (the\n * localized build, e.g. `npm run serve:i18n`), not under plain `ng serve` (nl-only at `/`).\n *\n * The shell (and this switcher within it) is a persistent parent — only the routed child\n * swaps — so `location.pathname` must be re-read on every completed navigation (same\n * `toSignal(router.events...)` idiom as `site-header.component.ts`'s breadcrumb `url`), or the\n * target link freezes at whichever route was active when the switcher was first constructed.\n */\n@Component({\n selector: 'app-language-switcher',\n styles: [\n `\n nav {\n display: flex;\n justify-content: flex-end;\n gap: var(--rhc-space-max-md);\n padding: var(--rhc-space-max-sm) var(--rhc-space-max-2xl);\n font-size: var(--rhc-text-font-size-sm);\n }\n a {\n color: var(--rhc-color-hemelblauw-700);\n }\n [aria-current] {\n font-weight: var(--rhc-text-font-weight-semi-bold);\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n }\n `,\n ],\n template: `\n <nav [attr.aria-label]=\"navLabel\">\n <h2 class=\"sr-only\">{{ heading }}</h2>\n @for (l of links(); track l.locale) {\n @if (l.active) {\n <span [attr.lang]=\"l.locale\" aria-current=\"true\">{{ l.label }}</span>\n } @else {\n <a [attr.lang]=\"l.locale\" [attr.hreflang]=\"l.locale\" [href]=\"l.href\">{{ l.label }}</a>\n }\n }\n </nav>\n `,\n})\nexport class LanguageSwitcherComponent {\n /** Override the detected locale (stories/tests); the app detects it from the base href. */\n activeLocale = input<Locale | undefined>(undefined);\n\n private readonly detected: Locale = /\\/en\\//.test(document.baseURI) ? 'en' : 'nl';\n private readonly loc =\n typeof location !== 'undefined'\n ? location\n : ({ pathname: '/', search: '', hash: '' } as Location);\n\n private router = inject(Router, { optional: true });\n private nav = toSignal(\n this.router?.events.pipe(filter((e) => e instanceof NavigationEnd)) ?? EMPTY,\n { initialValue: null },\n );\n\n protected links = computed(() => {\n this.nav(); // recompute on every completed navigation — loc.pathname is read fresh below\n return localeLinks(\n this.loc.pathname,\n this.activeLocale() ?? this.detected,\n this.loc.search,\n this.loc.hash,\n );\n });\n\n protected navLabel = $localize`:@@lang.navLabel:Taal / Language`;\n protected heading = $localize`:@@lang.heading:Kies een taal`;\n}\n",
"assetsDirs": [],
"styleUrlsData": "",
"stylesData": "\n nav {\n display: flex;\n justify-content: flex-end;\n gap: var(--rhc-space-max-md);\n padding: var(--rhc-space-max-sm) var(--rhc-space-max-2xl);\n font-size: var(--rhc-text-font-size-sm);\n }\n a {\n color: var(--rhc-color-hemelblauw-700);\n }\n [aria-current] {\n font-weight: var(--rhc-text-font-weight-semi-bold);\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n }\n \n",
@@ -34438,6 +34466,16 @@
"rawdescription": "Used by the shell to find what to poll on return: still-in-flight uploads.",
"description": "<p>Used by the shell to find what to poll on return: still-in-flight uploads.</p>\n"
},
{
"name": "initial",
"ctype": "miscellaneous",
"subtype": "variable",
"file": "src/app/beheer/domain/stamdata-editor.machine.ts",
"deprecated": false,
"deprecationMessage": "",
"type": "StamdataEditorState",
"defaultValue": "{ tag: 'loading' }"
},
{
"name": "initial",
"ctype": "miscellaneous",
@@ -34458,16 +34496,6 @@
"type": "IntakeState",
"defaultValue": "{\n tag: 'Answering',\n answers: {},\n cursor: 0,\n errors: {},\n scholingThreshold: SCHOLING_THRESHOLD_DEFAULT,\n}"
},
{
"name": "initial",
"ctype": "miscellaneous",
"subtype": "variable",
"file": "src/app/beheer/domain/stamdata-editor.machine.ts",
"deprecated": false,
"deprecationMessage": "",
"type": "StamdataEditorState",
"defaultValue": "{ tag: 'loading' }"
},
{
"name": "initial",
"ctype": "miscellaneous",
@@ -40357,6 +40385,50 @@
}
]
},
{
"name": "reduce",
"file": "src/app/beheer/domain/stamdata-editor.machine.ts",
"ctype": "miscellaneous",
"subtype": "function",
"deprecated": false,
"deprecationMessage": "",
"description": "",
"args": [
{
"name": "s",
"type": "StamdataEditorState",
"deprecated": false,
"deprecationMessage": ""
},
{
"name": "m",
"type": "StamdataEditorMsg",
"deprecated": false,
"deprecationMessage": ""
}
],
"returnType": "StamdataEditorState",
"jsdoctags": [
{
"name": "s",
"type": "StamdataEditorState",
"deprecated": false,
"deprecationMessage": "",
"tagName": {
"text": "param"
}
},
{
"name": "m",
"type": "StamdataEditorMsg",
"deprecated": false,
"deprecationMessage": "",
"tagName": {
"text": "param"
}
}
]
},
{
"name": "reduce",
"file": "src/app/herregistratie/domain/herregistratie.machine.ts",
@@ -40445,50 +40517,6 @@
}
]
},
{
"name": "reduce",
"file": "src/app/beheer/domain/stamdata-editor.machine.ts",
"ctype": "miscellaneous",
"subtype": "function",
"deprecated": false,
"deprecationMessage": "",
"description": "",
"args": [
{
"name": "s",
"type": "StamdataEditorState",
"deprecated": false,
"deprecationMessage": ""
},
{
"name": "m",
"type": "StamdataEditorMsg",
"deprecated": false,
"deprecationMessage": ""
}
],
"returnType": "StamdataEditorState",
"jsdoctags": [
{
"name": "s",
"type": "StamdataEditorState",
"deprecated": false,
"deprecationMessage": "",
"tagName": {
"text": "param"
}
},
{
"name": "m",
"type": "StamdataEditorMsg",
"deprecated": false,
"deprecationMessage": "",
"tagName": {
"text": "param"
}
}
]
},
{
"name": "reduce",
"file": "src/app/brief/domain/brief.machine.ts",
@@ -59075,9 +59103,9 @@
"type": "component",
"linktype": "component",
"name": "LanguageSwitcherComponent",
"coveragePercent": 28,
"coverageCount": "2/7",
"status": "medium"
"coveragePercent": 22,
"coverageCount": "2/9",
"status": "low"
},
{
"filePath": "src/app/shared/layout/language-switcher/locale-links.ts",