Skip to content

Build the For You feed

The For You surface is the first thing a returning user sees. It’s a stack of rails (horizontal rows). Each rail points at a collection (a list of series). A collection is either manual (a curator hand-picked series) or rule-based (a query, e.g. “top romance this week”).

  • Rail: one row on the For You screen. Has a sort order (0, 1, 2, …), a surface (for_you or discover), and points at exactly one collection.
  • Collection: a named, ordered list of series. Reusable across surfaces.
  • Collection items: the join table (collection_id, series_id, sort) for manual collections.
  • Rule: the JSON query for rule-based collections ({genre, sort, window, limit, market}).

Curation → For You home: drag-order the rails, add/remove rails, edit each rail’s collection inline.

Curation → Collections: manage collections independently. A collection can power multiple rails.

  1. Curation → Collections → New collection
  2. Type: Manual.
  3. Fill:
    • slug (immutable)
    • title_i18n: EN/AR/ID titles (visible on the rail header on mobile)
    • Explanation string: required. See below.
  4. Add series: search picker; drag to reorder.
  5. Save.
  1. Curation → Collections → New collection
  2. Type: Rule-based.
  3. Fill the rule JSON:
{
"genre": "romance",
"trope": null,
"sort": "top_this_week",
"market": "PH",
"limit": 20,
"window_days": 7
}

Supported sort values: top_this_week, newest, most_unlocks, most_saves, trending, editor_score.

Rules are recomputed by the feed composer on read (with a short Redis cache), so the rail stays fresh without manual intervention.

Curation → For You home → Add rail → pick the collection, set sort, save. Existing rails can be reordered by dragging.

Good explanations:

  • “Because you love Enemies to Lovers”
  • “Top romance in the Philippines this week”
  • “New episodes just dropped”
  • “Popular with viewers in Egypt”

Bad explanations:

  • “Recommended for you” (useless: that’s the rail’s whole point)
  • “Series 123” (exposes internals)
  • (empty)

The explanation renders on the mobile app just under the rail title, small caption text.

Every collection edit page has a live mobile preview iframe: reuses the mobile app’s web export, showing exactly what a user in that market would see.

SurfaceMax railsNotes
for_you12Above ~12 the mobile app truncates for scroll performance.
discoverUnlimitedCategory page: long-scroll expected.

The mobile app calls GET /v1/feed?market=…&lang=…. That endpoint asks the feed composer for the current rails, resolves each collection to a list of series, and returns the full payload.

Fallback: if the composer returns zero rails (e.g. curation is empty in a new market), the API falls back to a hardcoded “newest published” collection so the app never renders empty. This is a safety net: you should still populate curation for every launch market.

  • A collection can power multiple rails. Deleting a collection with rails still pointing at it is refused: unlink the rails first.
  • market filter on rules: if you leave market null, the rule runs across all launch markets. Explicit is safer.
  • newest sort windows are 7 days by default: a series stops appearing after that. Set window_days explicitly if you want a different feel.
  • Editorial hero is separate: see Preview-reel hero ordering.
ActionEndpoint
List collectionsGET /v1/admin/collections
CRUD collectionPOST/PUT/DELETE /v1/admin/collections[/:id]
Reorder itemsPUT /v1/admin/collections/:id/items
List railsGET /v1/admin/rails
CRUD railPOST/PUT/DELETE /v1/admin/rails[/:id]
Reorder railsPUT /v1/admin/rails/reorder

Full details in API: Curation.