posimai-root/docs/synology/synology-brain-migration.sql

142 lines
9.0 KiB
MySQL
Raw Normal View History

-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-- Posimai Brain Full-Text Save Migration
-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-- Purpose: Add full_text column to store article body from Reader
-- Date: 2026-03-01
-- Impact: Critical data loss prevention
-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-- ──────────────────────────────────────────────────────────────────────
-- STEP 1: Backup existing data
-- ──────────────────────────────────────────────────────────────────────
-- Before running migration, create backup:
-- pg_dump -U brain_user -d brain_db -t articles > /backup/articles_$(date +%Y%m%d).sql
-- ──────────────────────────────────────────────────────────────────────
-- STEP 2: Add full_text column
-- ──────────────────────────────────────────────────────────────────────
BEGIN;
-- Add full_text column for storing article body
ALTER TABLE articles
ADD COLUMN IF NOT EXISTS full_text TEXT;
-- Add images column (optional, for future use)
ALTER TABLE articles
ADD COLUMN IF NOT EXISTS images TEXT[];
-- Add updated_at if it doesn't exist
ALTER TABLE articles
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP DEFAULT NOW();
COMMIT;
-- ──────────────────────────────────────────────────────────────────────
-- STEP 3: Create indexes for performance
-- ──────────────────────────────────────────────────────────────────────
BEGIN;
-- Full-text search index (Japanese language support)
-- This enables fast text search in Brain UI
CREATE INDEX IF NOT EXISTS idx_articles_full_text_search
ON articles USING gin(to_tsvector('english', COALESCE(full_text, '')));
-- Note: PostgreSQL doesn't have built-in Japanese tokenizer by default
-- For better Japanese search, consider installing pg_bigm extension:
-- CREATE EXTENSION IF NOT EXISTS pg_bigm;
-- CREATE INDEX IF NOT EXISTS idx_articles_full_text_bigm
-- ON articles USING gin(full_text gin_bigm_ops);
-- Index for finding articles without full_text (for migration/cleanup)
CREATE INDEX IF NOT EXISTS idx_articles_missing_full_text
ON articles (id) WHERE full_text IS NULL;
COMMIT;
-- ──────────────────────────────────────────────────────────────────────
-- STEP 4: Verify schema changes
-- ──────────────────────────────────────────────────────────────────────
-- \d articles
-- Expected output should include:
-- | Column | Type | Nullable | Description |
-- |-------------|-----------|----------|--------------------------------|
-- | id | SERIAL | NOT NULL | Primary key |
-- | user_id | INTEGER | NOT NULL | Foreign key to users table |
-- | url | TEXT | NOT NULL | Original article URL |
-- | title | TEXT | NOT NULL | Article title |
-- | full_text | TEXT | NULL | ← NEW! Article body from Reader|
-- | summary | TEXT | NULL | AI-generated 3-sentence summary|
-- | topics | TEXT[] | NULL | AI-generated topic tags |
-- | source | TEXT | NULL | Source (reader/feed/bookmarklet)|
-- | reading_time| INTEGER | NULL | Estimated reading time (minutes)|
-- | favicon | TEXT | NULL | Site favicon URL |
-- | og_image | TEXT | NULL | OGP image URL |
-- | images | TEXT[] | NULL | ← NEW! Article images (future) |
-- | status | TEXT | NOT NULL | inbox/favorite/shared/archived |
-- | created_at | TIMESTAMP | NOT NULL | Record creation time |
-- | updated_at | TIMESTAMP | NULL | ← NEW! Record update time |
-- ──────────────────────────────────────────────────────────────────────
-- STEP 5: Test query (verify columns exist)
-- ──────────────────────────────────────────────────────────────────────
SELECT
id,
title,
LENGTH(full_text) as text_length,
LEFT(full_text, 50) as text_preview,
summary,
topics,
created_at
FROM articles
ORDER BY created_at DESC
LIMIT 5;
-- Expected: All existing articles will have NULL for full_text
-- New articles saved after API update will have full_text populated
-- ──────────────────────────────────────────────────────────────────────
-- STEP 6: Clean up old articles (optional)
-- ──────────────────────────────────────────────────────────────────────
-- If you want to delete old articles without full_text after migration:
-- (Run this ONLY after confirming new articles are saving correctly)
-- Count articles without full_text
SELECT COUNT(*) as articles_without_fulltext
FROM articles
WHERE full_text IS NULL;
-- Optionally delete old articles without full_text (BE CAREFUL!)
-- DELETE FROM articles WHERE full_text IS NULL AND created_at < NOW() - INTERVAL '30 days';
-- ──────────────────────────────────────────────────────────────────────
-- STEP 7: Add constraint for new articles (optional, recommended)
-- ──────────────────────────────────────────────────────────────────────
-- After confirming Reader is sending full_text correctly,
-- you can add a constraint to ensure all new articles have full_text:
-- ALTER TABLE articles
-- ADD CONSTRAINT full_text_required
-- CHECK (
-- (source = 'reader' AND full_text IS NOT NULL) OR
-- (source != 'reader')
-- );
-- This ensures Reader-sourced articles MUST have full_text
-- ──────────────────────────────────────────────────────────────────────
-- STEP 8: Grant permissions (if needed)
-- ──────────────────────────────────────────────────────────────────────
-- If using a separate API user, grant access to new columns:
-- GRANT SELECT, INSERT, UPDATE ON articles TO brain_api_user;
-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-- Migration Complete!
-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-- Next steps:
-- 1. Update Brain API server code (see BRAIN_FULLTEXT_IMPLEMENTATION_GUIDE.md)
-- 2. Test saving an article from Reader
-- 3. Verify full_text is populated in database
-- 4. Deploy Brain API changes to production
-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━