Skip to content

epic(scanner): country-aware scanner & submission pipeline #920

@ericsocrat

Description

@ericsocrat

Epic: Country-Aware Scanner & Submission Pipeline

Product principle: Global capture, country-aware interpretation, routing, and review.
Scanning remains permissive. Submissions capture country context. Admin review surfaces mismatch signals. GS1 prefixes are hints, not truth.


Problem Statement

The scanner and submission pipeline currently operates in a country-blind fashion while the search/browse pipeline is correctly country-scoped. This inconsistency creates five concrete data-quality and moderation problems:

  1. Ambiguous scan results. api_record_scan() does WHERE ean = TRIM(p_ean) LIMIT 1 — no ORDER BY, no country filter. If the same EAN exists in PL and DE, the result is nondeterministic.

  2. Country-blind submissions. product_submissions has no country column. When a user in Germany submits a product, the admin reviewer has zero signal about which catalog it should enter.

  3. Global has_pending_submission check. The not-found screen checks globally for pending submissions. If a PL user submitted for EAN 590..., a DE user scanning the same EAN sees "already submitted" — even though the DE catalog still needs it.

  4. Admin review without country context. api_admin_get_submissions() returns submissions with zero country metadata. The admin cannot route submissions to the correct catalog.

  5. Scan history without context. scan_history records {ean, product_id, found} with no country context. Analytics cannot distinguish "scanned from DE region" vs "scanned from PL region."


Architecture Decision

Hybrid Model: Global capture + country-aware routing (Option 3 of 4 evaluated).

Model Verdict Rationale
Strict region lock ❌ Rejected Too restrictive. Blocks legitimate cross-border product discovery. Goes against user's intent.
Fully global flat catalog ❌ Rejected Destroys country isolation (same EAN can have different formulations). Fails at 3+ countries.
Hybrid: global capture + country-aware routing ✅ Chosen Minimal change, high value. Preserves permissive scanning while adding context for routing and review. Works to 10 countries.
Canonical product + country overlay ❌ Deferred Over-engineered for 2 countries. product_links table already provides this capability at a basic level. Revisit at 4+ countries.

Phased Implementation Plan

Phase 1 — Country Context Capture (no behavioral changes)

Phase 2 — Smart Lookup & Cross-Country Visibility

Phase 3 — Submission Quality & Future Foundation


Scenarios Matrix

# Scenario User sees Stored Admin sees Flags
1 Region=DE, product in DE Normal result card scan_country=DE, product_id=DE N/A None
2 Region=DE, product in PL only Result + "From Polish catalog" badge scan_country=DE, product_id=PL N/A None
3 Region=DE, product in both DE version (preferred) scan_country=DE, product_id=DE N/A None
4 Region=DE, product only in PL Result + "Polish catalog" badge scan_country=DE, product_id=PL N/A None
5 Region=DE, product not found Not-found + submit CTA (country=DE pre-filled) scan_country=DE, found=false suggested_country=DE, scan_country=DE GS1 mismatch if applicable
6 Imported product Same as 4 or 5 depending on catalog User's region flows through GS1 mismatch expected for imports Info only
7 Same EAN, different formulation Region-preferred match Region-preferred product_id "EAN exists in {other country}" Admin decides: new entry or link
8 Wrong country submission Form with country defaulted to region, editable Whatever user selected GS1 mismatch hint if applicable Admin can override
9 Admin reviews mismatch N/A N/A Visual warning badges for conflicts Approve/override/reject

Strategic Decisions

  1. Canonical product model: Defer until 4+ countries. product_links is sufficient for now.
  2. Minimum safe first implementation: Phase 1 issues only — add country columns + pass through pipeline. No behavioral changes.
  3. Country override in submit form: Yes — default to user's region, allow editing.
  4. Scan history country: Store user's region at scan time, not physical location.
  5. GS1 prefix trust level: Hint only. Never block or auto-assign based on GS1.
  6. has_pending_submission scope: Country-scope it in Phase 3 — currently blocking cross-country submissions incorrectly.
  7. Admin routing by country: Phase 2–3. For now, just show country context in the existing global queue.

Risks If We Do Nothing

  1. Growing DE catalog → more ambiguous scan matches. As DE reaches PL product count (~1,380), LIMIT 1 nondeterminism affects more users.
  2. Admin review errors. Without country context, admins will approve products into wrong catalogs.
  3. Blocked cross-country submissions. Global pending index prevents legitimate multi-country submissions for same EAN.
  4. Unusable scan analytics. Cannot distinguish scan-miss rates by country → cannot prioritize catalog gaps.
  5. Trust scoring false signals. _score_submission_quality awards points for EAN match against ANY country's product — inflates confidence for wrong-country submissions.

What to Defer

  • Physical scan geolocation (never needed — region preference is sufficient)
  • Canonical product graph / country overlay model (until 4+ countries)
  • Auto-routing submissions to country-specific admin queues (until admin team grows)
  • Cross-country product suggestion in not-found screen ("This product exists in PL — want to import it?" — nice but complex)
  • Multi-language product name resolution in scan results (already partially handled by resolve_language())

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions