Skip to content

feat(scanner): region-preferred product matching in api_record_scan (#926)#938

Merged
ericsocrat merged 1 commit intomainfrom
feat/926-region-preferred-scan-matching
Mar 17, 2026
Merged

feat(scanner): region-preferred product matching in api_record_scan (#926)#938
ericsocrat merged 1 commit intomainfrom
feat/926-region-preferred-scan-matching

Conversation

@ericsocrat
Copy link
Owner

Summary

Implements issue #926 — region-preferred product matching in api_record_scan.

When a barcode exists in multiple countries (e.g., both PL and DE), the function now prefers the product whose country matches the user's resolved scan_country. Deprecated products are excluded from lookup.

Changes

Migration: 20260321000200_region_preferred_scan_matching.sql

Three changes to api_record_scan:

  1. Deprecated exclusion: AND p.is_deprecated IS NOT TRUE in EAN lookup WHERE clause
  2. Region-preferred ordering: ORDER BY (p.country = v_scan_country) DESC, p.product_id — same-country products sort first, with deterministic tiebreak
  3. Cross-country flag: is_cross_country (boolean) added to found response — true when matched product's country differs from scan_country and scan_country is not NULL

Also fixes stale 3-param api_admin_get_submissions overload from #925 (DROP + re-COMMENT with qualified signature).

Bug fix: 20260321000100_admin_submissions_country_context.sql

Fixed COMMENT ON FUNCTION ambiguity (SQLSTATE 42725) — qualified with parameter types (text, integer, integer, text).

pgTAP tests: scanner_functions.test.sql

  • Plan: 72 → 80 (+8 new tests)
  • Section 15 added: "Region-preferred matching + is_cross_country (feat(scanner): region-preferred product matching in api_record_scan #926)"
    • Fixtures: dual-EAN product (PL + DE with same EAN), deprecated product
    • Tests: is_cross_country key exists, cross-country flag values, DE/PL preference with dual-EAN, cross-country fallback, deprecated exclusion
  • Pre-existing fixes: NULL user_id trigger crash in section 10, invalid session_replication_role in section 14

Docs: API_CONTRACTS.md

  • Added is_cross_country to found response schema
  • Added matching behaviour note (region preference, deprecated exclusion)

Acceptance Criteria (from #926)

  • api_record_scan returns same-region product when EAN exists in both PL and DE
  • is_cross_country boolean flag in found response
  • Deprecated products excluded from scan lookup
  • Deterministic tiebreak via product_id when no country preference
  • No breaking changes to existing response shape (additive only)

Verification

supabase db reset --local          → all 210 migrations applied ✓
supabase test db                   → 80/80 ran, 74 pass, 6 pre-existing failures
                                     (tests 53-57 submission quality, test 65 admin velocity)
                                     8/8 new section 15 tests PASS ✓
.\RUN_QA.ps1                      → 44/49 suites pass (5 pre-existing failures)
                                     Suite 17 (Contract) 33/33 PASS ✓
                                     Suite 19 (Country) 11/11 PASS ✓
                                     Suite 22 (Barcode) 9/9 PASS ✓
                                     Suite 27 (Scanner) 15/15 PASS ✓
                                     No new regressions ✓

File Impact

4 files changed, +274 / -7 lines

  • 1 new DB migration (154 lines)
  • 1 modified DB migration (1 line — COMMENT fix)
  • 1 modified pgTAP test file (+112 lines: 8 new tests + trigger/replication fixes)
  • 1 modified doc (API_CONTRACTS.md — is_cross_country added)

Closes #926

…926)

- Prefer same-country product when EAN exists in multiple countries
- Exclude deprecated products from scan lookup
- Add is_cross_country flag to found response
- Fix COMMENT ambiguity on api_admin_get_submissions overload (#925)
- Fix pre-existing pgTAP bugs: NULL user_id trigger crash, invalid session_replication_role
- 8 new pgTAP tests (plan 72→80): dual-EAN preference, cross-country flag, deprecated exclusion
Copilot AI review requested due to automatic review settings March 17, 2026 14:25
@vercel
Copy link

vercel bot commented Mar 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tryvit Ready Ready Preview, Comment Mar 17, 2026 2:26pm

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements smarter barcode scan lookup in the Supabase scanner RPC by preferring same-country matches when multiple products share an EAN, excluding deprecated products, and exposing cross-country context to clients.

Changes:

  • Update public.api_record_scan() to (a) prefer same-country matches, (b) exclude deprecated products, and (c) return is_cross_country.
  • Fix api_admin_get_submissions overload/comment ambiguity by dropping the stale 3-arg overload and qualifying the function signature in COMMENT ON.
  • Extend pgTAP coverage for cross-country behavior and document the updated response contract.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
supabase/tests/scanner_functions.test.sql Expands pgTAP coverage for is_cross_country, region-preferred matching, deprecated exclusion, and adjusts plan/replication-role usage.
supabase/migrations/20260321000200_region_preferred_scan_matching.sql Updates api_record_scan lookup/response, excludes deprecated products, adds is_cross_country, and removes stale api_admin_get_submissions overload.
supabase/migrations/20260321000100_admin_submissions_country_context.sql Qualifies the COMMENT ON FUNCTION signature to avoid overload ambiguity.
docs/API_CONTRACTS.md Documents region-preferred matching behavior and the new is_cross_country response key.

Comment on lines +57 to +63
-- Validate EAN format
IF p_ean IS NULL OR LENGTH(TRIM(p_ean)) NOT IN (8, 13) THEN
RETURN jsonb_build_object(
'api_version', '1.0',
'error', 'EAN must be 8 or 13 digits'
);
END IF;
Comment on lines +81 to +83
v_scan_country := p_scan_country;
IF v_scan_country IS NULL AND v_user_id IS NOT NULL THEN
SELECT up.country INTO v_scan_country
Comment on lines +92 to +103
-- When v_scan_country IS NULL, (p.country = NULL) evaluates to NULL (FALSE),
-- so ORDER BY degrades to product_id only — stable backward compat.
SELECT p.product_id, p.product_name, p.product_name_en, p.name_translations,
p.brand, p.category, p.country, p.unhealthiness_score, p.nutri_score_label
INTO v_product
FROM public.products p
WHERE p.ean = TRIM(p_ean)
AND p.is_deprecated IS NOT TRUE
ORDER BY (p.country = v_scan_country) DESC,
p.product_id
LIMIT 1;

Comment on lines +634 to +639
-- Cross-country fallback: user in XX scans PL-only EAN
SELECT is(
(public.api_record_scan('5901234123457', 'PL'))->>'found',
'true',
'cross-country fallback: PL user still finds XX-only product (#926)'
);
@ericsocrat ericsocrat merged commit 03a0e56 into main Mar 17, 2026
18 of 19 checks passed
@ericsocrat ericsocrat deleted the feat/926-region-preferred-scan-matching branch March 17, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(scanner): region-preferred product matching in api_record_scan

2 participants