-- Migration 003: enforce per-user isolation at the DB layer via row-level
-- security (ADR-012, data-model.md "Isolation invariant"). Stage 1 ships
-- multi-user WITH this enforcement; it is the proof that user A cannot read or
-- write user B's rows even if application-level WHERE clauses are wrong.
--
-- How it works:
--   * Every policy keys off the per-request GUC tapir.current_user_id, set by the
--     store's withUser helper via set_config('tapir.current_user_id', $1, true)
--     (transaction-local — auto-reset on commit/rollback, never leaks across a
--     pooled connection's requests).
--   * current_setting('tapir.current_user_id', true) uses missing_ok = true: an
--     UNSET GUC yields NULL, so the predicate is NULL → no rows match → deny-all.
--     That is the safe default and is asserted in rls_test.go.
--   * FORCE ROW LEVEL SECURITY: the app connects as the table OWNER (tapir), and
--     owners BYPASS RLS unless forced. Without FORCE the policies below are dead
--     for the production user. FORCE makes the owner subject to them. (A superuser
--     DSN still bypasses RLS regardless — the test connects as a non-superuser,
--     non-BYPASSRLS role so the enforcement is real, not theatre.)

-- users: the row's own id IS the user_id for this table.
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE users FORCE ROW LEVEL SECURITY;
CREATE POLICY users_isolation ON users
    FOR ALL
    USING (id = current_setting('tapir.current_user_id', true)::uuid);

ALTER TABLE videos ENABLE ROW LEVEL SECURITY;
ALTER TABLE videos FORCE ROW LEVEL SECURITY;
CREATE POLICY videos_isolation ON videos
    FOR ALL
    USING (user_id = current_setting('tapir.current_user_id', true)::uuid);

ALTER TABLE transcripts ENABLE ROW LEVEL SECURITY;
ALTER TABLE transcripts FORCE ROW LEVEL SECURITY;
CREATE POLICY transcripts_isolation ON transcripts
    FOR ALL
    USING (user_id = current_setting('tapir.current_user_id', true)::uuid);

ALTER TABLE summaries ENABLE ROW LEVEL SECURITY;
ALTER TABLE summaries FORCE ROW LEVEL SECURITY;
CREATE POLICY summaries_isolation ON summaries
    FOR ALL
    USING (user_id = current_setting('tapir.current_user_id', true)::uuid);

ALTER TABLE summary_actions ENABLE ROW LEVEL SECURITY;
ALTER TABLE summary_actions FORCE ROW LEVEL SECURITY;
CREATE POLICY summary_actions_isolation ON summary_actions
    FOR ALL
    USING (user_id = current_setting('tapir.current_user_id', true)::uuid);

-- sink_deliveries has NO user_id of its own; ownership is derived from the
-- summary it belongs to. We key the policy directly off the GUC via EXISTS
-- (rather than `summary_id IN (SELECT id FROM summaries)`) so it is self-contained
-- and does not silently depend on summaries' own RLS being applied to the
-- subquery. The WITH CHECK clause (defaulting to USING under FOR ALL) means a
-- delivery row can only be inserted/updated when its summary is owned by the
-- current user.
ALTER TABLE sink_deliveries ENABLE ROW LEVEL SECURITY;
ALTER TABLE sink_deliveries FORCE ROW LEVEL SECURITY;
CREATE POLICY sink_deliveries_isolation ON sink_deliveries
    FOR ALL
    USING (
        EXISTS (
            SELECT 1 FROM summaries s
             WHERE s.id = sink_deliveries.summary_id
               AND s.user_id = current_setting('tapir.current_user_id', true)::uuid
        )
    );
