The free-text 'channel' filter was dead: it exact-matched SummaryRow.Channel,
which is just the provider ('youtube'), because videos never stored their source
channel. Now they do.
- migration 014: videos.channel_title (nullable; existing rows backfill on the
next discovery pass, pasted videos immediately).
- discovery (NewVideos) + paste (VideoByID) populate channel_title; UpsertVideo
persists it, preserving an existing title when an update arrives empty.
- store.DistinctChannels lists a user's channels (RLS-scoped); SummaryRow carries
ChannelTitle via the shared projection.
- Filter: single Channel -> Channels []string, matching on ChannelTitle; the feed
renders a multi-select of DistinctChannels (hidden until channels exist).
- migrate tests: 014 reversibility + fixed the relative-step counts in the 010/011
up/down tests (014 shifted the topology).
TDD throughout: channel persist + distinct, adapter channel wiring, multi-channel
filter match, handler channel filter, migration up/down.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9 lines
583 B
SQL
9 lines
583 B
SQL
-- Store the source channel's title per video so the list can offer a real
|
|
-- channel filter (multi-select of the user's channels) instead of the dead
|
|
-- free-text field that only ever matched the provider string. Nullable: existing
|
|
-- rows backfill on the next discovery pass (UpsertVideo writes it); pasted videos
|
|
-- get it immediately from videos.list. No FK to a channels table at Stage 0 — the
|
|
-- title is a denormalised display/filter value, consistent with the existing
|
|
-- subscription_id-stays-NULL stance (data-model.md).
|
|
ALTER TABLE videos ADD COLUMN channel_title TEXT;
|