feat(13-02): generalize adapter contract with portals[] array

TenderSourceAdapter gains a readonly portals: readonly string[] field
so one adapter can serve multiple portals (NetServer: 3, Plan 13-04)
and so SourceRegistry can gate registration per-portal (INGEST-07).
DoeOpenDataAdapter declares portals = ['doe-opendata'] additively,
no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-23 08:42:23 +02:00
parent a547a1d31d
commit 1b11ada112
2 changed files with 13 additions and 0 deletions
@@ -56,6 +56,8 @@ export function isOpenTenderNotice(tag: string[] | undefined): boolean {
@Injectable() @Injectable()
export class DoeOpenDataAdapter implements TenderSourceAdapter { export class DoeOpenDataAdapter implements TenderSourceAdapter {
readonly sourceType: SourceType = 'doe-opendata'; readonly sourceType: SourceType = 'doe-opendata';
/** Single-portal adapter — see TenderSourceAdapter.portals doc. */
readonly portals = ['doe-opendata'] as const;
private readonly logger = new Logger(DoeOpenDataAdapter.name); private readonly logger = new Logger(DoeOpenDataAdapter.name);
private readonly xmlParser = new XMLParser({ private readonly xmlParser = new XMLParser({
@@ -15,6 +15,17 @@ import type { RawTenderRecord, SourceType } from '../tender.types';
export interface TenderSourceAdapter { export interface TenderSourceAdapter {
readonly sourceType: SourceType; readonly sourceType: SourceType;
/**
* The source portal(s) this adapter serves (e.g. `['doe-opendata']`, or
* `['tender24', 'lhs-vpbw', 'vergabe.landbw']` for the config-driven
* NetServer adapter, Plan 13-04). `portals` decouples "one adapter" from
* "one portal" (INGEST-02) and is the hook `SourceRegistry.register()`
* checks against the AGB-prohibited denylist (INGEST-07/D-06) — every
* portal an adapter declares is checked, so a mixed array containing a
* denylisted portal alongside legitimate ones is rejected wholesale.
*/
readonly portals: readonly string[];
/** /**
* Fetch and lightly parse all open-tender ("tender"-tagged", D-02) * Fetch and lightly parse all open-tender ("tender"-tagged", D-02)
* notices for the given calendar day (Europe/Berlin), already filtered — * notices for the given calendar day (Europe/Berlin), already filtered —