From cee4ab93173f75bae259cd79e4cc3397a4fc215e Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Sun, 27 Sep 2026 14:44:56 +0900 Subject: [PATCH] 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. --- ...927000035_sync_knowledge_and_retention.sql | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 server/supabase/migrations/20260927000035_sync_knowledge_and_retention.sql diff --git a/server/supabase/migrations/20260927000035_sync_knowledge_and_retention.sql b/server/supabase/migrations/20260927000035_sync_knowledge_and_retention.sql new file mode 100644 index 0000000..087568f --- /dev/null +++ b/server/supabase/migrations/20260927000035_sync_knowledge_and_retention.sql @@ -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()$$ +);