create extension if not exists pgcrypto; create table if not exists users ( id uuid primary key default gen_random_uuid(), email text not null unique, password_hash text not null, role text not null default 'user', created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create table if not exists bookmark_folders ( id uuid primary key default gen_random_uuid(), user_id uuid not null references users(id) on delete cascade, parent_id uuid null references bookmark_folders(id) on delete cascade, name text not null, visibility text not null default 'private', created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); create index if not exists idx_bookmark_folders_user_parent on bookmark_folders (user_id, parent_id); create table if not exists bookmarks ( id uuid primary key default gen_random_uuid(), user_id uuid not null references users(id) on delete cascade, folder_id uuid null references bookmark_folders(id) on delete set null, title text not null, url text not null, url_normalized text not null, url_hash text not null, visibility text not null default 'private', source text not null default 'manual', created_at timestamptz not null default now(), updated_at timestamptz not null default now(), deleted_at timestamptz null ); create index if not exists idx_bookmarks_user_updated_at on bookmarks (user_id, updated_at); create index if not exists idx_bookmarks_user_url_hash on bookmarks (user_id, url_hash); create index if not exists idx_bookmarks_visibility on bookmarks (visibility);