You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.9 KiB
129 lines
3.9 KiB
-- Schema for app tables (Supabase API uses db.schema: 'omotomo' in config)
|
|
CREATE SCHEMA IF NOT EXISTS omotomo;
|
|
|
|
-- Decks table (metadata + config for Decky quiz/flashcard app)
|
|
CREATE TABLE IF NOT EXISTS omotomo.decks (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
owner_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
title text NOT NULL,
|
|
description text NOT NULL DEFAULT '',
|
|
config jsonb NOT NULL DEFAULT '{
|
|
"requiredConsecutiveCorrect": 3,
|
|
"defaultAttemptSize": 10,
|
|
"priorityIncreaseOnIncorrect": 5,
|
|
"priorityDecreaseOnCorrect": 2,
|
|
"immediateFeedbackEnabled": true,
|
|
"includeKnownInAttempts": false,
|
|
"shuffleAnswerOrder": true,
|
|
"excludeFlaggedQuestions": false,
|
|
"timeLimitSeconds": null
|
|
}'::jsonb,
|
|
published boolean NOT NULL DEFAULT false,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Questions table (deck content)
|
|
CREATE TABLE IF NOT EXISTS omotomo.questions (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
deck_id uuid NOT NULL REFERENCES omotomo.decks(id) ON DELETE CASCADE,
|
|
sort_order int NOT NULL DEFAULT 0,
|
|
prompt text NOT NULL,
|
|
explanation text,
|
|
answers jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
correct_answer_indices jsonb NOT NULL DEFAULT '[]'::jsonb
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_questions_deck_id ON omotomo.questions(deck_id);
|
|
CREATE INDEX IF NOT EXISTS idx_decks_owner_id ON omotomo.decks(owner_id);
|
|
CREATE INDEX IF NOT EXISTS idx_decks_published ON omotomo.decks(published) WHERE published = true;
|
|
|
|
-- updated_at trigger for decks
|
|
CREATE OR REPLACE FUNCTION omotomo.set_decks_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS decks_updated_at ON omotomo.decks;
|
|
CREATE TRIGGER decks_updated_at
|
|
BEFORE UPDATE ON omotomo.decks
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE omotomo.set_decks_updated_at();
|
|
|
|
-- RLS
|
|
ALTER TABLE omotomo.decks ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE omotomo.questions ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- decks: SELECT if owner or published; mutate only if owner
|
|
DROP POLICY IF EXISTS decks_select ON omotomo.decks;
|
|
DROP POLICY IF EXISTS decks_insert ON omotomo.decks;
|
|
DROP POLICY IF EXISTS decks_update ON omotomo.decks;
|
|
DROP POLICY IF EXISTS decks_delete ON omotomo.decks;
|
|
CREATE POLICY decks_select ON omotomo.decks
|
|
FOR SELECT
|
|
USING (owner_id = auth.uid() OR published = true);
|
|
|
|
CREATE POLICY decks_insert ON omotomo.decks
|
|
FOR INSERT
|
|
WITH CHECK (owner_id = auth.uid());
|
|
|
|
CREATE POLICY decks_update ON omotomo.decks
|
|
FOR UPDATE
|
|
USING (owner_id = auth.uid())
|
|
WITH CHECK (owner_id = auth.uid());
|
|
|
|
CREATE POLICY decks_delete ON omotomo.decks
|
|
FOR DELETE
|
|
USING (owner_id = auth.uid());
|
|
|
|
-- questions: SELECT if deck is visible; mutate only if deck is owned
|
|
DROP POLICY IF EXISTS questions_select ON omotomo.questions;
|
|
DROP POLICY IF EXISTS questions_insert ON omotomo.questions;
|
|
DROP POLICY IF EXISTS questions_update ON omotomo.questions;
|
|
DROP POLICY IF EXISTS questions_delete ON omotomo.questions;
|
|
CREATE POLICY questions_select ON omotomo.questions
|
|
FOR SELECT
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1 FROM omotomo.decks d
|
|
WHERE d.id = questions.deck_id
|
|
AND (d.owner_id = auth.uid() OR d.published = true)
|
|
)
|
|
);
|
|
|
|
CREATE POLICY questions_insert ON omotomo.questions
|
|
FOR INSERT
|
|
WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1 FROM omotomo.decks d
|
|
WHERE d.id = questions.deck_id AND d.owner_id = auth.uid()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY questions_update ON omotomo.questions
|
|
FOR UPDATE
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1 FROM omotomo.decks d
|
|
WHERE d.id = questions.deck_id AND d.owner_id = auth.uid()
|
|
)
|
|
)
|
|
WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1 FROM omotomo.decks d
|
|
WHERE d.id = questions.deck_id AND d.owner_id = auth.uid()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY questions_delete ON omotomo.questions
|
|
FOR DELETE
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1 FROM omotomo.decks d
|
|
WHERE d.id = questions.deck_id AND d.owner_id = auth.uid()
|
|
)
|
|
);
|