Skip to content

Move recommendation algorithm into the application layer - #90

Merged
ghidalgo3 merged 1 commit into
mainfrom
recommendations-app-algorithm
Jun 15, 2026
Merged

ghidalgo3 merged 1 commit into
mainfrom
recommendations-app-algorithm

Conversation

@ghidalgo3

Copy link
Copy Markdown
Owner

Follow-up to #89.

Summary

Relocates the recipe recommendation algorithm from a single PostgreSQL function into the C# application, and adjusts the algorithm: the ownership signal is gone and a recipe must share at least 2 ingredients with the source to be recommended.

Why: the database is great at indexes and set-membership lookups, but the recommendation policy (scoring, weighting, thresholds, ranking) is easier to read, unit-test, and evolve in application code without a migration. The DB now exposes primitives; the app composes them.

Changes

Database — new migration 018_recommendation_primitives.sql:

  • Drops cooktime.recommend_recipes.
  • Adds four data-only primitives: get_candidate_ingredient_sets, get_user_favorite_recipe_ids, get_user_last_cooked, get_recipe_summaries.

Application — new RecommendationService:

  • Owns the algorithm. Pure static ScoreCandidates(...) does Jaccard similarity, the >=2-overlap gate, weighting, and ranking with no DB access (directly unit-testable).
  • CookTimeDB drops GetRecipeRecommendationsAsync, gains the four primitive fetch methods.
  • Endpoint resolves RecommendationService; the service performs the existence check (null -> 404).

Algorithm changes

  • Ownership signal removed entirely.
  • A recipe must share >=2 ingredients with the source to appear at all; favorite/novelty only re-rank within that set.
  • Weights renormalized to sum to 1.0: ingredient similarity 0.70, favorite 0.18, novelty 0.12.

Contract + frontend — ownedByUser / "Your recipe" removed from the DTO, the TS type, and the admin score breakdown.

Docs — blog post updated to describe the app-side algorithm, the overlap gate, and new weights.

Tests

  • scripts/test -> 47/47 pass (43 existing + 4 new pure unit tests in TestRecommendationService).
  • Rewrote the two recommendation integration tests for the new weights and gate.
  • scripts/test --lint -> 0 errors.

Test plan

  • On a recipe with neighbors sharing >=2 ingredients, recommendations appear; recipes with only 1 shared ingredient do not.
  • Signed in as Administrator, the score breakdown rows sum to the displayed score and there is no "Your recipe" row.
  • Anonymous users still get similarity-only recommendations.

🤖 Generated with Claude Code

The recommendation algorithm previously lived entirely in a single
PostgreSQL function. This moves scoring, the overlap gate, weighting, and
ranking into a new C# RecommendationService, leaving the database to
expose only data primitives (candidate ingredient sets, favorites, cook
dates, summaries) via migration 018. The pure ScoreCandidates method has
no DB dependency, so the policy is directly unit-testable.

Also adjusts the algorithm itself:
- Remove the ownership signal entirely.
- Require >=2 shared ingredients before a recipe is recommended (a hard
  gate for everyone; favorite/novelty only re-rank within that set).
- Renormalize weights to sum to 1.0: similarity 0.70, favorite 0.18,
  novelty 0.12.

Drops ownedByUser from the DTO, TS type, and admin score breakdown.
Adds pure unit tests for the scoring policy and updates the integration
tests for the new weights and gate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ghidalgo3
ghidalgo3 merged commit 27a007e into main Jun 15, 2026
3 checks passed
@ghidalgo3
ghidalgo3 deleted the recommendations-app-algorithm branch June 15, 2026 02:07
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.

1 participant