음성 재생과 운영 배포 정리
This commit is contained in:
parent
8ed185ce6c
commit
ac7db95542
1020 changed files with 46863 additions and 2175 deletions
|
|
@ -128,3 +128,162 @@ CREATE POLICY p_case_worksheet_delete
|
|||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Live coaching interventions delivered during a session.
|
||||
CREATE TABLE IF NOT EXISTS app.live_coach_events (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id UUID NOT NULL REFERENCES app.sessions(id) ON DELETE CASCADE,
|
||||
turn_seq INT NOT NULL CHECK (turn_seq >= 1),
|
||||
stage TEXT NOT NULL,
|
||||
learner_text_excerpt TEXT,
|
||||
client_reply_excerpt TEXT,
|
||||
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_live_coach_events_session_turn
|
||||
ON app.live_coach_events(session_id, turn_seq, created_at);
|
||||
|
||||
ALTER TABLE app.live_coach_events ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS p_live_coach_events_select ON app.live_coach_events;
|
||||
DROP POLICY IF EXISTS p_live_coach_events_insert ON app.live_coach_events;
|
||||
|
||||
CREATE POLICY p_live_coach_events_select
|
||||
ON app.live_coach_events FOR SELECT USING (
|
||||
app.current_role_name() IN ('admin','instructor')
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.live_coach_events.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY p_live_coach_events_insert
|
||||
ON app.live_coach_events FOR INSERT WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.live_coach_events.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Public share cards for learner-owned session reviews. Payload is intentionally
|
||||
-- a sanitized preview, not the transcript or worksheet raw source.
|
||||
CREATE TABLE IF NOT EXISTS app.session_share_link (
|
||||
session_id UUID PRIMARY KEY REFERENCES app.sessions(id) ON DELETE CASCADE,
|
||||
created_by UUID NOT NULL REFERENCES app.app_user(user_id),
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
payload JSONB NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
revoked_at TIMESTAMPTZ
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_share_token_active
|
||||
ON app.session_share_link(token_hash)
|
||||
WHERE revoked_at IS NULL;
|
||||
|
||||
ALTER TABLE app.session_share_link ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS p_session_share_select ON app.session_share_link;
|
||||
DROP POLICY IF EXISTS p_session_share_insert ON app.session_share_link;
|
||||
DROP POLICY IF EXISTS p_session_share_update ON app.session_share_link;
|
||||
DROP POLICY IF EXISTS p_session_share_delete ON app.session_share_link;
|
||||
|
||||
CREATE POLICY p_session_share_select
|
||||
ON app.session_share_link FOR SELECT USING (
|
||||
app.is_ai_context()
|
||||
OR app.current_role_name() IN ('admin','instructor')
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_share_link.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
CREATE POLICY p_session_share_insert
|
||||
ON app.session_share_link FOR INSERT WITH CHECK (
|
||||
app.is_ai_context()
|
||||
OR (
|
||||
created_by = app.current_uid()
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_share_link.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
)
|
||||
);
|
||||
CREATE POLICY p_session_share_update
|
||||
ON app.session_share_link FOR UPDATE USING (
|
||||
app.is_ai_context()
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_share_link.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
) WITH CHECK (
|
||||
app.is_ai_context()
|
||||
OR (
|
||||
created_by = app.current_uid()
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_share_link.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
)
|
||||
);
|
||||
CREATE POLICY p_session_share_delete
|
||||
ON app.session_share_link FOR DELETE USING (
|
||||
app.is_ai_context()
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_share_link.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Learner-owned history archive state. This is display state only; session,
|
||||
-- turn, review, share, research, and audit evidence remain intact.
|
||||
CREATE TABLE IF NOT EXISTS app.session_archive_state (
|
||||
session_id UUID PRIMARY KEY REFERENCES app.sessions(id) ON DELETE CASCADE,
|
||||
learner_id UUID NOT NULL REFERENCES app.app_user(user_id),
|
||||
archived_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_session_archive_learner
|
||||
ON app.session_archive_state(learner_id, archived_at DESC);
|
||||
|
||||
ALTER TABLE app.session_archive_state ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS p_session_archive_select ON app.session_archive_state;
|
||||
DROP POLICY IF EXISTS p_session_archive_insert ON app.session_archive_state;
|
||||
DROP POLICY IF EXISTS p_session_archive_update ON app.session_archive_state;
|
||||
DROP POLICY IF EXISTS p_session_archive_delete ON app.session_archive_state;
|
||||
|
||||
CREATE POLICY p_session_archive_select
|
||||
ON app.session_archive_state FOR SELECT USING (
|
||||
app.current_role_name() IN ('admin','instructor')
|
||||
OR learner_id = app.current_uid()
|
||||
);
|
||||
CREATE POLICY p_session_archive_insert
|
||||
ON app.session_archive_state FOR INSERT WITH CHECK (
|
||||
learner_id = app.current_uid()
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_archive_state.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
CREATE POLICY p_session_archive_update
|
||||
ON app.session_archive_state FOR UPDATE USING (
|
||||
learner_id = app.current_uid()
|
||||
) WITH CHECK (
|
||||
learner_id = app.current_uid()
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM app.sessions s
|
||||
WHERE s.id = app.session_archive_state.session_id
|
||||
AND s.learner_id = app.current_uid()
|
||||
)
|
||||
);
|
||||
CREATE POLICY p_session_archive_delete
|
||||
ON app.session_archive_state FOR DELETE USING (
|
||||
learner_id = app.current_uid()
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue