feat(vehicles): automatic Vinpin VIN-decode fallback (flag-gated, off by default)

When PL24/pcat/emex can't decode a Fiat VIN, decode it via the Vinpin ePER
web catalog (warm-session Playwright worker, single seat, BullMQ concurrency 1),
cache the exact vehicle in vinpin_decodes, match it to PL24's existing
catalog_vehicle for that model, and serve the parts from there. Vinpin = decode
oracle only; PL24 already holds the parts (e.g. Egea/Linea/Doblo).

Strictly gated behind VINPIN_ENABLED (default false) + a Fiat-only brand
allowlist: with the flag off, decodeVin behaviour is byte-identical and the
queue is never touched (covered by tests). Coordinates/selectors in
vinpin.constants.ts are marked TUNE-AGAINST-LIVE-PAID-SEAT.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 07:36:39 +03:00
parent 3096d35113
commit dfe90fb968
22 changed files with 1310 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
-- Vinpin ePER decode-oracle cache (feature-flagged: VINPIN_ENABLED).
-- One row per VIN. The vinpin-decode BullMQ job drives the Vinpin ePER web
-- catalog for Fiat VINs the normal chain (PL24/pcat/emex) can't identify, then
-- matches the decoded model to an EXISTING PL24 catalog_vehicle. Vinpin is ONLY
-- a decode oracle — parts are always served from PL24's existing catalog.
-- status: 'pending' | 'decoded' | 'not_found' | 'failed'.
CREATE TABLE IF NOT EXISTS "vinpin_decodes" (
"vin" text PRIMARY KEY NOT NULL,
"status" text DEFAULT 'pending' NOT NULL,
"brand_name" text,
"model" text,
"sincom" text,
"trim" text,
"model_year" text,
"engine" text,
"catalog_vehicle_id" uuid,
"raw" jsonb,
"attempts" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone,
"decoded_at" timestamp with time zone
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "vinpin_decodes" ADD CONSTRAINT "vinpin_decodes_catalog_vehicle_id_catalog_vehicles_id_fk" FOREIGN KEY ("catalog_vehicle_id") REFERENCES "public"."catalog_vehicles"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "vinpin_decodes_status_idx" ON "vinpin_decodes" USING btree ("status");