feat(store): shared, video-keyed transcript persistence (ADR-021)
Reshape the dead per-user transcripts table (PK videos.id, user_id, RLS-FORCEd — never read or written by app code) into the shared public caption store ADR-021 specifies: keyed by (provider, provider_video_id), no user_id, NOT RLS-scoped. Migration 015 (reversible). Add ports.TranscriptStore + Store.GetTranscript/SaveTranscript via the raw pool (no withUser): public content, shared across users by construction. SaveTranscript persists only terminal outcomes (captions/none) and refuses SourceRateLimited so a transient 429 can never be stored as a false permanent absence (ADR-014). Flip the isolation proof: transcripts leaves the RLS-scoped set; TestTranscriptsTableIsSharedNotRLS asserts it is the SINGLE non-RLS surface (writable/readable with no user scope, no user_id column, RLS off on it alone, still on every user-owned table) — the proof the public-content classification was applied exactly here and leaked nowhere. appPool made idempotent so two tests can build it. Adjust the 010/011/014 up-down migration tests for the new HEAD. account.go: user deletion no longer strips shared transcripts. Reconcile data-model.md + CLAUDE.md. Wiring the engine to read-stored-first is the next commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,13 @@ import (
|
||||
// DeleteUser permanently removes a user and all of their data. It runs through
|
||||
// withUser so RLS confines every statement to the calling user's own rows.
|
||||
//
|
||||
// Deleting the users row cascades (ON DELETE CASCADE) to videos, transcripts,
|
||||
// summaries (→ sink_deliveries), video_connections, and the user_identities map
|
||||
// — referential-integrity cascades bypass RLS, so a user's child rows are removed
|
||||
// even though the deleting connection is scoped. summary_actions and login_events
|
||||
// Deleting the users row cascades (ON DELETE CASCADE) to videos, summaries
|
||||
// (→ sink_deliveries), video_connections, and the user_identities map —
|
||||
// referential-integrity cascades bypass RLS, so a user's child rows are removed
|
||||
// even though the deleting connection is scoped. Transcripts are NOT removed:
|
||||
// since ADR-021 they are shared public content keyed by (provider,
|
||||
// provider_video_id) with no user_id, so another user may still reference the
|
||||
// same row — a user deletion must not strip shared caption content. summary_actions and login_events
|
||||
// are the exceptions: each carries a user_id but has NO foreign key to users
|
||||
// (migrations 002 and 010), so the cascade does not reach them; they are deleted
|
||||
// explicitly in the same scoped transaction. Deleting an absent user is a no-op
|
||||
|
||||
Reference in New Issue
Block a user