Skip to content

Optimization of Location Processing and Data Stability#279

Merged
driedpampas merged 6 commits into
mainfrom
fix/store-matching-bug
May 19, 2026
Merged

Optimization of Location Processing and Data Stability#279
driedpampas merged 6 commits into
mainfrom
fix/store-matching-bug

Conversation

@bmbianca
Copy link
Copy Markdown
Contributor

@bmbianca bmbianca commented May 18, 2026

Fixed issues with telemetry-imported stores disappearing and improved overall location accuracy.
Data Stability: Refactored LocationProcessorWorker to use atomic UPSERT operations instead of a DELETE-and-REINSERT cycle. This prevents the transient "0 stores found" state and ensures that manually populated test data is preserved alongside telemetry updates.
Accuracy Thresholds: Increased the GPS accuracy threshold from 12m to 30m and adjusted the DBSCAN clustering radius (eps) to 30m. These changes allow the system to successfully ingest and cluster mobile telemetry data which typically has a higher error margin than indoor WiFi-RTT signals.
Low-Density Clustering: Synchronized clustering requirements (minpoints := 3) across background and on-demand jobs, ensuring that items with few telemetry pings are still correctly mapped to store shelves.
Test Alignment: Updated theLocationProcessorWorkerTest suite to reflect the architectural shift to UPSERT semantics, ensuring full CI/CD compatibility and SonarQube quality gate compliance.

Summary by CodeRabbit

  • New Features

    • Store matching accepts item names as well as item IDs.
    • Store match responses now include a per-store match percentage in a compact payload.
  • Improvements

    • More robust item matching across catalog links, external IDs, and normalized name comparisons.
    • Inventory location processing now upserts data and uses adjusted accuracy/clustering thresholds for more stable location results.
  • Tests

    • Expanded tests covering mixed ID/name searches and updated matching expectations.

Review Change Stack

@bmbianca bmbianca requested a review from a team as a code owner May 18, 2026 18:24
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

📝 Walkthrough

Walkthrough

This PR adds name-based store matching with a compact StoreMatchResponse API, expands matching to use catalog and external IDs across routing and inventory lookups, propagates catalogId through item services/DTOs, and adjusts location clustering to use UPSERT and relaxed DBSCAN/accuracy thresholds.

Changes

Multi-Name Store Matching Flow

Layer / File(s) Summary
API request/response types
src/main/java/com/p2ps/controller/StoreMatchResponse.java, src/main/java/com/p2ps/controller/StoreMatchRequest.java
Adds StoreMatchResponse record and StoreMatchRequest.itemNames to accept name-based lookups.
StoreMatchingEngine: name resolution & CTE SQL
src/main/java/com/p2ps/service/StoreMatchingEngine.java
New overload accepts item names, resolves routable IDs from names, rewrites matching SQL to use requested_items/matched_inventory CTEs, and counts COUNT(DISTINCT mi.requested_item_id).
Inventory lookup native query
src/main/java/com/p2ps/repository/StoreInventoryMapRepository.java
Adds findRoutableByStoreIdAndItemId native query with multi-strategy matching (item id, catalog id, external id, normalized names, catalog product names/LIKE), ordered by priority and confidence, limited to 1.
Controller integration & mapping
src/main/java/com/p2ps/controller/RoutingController.java
lookupStores computes distinct requested totals from IDs/names, calls findOptimalStores(itemIds,itemNames), maps results to StoreMatchResponse with capped matchPercentage, and updates getItemLocation to use routable lookup.
Controller & engine tests
src/test/java/com/p2ps/controller/*, src/test/java/com/p2ps/service/StoreMatchingEngineTest.java
Updates tests to mock new method signatures, assert matchPercentage and compact payload fields, add name-resolution tests, and tighten SQL assertions for the CTE-based query.

Catalog Linking and DTO Propagation

Layer / File(s) Summary
ItemService: catalog resolution & helpers
src/main/java/com/p2ps/lists/service/ItemService.java
Passes user to AI validation flow, adds ensureResolvableProductLink to set catalogItem and attach routable external id, trims names on update, re-resolves catalog matches on updates/syncs, and refactors brand/name matching logic.
DTO field and ShoppingList import propagation
src/main/java/com/p2ps/lists/dto/ItemDTO.java, src/main/java/com/p2ps/lists/service/ShoppingListService.java
Adds catalogId to ItemDTO, populates it when catalogItem exists, and copies catalogItem/externalItemId during shopping-list imports.
RoutingService: include catalog_id in SQL
src/main/java/com/p2ps/service/RoutingService.java
queryInventoryMap and queryRawPingsCentroid include catalog_id in requested_items and add OR branches to match located_item via catalog-based name checks.
Catalog-related tests
src/test/java/com/p2ps/lists/service/ItemServiceTest.java
Updates test expectations to assert items link to matched catalog products and adjusts mocks/captor assertions accordingly.

Location Clustering Parameter Updates

Layer / File(s) Summary
DBSCAN tuning and UPSERT
src/main/java/com/p2ps/service/LocationProcessorWorker.java
Increases accuracy cutoff to accuracy_m < 30.0, sets DBSCAN eps := 30.0 and minpoints := 3, and changes scheduled insert into store_inventory_map to ON CONFLICT (store_id, item_id) DO UPDATE (UPSERT).
Clustering tests updates
src/test/java/com/p2ps/service/LocationProcessorWorkerTest.java
Adjusts tests for INSERT-only behavior, reduces expected jdbcTemplate.update calls, and adds startup DB-detection retry/failure tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • P2P-Shopping/server#232: Prior work on store-matching API and engine wiring that this change extends with name resolution and response wrapping.
  • P2P-Shopping/server#166: Earlier clustering changes to LocationProcessorWorker; related to the DBSCAN/accuracy updates here.
  • P2P-Shopping/server#192: Introduced base store-matching logic/record that this PR refactors into CTEs and adds name-resolution.

Suggested reviewers

  • driedpampas
  • Bianca-Alexandru
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title is vague and does not clearly reflect the primary changes in the changeset. While it mentions 'Location Processing', most code changes involve store matching, routing, item resolution, and product catalog integration—only a small portion relates directly to location processing optimization. Consider a more specific title that captures the main changes, such as 'Add store matching by item names and refactor location processing' or 'Enhance routing with multi-strategy item matching and catalog resolution'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/store-matching-bug

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/p2ps/lists/service/ItemService.java (1)

231-243: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing-ID AI results can silently drop items.

On Line 241, when AI returns an item without id, trackingMap.get(dto.getId()) is null and the item is skipped. If all DTOs lose IDs, Line 202 saves an empty list and user items disappear. Treat null IDs as hallucination and trigger the same fallback as unknown IDs.

Suggested fix
 for (ItemDTO dto : validatedDtos) {
-    // 💡 FIX 1: Protecție împotriva halucinațiilor de ID
-    if (dto.getId() != null && !trackingMap.containsKey(dto.getId())) {
+    if (dto.getId() == null || !trackingMap.containsKey(dto.getId())) {
         logger.error("AI hallucinated an unknown ID: {}. Triggering full fallback.", dto.getId());
-        return new ArrayList<>(trackingMap.values()); // Fallback total la lista originală!
+        return new ArrayList<>(trackingMap.values());
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/p2ps/lists/service/ItemService.java` around lines 231 -
243, In applyAiValidationResults, treat DTOs with null IDs as hallucinations the
same as unknown IDs: before calling trackingMap.get(dto.getId()) check if
dto.getId() == null || !trackingMap.containsKey(dto.getId()), log the
hallucination (using logger.error with the DTO or explicit "null id") and return
a full fallback new ArrayList<>(trackingMap.values()) so items aren't silently
dropped; update the existing if block that currently only checks containsKey to
include the null-ID check and ensure subsequent code (applyRefinedAiUpdates,
itemsToSave population) only runs when originalItem != null.
🧹 Nitpick comments (1)
src/test/java/com/p2ps/controller/RoutingControllerTest.java (1)

111-150: ⚡ Quick win

Add a lookup test for itemNames-only requests.

Current lookup tests only validate ID-based inputs. Add one case with itemIds == null and non-blank itemNames to lock down request counting and response matchPercentage behavior for the new API path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/com/p2ps/controller/RoutingControllerTest.java` around lines
111 - 150, Add a new unit test in RoutingControllerTest (e.g.,
lookupStores_shouldHandleItemNamesOnly) that builds a StoreMatchRequest with
itemIds set to null and itemNames set to a non-empty list, then mock
StoreMatchingEngine.findOptimalStores to expect (47.15, 27.58, 5000, null,
request.getItemNames()) and return a sample matches list; call
controller.lookupStores(request) and assert the ResponseEntity status is 200,
body is not null, list size matches the mock, the first
StoreMatchResponse.storeId matches the first mock result and its matchPercentage
equals the expected computed value, and verify any request counting/metrics
behavior if present. Ensure you reference controller.lookupStores,
StoreMatchRequest, StoreMatchingEngine.findOptimalStores, StoreMatchResponse
when adding the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/p2ps/lists/service/ItemService.java`:
- Around line 434-435: Normalize the item's name before calling
resolveCatalogMatch so trailing/leading spaces don't prevent finding an existing
catalog link: retrieve and trim the name from item (use a null-safe/trim
operation), pass that normalized name into resolveCatalogMatch(itemName,
item.getBrand(), item.getShoppingList().getUser()) instead of item.getName(),
then continue to call attachRoutableExternalItemId(item) as before.

In `@src/main/java/com/p2ps/repository/StoreInventoryMapRepository.java`:
- Around line 55-56: In StoreInventoryMapRepository, the CASE in the ORDER BY
uses WHEN requested_item.external_item_id IS NOT NULL AND
located_item.external_item_id = requested_item.external_item_id THEN 2 which can
still prioritize empty strings even though the WHERE filter enforces
external_item_id <> ''; update that CASE to mirror the non-empty guard used in
filtering by adding checks like requested_item.external_item_id <> '' and
located_item.external_item_id <> '' (e.g., WHEN requested_item.external_item_id
IS NOT NULL AND requested_item.external_item_id <> '' AND
located_item.external_item_id = requested_item.external_item_id AND
located_item.external_item_id <> '' THEN 2) so the ordering prefers non-empty
external_id matches consistent with the WHERE clause.

In `@src/main/java/com/p2ps/service/StoreMatchingEngine.java`:
- Around line 69-70: The current COALESCE(ri.id, sim.item_id) fallback causes
one logical requested item to be counted multiple times when a store maps that
request to several inventory variants; instead, add a dedicated "requested_key"
CTE (or column) built from the original input identifier(s) (IDs, catalog/name)
and use that key wherever you produce requested_item_id and compute
matched_items; replace COALESCE(ri.id, sim.item_id) with the canonical
requested_key reference in the SELECTs and change aggregations (e.g.,
matched_items) to COUNT(DISTINCT requested_key) so counts are per logical
request not per inventory row (apply same change to the other occurrence around
the matched_items aggregation).

---

Outside diff comments:
In `@src/main/java/com/p2ps/lists/service/ItemService.java`:
- Around line 231-243: In applyAiValidationResults, treat DTOs with null IDs as
hallucinations the same as unknown IDs: before calling
trackingMap.get(dto.getId()) check if dto.getId() == null ||
!trackingMap.containsKey(dto.getId()), log the hallucination (using logger.error
with the DTO or explicit "null id") and return a full fallback new
ArrayList<>(trackingMap.values()) so items aren't silently dropped; update the
existing if block that currently only checks containsKey to include the null-ID
check and ensure subsequent code (applyRefinedAiUpdates, itemsToSave population)
only runs when originalItem != null.

---

Nitpick comments:
In `@src/test/java/com/p2ps/controller/RoutingControllerTest.java`:
- Around line 111-150: Add a new unit test in RoutingControllerTest (e.g.,
lookupStores_shouldHandleItemNamesOnly) that builds a StoreMatchRequest with
itemIds set to null and itemNames set to a non-empty list, then mock
StoreMatchingEngine.findOptimalStores to expect (47.15, 27.58, 5000, null,
request.getItemNames()) and return a sample matches list; call
controller.lookupStores(request) and assert the ResponseEntity status is 200,
body is not null, list size matches the mock, the first
StoreMatchResponse.storeId matches the first mock result and its matchPercentage
equals the expected computed value, and verify any request counting/metrics
behavior if present. Ensure you reference controller.lookupStores,
StoreMatchRequest, StoreMatchingEngine.findOptimalStores, StoreMatchResponse
when adding the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4a5d02bb-94d7-4b57-a098-3f6180475fc0

📥 Commits

Reviewing files that changed from the base of the PR and between af1ad63 and 73e240b.

📒 Files selected for processing (15)
  • src/main/java/com/p2ps/controller/RoutingController.java
  • src/main/java/com/p2ps/controller/StoreMatchRequest.java
  • src/main/java/com/p2ps/controller/StoreMatchResponse.java
  • src/main/java/com/p2ps/lists/dto/ItemDTO.java
  • src/main/java/com/p2ps/lists/service/ItemService.java
  • src/main/java/com/p2ps/lists/service/ShoppingListService.java
  • src/main/java/com/p2ps/repository/StoreInventoryMapRepository.java
  • src/main/java/com/p2ps/service/LocationProcessorWorker.java
  • src/main/java/com/p2ps/service/RoutingService.java
  • src/main/java/com/p2ps/service/StoreMatchingEngine.java
  • src/test/java/com/p2ps/controller/RoutingControllerTest.java
  • src/test/java/com/p2ps/controller/RoutingControllerWebMvcTest.java
  • src/test/java/com/p2ps/lists/service/ItemServiceTest.java
  • src/test/java/com/p2ps/service/LocationProcessorWorkerTest.java
  • src/test/java/com/p2ps/service/StoreMatchingEngineTest.java

Comment thread src/main/java/com/p2ps/lists/service/ItemService.java
Comment thread src/main/java/com/p2ps/repository/StoreInventoryMapRepository.java
Comment thread src/main/java/com/p2ps/service/StoreMatchingEngine.java
bmbianca and others added 4 commits May 18, 2026 21:47
# Conflicts:
#	src/main/java/com/p2ps/lists/dto/ItemDTO.java
#	src/main/java/com/p2ps/lists/service/ItemService.java
#	src/test/java/com/p2ps/lists/service/ItemServiceTest.java
coderabbitai[bot]

This comment was marked as abuse.

@sonarqubecloud
Copy link
Copy Markdown

@driedpampas driedpampas merged commit 361a849 into main May 19, 2026
4 checks passed
@driedpampas driedpampas deleted the fix/store-matching-bug branch May 19, 2026 16:00
@coderabbitai coderabbitai Bot mentioned this pull request Jun 2, 2026
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.

2 participants