pollDueSources now collects genuinely-new tender IDs via an indexed
dedupKey pre-check (existing upsert doesn't report create-vs-update),
and calls TenderMatchingService.matchDelta(newTenderIds) once at the
end of the tick — the delta-only matching boundary (D-07). Changed/
re-seen rows are excluded, only genuinely new rows trigger matching.
TenderMatchingService registered as a provider in TendersModule and
injected into TenderIngestionService. Ingestion spec extended to
assert matchDelta receives only the new IDs, and is not called when
no new tenders were ingested this tick.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds Tender.cpvDivisions String[] (@@index Gin) derived at ingestion time
via cpv-catalog.ts's divisionOf() — replaces exact-match cpvCodes
comparison with a typesafe, GIN-indexable hasSome target (FILTER-03,
Pitfall 2). Backfill migration 20260721150000_tender_cpv_divisions_backfill
applied locally: 1612/1671 rows populated across all observed divisions
(741 rows carry division '45' — Bauarbeiten); idempotent (second run:
UPDATE 0, ADD COLUMN IF NOT EXISTS / CREATE INDEX IF NOT EXISTS both skip
cleanly). Applied via docker exec psql + `prisma migrate resolve
--applied` + `prisma generate` against the local dev DB only — no
Docker deploy on the test server.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- pollDueSources(): singleton doe-opendata config via findUnique (fixed slug,
not findFirst); day-cursor gate (nextDayToFetch) no-ops when nothing new
(Pitfall A); catch-up loop from lastIngestedDay+1 to today-1 with a polite
1.5s delay between successive day-fetches
- prisma.tender.upsert({ where: { dedupKey } }) — SCHEMA-02 change-detection
seam: identical notice does not duplicate, changed contentHash updates in
place
- pruneExpiredTenders(): marks active+past-deadline rows 'expired', deletes
expired rows older than 90 days, never touches deadlineAt=null rows (D-05)
- Plain PrismaService throughout — no tenant RLS extension on the global
Tender/TenderSourcePollConfig tables (D-03, T-10-09)
- Registered in TendersModule.providers