Sync Superhuman Docs seguimiento/KPI pages into the portal (never passwords) and show clients a dynamic timeline plus per-channel kpi_weekly charts. Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
2.8 KiB
SQL
88 lines
2.8 KiB
SQL
-- Seguimiento: Superhuman Docs timeline + integration slot
|
|
-- Idempotent. Never stores passwords.
|
|
|
|
alter table public.integrations drop constraint if exists integrations_provider_check;
|
|
alter table public.integrations
|
|
add constraint integrations_provider_check
|
|
check (provider in (
|
|
'meta_ads',
|
|
'google_ads',
|
|
'ga4',
|
|
'search_console',
|
|
'tag_manager',
|
|
'clientify',
|
|
'klaviyo',
|
|
'mailchimp',
|
|
'google_drive',
|
|
'wordpress',
|
|
'prestashop',
|
|
'shopify',
|
|
'instagram',
|
|
'facebook',
|
|
'tiktok',
|
|
'linkedin',
|
|
'superhuman_docs'
|
|
));
|
|
|
|
insert into public.integrations (tenant_id, provider, status, label)
|
|
select t.id, 'superhuman_docs', 'disconnected', 'Superhuman Docs'
|
|
from public.tenants t
|
|
on conflict (tenant_id, provider) do nothing;
|
|
|
|
create table if not exists public.seguimiento_entries (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
source text not null default 'superhuman'
|
|
check (source in ('superhuman', 'manual')),
|
|
entry_type text not null default 'topic'
|
|
check (entry_type in ('meeting', 'topic', 'kpis', 'note')),
|
|
external_id text not null,
|
|
title text not null,
|
|
summary text,
|
|
body_md text,
|
|
browser_link text,
|
|
metrics jsonb not null default '{}'::jsonb,
|
|
occurred_at timestamptz,
|
|
synced_at timestamptz not null default now(),
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, source, external_id)
|
|
);
|
|
|
|
create index if not exists seguimiento_entries_tenant_occurred_idx
|
|
on public.seguimiento_entries (tenant_id, occurred_at desc nulls last);
|
|
|
|
create index if not exists seguimiento_entries_tenant_synced_idx
|
|
on public.seguimiento_entries (tenant_id, synced_at desc);
|
|
|
|
alter table public.seguimiento_entries enable row level security;
|
|
|
|
drop policy if exists seguimiento_entries_tenant_select on public.seguimiento_entries;
|
|
drop policy if exists seguimiento_entries_tenant_write on public.seguimiento_entries;
|
|
|
|
create policy seguimiento_entries_tenant_select on public.seguimiento_entries
|
|
for select using (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
-- Clients read-only via RLS; agency writes with service role.
|
|
create policy seguimiento_entries_tenant_write on public.seguimiento_entries
|
|
for all using (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
)
|
|
with check (
|
|
tenant_id::text = coalesce(
|
|
auth.jwt() -> 'app_metadata' ->> 'tenant_id',
|
|
auth.jwt() -> 'user_metadata' ->> 'tenant_id'
|
|
)
|
|
);
|
|
|
|
comment on table public.seguimiento_entries is
|
|
'Client-facing seguimiento timeline (Superhuman Docs). No passwords.';
|