HWHeat Waves
    DashboardUtforsk
    Analyse
    Data Kilder
      • Catalog
      • Pipeline
      • Entrypoints
    • Design Rationale
    • Doc Map
    DocsSettings
    DashboardAtlasUtforsk
    Analyse
    Data Kilder
    1. Documentation
    2. Ingestion
    3. TypeScript ingestion entrypoints — dispatcher and registry

    Loading documentation...

    TypeScript ingestion entrypoints — dispatcher and registry

    Where `ingestBySourceId`, per-source adapters, and `loadSourceRegistry` live in the repo. Split from the former data_model inventory.

    TypeScript ingestion entrypoints — dispatcher and registry

    This document lists TypeScript entrypoints for moving data into fire_data. For pipeline semantics and triggers, see pipeline-slices-idempotency-and-triggers.md. For how /explore triggers ingest, see ../application-architecture/explore-fire-data-slice-probe-and-ingest.md.


    1. Dispatcher (ingestBySourceId)

    File: lib/data-model/adapters/_dispatch.ts

    export type IngestGrain = 'yearly' | 'daily' export async function ingestBySourceId( supabase: FireDataClient, source_id: number, slices?: readonly unknown[], progress?: IngestProgressCb, runId?: string | null, grain: IngestGrain = 'yearly', ): Promise<IngestResult>

    FireDataClient is local: SupabaseClient<FireDataDatabase, 'fire_data'>. When grain === 'daily':

    source_idAdapter forwarded toModule
    1 (BRASK)ingestBraskDailybrask.daily.ts (per-month form fan-out)
    2 (BRIS Police)ingestBrisDailybris.daily.ts (single-POST per tier)

    Any other source_id raises Error('Daily ingest not supported for source_id=X.'). Per-source sub-yearly capability is documented in taxonomy-and-eu-firestat-alignment.md and enforced upstream via sources.supports_subyear. See pipeline-slices-idempotency-and-triggers.md §10.4 for the BRIS Police daily tier model.


    2. Adapter entrypoints and registry loader

    Types below use FireDataClient = SupabaseClient<FireDataDatabase, 'fire_data'>. Slice shapes, SliceResult, IngestResult, and IngestProgressCb live in lib/data-model/types.ts. YearlyPhaseEmitter is lib/data-model/adapters/_phaseEmit.ts (optional per-slice progress for yearly adapters).

    Registry

    File: lib/data-model/adapters/_registry.ts

    export async function loadSourceRegistry( supabase: FireDataClient, source_id: number, ): Promise<SourceRegistry>

    Also exported: catKey(dim_code: number, native_name: string): string.

    BRIS

    File: lib/data-model/adapters/bris.ts

    Police /aggregate building-type requests are built in policeAggregateBuildingParams: Matrikkel leaf native_code → buildingTypeIdsOverride before any RESIDENTIAL → whole-Bolig fallback. Fire type and region slices already send a single native_code per slice. See adapter-mappings/filter-axes-native-to-filter-id.md («ETL rule — native wins»).

    export async function ingestBrisSlice( supabase: FireDataClient, registry: SourceRegistry, rawSlice: BrisSlice, runId?: string | null, emitter?: YearlyPhaseEmitter, ): Promise<SliceResult> export async function ingestBrisSource( supabase: FireDataClient, sub: BrisSubSource, slices: readonly BrisSlice[], progress?: IngestProgressCb, runId?: string | null, ): Promise<IngestResult>

    BRASK

    File: lib/data-model/adapters/brask.ts

    export async function ingestBraskSlice( supabase: FireDataClient, registry: SourceRegistry, slice: BraskSlice, runId?: string | null, emitter?: YearlyPhaseEmitter, ): Promise<SliceResult> export async function ingestBrask( supabase: FireDataClient, slices: readonly BraskSlice[], progress?: IngestProgressCb, runId?: string | null, ): Promise<IngestResult>

    BRASK — daily grain

    File: lib/data-model/adapters/brask.daily.ts

    export async function ingestBraskDailySlice( supabase: FireDataClient, registry: SourceRegistry, slice: BraskDailySlice, runId?: string | null, progress?: IngestProgressCb, ): Promise<SliceResult> export async function ingestBraskDaily( supabase: FireDataClient, slices: readonly BraskDailySlice[], progress?: IngestProgressCb, runId?: string | null, ): Promise<IngestResult>

    BRIS — daily grain (Police only)

    File: lib/data-model/adapters/bris.daily.ts

    export interface BrisDailySlice extends BrisSlice { date_start: string // YYYY-MM-DD inclusive date_end: string // YYYY-MM-DD inclusive } export async function ingestBrisDailySlice( supabase: FireDataClient, registry: SourceRegistry, slice: BrisDailySlice, runId?: string | null, progress?: IngestProgressCb, ): Promise<SliceResult> export async function ingestBrisDaily( supabase: FireDataClient, slices: readonly BrisDailySlice[], progress?: IngestProgressCb, runId?: string | null, ): Promise<IngestResult>

    Slices must carry sub: 'POLICE'; Brigade/DSB are blocked at the BRIS endpoint and the entry guards against them. Internally walks the four-tier probe described in pipeline-slices-idempotency-and-triggers.md §10.4 and reuses the daily helpers shipped for BRASK (fact_daily_slice_ingest_prefetch, upsert_fact_daily_batch, dedupeByNaturalKeyDaily, classifyWritesForDailySlice, buildLedgerEventsDaily).

    SSB

    File: lib/data-model/adapters/ssb.ts

    export async function ingestSsbSlice( supabase: FireDataClient, registry: SourceRegistry, slice: SsbSlice, emitter?: YearlyPhaseEmitter, ): Promise<SliceResult> export async function ingestSsb( supabase: FireDataClient, slices: readonly SsbSlice[], progress?: IngestProgressCb, ): Promise<IngestResult>

    2b. Shared adapter helpers (lib/data-model/adapters/)

    FileResponsibility
    _registry.tsloadSourceRegistry, catKey
    _dedupe.tsNatural-key dedupe before upsert
    _validate.tsAtom rows only (no x00 rollups)
    _factPrefetch.tsYearly/daily prefetch RPCs for drift tiers
    _factBulkUpsert.tsupsert_fact_yearly_batch
    _factDailyBulkUpsert.tsupsert_fact_daily_batch
    _ledger.tsIngest ledger / undo snapshots
    _writeStats.tsWrite classification stats
    _yearWindow.tsIngested year window aggregation
    _phaseEmit.tsYearly canonical_progress phase emitter
    _braskWebForms.tsBRASK HTTP/form transport
    _braskWebForms.constants.tsBRASK axis/URL constants
    brask-yearly-metrics.tsBRASK tier-1/2 equality helpers

    3. Ingestion: Server Action vs Route Handler

    • ingestBySourceId is invoked from app/api/admin/ingest/route.ts (service role, after()), not from random Server Actions.
    • /explore still has user-facing app/(main)/explore/actions.ts: triggerSliceIngest inserts fire_data.ingest_runs, then fetches same-origin POST /api/admin/ingest inside after() with the ingest key — it does not import ingestBySourceId directly.
    • Other "use server" modules (app/actions.ts, …) handle auth or non-ETL reads.

    Only app/api/admin/ingest/route.ts imports ingestBySourceId among app/api/*/route.ts handlers.


    Maintenance

    When you add a source adapter or change dispatch, update this file and pipeline-slices-idempotency-and-triggers.md so cross-links stay accurate.