-- Create shared_notes table for public sharing functionality CREATE TABLE IF NOT EXISTS shared_notes ( note_id TEXT PRIMARY KEY, user_id UUID NOT NULL, is_public BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Foreign key constraint to notes table CONSTRAINT fk_shared_notes_note_id FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE, -- Foreign key constraint to users table (auth.users) CONSTRAINT fk_shared_notes_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE ); -- Create index for performance on public notes CREATE INDEX IF NOT EXISTS idx_shared_notes_is_public ON shared_notes(is_public); CREATE INDEX IF NOT EXISTS idx_shared_notes_user_id ON shared_notes(user_id); -- Enable Row Level Security ALTER TABLE shared_notes ENABLE ROW LEVEL SECURITY; -- Policy to allow users to view their own shared_notes entries CREATE POLICY "Users can view their own shared notes" ON shared_notes FOR SELECT TO authenticated USING (user_id = (SELECT auth.uid())); -- Policy to allow anonymous users to view public notes CREATE POLICY "Anyone can view public notes" ON shared_notes FOR SELECT TO anon USING (is_public = TRUE); -- Policy to allow users to insert their own shared_notes entries CREATE POLICY "Users can insert their own shared notes" ON shared_notes FOR INSERT TO authenticated WITH CHECK (user_id = (SELECT auth.uid())); -- Policy to allow users to update their own shared_notes entries CREATE POLICY "Users can update their own shared notes" ON shared_notes FOR UPDATE TO authenticated USING (user_id = (SELECT auth.uid())) WITH CHECK (user_id = (SELECT auth.uid())); -- Policy to allow users to delete their own shared_notes entries CREATE POLICY "Users can delete their own shared notes" ON shared_notes FOR DELETE TO authenticated USING (user_id = (SELECT auth.uid())); -- Create note_access table for tablo-based sharing CREATE TABLE IF NOT EXISTS note_access ( id SERIAL PRIMARY KEY, note_id TEXT NOT NULL, user_id UUID NOT NULL, tablo_id TEXT, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, -- Foreign key constraint to notes table CONSTRAINT fk_note_access_note_id FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE, -- Foreign key constraint to users table (auth.users) CONSTRAINT fk_note_access_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE, -- Foreign key constraint to tablos table (nullable for "all tablos" sharing) CONSTRAINT fk_note_access_tablo_id FOREIGN KEY (tablo_id) REFERENCES tablos(id) ON DELETE CASCADE ); -- Create indexes for performance CREATE INDEX IF NOT EXISTS idx_note_access_note_id ON note_access(note_id); CREATE INDEX IF NOT EXISTS idx_note_access_user_id ON note_access(user_id); CREATE INDEX IF NOT EXISTS idx_note_access_tablo_id ON note_access(tablo_id); CREATE INDEX IF NOT EXISTS idx_note_access_is_active ON note_access(is_active); -- Unique constraint for specific tablo sharing (when tablo_id IS NOT NULL) CREATE UNIQUE INDEX IF NOT EXISTS unique_note_access_with_tablo ON note_access(note_id, user_id, tablo_id) WHERE tablo_id IS NOT NULL; -- Unique constraint for "all tablos" sharing (when tablo_id IS NULL) -- Only one NULL tablo_id per (note_id, user_id) combination CREATE UNIQUE INDEX IF NOT EXISTS unique_note_access_all_tablos ON note_access(note_id, user_id) WHERE tablo_id IS NULL; -- Enable Row Level Security ALTER TABLE note_access ENABLE ROW LEVEL SECURITY; -- Policy to allow users to view their own note_access entries CREATE POLICY "Users can view their own note access" ON note_access FOR SELECT TO authenticated USING (user_id = (SELECT auth.uid())); -- Policy to allow users to view notes shared with their tablos CREATE POLICY "Users can view notes shared with their tablos" ON note_access FOR SELECT TO authenticated USING ( is_active = TRUE AND ( -- Shared with all tablos (tablo_id is NULL) tablo_id IS NULL -- Or shared with a specific tablo where the user has access OR EXISTS ( SELECT 1 FROM tablo_access WHERE tablo_access.tablo_id = note_access.tablo_id AND tablo_access.user_id = (SELECT auth.uid()) AND tablo_access.is_active = TRUE ) ) ); -- Policy to allow users to insert their own note_access entries CREATE POLICY "Users can insert their own note access" ON note_access FOR INSERT TO authenticated WITH CHECK (user_id = (SELECT auth.uid())); -- Policy to allow users to update their own note_access entries CREATE POLICY "Users can update their own note access" ON note_access FOR UPDATE TO authenticated USING (user_id = (SELECT auth.uid())) WITH CHECK (user_id = (SELECT auth.uid())); -- Policy to allow users to delete their own note_access entries CREATE POLICY "Users can delete their own note access" ON note_access FOR DELETE TO authenticated USING (user_id = (SELECT auth.uid())); -- Add comments to document the tables COMMENT ON TABLE shared_notes IS 'Tracks which notes are shared publicly with Row Level Security'; COMMENT ON COLUMN shared_notes.note_id IS 'Foreign key reference to notes.id'; COMMENT ON COLUMN shared_notes.user_id IS 'Foreign key reference to auth.users.id - owner of the note'; COMMENT ON COLUMN shared_notes.is_public IS 'When TRUE, the note is publicly accessible via /notes/public/:noteId'; COMMENT ON TABLE note_access IS 'Tracks which notes are shared with tablos. When tablo_id IS NULL and is_active = TRUE, the note is shared with all user tablos. Uses partial unique indexes to handle NULL values correctly.'; COMMENT ON COLUMN note_access.tablo_id IS 'Foreign key reference to tablos.id - NULL means shared with all user tablos. Partial unique indexes ensure only one NULL per (note_id, user_id) combination.'; COMMENT ON COLUMN note_access.is_active IS 'When TRUE, the sharing is active';