---
title: Subscribe to player betting markets for notifications
type: task
status: draft
description: >-
  Let a user follow a player's markets and be notified on a new market, a line move, an odds move,
  or an open/close change. Split out of GitHub issue 170: no subscription table, no movement
  detector, and no per-user delivery address exist today.
base_uri: user:task/league/subscribe-to-player-betting-markets.md
created_at: '2026-09-04T06:41:31.344Z'
entity_id: 5af300f7-1490-488e-b99a-d97fee905180
owner_identity_uri: █████████████████████████
priority: Low
public_read: true
relations:
  - relates [[user:task/league/redesign-selected-player-betting-markets-view.md]]
  - >-
    relates
    [[user:task/github/mistakia/league/170-enable-subscribing-to-player-betting-markets-for-notifications.md]]
  - follows [[█████████████████████████-████-██████-█████-████████]]
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-09-04T06:45:05.279Z'
visibility_analyzed_at: '2026-11-05T23:50:31.576Z'
---

# Subscribe to Player Betting Markets

## Overview

- Let a user follow a player's betting markets and receive a notification on a new market, a line move, an odds move, or an open/close status change — the four events named in GitHub issue 170.
- Impact: today a user has to reopen the selected-player Betting Markets tab and read it by eye to notice a line moved. Nothing in the system pushes a market change to a person.
- Ordering: independent of the tab redesign it was split out of. Shares the tab only as a plausible entry point for the subscribe control.

## Background

Split out of [[user:task/github/mistakia/league/170-enable-subscribing-to-player-betting-markets-for-notifications.md]] during the 2026-09-04 consolidation of the selected-player ███████████████ tasks. It was separated because it shares no code with the viz work: it is a subscription table, a movement detector, and a per-user delivery channel, none of which exist.

### What exists

- **The movement substrate exists and is unused.** `prop_market_selections_history` carries `selection_metric_line`, `odds_american`, `odds_decimal` and `observed_at` per `source_selection_id` — the line-movement and odds-movement series. `prop_markets_history` carries `is_open` and `is_live` per market observation — the status-change series.
- **No movement detection code exists anywhere.** A case-insensitive grep for line or odds movement across `libs-server/`, `jobs/`, `scripts/` and `api/` returns only Swagger prose at `api/routes/players.mjs:741` and `api/routes/markets.mjs:382`.
- **No subscription infrastructure exists.** `grep -c "subscri"` over `db/schema.postgres.sql` returns 0. There is no `alert`, `watch` or `follow` table.
- **`league_notifications` is not a user subscription.** It is a league-scoped dedupe ledger keyed `(lid, season_year, notification_type, event_timestamp)`, read through `libs-server/league-notifications.mjs`.
- **There is no per-user delivery address.** `libs-server/send-notifications.mjs` has exactly one path — `league.discord_webhook_url`, a league-level column. The `users` table carries `email` but no notification preference or push token. `libs-server/send-email.mjs` exists (Resend) but is reached only from auth and waitlist paths.
- **`users.watchlist`** is a free-text blob of player ids — the closest thing to a follow today, with no notification semantics and no market grain.
- **Closest structural template for a new per-user resource collection**: `api/routes/settings/api-keys.mjs`.

### Assumptions

- **The two history tables are append-only and complete enough to diff for movement.** UNCHECKED at this grain — the sibling task `redesign-prop-market-table-grain.md` measured them at 10.5 GB and is re-keying both, so measure after that lands rather than against today's shape.
- **Delivery channel is undecided.** Discord DM, email, and web push are all reachable in principle; none has a per-user address stored today. This is the first design question and it is an operator decision, not a technical one.

## Notes

- **Do not start this before the grain redesign settles.** `redesign-prop-market-table-grain.md` renames both history tables, moves `selection_metric_line` onto an observation row, and deletes `time_type`. A movement detector written against today's shape would be rewritten wholesale.
- The detector is the piece with real design risk: a naive diff over an append-only table at this volume fires on every re-post, and the taxonomy work has already shown books retire and re-post ladders under new market ids several times a day.

## Next step

Draft — no implementation plan yet. Write one with [[user:workflow/write/write-software-implementation-plan.md]] once the grain redesign has landed and the delivery channel is chosen.
