realtimex-crm 0.9.1 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/bin/realtimex-crm.js +56 -32
  2. package/dist/assets/{DealList-DnGVfS15.js → DealList-Dxd6Tt9n.js} +2 -2
  3. package/dist/assets/{DealList-DnGVfS15.js.map → DealList-Dxd6Tt9n.js.map} +1 -1
  4. package/dist/assets/index-CGJPhLfC.js +166 -0
  5. package/dist/assets/{index-DPrpo5Xq.js.map → index-CGJPhLfC.js.map} +1 -1
  6. package/dist/assets/index-C__S90Gb.css +1 -0
  7. package/dist/index.html +1 -1
  8. package/dist/stats.html +1 -1
  9. package/package.json +2 -1
  10. package/src/components/atomic-crm/activities/ActivitiesPage.tsx +16 -0
  11. package/src/components/atomic-crm/activities/ActivityFeed.tsx +212 -0
  12. package/src/components/atomic-crm/activities/FileUpload.tsx +359 -0
  13. package/src/components/atomic-crm/contacts/ContactShow.tsx +28 -10
  14. package/src/components/atomic-crm/integrations/CreateChannelDialog.tsx +139 -0
  15. package/src/components/atomic-crm/integrations/IngestionChannelsTab.tsx +188 -0
  16. package/src/components/atomic-crm/integrations/IntegrationsPage.tsx +15 -3
  17. package/supabase/fix_webhook_hardcoded.sql +34 -0
  18. package/supabase/functions/_shared/ingestionGuard.ts +128 -0
  19. package/supabase/functions/_shared/utils.ts +1 -1
  20. package/supabase/functions/ingest-activity/.well-known/supabase/config.toml +4 -0
  21. package/supabase/functions/ingest-activity/index.ts +261 -0
  22. package/supabase/migrations/20251219120100_webhook_triggers.sql +10 -5
  23. package/supabase/migrations/20251220120000_realtime_ingestion.sql +154 -0
  24. package/supabase/migrations/20251221000000_contact_matching.sql +94 -0
  25. package/supabase/migrations/20251221000001_fix_ingestion_providers_rls.sql +23 -0
  26. package/supabase/migrations/20251221000002_fix_contact_matching_jsonb.sql +67 -0
  27. package/supabase/migrations/20251221000003_fix_email_matching.sql +70 -0
  28. package/supabase/migrations/20251221000004_time_based_work_stealing.sql +99 -0
  29. package/supabase/migrations/20251221000005_realtime_functions.sql +73 -0
  30. package/supabase/migrations/20251221000006_enable_pg_net.sql +3 -0
  31. package/supabase/migrations/20251222075019_enable_extensions_and_configure_cron.sql +86 -0
  32. package/supabase/migrations/20251222094036_large_payload_storage.sql +213 -0
  33. package/supabase/migrations/20251222094247_large_payload_cron.sql +28 -0
  34. package/supabase/migrations/20251222220000_fix_large_payload_types.sql +72 -0
  35. package/supabase/migrations/20251223000000_enable_realtime_all_crm_tables.sql +50 -0
  36. package/supabase/migrations/20251223185638_remove_large_payload_storage.sql +54 -0
  37. package/supabase/migrations/20251224000000_fix_webhook_function.sql +27 -0
  38. package/supabase/migrations/20251224000001_fix_webhook_function_explicit.sql +164 -0
  39. package/dist/assets/index-DPrpo5Xq.js +0 -159
  40. package/dist/assets/index-kM1Og1AS.css +0 -1
@@ -0,0 +1,50 @@
1
+ -- Enable Realtime for all core CRM tables
2
+ -- This migration adds realtime support for tables not covered in the initial setup
3
+ -- Safe to run on existing deployments (idempotent - won't duplicate if already enabled)
4
+
5
+ -- Enable realtime for core CRM entities
6
+ select enable_realtime_for_table('contacts');
7
+ select enable_realtime_for_table('companies');
8
+ select enable_realtime_for_table('deals');
9
+ select enable_realtime_for_table('contactNotes');
10
+ select enable_realtime_for_table('dealNotes');
11
+ select enable_realtime_for_table('sales');
12
+ select enable_realtime_for_table('ingestion_providers');
13
+
14
+ -- Verify all tables are enabled
15
+ do $$
16
+ declare
17
+ expected_tables text[] := ARRAY[
18
+ 'activities',
19
+ 'tasks',
20
+ 'contacts',
21
+ 'companies',
22
+ 'deals',
23
+ 'contactNotes',
24
+ 'dealNotes',
25
+ 'sales',
26
+ 'ingestion_providers'
27
+ ];
28
+ enabled_tables text[];
29
+ missing_tables text[];
30
+ begin
31
+ -- Get list of enabled tables
32
+ select array_agg(tablename)
33
+ into enabled_tables
34
+ from pg_publication_tables
35
+ where pubname = 'supabase_realtime'
36
+ and schemaname = 'public';
37
+
38
+ -- Find missing tables
39
+ select array_agg(t)
40
+ into missing_tables
41
+ from unnest(expected_tables) as t
42
+ where t != ALL(coalesce(enabled_tables, ARRAY[]::text[]));
43
+
44
+ -- Report results
45
+ if missing_tables is null or array_length(missing_tables, 1) = 0 then
46
+ raise notice '✅ All CRM tables have realtime enabled';
47
+ else
48
+ raise warning '⚠️ Missing realtime for: %', array_to_string(missing_tables, ', ');
49
+ end if;
50
+ end $$;
@@ -0,0 +1,54 @@
1
+ -- Remove Large JSON Payload Storage System
2
+ -- This migration removes the move_payload_to_storage function and related infrastructure
3
+ -- that was designed to move large JSON payloads to storage.
4
+ --
5
+ -- Decision: Files are now uploaded directly to storage in the incoming/ folder
6
+ -- and marked as 'in_storage' immediately. No cron job needed to move them.
7
+
8
+ -- Unschedule the cron job (safe to run even if it doesn't exist)
9
+ SELECT cron.unschedule('process-large-payloads') WHERE EXISTS (
10
+ SELECT 1 FROM cron.job WHERE jobname = 'process-large-payloads'
11
+ );
12
+
13
+ -- Drop the trigger that auto-detects large payloads
14
+ DROP TRIGGER IF EXISTS trigger_check_payload_size ON activities;
15
+
16
+ -- Drop the trigger function
17
+ DROP FUNCTION IF EXISTS check_payload_size();
18
+
19
+ -- Drop the move_payload_to_storage function
20
+ DROP FUNCTION IF EXISTS move_payload_to_storage(UUID, TEXT);
21
+
22
+ -- Drop the get_activity_payload helper function (no longer needed)
23
+ DROP FUNCTION IF EXISTS get_activity_payload(UUID);
24
+
25
+ -- Drop the calculate_payload_size helper function (no longer needed)
26
+ DROP FUNCTION IF EXISTS calculate_payload_size(JSONB);
27
+
28
+ -- Drop the index for pending_move queries (no longer needed)
29
+ DROP INDEX IF EXISTS idx_activities_pending_storage;
30
+
31
+ -- Remove the CHECK constraint on payload_storage_status to allow NULL and 'in_storage' only
32
+ -- First drop the constraint, then add a new one
33
+ ALTER TABLE activities DROP CONSTRAINT IF EXISTS activities_payload_storage_status_check;
34
+ ALTER TABLE activities ADD CONSTRAINT activities_payload_storage_status_check
35
+ CHECK (payload_storage_status IS NULL OR payload_storage_status = 'in_storage');
36
+
37
+ -- Update pg_cron comment to remove reference to process-large-payloads
38
+ COMMENT ON EXTENSION pg_cron IS
39
+ 'Cron jobs:
40
+ - webhook-dispatcher: Runs every minute to dispatch webhooks';
41
+
42
+ -- Add comment to explain the simplified storage model
43
+ COMMENT ON COLUMN activities.payload_storage_status IS
44
+ 'Storage status for file attachments:
45
+ - NULL: No files attached (raw_data is pure JSON)
46
+ - ''in_storage'': Files uploaded to storage/incoming/ folder, referenced in raw_data.storage_path
47
+
48
+ Files are uploaded directly to storage by the ingest-activity Edge Function.
49
+ No post-processing or file moving is needed.';
50
+
51
+ COMMENT ON COLUMN activities.storage_path IS
52
+ 'Storage path for file attachments. Populated when raw_data.source_type = ''storage_ref''.
53
+ Files are stored in the activity-payloads bucket under incoming/ folder.
54
+ Example: incoming/1766514359388_document.pdf';
@@ -0,0 +1,27 @@
1
+ -- Function to enqueue webhook events
2
+ create or replace function enqueue_webhook_event(
3
+ p_event_type text,
4
+ p_payload jsonb
5
+ ) returns void
6
+ language plpgsql
7
+ security definer
8
+ set search_path = public
9
+ as $$
10
+ begin
11
+ -- Find all active webhooks that listen to this event
12
+ insert into public.webhook_queue (webhook_id, event_type, payload, next_retry_at)
13
+ select
14
+ id,
15
+ p_event_type,
16
+ p_payload,
17
+ now()
18
+ from public.webhooks
19
+ where is_active = true
20
+ and p_event_type = any(events);
21
+ end;
22
+ $$;
23
+
24
+ -- Grant execute permissions on webhook functions
25
+ grant execute on function enqueue_webhook_event(text, jsonb) to authenticated;
26
+ grant execute on function enqueue_webhook_event(text, jsonb) to service_role;
27
+ grant execute on function enqueue_webhook_event(text, jsonb) to anon;
@@ -0,0 +1,164 @@
1
+ -- Explicitly define function in public schema
2
+ create or replace function public.enqueue_webhook_event(
3
+ p_event_type text,
4
+ p_payload jsonb
5
+ ) returns void
6
+ language plpgsql
7
+ security definer
8
+ set search_path = public
9
+ as $$
10
+ begin
11
+ -- Find all active webhooks that listen to this event
12
+ insert into public.webhook_queue (webhook_id, event_type, payload, next_retry_at)
13
+ select
14
+ id,
15
+ p_event_type,
16
+ p_payload,
17
+ now()
18
+ from public.webhooks
19
+ where is_active = true
20
+ and p_event_type = any(events);
21
+ end;
22
+ $$;
23
+
24
+ -- Grant execute permissions
25
+ grant execute on function public.enqueue_webhook_event(text, jsonb) to authenticated;
26
+ grant execute on function public.enqueue_webhook_event(text, jsonb) to service_role;
27
+ grant execute on function public.enqueue_webhook_event(text, jsonb) to anon;
28
+
29
+ -- Update triggers to use fully qualified name
30
+
31
+ -- Trigger function for contact CRUD events
32
+ create or replace function public.trigger_contact_webhooks()
33
+ returns trigger
34
+ language plpgsql
35
+ security definer
36
+ set search_path = public
37
+ as $$
38
+ declare
39
+ event_type text;
40
+ payload jsonb;
41
+ begin
42
+ if (TG_OP = 'INSERT') then
43
+ event_type := 'contact.created';
44
+ payload := to_jsonb(NEW);
45
+ elsif (TG_OP = 'UPDATE') then
46
+ event_type := 'contact.updated';
47
+ payload := jsonb_build_object('old', to_jsonb(OLD), 'new', to_jsonb(NEW));
48
+ elsif (TG_OP = 'DELETE') then
49
+ event_type := 'contact.deleted';
50
+ payload := to_jsonb(OLD);
51
+ end if;
52
+
53
+ perform public.enqueue_webhook_event(event_type, payload);
54
+
55
+ if (TG_OP = 'DELETE') then
56
+ return OLD;
57
+ else
58
+ return NEW;
59
+ end if;
60
+ end;
61
+ $$;
62
+
63
+ -- Trigger function for company CRUD events
64
+ create or replace function public.trigger_company_webhooks()
65
+ returns trigger
66
+ language plpgsql
67
+ security definer
68
+ set search_path = public
69
+ as $$
70
+ declare
71
+ event_type text;
72
+ payload jsonb;
73
+ begin
74
+ if (TG_OP = 'INSERT') then
75
+ event_type := 'company.created';
76
+ payload := to_jsonb(NEW);
77
+ elsif (TG_OP = 'UPDATE') then
78
+ event_type := 'company.updated';
79
+ payload := jsonb_build_object('old', to_jsonb(OLD), 'new', to_jsonb(NEW));
80
+ elsif (TG_OP = 'DELETE') then
81
+ event_type := 'company.deleted';
82
+ payload := to_jsonb(OLD);
83
+ end if;
84
+
85
+ perform public.enqueue_webhook_event(event_type, payload);
86
+
87
+ if (TG_OP = 'DELETE') then
88
+ return OLD;
89
+ else
90
+ return NEW;
91
+ end if;
92
+ end;
93
+ $$;
94
+
95
+ -- Trigger function for deal CRUD and stage change events
96
+ create or replace function public.trigger_deal_webhooks()
97
+ returns trigger
98
+ language plpgsql
99
+ security definer
100
+ set search_path = public
101
+ as $$
102
+ declare
103
+ event_type text;
104
+ payload jsonb;
105
+ begin
106
+ if (TG_OP = 'INSERT') then
107
+ event_type := 'deal.created';
108
+ payload := to_jsonb(NEW);
109
+ perform public.enqueue_webhook_event(event_type, payload);
110
+ elsif (TG_OP = 'UPDATE') then
111
+ -- Check for stage changes
112
+ if (OLD.stage <> NEW.stage) then
113
+ event_type := 'deal.stage_changed';
114
+ payload := jsonb_build_object(
115
+ 'deal_id', NEW.id,
116
+ 'old_stage', OLD.stage,
117
+ 'new_stage', NEW.stage,
118
+ 'deal', to_jsonb(NEW)
119
+ );
120
+ perform public.enqueue_webhook_event(event_type, payload);
121
+
122
+ -- Check for won/lost
123
+ if (NEW.stage = 'won') then
124
+ perform public.enqueue_webhook_event('deal.won', to_jsonb(NEW));
125
+ elsif (NEW.stage = 'lost') then
126
+ perform public.enqueue_webhook_event('deal.lost', to_jsonb(NEW));
127
+ end if;
128
+ end if;
129
+
130
+ event_type := 'deal.updated';
131
+ payload := jsonb_build_object('old', to_jsonb(OLD), 'new', to_jsonb(NEW));
132
+ perform public.enqueue_webhook_event(event_type, payload);
133
+ elsif (TG_OP = 'DELETE') then
134
+ event_type := 'deal.deleted';
135
+ payload := to_jsonb(OLD);
136
+ perform public.enqueue_webhook_event(event_type, payload);
137
+ end if;
138
+
139
+ if (TG_OP = 'DELETE') then
140
+ return OLD;
141
+ else
142
+ return NEW;
143
+ end if;
144
+ end;
145
+ $$;
146
+
147
+ -- Trigger function for task completion
148
+ create or replace function public.trigger_task_webhooks()
149
+ returns trigger
150
+ language plpgsql
151
+ security definer
152
+ set search_path = public
153
+ as $$
154
+ begin
155
+ if (TG_OP = 'UPDATE' and OLD.done_date is null and NEW.done_date is not null) then
156
+ perform public.enqueue_webhook_event('task.completed', to_jsonb(NEW));
157
+ end if;
158
+
159
+ return NEW;
160
+ end;
161
+ $$;
162
+
163
+ -- Reload schema cache
164
+ NOTIFY pgrst, 'reload schema';