-- Create normalized article table for blog-backup. -- One row = one article. digest_date groups rows by daily digest. CREATE TABLE IF NOT EXISTS public.blog_articles ( id TEXT PRIMARY KEY, title TEXT NOT NULL, summary TEXT NOT NULL, source_url TEXT, digest_date DATE, published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), tags TEXT[] NOT NULL DEFAULT '{}'::TEXT[], audio_url TEXT, audio_duration INTEGER, is_published BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_blog_articles_published_at ON public.blog_articles (published_at DESC); CREATE INDEX IF NOT EXISTS idx_blog_articles_digest_date ON public.blog_articles (digest_date DESC); CREATE INDEX IF NOT EXISTS idx_blog_articles_tags ON public.blog_articles USING GIN (tags); CREATE INDEX IF NOT EXISTS idx_blog_articles_audio ON public.blog_articles (audio_url) WHERE audio_url IS NOT NULL; COMMENT ON TABLE public.blog_articles IS 'One row per article. digest_date groups rows into a daily digest.'; COMMENT ON COLUMN public.blog_articles.summary IS 'Structured article summary body shown in UI and RSS.'; COMMENT ON COLUMN public.blog_articles.digest_date IS 'Logical daily digest date (YYYY-MM-DD). Multiple articles can share one date.'; COMMENT ON COLUMN public.blog_articles.is_published IS 'Controls public visibility in /api/articles and RSS.';