Skip to content

feat: in-app media recommendations (recommend a movie to a friend) #33

Description

@miicolas

Problem Statement

When I find a movie or show I think a friend would love, I have no way to tell them inside Seen. I have to leave the app and message them elsewhere, and the recommendation lives outside the product — my friend can't act on it in one tap.

Solution

From a media detail page I can recommend the title to people I follow, optionally with a short message. They receive a push notification and find the recommendation in a dedicated "Received" inbox, where they can read who sent it (and their note) and jump straight to the title.

User Stories

  1. As a viewer on a media detail page, I want a recommend button in the header, so that I can send the title to friends without cluttering the main action bar.
  2. As a sender, I want to pick from the people I follow, so that I can recommend to anyone I follow (no mutual-follow requirement).
  3. As a sender, I want to select multiple friends at once with a running count, so that I can recommend to several people in one action.
  4. As a sender, I want to attach an optional short message, so that I can say why I'm recommending it.
  5. As a sender, I want clear confirmation that the recommendation was sent, so that I trust it went through.
  6. As a recipient, I want a push notification when someone recommends a title to me, so that I find out promptly.
  7. As a recipient, I want tapping that notification to deep-link me to my "Received" inbox, so that I land in the right place.
  8. As a recipient, I want a dedicated "Received" inbox listing recommendations sent to me, so that I never lose one even if I miss the notification.
  9. As a recipient, I want each inbox entry to show who sent it, the title, and their message, so that I have full context.
  10. As a recipient, I want to tap an inbox entry and open the title's media detail page, so that I can decide whether to watch it.
  11. As a recipient, I want a bell/badge with an unread count in my profile header, so that I notice new recommendations.
  12. As a recipient, I want recommendations to be marked read once I view them, so that the unread badge stays accurate.
  13. As a user, I want recommendations to work for both movies and TV shows, so that the feature is consistent.

Implementation Decisions

  • New recommendations domain across DB, API, and mobile, modeled on the existing watch-sessions feature (its friend picker, invite mutation, push dispatch, and deep-link handling are the closest prior art and should be reused).
  • Schema: new media_recommendations table (its own schema folder following the per-domain convention) with: id, senderId, recipientId (→ user), tmdbId, mediaType, a display snapshot (title, poster path), optional message, readAt (nullable), createdAt. Generate + apply via the root db scripts.
  • API contract (new module):
    • POST /recommendations — body { tmdbId, mediaType, recipientIds[], message? }; inserts one row per recipient and dispatches a push to each.
    • GET /recommendations/received — the recipient's inbox list.
    • POST /recommendations/:id/read — mark one as read.
    • GET /recommendations/recommendable-friends — candidate recipients = people the current user follows (reuse the existing get-following query; one-directional, not mutual).
  • Push: reuse the existing Expo push library and the watch-sessions notify pattern; introduce a new push type (e.g. recommendation.received). Extend the mobile deep-link decoder to route that type to the inbox route.
  • Mobile:
    • New recommendations service (eden handlers: send, list-received, mark-read, list-recommendable-friends) and React Query hooks (send + friend list, received list) with a dedicated query-key factory.
    • Send sheet (form-sheet presentation) reusing the watch-invite multi-select friend list UI, plus an optional message field. Opened from the media-detail header button.
    • Inbox screen ("Received") modeled on the existing watch-invitations screen; opens its items to the corresponding media detail; marks entries read on view.
    • Unread bell + badge in the profile header.
    • New i18n keys (FR + EN) for button labels, inbox title, and push copy.
  • Follow naming (this is a "media recommendation", distinct from TMDB recommendations), expo-ui-swiftui, and haptics skills.

Testing Decisions

  • The repo has no automated test framework wired up (per AGENTS.md).
  • Seams:
    • Highest integration seams: the four new recommendations API routes (HTTP contracts) — especially POST /recommendations (fan-out to N recipients + push) and GET /recommendations/received.
    • Unit-level seam: the recommendable-friends query (returns people the user follows) and the inbox serializer (row → inbox DTO).
  • Good tests assert external behavior: sending to N recipients creates N received rows and N push messages; the inbox returns sender + title + message; marking read flips unread state — not the push transport internals.
  • Prior art: the watch-sessions module (invite-to-session mutation, list-invitable-friends query, notify dispatch) is the direct template.
  • Until a harness exists, verify manually with two accounts: send a recommendation to several followed users with a message → 200 and rows created; on a recipient device confirm the push, tap → "Received" inbox, see sender/title/message, badge decrements on read, tapping the title opens its media detail.

Out of Scope

  • The OS share sheet path (sharing via Messages/WhatsApp with a deep link) — explicitly deprioritized in favor of in-app recommendations.
  • Recommending to users you do not follow / open user search as recipients.
  • Threaded replies or chat on a recommendation.
  • Recommendations surfaced inside the existing social activity feed (the dedicated inbox is the chosen surface).
  • Recommending individual episodes (movie/TV only for now).

Further Notes

The heaviest feature (new DB table + API module + two screens + push wiring). Depends on the existing social graph and push infrastructure, both of which already exist. Part of the "richer media detail page" epic. Consider a whats-new announcement when shipped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentPRD ready for an agent to implement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions