-- SCHEMA-03 (D-03/D-04) — TenderSource 1:n model + Tender.fingerprint. -- -- Two-step ordering (Pitfall 5, 13-RESEARCH.md): (1) create the table and -- add the additive Tender.fingerprint column BEFORE (2) backfilling -- TenderSource rows from the pre-existing ~2851 DÖE Tender rows, and only -- THEN activating the unique constraint. DÖE sourceNoticeIds are live-unique -- (0% NULL OCID) so the backfill insert itself will not violate the -- constraint, but the ordering is kept strict regardless. -- -- fingerprint backfill (Tender.fingerprint) is NOT done here in SQL — the -- umlaut/CPV-division normalization it needs lives in code -- (tender-fingerprint.ts). It is populated by the one-time TS script -- `backfill-tender-source.ts`, run once after this migration is applied. -- Step 1a: additive nullable column on Tender. ALTER TABLE "Tender" ADD COLUMN "fingerprint" TEXT; CREATE INDEX "Tender_fingerprint_idx" ON "Tender"("fingerprint"); -- Step 1b: TenderSource table. CREATE TABLE "TenderSource" ( "id" TEXT NOT NULL, "tenderId" TEXT NOT NULL, "sourcePortal" TEXT NOT NULL, "sourceNoticeId" TEXT NOT NULL, "ocid" TEXT, "sourceUrl" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "TenderSource_pkey" PRIMARY KEY ("id") ); CREATE INDEX "TenderSource_tenderId_idx" ON "TenderSource"("tenderId"); ALTER TABLE "TenderSource" ADD CONSTRAINT "TenderSource_tenderId_fkey" FOREIGN KEY ("tenderId") REFERENCES "Tender"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- Step 2: backfill — one TenderSource row per pre-existing Tender, from its -- current sourcePortal/sourceNoticeId/sourceUrl/ocid (D-05). INSERT INTO "TenderSource" (id, "tenderId", "sourcePortal", "sourceNoticeId", ocid, "sourceUrl", "createdAt") SELECT gen_random_uuid(), t.id, t."sourcePortal", t."sourceNoticeId", t.ocid, t."sourceUrl", now() FROM "Tender" t; -- Step 3: unique constraint, applied AFTER the backfill insert succeeds. CREATE UNIQUE INDEX "TenderSource_sourcePortal_sourceNoticeId_key" ON "TenderSource"("sourcePortal", "sourceNoticeId");