Banco de Dados — Schema Completo (Supabase / PostgreSQL)¶
Visão Geral¶
O Vox AI usa o Supabase como backend de dados completo. O banco é PostgreSQL 17 com:
- 7 tabelas
- 3 funções customizadas (incluindo 2 usadas como triggers)
- 3 triggers ativas
- 7 índices de performance (incluindo 1 HNSW para busca vetorial)
- 6 constraints de chave estrangeira
- RLS (Row Level Security) habilitada em todas as tabelas
- 5 extensões ativas
Esta seção foi gerada diretamente a partir do dump do schema SQL do banco de produção.
Extensões Ativas¶
| Extensão | Schema | Finalidade |
|---|---|---|
| vector | public | Adiciona o tipo vector, o operador de distância coseno (<=>), funções de similaridade e suporte a índices HNSW. É o núcleo do sistema RAG. |
| pg_graphql | graphql | Expoe o schema do banco como uma API GraphQL automaticamente. Usado pelo Supabase Studio. |
| pg_stat_statements | extensions | Coleta estatísticas de execução de queries SQL (tempo, chamadas, rows). Útil para profiling e otimização. |
| pgcrypto | extensions | Funções criptográficas (hash, UUID, criptografia simetrica). Usada internamente pelo Supabase Auth. |
| supabase_vault | vault | Cofre seguro para armazenar segredos (API keys, tokens) diretamente no banco, criptografados. |
| uuid-ossp | extensions | Gera UUIDs v1, v3, v4 e v5 via SQL. Usada para geração de IDs únicos em contextos SQL puros. |
Tabelas¶
knowledge_base — Base de Conhecimento¶
A tabela mais importante do sistema. Cada linha representa um "chunk" de conhecimento curado pela equipe. E aqui que o RAG busca as informações para embasar as respostas da IA.
| Coluna | Tipo SQL | Nullable | Default | Descrição |
|---|---|---|---|---|
kb_id |
text | NOT NULL | 'vox-kb-' \|\| lpad(nextval('kb_id_seq'),4,'0') |
PK. ID legivel gerado automaticamente (ex: vox-kb-0001). Usa a sequence kb_id_seq compartilhada com a tabela ETL. |
topico |
text | NULL | — | Nome do tópico macro (ex: "PrEP"). Indexado (idx_kb_topico). |
eixo_tematico |
text | NULL | — | Eixo temático superior (ex: "Saúde"). Indexado (idx_kb_eixo). |
descricao |
text | NOT NULL | — | O texto do conhecimento em si. É este campo que é convertido em vetor e recuperado pelo RAG. |
referencias |
text | NULL | — | Fontes e referências bibliográficas do conhecimento. |
tags |
text[] | NULL | — | Array de tags para categorização auxiliar. |
autor |
text | NULL | — | Responsável pela inserção do chunk. |
created_at |
timestamptz | NULL | now() |
Data de criação do registro. |
kb_count |
numeric | NULL | — | Contador de quantas vezes o chunk foi recuperado. Incrementado automaticamente pela trigger tg_update_kb_usage. |
embedding |
vector(1536) | NULL | — | Vetor semântico de 1536 dimensões. Indexado com HNSW (idx_kb_embedding). Gerado pelo modelo gemini-embedding-001. |
modificado_em |
timestamptz | NULL | now() |
Data da última modificação. Atualizado automaticamente pela trigger update_kb_modificado_em. |
Nota: O
kb_ide gerado automaticamente pelo banco usando a expressãoDEFAULT. A sequencekb_id_seqé compartilhada entreknowledge_baseeknowledge_base_etl, o que garante que os IDs são únicos globalmente entre as duas tabelas.
knowledge_base_etl — Tabela de Staging (ETL)¶
Tabela de staging com estrutura identica a knowledge_base, mas com a coluna embedding sem dimensão fixa (aceita qualquer tamanho de vetor). Usada para importar, processar e validar novos dados da curadoria antes de promove-los para a tabela principal. Possui os mesmos triggers de modificado_em.
Diferenca em relacao a knowledge_base |
Detalhe |
|---|---|
Coluna embedding |
vector sem dimensão fixa — aceita qualquer tamanho de vetor |
| Sem índice HNSW | Não há idx_kb_embedding nesta tabela (dados ainda não são buscados) |
Sequence kb_id_seq compartilhada |
O ID gerado aqui tambem consome da mesma sequence da knowledge_base |
Nota: Pense no
knowledge_base_etlcomo uma "fila de aprovação": novos chunks entram aqui, são validados pela curadoria e depois movidos (INSERT + DELETE) para aknowledge_base, momento em que o embedding com dimensão correta é gerado.
sessions¶
| Coluna | Tipo SQL | Descrição |
|---|---|---|
session_id |
text (PK) | UUID anônimo gerado pelo front-end via uuid.uuid4(). Identifica a sessão do usuário. |
id |
bigint (UNIQUE, IDENTITY) | ID numérico auto-incremental interno. Gerado BY DEFAULT AS IDENTITY. |
created_at |
timestamptz | Momento de criação da sessão. DEFAULT now(). |
Nota: A tabela
sessionsé a âncora de integridade referencial do banco. As tabelaschat_logs,error_logseuser_reportstem FK parasessions.session_idcomON DELETE RESTRICT, ou seja, uma sessão só pode ser deletada se não houver registros dependentes.
chat_logs¶
| Coluna | Tipo SQL | Descrição |
|---|---|---|
chat_id |
bigint (PK, IDENTITY) | ID auto-incremental gerado BY DEFAULT AS IDENTITY. |
session_id |
text (FK -> sessions) | Referencia a sessão. ON DELETE RESTRICT. |
prompt |
text | Pergunta enviada pelo usuário. |
response |
text | Resposta gerada pelo Vox AI. |
git_version |
text | Versão do software no momento da conversa (para rastrear bugs em releases). |
created_at |
timestamptz | Data e hora da interação. DEFAULT now(). |
chat_logs_kb — Pivot de Auditoria RAG¶
Tabela fundamental para auditabilidade. Conecta cada resposta da IA (chat_logs) com os fragmentos exatos de conhecimento (knowledge_base) que foram usados para gerá-la. Permite rastrear a origem de possíveis alucinações e medir a utilidade de cada chunk.
| Coluna | Tipo SQL | Descrição |
|---|---|---|
chat_log_kb_id |
bigint (PK, UNIQUE, IDENTITY) | ID auto-incremental gerado BY DEFAULT AS IDENTITY. |
chat_id |
bigint (FK -> chat_logs) | Referencia ao log de chat. ON UPDATE CASCADE. |
kb_id |
text (FK -> knowledge_base) | Referencia ao chunk usado. ON UPDATE CASCADE. |
similarity |
double precision | Score de similaridade cosseno (0 a 1). Pode ser NULL quando a Estratégia de Contexto Expandido e usada (busca direta por tópico, sem score de similaridade). |
created_at |
timestamptz | Data do registro. DEFAULT now(). |
Nota: O INSERT nesta tabela aciona automaticamente o trigger
tg_update_kb_usage, que chamaincrement_kb_count()e incrementakb_countnaknowledge_base. Isso cria um sistema automático de métricas de utilidade dos chunks sem nenhuma lógica extra no Python.
user_reports¶
| Coluna | Tipo SQL | Descrição |
|---|---|---|
id |
bigint (PK, IDENTITY) | ID auto-incremental gerado ALWAYS AS IDENTITY. |
session_id |
text (FK -> sessions) | Sessão que originou o report. ON DELETE RESTRICT. |
category_id |
bigint (FK -> report_categories) | Categoria da denuncia. ON UPDATE CASCADE. |
comment |
text | Comentário textual do usuário descrevendo o problema. |
chat_history |
text | Histórico completo da conversa no momento do report (JSON serializado como string). |
git_version |
text | Versão do software para correlacionar com releases. |
created_at |
timestamptz | Data do report. DEFAULT now(). |
report_categories¶
Tabela de referencia com as categorias disponíveis para classificar um report. Possui COMMENT no schema: "Tags para o erro que o usuário deseja reportar."
| Coluna | Tipo SQL | Descrição |
|---|---|---|
id |
integer (PK, SERIAL) | ID auto-incremental via sequence report_categories_id_seq. |
label |
text | Nome da categoria exibido ao usuário (ex: "Alucinacao", "Conteúdo Ofensivo"). |
description |
text | Descrição detalhada do que se enquadra nessa categoria. |
created_at |
timestamptz | Data de criação. DEFAULT now(). |
error_logs¶
| Coluna | Tipo SQL | Descrição |
|---|---|---|
id |
bigint (PK, IDENTITY) | ID auto-incremental gerado ALWAYS AS IDENTITY. |
error_id |
text | Hash curto de 8 caracteres gerado por uuid4()[:8]. Exibido ao usuário para facilitar o reporte a equipe. |
error_message |
text | Mensagem de erro completa capturada pelo bloco except. |
session_id |
text (FK -> sessions) | Sessão onde o erro ocorreu. ON DELETE RESTRICT. |
git_version |
text | Versão do software onde o erro foi detectado. |
created_at |
timestamptz | Data e hora do erro. DEFAULT now(). |
Funções PostgreSQL¶
match_knowledge_base() — Busca Vetorial RPC¶
A função mais crítica do sistema. Executa a busca vetorial por similaridade de cosseno usando o operador <=> do pgvector. E exposta como RPC pelo Supabase e chamada pelo Python via client.rpc().
CREATE OR REPLACE FUNCTION public.match_knowledge_base(
query_embedding vector, -- vetor de 1536 dimensões
match_threshold double precision, -- similaridade mínima (ex: 0.5)
match_count integer, -- máximo de resultados (ex: 10)
filter_topic text DEFAULT NULL -- filtro opcional por tópico
) RETURNS TABLE (
id text, topico text, eixo_tematico text, descrição text, similarity double precision
)
-- Fórmula da similaridade coseno:
-- similarity = 1 - (embedding <=> query_embedding)
-- Onde <=> e o operador de distância coseno do pgvector.
-- Quanto menor a distância, maior a similaridade.
-- Resultados ordenados pela distância (ASC) = maior similaridade primeiro.
Nota: O operador
<=>calcula a distância coseno entre dois vetores. A formula1 - distânciaconverte isso em um score de similaridade entre 0 e 1, onde 1 significa idêntico e 0 significa completamente diferente. O threshold de 0.5 descarta resultados com mais de 50% de diferença semântica.
increment_kb_count() — Trigger Function¶
Função chamada automaticamente pelo trigger tg_update_kb_usage após cada INSERT na tabela chat_logs_kb. Incrementa o campo kb_count na knowledge_base para o kb_id recém-inserido.
CREATE OR REPLACE FUNCTION public.increment_kb_count()
RETURNS trigger LANGUAGE plpgsql AS $$
begin
UPDATE knowledge_base
set kb_count = kb_count + 1
where kb_id = new.kb_id;
return new;
end
$$;
update_modificado_em() — Trigger Function¶
Função chamada automaticamente pelos triggers update_kb_modificado_em e update_kb_etl_modificado_em antes de qualquer UPDATE nas tabelas knowledge_base e knowledge_base_etl. Garante que o campo modificado_em seja sempre atualizado para o timestamp atual.
CREATE OR REPLACE FUNCTION public.update_modificado_em()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
NEW.modificado_em = now();
RETURN NEW;
END;
$$;
Nota: Este campo e utilizado pelo
dashboard.jspara calcular a "versão" da base de conhecimento. Formato:v{ano}.{mes}.{dia}baseado na data da última modificação.
Triggers¶
| Nome do Trigger | Tabela | Evento | Momento | Função Chamada | Descrição |
|---|---|---|---|---|---|
tg_update_kb_usage |
chat_logs_kb | INSERT | AFTER | increment_kb_count() |
Incrementa kb_count no chunk da KB sempre que ele é registrado como utilizado em uma resposta. |
update_kb_modificado_em |
knowledge_base | UPDATE | BEFORE | update_modificado_em() |
Atualiza o timestamp modificado_em automaticamente em qualquer UPDATE na KB. |
update_kb_etl_modificado_em |
knowledge_base_etl | UPDATE | BEFORE | update_modificado_em() |
Mesma função, aplicada a tabela de staging ETL. |
Índices¶
| Nome | Tabela | Tipo | Coluna(s) | Finalidade |
|---|---|---|---|---|
idx_kb_embedding |
knowledge_base | HNSW | embedding (vector_cosine_ops) | Índice principal do RAG. Permite busca por vizinhos mais próximos (cosine) em milissegundos mesmo com milhares de chunks. |
idx_kb_topico |
knowledge_base | B-tree | tópico | Acelera a estratégia de Contexto Expandido (busca WHERE topico = ?). |
idx_kb_eixo |
knowledge_base | B-tree | eixo_temático | Acelera filtros por eixo temático. |
idx_chat_logs_session_id |
chat_logs | B-tree | session_id | Acelera a recuperação do historico de uma sessão específica. |
idx_chat_logs_kb_log |
chat_logs_kb | B-tree | chat_log_kb_id | Suporte a queries na tabela pivot de auditoria. |
idx_error_logs_session_id |
error_logs | B-tree | session_id | Acelera a busca de erros por sessão. |
idx_user_reports_session_id |
user_reports | B-tree | session_id | Acelera a busca de reports por sessão. |
Nota: O índice HNSW (Hierarchical Navigable Small World) é um algoritmo de busca aproximada de vizinhos mais próximos. Ele constroi um grafo hierárquico de nos conectados e permite navegar para o vizinho mais próximo em tempo sub-linear. É a escolha padrão para produção com
pgvector.
Foreign Keys e Integridade Referencial¶
| Constraint | De | Para | ON UPDATE | ON DELETE |
|---|---|---|---|---|
chat_log_kb_chat_id_fkey |
chat_logs_kb.chat_id | chat_logs.chat_id | CASCADE | — |
chat_log_kb_kb_id_fkey |
chat_logs_kb.kb_id | knowledge_base.kb_id | CASCADE | — |
chat_logs_session_id_fkey |
chat_logs.session_id | sessions.session_id | — | RESTRICT |
error_logs_session_id_fkey |
error_logs.session_id | sessions.session_id | — | RESTRICT |
user_reports_session_id_fkey |
user_reports.session_id | sessions.session_id | — | RESTRICT |
user_reports_category_id_fkey |
user_reports.category_id | report_categories.id | CASCADE | — |
Nota: O
ON DELETE RESTRICTna sessão significa que não e possivel deletar uma sessão diretamente enquanto houver registros dependentes. Para deletar uma sessão, é necessário primeiro deletar todos oschat_logs,error_logseuser_reportsassociados a ela.
Row Level Security (RLS)¶
RLS está habilitada em todas as tabelas do schema public. Por padrão, nenhum usuário pode ler ou escrever em nenhuma tabela sem uma policy explícita autorizando.
| Tabela | RLS | Policy Ativa | Detalhe |
|---|---|---|---|
| knowledge_base | Habilitada | 1 policy pública | FOR SELECT TO anon USING (true) — qualquer usuário anônimo pode ler a KB. Escrita requer service_role. |
| chat_logs | Habilitada | Nenhuma | Apenas service_role pode inserir (SDK Python do backend). |
| chat_logs_kb | Habilitada | Nenhuma | Apenas service_role pode inserir. |
| sessions | Habilitada | Nenhuma | Apenas service_role pode inserir. |
| user_reports | Habilitada | Nenhuma | Apenas service_role pode inserir. |
| error_logs | Habilitada | Nenhuma | Apenas service_role pode inserir. |
| report_categories | Habilitada | Nenhuma | Apenas service_role pode modificar. |
| knowledge_base_etl | Habilitada | Nenhuma | Uso interno pela equipe de curadoria. |
ATENÇÃO: A chave
anondo Supabase é segura de expor no frontend (Dashboard) porque as policies RLS garantem que mesmo com ela em mãos, um atacante so consegue fazerSELECTnaknowledge_base. Todas as operações de escrita exigem a chaveservice_role, que fica apenas no backend/CI.
Migrations¶
Migration 1: 20260410192141_remote_schema.sql¶
Schema inicial completo do banco. Cria toda a estrutura descrita nesta seção: extensões, sequences, tabelas, funções, triggers, índices, foreign keys, grants de permissão e RLS policies. E o estado base do banco antes de qualquer alteração posterior.
Migration 2: 20260418194905_alter_vetor_tamanho_1536_knowledge_base.sql¶
Necessária para mudar o modelo de embeddings de uma versão anterior (vetores de 768 dimensões) para o gemini-embedding-001 (1536 dimensões). Como o PostgreSQL não permite alterar a dimensão de uma coluna vector diretamente com dados, a migration faz o processo em duas etapas:
-- Passo 1: Zerar todos os embeddings existentes
UPDATE knowledge_base SET embedding = null WHERE embedding IS NOT NULL;
-- Passo 2: Alterar o tipo da coluna para o novo tamanho
ALTER TABLE public.knowledge_base
ALTER COLUMN embedding
SET DATA TYPE public.vector(1536)
USING embedding::public.vector(1536);
ATENÇÃO: Após esta migration, todos os registros tiveram seus embeddings zerados. Foi necessário rodar
scripts/gerar_embedding.pypara reindexar toda a base de conhecimento com os novos vetores de 1536 dimensões.
Sequences (Auto-increment)¶
| Sequence | Tipo | Usada por | Comportamento |
|---|---|---|---|
kb_id_seq |
SEQUENCE (bigint) | knowledge_base.kb_id e knowledge_base_etl.kb_id |
Compartilhada entre as duas tabelas. Gera o numero do ID legivel (ex: vox-kb-0001). Comeca em 1, incrementa 1. |
chat_log_kb_chat_log_kb_id_seq |
IDENTITY (bigint) | chat_logs_kb.chat_log_kb_id |
Gerenciada automaticamente pelo GENERATED BY DEFAULT AS IDENTITY. |
chat_logs_id_seq |
IDENTITY (bigint) | chat_logs.chat_id |
Idem. |
error_logs_id_seq |
IDENTITY (bigint) | error_logs.id |
GENERATED ALWAYS AS IDENTITY — não aceita valores manuais. |
report_categories_id_seq |
SEQUENCE (integer) | report_categories.id |
Sequence clássica linkada via OWNED BY. |
sessions_id_seq |
IDENTITY (bigint) | sessions.id |
GENERATED BY DEFAULT AS IDENTITY. |
user_reports_id_seq |
IDENTITY (bigint) | user_reports.id |
GENERATED ALWAYS AS IDENTITY. |