一键导入
frontend-realtime-sync
Use when adding new tables to realtime events system, implementing realtime subscriptions, or debugging org-scoped table sync issues
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when adding new tables to realtime events system, implementing realtime subscriptions, or debugging org-scoped table sync issues
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | frontend-realtime-sync |
| description | Use when adding new tables to realtime events system, implementing realtime subscriptions, or debugging org-scoped table sync issues |
Organization-scoped realtime synchronization pattern that automatically invalidates TanStack Query caches when database changes occur.
Organization-scoped notification system that eliminates need for organization_id on junction tables:
realtime_table_events tablerealtime_table_events filtered by organization{ table_name, event_type, organization_id }org:org_123realtime_table_events table with filter: organization_id=eq.{orgId}realtime_table_events with table_name and record_idtable_name and record_id in payload.list() queries: ALWAYS invalidate on any table change.record(id) queries: ONLY invalidate when record_id matchesPerformance benefit: With 500 concurrent users updating different records, only affected queries refetch instead of all table queries.
Database Change (Postgres)
|
v
Trigger: get_organization_id_for_change()
(Traces change to affected organization + extract record ID)
|
v
INSERT into realtime_table_events
(table_name, event_type, organization_id, record_id)
|
v
Supabase Realtime Publication
|
v
Organization Channel (org:org_123)
|
v
useSupabaseRealtimeSync Hook
|
v
Extract table_name and record_id from payload
|
v
Query Invalidation (granular predicate):
- .list() queries: Always invalidate
- .record(id) queries: Only if record_id matches
|
v
UI Re-fetch & Update (only affected queries)
Frontend: No changes needed! Just ensure QueryKeys use .list() for list queries or .record(id) for single-record queries.
Backend only (in migration):
Create your table (no organization_id required for junction tables)
-- Example: Junction table without organization_id
CREATE TABLE my_junction_table (
parent_id uuid REFERENCES parent_table(id),
child_id uuid REFERENCES child_table(id),
PRIMARY KEY (parent_id, child_id)
);
Update get_organization_id_for_change() function:
CREATE OR REPLACE FUNCTION public.get_organization_id_for_change()
RETURNS TEXT AS $$
DECLARE
org_id TEXT;
record_data JSONB;
BEGIN
IF TG_OP = 'DELETE' THEN
record_data := to_jsonb(OLD);
ELSE
record_data := to_jsonb(NEW);
END IF;
CASE TG_TABLE_NAME
-- Add your new table:
WHEN 'my_junction_table' THEN
SELECT p.organization_id INTO org_id
FROM parent_table p
WHERE p.id = (record_data->>'parent_id');
-- ... other tables ...
END CASE;
RETURN org_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;
Attach trigger:
DROP TRIGGER IF EXISTS trigger_notify_org_change ON my_junction_table;
CREATE TRIGGER trigger_notify_org_change
AFTER INSERT OR UPDATE OR DELETE ON my_junction_table
FOR EACH ROW
EXECUTE FUNCTION notify_organization_of_table_change();
Verify QueryKeys exist (usually already present):
// src/utils/query/queryKeys.ts
export const QueryKeys = {
my_junction_table: createTableFactory("my_junction_table"),
};
That's it! Frontend automatically invalidates queries when it receives table_name: "my_junction_table" in event payload.
Tables WITHOUT organization_id should use manual invalidation:
organizations - Use manual invalidation in mutation hooksprofiles - Use manual invalidation in mutation hooksrole_permissions - Use manual invalidation in mutation hooksWhy no realtime for global tables?
// App.tsx
<Provider_Query>
<Provider_ANTD>
<Provider_SupabaseRealtimeSync>
<RouterProvider router={router} />
</Provider_SupabaseRealtimeSync>
</Provider_ANTD>
</Provider_Query>
The provider should be:
QueryClientProvider (needs query client context)org_123projects tableget_organization_id_for_change() → returns org_123realtime_table_events: {organization_id: 'org_123', table_name: 'projects', event_type: 'INSERT'}org:org_123org:org_123 receive notification eventtable_name: 'projects' from payloadhandleTableChange invalidates all queries with 'projects' in query keysKey Advantage: Works even for junction tables without organization_id column, as backend traces relationship to affected organization.
Use when deploying Cloudflare Workers, managing R2 storage, or working with Cloudflare infrastructure
Use when working with ANTD components, theme tokens, icons, forms, or feedback components (message/notification/modal)
Use when adding, referencing, or serving static assets (images, fonts, videos, 3D models) through the R2 CDN pipeline with type-safe imports
Use when writing or reviewing JavaScript/TypeScript code for style patterns like concise arrows, inline handlers, expression formatting, or when tempted to use eslint-disable
Use when working with environment variables in frontend code
Use when creating or modifying keyboard shortcuts/hotkeys in frontend code