feat(WP-67): merge behandelportal into this repo as a monorepo
Restructures into apps/ssp + apps/behandelportal (two Angular projects) plus libs/shared + libs/beheer (cross-app libraries), replacing WP-61's separate sibling repo. That split had already produced real drift: a hand-vendored copy of the backend's OpenAPI doc, a shared/ui+layout tree forked and silently diverging (7 files), and beheer + the styles.scss token bridge duplicated byte-for-byte across both repos. - git mv the SSP's src/app/* into apps/ssp/; fold shared/, beheer/, environments/, the Storybook docs/*.mdx, and styles.scss into libs/shared + libs/beheer (all confirmed identical between the two repos before merging). auth stays deliberately duplicated per ADR-0002 (actor-specific, expected to diverge) - amended there. - One generated API client (libs/shared), no more vendored swagger.json. - .dependency-cruiser split into a base factory + one config per app, and Storybook into .storybook-ssp/.storybook-behandelportal - both forced by the @auth/* alias resolving to different directories per app. - SiteHeaderComponent/ShellComponent gained HEADER_NAV_ITEMS/ HEADER_ADMIN_LINKS/DEBUG_PANEL injection tokens so each app supplies its own nav/admin-links/dev-panel instead of one being hardcoded. - CLAUDE.md, ARCHITECTURE.md, dependencies.md, and ADR-0002 updated; WP-67 backlog entry documents the full decision trail. npm run ci green (lint, dep:check x2, 360 tests across ssp/ behandelportal/shared/beheer, both localized builds, backend tests, snippet + api-client drift); both dev servers, both Storybook instances, and docker compose verified working. The old sibling repo (/home/eho/repos/behandelportal) is left untouched, not deleted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { Injectable, computed, inject } from '@angular/core';
|
||||
import { RemoteData, fromResource } from '@shared/application/remote-data';
|
||||
import { DuoLookupDto } from '../contracts/duo-diplomas.dto';
|
||||
import { BrpAdapter, parseBrpAddress } from '../infrastructure/brp.adapter';
|
||||
import { DuoAdapter, parseDuoLookup } from '../infrastructure/duo.adapter';
|
||||
|
||||
type Err = Error | undefined;
|
||||
|
||||
/**
|
||||
* Application-layer facade for the registratie wizard's two lookups (BRP address,
|
||||
* DUO diplomas). It owns the httpResources (created here, in the required injection
|
||||
* context), runs the trust-boundary parse, and exposes RemoteData / derived signals
|
||||
* — so the UI reaches the network through application/, never infrastructure/
|
||||
* directly (CLAUDE.md §1: ui → application → domain). Same facade shape as
|
||||
* BigProfileStore.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RegistratieLookupStore {
|
||||
private brp = inject(BrpAdapter);
|
||||
private duo = inject(DuoAdapter);
|
||||
|
||||
private adresRes = this.brp.adresResource();
|
||||
private diplomasRes = this.duo.diplomasResource();
|
||||
|
||||
/** BRP lookup outcome. A failure or "geen adres" never blocks the wizard — both
|
||||
fall back to manual entry (PRD §7). 'geen' covers both no-address-found and a
|
||||
malformed response; 'fout' is an unreachable BRP. */
|
||||
readonly adresStatus = computed<'laden' | 'gevonden' | 'geen' | 'fout'>(() => {
|
||||
const st = this.adresRes.status();
|
||||
if (st === 'loading' || st === 'reloading') return 'laden';
|
||||
if (st === 'error') return 'fout';
|
||||
const json = this.adresRes.value();
|
||||
const parsed = json !== undefined ? parseBrpAddress(json) : null;
|
||||
return parsed && parsed.ok && parsed.value.gevonden ? 'gevonden' : 'geen';
|
||||
});
|
||||
|
||||
/** The address to prefill the draft with, once BRP resolves with a found address;
|
||||
null otherwise (loading, error, no address, malformed). */
|
||||
readonly prefillAdres = computed<{ straat: string; postcode: string; woonplaats: string } | null>(
|
||||
() => {
|
||||
const json = this.adresRes.value();
|
||||
if (json === undefined) return null;
|
||||
const parsed = parseBrpAddress(json);
|
||||
return parsed.ok && parsed.value.gevonden && parsed.value.adres ? parsed.value.adres : null;
|
||||
},
|
||||
);
|
||||
|
||||
/** The DUO lookup (diplomas + manual fallback), validated at the trust boundary. */
|
||||
readonly duoLookup = computed<RemoteData<Err, DuoLookupDto>>(() => {
|
||||
const rd = fromResource(this.diplomasRes);
|
||||
if (rd.tag !== 'Success') return rd;
|
||||
const parsed = parseDuoLookup(rd.value);
|
||||
return parsed.ok
|
||||
? { tag: 'Success', value: parsed.value }
|
||||
: { tag: 'Failure', error: new Error(parsed.error) };
|
||||
});
|
||||
|
||||
/** Reload the BRP lookup (e.g. when the wizard restarts) so the address re-prefills. */
|
||||
reloadAdres() {
|
||||
this.adresRes.reload();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user