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

-- 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()
)
);

Powered by TurnKey Linux.