## What & why S-15b, second of the S-15 (#16) split, on top of S-15a (#133). A beheerder edits the ACL's ZGW **default-fill** values from the beheer portal, and the next zaak is stamped with the new values — no restart. Closes #131 ### The vertical portal → BFF `GET/PUT /beheer/default-fill` (medewerker realm + `beheerder` role) → ACL `GET/PUT /default-fill` → a runtime-mutable in-memory store the ACL reads **per zaak**. - **ACL**: `IDefaultFillStore` / `InMemoryDefaultFillStore` (thread-safe, seeded from `Acl:Defaults`); `AclService` reads `fill.Current` per zaak (not cached at construction); `GET`/`PUT /default-fill` with required-field validation. - **BFF**: `IAclClient` gains `GetDefaultFillAsync`/`UpdateDefaultFillAsync`; `GET`/`PUT /beheer/default-fill` behind the `beheerder` policy. OpenAPI + generated client regenerated. - **Frontend**: a *Default-fill* editor page in the beheer app (load → edit → save, with saved/failure states) + nav between Catalogus and Default-fill. ### Scope decision → ADR-0026 Only the **three ZGW fill fields** (bronorganisatie, verantwoordelijke organisatie, vertrouwelijkheidaanduiding) are editable. The S-27 catalog-resolution keys stay **static config** — editing them would desync the zaaktype-URL cache (ADR-0021), and they're catalogus wiring, not "default fill". The store is **in-memory** (seeded from config): an edit reverts on restart. That's the reference-app-appropriate ceiling (no DB added to the stateless ACL); upgrade path documented. Recorded in **ADR-0026**. ## Verified locally lint (`dotnet format`) ✓ · .NET unit — acl 60 / bff 45 / domain 152 / event-subscriber 19 / acceptance 17 ✓ · frontend lint+test (8 projects) ✓ · beheer build ✓. Clean full-solution build (caught + fixed the acceptance `AclService` ctor drift). TDD red→green per layer (ACL store, ACL endpoints, BFF, frontend). ## Definition of Done - [x] Failing test committed before each implementation (red→green per layer). - [x] Conventional Commits referencing #131. - [ ] CI green — see note below. - [x] Docs: ADR-0026 + S-15b demo note. - [x] Demo note in `docs/demo-script.md`. ## Note on CI The bulk validates in the fast jobs (lint/build/unit/frontend/mutation). The **verify-stack e2e** (incl. the new `default-fill.spec.ts`) can't go green until the pre-existing **verify-stack bring-up failure on the 1.27/2.0.0 runner** is resolved (that fails on plain `main` too — unrelated to this PR). Additive change; no existing e2e touched. 🤖 Generated with [Claude Code](https://claude.com/claude-code)Reviewed-on: #138
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
import { Component, inject, signal } from '@angular/core';
|
|
import { BeheerDefaultFill, BffApiV1Service } from 'api-client';
|
|
import { UtrechtComponentsModule } from 'ui';
|
|
|
|
/**
|
|
* The beheer default-fill editor (S-15b): a beheerder reads and edits the ZGW default-fill values the
|
|
* ACL stamps on every zaak (ADR-0003). Load and save go through the BFF (`/beheer/default-fill`),
|
|
* which proxies the ACL (ADR-0025). A save takes effect on the next zaak (the ACL reads it per zaak).
|
|
*/
|
|
@Component({
|
|
selector: 'app-default-fill-page',
|
|
imports: [UtrechtComponentsModule],
|
|
templateUrl: './default-fill-page.html',
|
|
})
|
|
export class DefaultFillPage {
|
|
private readonly bff = inject(BffApiV1Service);
|
|
|
|
protected readonly bronorganisatie = signal('');
|
|
protected readonly verantwoordelijkeOrganisatie = signal('');
|
|
protected readonly vertrouwelijkheidaanduiding = signal('');
|
|
protected readonly loading = signal(false);
|
|
protected readonly loaded = signal(false);
|
|
protected readonly saving = signal(false);
|
|
protected readonly failed = signal(false);
|
|
protected readonly saved = signal(false);
|
|
|
|
constructor() {
|
|
this.load();
|
|
}
|
|
|
|
load(): void {
|
|
this.loading.set(true);
|
|
this.failed.set(false);
|
|
this.saved.set(false);
|
|
this.bff.getBeheerDefaultFill().subscribe({
|
|
next: (d: BeheerDefaultFill) => {
|
|
this.bronorganisatie.set(d.bronorganisatie);
|
|
this.verantwoordelijkeOrganisatie.set(d.verantwoordelijkeOrganisatie);
|
|
this.vertrouwelijkheidaanduiding.set(d.vertrouwelijkheidaanduiding);
|
|
this.loading.set(false);
|
|
this.loaded.set(true);
|
|
},
|
|
error: () => {
|
|
this.loading.set(false);
|
|
this.loaded.set(true);
|
|
this.failed.set(true);
|
|
},
|
|
});
|
|
}
|
|
|
|
save(): void {
|
|
this.saving.set(true);
|
|
this.failed.set(false);
|
|
this.saved.set(false);
|
|
this.bff
|
|
.putBeheerDefaultFill({
|
|
bronorganisatie: this.bronorganisatie(),
|
|
verantwoordelijkeOrganisatie: this.verantwoordelijkeOrganisatie(),
|
|
vertrouwelijkheidaanduiding: this.vertrouwelijkheidaanduiding(),
|
|
})
|
|
.subscribe({
|
|
next: () => {
|
|
this.saving.set(false);
|
|
this.saved.set(true);
|
|
},
|
|
error: () => {
|
|
this.saving.set(false);
|
|
this.failed.set(true);
|
|
},
|
|
});
|
|
}
|
|
}
|