Pular para o conteúdo

Database Documentation

AtributoValor
Project refosytjlchrelbuphsvfax
Regiaosa-east-1 (Sao Paulo)
PlanPro
PostgreSQL15.x
URL basehttps://osytjlchrelbuphsvfax.supabase.co

  • Toda tabela usa id uuid PRIMARY KEY DEFAULT gen_random_uuid() como chave primaria.
  • FKs seguem o padrão tabela_referênciada_id (ex: account_id, contact_id).
  • Colunas booleanas usam prefixo is_ (ex: is_active, is_dynamic).
  • created_at timestamptz NOT NULL DEFAULT now() — presente em todas as tabelas.
  • updated_at timestamptz NOT NULL DEFAULT now() — tabelas editaveis via trigger.
  • deleted_at timestamptz DEFAULT NULL — soft-delete em 4 tabelas críticas.
  • Toda tabela de dados de usuário tem account_id uuid NOT NULL REFERENCES accounts(id).
  • Tabelas filhas (sem account_id direto) usam RLS via EXISTS subquery para o parent.
  • Excecoes: contact_tags, webhook_logs, automation_steps, campaign_sends, automation_execution_steps, segment_members.
  • Moeda/valores: DECIMAL(12,2) ou DECIMAL(15,2) — nunca float.
  • Texto curto com opções fixas: text com CHECK (col IN (...)) — sem ENUM (exceto shipment_tracking_status).
  • Payloads flexiveis: jsonb com default '{}' ou '[]'.
  • Arrays fixos: text[] (ex: events, scopes).
  • Telefones: formato E.164 (+[1-9][0-9]{1,14}) com constraint CHECK.

ExtensaoFinalidade
pg_trgmTrigram indexes para busca fuzzy/ILIKE em contacts.name
pg_cronCron jobs diretamente no banco
pg_netHTTP requests assíncronos (não usado ativamente)
pgmqMessage queue (habilitado, não em uso ativo)

RLS é habilitado em todas as tabelas do schema public. Existem dois padroes:

Para tabelas que tem account_id na própria tabela:

USING (account_id IN (SELECT get_user_account_ids()))

Para tabelas sem account_id, que dependem de uma tabela parent:

USING (EXISTS (
SELECT 1 FROM parent_table
WHERE parent_table.id = child_table.parent_id
AND parent_table.account_id IN (SELECT get_user_account_ids())
))
-- Retorna todos os account_ids do usuário autenticado (multi-conta)
get_user_account_ids() RETURNS SETOF uuid
-- Retorna um account_id único (legado, single-account)
get_user_account_id() RETURNS uuid

O projeto usa um BaseRepository<T> genérico em TypeScript localizado em: src/lib/repositories/base.ts

Métodos disponíveis:

MétodoDescrição
findById(id, accountId?)Busca por PK, opcionalmente scoped por account
findAll(accountId, págination, filters?)Listagem páginada (offset-based) com filtros
findAllCursor(accountId, opts)Listagem cursor-based (mais eficiente para grandes volumes)
create(accountId, input)INSERT com account_id automático
update(id, accountId, input)UPDATE scoped por account
delete(id, accountId)DELETE fisico scoped por account
softDelete(id, accountId)SET deleted_at = now()
count(accountId, filters?)Contagem com filtros

Páginação:

  • Offset-based (findAll): padrão para listagens com total de páginas. Ineficiente acima de ~10k rows por conta.
  • Cursor-based (findAllCursor): para feeds e timelines. Usa gt/lt no campo orderBy.

  • message_stats(p_account_id) — totais (sent, received, delivered, read)
  • message_stats_by_day(p_account_id, p_days_back) — métricas diarias com dias vazios preenchidos
  • delivery_funnel(p_account_id) — funil sent -> delivered -> read
  • campaign_stats_agg(p_campaign_id) — stats agregadas de campanha
  • revenue_overview(account, start, end) — receita total e atribuida
  • revenue_by_day(account, start, end) — receita diaria
  • revenue_by_automation(account, start, end) — receita por automação
  • revenue_by_campaign(account, start, end) — receita por campanha
  • revenue_with_costs(account, start, end) — receita com COGS, fees, ad spend, ROAS
  • revenue_by_link(account, start, end, limit) — receita por link rastreado
  • conversion_funnel_basic(account, start, end) — funil clicks -> orders
  • contact_event_timeline(contact_id, limit, cursor, metric_names) — timeline páginada por cursor
  • metric_counts(account_id, start, end) — contagem por métrica para dashboard
  • compute_rfm_scores(p_account_id) — calcula scores RFM de todos os contatos
  • rfm_distribution(p_account_id) — distribuição de segmentos RFM
  • link_stats_overview(account, from, to) — overview de links criados e cliques
  • top_tracked_links(account, from, to, limit) — ranking de links por cliques
  • tracking_status_counts(account_id) — contagem de rastreamentos por status
  • toggle_automation_active(automation_id) — alterna is_active
  • replace_automation_steps(automation_id, steps) — substitui todos os steps atomicamente
  • get_automation_execution_stats(automation_id) — stats de execução
  • evaluate_contact_filters(contact_id, conditions) — avalia se contato passa nos filtros
  • recalculate_segment(segment_id) — recalcula membros de um segmento
  • get_folder_tree(account_id, entity_type?) — arvore recursiva de pastas
  • seed_system_metrics(account_id) — cria métricas sistema para uma nova conta

JobScheduleComando
recalculate_all_segments*/5 * * * * (a cada 5 min)Recalcula todos os segmentos dinâmicos
execute-scheduled-campaigns* * * * * (a cada 1 min)Transita campanhas de scheduled para sending

BucketAcessoLimiteTipos permitidos
template-mediaUpload autenticado, leitura pública100MBimage/jpeg, image/png, image/webp, video/mp4, application/pdf

TriggerTabelaEventoFunção
on_auth_user_createdauth.usersAFTER INSERThandle_new_user() — cria account + account_user
trg_update_contact_metrics_summaryeventsAFTER INSERTupdate_contact_metrics_summary() — atualiza contadores
accounts_updated_ataccountsBEFORE UPDATEupdate_updated_at_column()
message_templates_updated_atmessage_templatesBEFORE UPDATEupdate_updated_at_column()
brand_context_updated_atbrand_contextBEFORE UPDATEupdate_updated_at_column()
quick_replies_updated_atquick_repliesBEFORE UPDATEupdate_updated_at_column()
billing_subscriptions_updated_atbilling_subscriptionsBEFORE UPDATEupdate_updated_at_column()
set_updated_at_segmentssegmentsBEFORE UPDATEupdate_updated_at_column()
set_updated_at_ecommerce_integrationsecommerce_integrationsBEFORE UPDATEupdate_updated_at_column()
set_updated_at_ecommerce_ordersecommerce_ordersBEFORE UPDATEupdate_updated_at_column()
set_updated_at_ecommerce_cartsecommerce_abandoned_cartsBEFORE UPDATEupdate_updated_at_column()
set_updated_at_contact_rfm_scorescontact_rfm_scoresBEFORE UPDATEupdate_updated_at_column()
trg_shipment_tracking_updated_atshipment_trackingsBEFORE UPDATEupdate_shipment_tracking_updated_at()
trg_tracking_settings_updated_attracking_settingsBEFORE UPDATEupdate_shipment_tracking_updated_at()
set_tracked_links_updated_attracked_linksBEFORE UPDATEupdate_updated_at_column()
set_updated_at_ad_spendad_spendBEFORE UPDATEupdate_updated_at_column()

Tabelas com alto volume de INSERT/UPDATE tem autovacuum acelerado:

  • events: scale_factor=0.05, analyze_scale_factor=0.02
  • contact_metrics_summary: mesmas configurações

  • schema — Schema completo de todas as tabelas, agrupadas por domínio