feat(store): persist summary actions (watch/skip/save) — Stage-0 metric
The summary_actions table records the maintainer's act on a summary, the
column that makes the Stage-0 headline test ("acts on >=1 summary") queryable
(ui-spec.md §5, ADR-011). This is the gate lanes B/C build on.
- Migration 002: summary_actions (id, user_id, video_id TEXT, action, acted_at)
with a CHECK on action IN ('watched','skipped','saved') and a UNIQUE
(user_id, video_id, action). Per-user isolation: every row carries user_id.
- New actions.go: SetAction (idempotent, atomic watched<->skipped mutual
exclusion in one tx; saved independent), ClearAction, ActionsFor for the list
view, plus Go-side action validation.
- reads.go: additive SummaryRow.Actions, populated by composing ActionsFor
(Go-side, not a SQL join — summaries.video_id is UUID, actions.video_id TEXT).
- embedded-postgres tests: set/clear, mutual exclusion, saved coexistence,
idempotency, invalid rejection, user scoping, read-view surfacing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
-- summary_actions records the maintainer's act on a summary (watch/skip/save) —
|
||||
-- the column that makes the Stage-0 headline metric ("acts on >=1 summary")
|
||||
-- queryable (ui-spec.md §5, ADR-011). Per-user isolation: every row carries
|
||||
-- user_id (dormant authz at Stage 0, single user). video_id is TEXT and not
|
||||
-- FK-constrained, mirroring summaries' standalone (user_id, video_id) key.
|
||||
|
||||
CREATE TABLE summary_actions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL,
|
||||
video_id TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
acted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT summary_actions_action_check
|
||||
CHECK (action IN ('watched', 'skipped', 'saved')),
|
||||
CONSTRAINT summary_actions_user_video_action_unique
|
||||
UNIQUE (user_id, video_id, action)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_summary_actions_user_video ON summary_actions(user_id, video_id);
|
||||
Reference in New Issue
Block a user