PiiGateService makes any future personal-data source (ratsit.se and other directory domains) technically GDPR-OK before the first byte is stored: - recorded legal basis (art. 6) with basis_ref evidence, no policy => fail-closed - data minimisation via field allowlist (art. 5(1)(c)) - storage limitation + enforceRetention purge (art. 5(1)(e)) - sha256-only identity keys + log redaction (art. 25/32) - accessStatement / erase subject-rights surfaces (art. 15/17) - robots/rate confirmation required for web+api sources; no stealth/bypass - audit trail via AUD0 at risk L3 (0pt.pii_*) - gate enabled by default in SourceQueryService 10 new tests; full suite 166 pass | 1 skip; typecheck (blocking gate) clean.
103 lines
3.9 KiB
TypeScript
103 lines
3.9 KiB
TypeScript
/**
|
|
* src/types/source.ts
|
|
* =====================
|
|
* 0pt.source.schema.v1 — a registered upstream data source (a database, a
|
|
* crawlable web domain, an API, a file drop, …). Owned by SourceService
|
|
* (src/services/source-service.ts); referenced by SourceRatePolicy
|
|
* (src/types/source-rate-policy.ts) and by the synchronous query path
|
|
* (src/services/source-query-service.ts), which reads `source_type` +
|
|
* `adapter_id` to decide whether a Source is queryable.
|
|
*
|
|
* This is a DIFFERENT, newer entity than the static provenance catalog in
|
|
* docs/03-data-model.md's `dim_source` table (the ~9-row list of national
|
|
* registries served today by GET /api/sources) -- this Source is a per-tenant
|
|
* registration of something 0pt can actually connect to. See
|
|
* docs/P0_QUERY_SOURCE_FLOW.md and src/services/source-query-service.ts, the
|
|
* first real consumer.
|
|
*
|
|
* `adapter_id` is the seam that lets a "database" source name the concrete
|
|
* driver 0pt should use for it (today only "fabric_onelake_sql" is wired on
|
|
* the synchronous path — see source-query-service.ts).
|
|
*
|
|
* `access` mirrors dim_source.access (docs/03-data-model.md) so a Source
|
|
* registered here can still be reported against the same legal-sourcing
|
|
* vocabulary CLAUDE.md §1 requires everywhere in this repo.
|
|
*/
|
|
|
|
/**
|
|
* Union of both source-type vocabularies that existed in this repo's two
|
|
* remotes; nothing is dropped by the unification merge.
|
|
*/
|
|
export type SourceType = "database" | "file" | "web" | "api" | "stream" | "manual";
|
|
|
|
/**
|
|
* Union of both status vocabularies. "archived" and "deprecated" both survive
|
|
* the unification merge -- they were introduced independently and no code
|
|
* treats either as canonical.
|
|
*
|
|
* "pending" (P060) is the state every newly registered source starts in. It
|
|
* exists because "active" used to be the CREATE default
|
|
* (postgres-source-repository.ts / in-memory-source-repository.ts both did
|
|
* `input.status ?? "active"`), which meant a source with no rights, no
|
|
* provenance and no authorization was live the instant it was registered.
|
|
* Reaching "active" now requires passing SourceRegistryService.activateSource's
|
|
* classification gate.
|
|
*/
|
|
export type SourceStatus = "pending" | "active" | "paused" | "archived" | "deprecated";
|
|
|
|
/** Legal-sourcing vocabulary, mirroring dim_source.access. */
|
|
export type SourceAccess = "api" | "bulk" | "authorized_web" | "licensed";
|
|
|
|
export interface Source {
|
|
source_id: string;
|
|
tenant_id: string;
|
|
project_id: string;
|
|
source_type: SourceType;
|
|
name: string;
|
|
/**
|
|
* Identifies which concrete adapter implementation this source is queried
|
|
* through (e.g. "fabric_onelake_sql" -- src/adapters/fabric-onelake-adapter.ts).
|
|
* Required in practice for source_type "database"; optional/unused for other
|
|
* types until they grow a synchronous query path of their own.
|
|
*/
|
|
adapter_id?: string;
|
|
/** Mirrors dim_source.access (docs/03-data-model.md). */
|
|
access?: SourceAccess;
|
|
/**
|
|
* Explicit self-flag that this source CAN expose personuppgifter. When
|
|
* true (or when the source is a known directory domain like ratsit.se),
|
|
* the PiiGateService requires a PiiPolicy with a recorded lawful basis
|
|
* before any storage/query (fail-closed, GDPR art. 6).
|
|
*/
|
|
touches_personal_data?: boolean;
|
|
description?: string;
|
|
status: SourceStatus;
|
|
correlation_id?: string;
|
|
created_at: string;
|
|
updated_at?: string;
|
|
/** Who registered the source. */
|
|
created_by?: string;
|
|
/**
|
|
* Who is ACCOUNTABLE for the source going forward (P060 "owner"). Distinct
|
|
* from `created_by`, which is only who typed the registration. Required by
|
|
* the activation gate.
|
|
*/
|
|
owner_id?: string;
|
|
}
|
|
|
|
export interface CreateSourceInput {
|
|
source_id: string;
|
|
tenant_id: string;
|
|
project_id: string;
|
|
source_type: SourceType;
|
|
name: string;
|
|
adapter_id?: string;
|
|
access?: SourceAccess;
|
|
touches_personal_data?: boolean;
|
|
description?: string;
|
|
status?: SourceStatus;
|
|
correlation_id?: string;
|
|
created_by?: string;
|
|
owner_id?: string;
|
|
}
|