Recommendation Model [WIP]
Status: This spec is a work-in-progress. The custom model architecture, scoring pipeline, training cycle, and embedding-based approach will be designed in a later phase. The current implementation uses a simple interim ranking (see below) to unblock the feed endpoint and UI.
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 (Current Phase)
Section titled “Interim Ranking (Current Phase)”Until the custom model is designed, GET /recommendations uses a simple heuristic ranking:
- Candidate selection: Events with status OPEN or IN_PROGRESS and startAt in the future.
- Interest matching: Events whose category matches any of the user’s interests are boosted.
- Popularity: Events with more total interactions rank higher.
- Recency: Events starting sooner rank higher.
- Dismiss penalty: Events the user has dismissed are excluded.
This is a deterministic query-time sort — no model training, no vectors, no caching layer. It is implemented as a database query with ORDER BY clauses.
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-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 recency