Recommendation Model [WIP]
Status: Planned. This spec is a work-in-progress, and the shipped API does not currently expose
GET /recommendations. The custom model architecture, scoring pipeline, training cycle, and embedding-based approach will be designed in a later phase. The interim ranking below describes the intended first shipped recommendation behavior.
Overview
Section titled “Overview”The recommendation model provides personalized ranking of events and gigs for each user. It operates independently from the LLM chatbot. The final model will be a purpose-built system trained on platform-specific signals.
Interim Ranking (Planned First Release)
Section titled “Interim Ranking (Planned First Release)”Until the custom model is designed, the GET /recommendations endpoint uses a weighted scoring model:
- Candidate selection: Events with status OPEN or IN_PROGRESS and startAt in the future.
- Dismiss exclusion: Events the user has dismissed are excluded before scoring.
- Scoring: Each candidate receives a score combining:
- Interest alignment (dominant weight): events whose category matches any stated user interest receive a large fixed bonus that cannot be overcome by popularity alone.
- Popularity (secondary, capped): log-normalized interaction count, capped so even very popular events cannot outrank an interest-matched one.
- Tiebreakers: Equal-score events are ordered by recency (sooner start first), then by stable id.
- Fallback: Users with no interests and no interactions receive popularity-then-recency ranking (
POPULARITY_FALLBACKmode).
This is a deterministic query-time computation — no model training, no vectors, no caching layer.
Input Signals (interim)
Section titled “Input Signals (interim)”| Signal | Source | Used in interim? |
|---|---|---|
| User interests | User.interests | Yes — category match boost |
| Interaction history | Interaction table | Partial — dismiss exclusion only |
| Event recency | Event.startAt | Yes |
| Event popularity | Aggregate interaction count | Yes |
| Category affinity | Frequency of interactions per category | No — deferred to custom model |
| Geographic proximity | User location vs. event lat/lng | No — deferred to custom model |
| Embeddings / semantic similarity | Event embeddings via pgvector | No — deferred to custom model |
| Collaborative filtering | User-event matrix | No — deferred to custom model |
Future Model Direction
Section titled “Future Model Direction”The custom model phase will evaluate:
- Embedding-based content scoring: Represent events as embeddings (via the AI module’s embedding task) and compute semantic similarity against user profile embeddings. Replaces manual feature vectors.
- Collaborative filtering: User-event interaction matrix with matrix factorization.
- Hybrid approach: Content-based as primary ranker, collaborative as boost signal.
- Training/update cycle: Nightly retraining for collaborative; real-time embedding updates for content.
- Caching: Per-user cache with TTL and invalidation on interaction/interest change.
These details will be spec’d when the model is designed.
Scenarios (interim ranking)
Section titled “Scenarios (interim ranking)”S-REC-MODEL-1: Interest-based boost
Section titled “S-REC-MODEL-1: Interest-based boost”GIVEN user A has interests ["music", "tech"]WHEN user A sends GET /recommendationsTHEN events with category "music" or "tech" appear higher in the listS-REC-MODEL-2: Popularity ranking
Section titled “S-REC-MODEL-2: Popularity ranking”GIVEN event E has 50 total interactions and event F has 5AND both match user A's interests equallyWHEN user A sends GET /recommendationsTHEN event E ranks higher than event FS-REC-MODEL-3: Recency ranking
Section titled “S-REC-MODEL-3: Recency ranking”GIVEN event A starts tomorrow and event B starts in 30 daysAND both have equal popularity and interest matchWHEN user A sends GET /recommendationsTHEN event A ranks higher than event BS-REC-MODEL-7: Profile alignment outranks high popularity
Section titled “S-REC-MODEL-7: Profile alignment outranks high popularity”GIVEN user A has interests ["music"]AND event E has category "music" and 0 interactionsAND event F has category "sports" and 100 interactionsWHEN user A sends GET /recommendationsTHEN event E ranks higher than event FS-REC-MODEL-4: Dismissed events excluded
Section titled “S-REC-MODEL-4: Dismissed events excluded”GIVEN user A dismissed event EWHEN user A sends GET /recommendationsTHEN event E does not appear in the resultsS-REC-MODEL-5: Past events excluded
Section titled “S-REC-MODEL-5: Past events excluded”GIVEN event E has startAt in the past and status COMPLETEDWHEN user A sends GET /recommendationsTHEN event E is not in the resultsS-REC-MODEL-6: No interests, no interactions — popularity fallback
Section titled “S-REC-MODEL-6: No interests, no interactions — popularity fallback”GIVEN user A has no interests and no interactionsWHEN user A sends GET /recommendationsTHEN events are sorted by popularity (interaction count) then recencyTest Cases
Section titled “Test Cases”See test-cases/recommendations/model.md for the full test case registry (TC-REC-MODEL-001 through TC-REC-MODEL-006).