import { Component, computed, signal } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HeadingComponent } from '@shared/ui/heading/heading.component'; import { TextInputComponent } from '@shared/ui/text-input/text-input.component'; import { MaskedValueComponent } from '@shared/ui/masked-value/masked-value.component'; import { parseBsn } from '@shared/kernel/bsn'; import { maskBsn } from '@shared/kernel/pii'; import { ConceptCardComponent } from './concept-card.component'; import { SNIPPETS } from './snippets.generated'; import { highlightTs } from './highlight-ts'; /** Section 6: PII — masking and parsing. A BSN (Dutch citizen service number) is special-category personal data (GDPR art. 9): masked by default, revealed only after a logged action; "parse, don't validate" on the most sensitive field — a pure function enforces the checksum. Composition-only. The ok/err result nests its own `` for its label, for the same reason section 2 does. */ @Component({ selector: 'app-concepts-pii-section', imports: [ FormsModule, HeadingComponent, TextInputComponent, MaskedValueComponent, ConceptCardComponent, ], template: `
6 · PII — maskeren & parsen

Een BSN is bijzondere persoonsgegevens (AVG art. 9). Dataminimalisatie: standaard gemaskeerd tonen, alleen tonen na een vastgelegde handeling; en"parse, don't validate" op het gevoeligste veld — een pure functie die de elfproef afdwingt.

BSN:

Standaard gemaskeerd; het echte tonen is step-up-geverifieerd én vastgelegd (zie het behandelscherm). De atom bevat de maskeer-detectie — geen los *-gesnuffel bij elke gebruiker.

@let b = bsnParsed(); @if (bsnRaw()) {
@if (b.ok) {
Bsn ="{{ b.value }}"
} @else {
{{ b.error }}
}
}
`, }) export class PiiSection { // Masked-by-default value that reveals locally (the real reveal is step-up-gated + // audited elsewhere); plus a live elfproef parse mirroring the postcode demo. demoBsn = '123456782'; bsnRevealed = signal(false); bsnShown = computed(() => (this.bsnRevealed() ? this.demoBsn : maskBsn(this.demoBsn))); bsnRaw = signal(''); bsnParsed = computed(() => parseBsn(this.bsnRaw())); protected readonly code: Record = { mask: highlightTs(SNIPPETS['mask']), parseBsn: highlightTs(SNIPPETS['parseBsn']), }; protected readonly src: Record = { mask: 'shared/kernel/pii.ts', parseBsn: 'shared/kernel/bsn.ts', }; }