feat(supabase): sync knowledge documents and prune tombstones daily

knowledge_documents deletions now leave a sync tombstone and have a cursor
index and Realtime, so the desktop mirror can follow them. pg_cron runs
prune_sync_tombstones_v1 every day at 03:17 UTC with the 180-day window.
This commit is contained in:
Yun Chan 2026-09-27 14:44:56 +09:00
parent bde8565fd2
commit cee4ab9317

View file

@ -0,0 +1,55 @@
-- Knowledge base joins the cross-device mirror; tombstones get a retention job.
--
-- 1. knowledge_documents deletions leave a tombstone like the other synced
-- tables, and a (user_id, updated_at, id) cursor index backs keyset pulls.
-- Chunks are re-read with their document, so they need neither.
-- 2. pg_cron prunes tombstones daily with the 180-day default of
-- prune_sync_tombstones_v1 (a device offline longer than that resyncs fully).
BEGIN;
-- 1) knowledge_documents ---------------------------------------------------------
ALTER TABLE public.sync_tombstones DROP CONSTRAINT IF EXISTS sync_tombstones_table_name_check;
ALTER TABLE public.sync_tombstones
ADD CONSTRAINT sync_tombstones_table_name_check CHECK (table_name IN (
'history',
'dictionary',
'meetings',
'meeting_memos',
'meeting_documents',
'memo_tags',
'custom_instructions',
'user_templates',
'knowledge_documents'
));
DROP TRIGGER IF EXISTS record_sync_tombstone_v1 ON public.knowledge_documents;
CREATE TRIGGER record_sync_tombstone_v1
AFTER DELETE ON public.knowledge_documents
FOR EACH ROW EXECUTE FUNCTION public.record_sync_tombstone_v1();
CREATE INDEX IF NOT EXISTS idx_knowledge_documents_sync_cursor
ON public.knowledge_documents(user_id, updated_at, id);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_publication_tables
WHERE pubname = 'supabase_realtime' AND schemaname = 'public' AND tablename = 'knowledge_documents'
) THEN
ALTER PUBLICATION supabase_realtime ADD TABLE public.knowledge_documents;
END IF;
END $$;
COMMIT;
-- 2) Tombstone retention ---------------------------------------------------------
-- Outside the transaction: extension creation and cron scheduling are
-- idempotent, and cron.schedule with an existing job name replaces it.
CREATE EXTENSION IF NOT EXISTS pg_cron WITH SCHEMA pg_catalog;
SELECT cron.schedule(
'prune-sync-tombstones',
'17 3 * * *',
$$SELECT public.prune_sync_tombstones_v1()$$
);