MÓDULO 2.2

🗄️ O banco de dados (Supabase)

Suba o esquema: rodar as migrations, conhecer as 14 tabelas, ligar o pgvector (memória), criar o bucket de fotos, trancar com RLS e testar a conexão. No fim deste módulo o banco está de pé e o coach já teria onde guardar tudo.

7
Tópicos
~35
Minutos
Intermediário
Nível
Prático
Tipo
Seu progresso neste módulo 0% · 0 de 7
1

🧱 Rodar as migrations

As migrations são arquivos .sql versionados em agent/supabase/migrations/ que descrevem o banco inteiro. Empurrá-las pro seu projeto Supabase cria, de uma vez, as 14 tabelas e liga a extensão pgvector — tudo pela primeira migration, a 0001_init.sql. Você não cria tabela na mão: o esquema vem pronto no blueprint.

🟢 Novo aqui?

  • Migration — um arquivo SQL numerado que aplica uma mudança no banco. Rodar todas, em ordem, reconstrói o esquema do zero em qualquer projeto.
  • Supabase CLI — a ferramenta de linha de comando do Supabase. Ela liga sua pasta local ao seu projeto na nuvem e empurra as migrations pra lá.
📁 migrations/ (.sql)0001_init · 0002_seed ⚙️ supabase CLIdb push ☁️ Postgres (nuvem)seu projeto privado 🗄️ 14 tabelas+ pgvector ligado um único `db push` reconstrói o banco inteiro — você nunca cria tabela na mão

📊 Como ler: da esquerda pra direita, os arquivos SQL viram o banco real. As caixas azuis com glow são onde a ação acontece (a CLI e o resultado); as cianas são origem e destino. O segredo é que o esquema mora em arquivo, não na sua memória.

🎯 Objetivo: ligar sua pasta ao projeto Supabase e empurrar as migrations (cria as 14 tabelas + pgvector).
# 1) na raiz do repo, ligue ao seu projeto (pede a senha do banco)
supabase link --project-ref <seu-project-ref>

# 2) empurre TODAS as migrations de agent/supabase/migrations/
supabase db push
✅ Como verificar: a CLI lista as migrations aplicadas (incluindo 0001_init.sql) sem erro. No painel do Supabase, em Table Editor, as 14 tabelas aparecem; em Database → Extensions, vector está habilitada.

💡 Onde vem a senha

O supabase link usa a SUPABASE_DB_PASSWORD que você guardou no ~/.env (Módulo 2.1). O <seu-project-ref> é o identificador do projeto — aparece na URL https://<ref>.supabase.co e em Settings.

Conceitos-chave

Migration

SQL numerado que reconstrói o esquema.

0001_init.sql

Cria as 14 tabelas e liga o pgvector.

db push

Um comando aplica tudo na nuvem.

Esquema em arquivo

Reproduzível em qualquer projeto.

2

📋 As 14 tabelas — visão geral

Cada coisa que você registra vira linha numa tabela. O esquema cobre as famílias de dados de saúde — comida, treino, peso, composição corporal, cafeína, suplementos, sinais vitais, exames, check-ins, metas e contexto — mais a memória semântica das mensagens. O diagrama mostra como as fontes alimentam as tabelas e como o coach lê de volta.

⌚ wearable 📷 fotos 💬 mensagens vitals food_log workouts weigh_ins lab_results goals · context messages (vector) …e mais: body_comp, caffeine, supplements, checkins, coach_summary (14 no total) 🤖 Coach lê o snapshot 💬 resposta com contexto

📊 Como ler: as fontes (ciano, à esquerda) escrevem nas tabelas (centro); o coach (azul) lê o snapshot dessas tabelas e responde. A tabela messages tem destaque porque é a única que guarda vetores (a memória semântica — Tópico 3).

food_log

Comida → macros + flags.

workouts

Treinos registrados.

weigh_ins

Pesagens (tendência).

body_comp

Composição corporal.

caffeine

Cafeína ao longo do dia.

supplements

Suplementos e horários.

vitals

PA, recovery, HRV, RHR, sono.

lab_results

Marcadores de sangue.

checkins

Check-ins diários.

goals

Suas metas.

context

Perfil e contexto fixo.

messages 🧲

Memória semântica (vetor).

Essas 12 famílias de dados + tabelas de apoio (como coach_summary, que guarda a recuperação e a sua causa) completam as 14 tabelas que a migration cria.

Conceitos-chave

Tudo é linha

Cada registro vira uma linha numa tabela.

Famílias

Uma tabela por tipo de dado.

Snapshot

O coach lê um resumo dessas tabelas.

messages

A única com vetores (memória).

3

🧲 pgvector — a memória

A migration 0001_init.sql liga o pgvector antes de criar as tabelas. É ele que dá ao banco a capacidade de guardar a memória semântica — buscar mensagens passadas por significado, não por palavra exata.

🟢 Novo aqui? O que é pgvector

pgvector é uma extensão do PostgreSQL que adiciona um tipo de coluna novo: vector. Cada mensagem vira um embedding (uma lista de números que representa o significado do texto). O pgvector compara esses vetores e acha o que é parecido em sentido — assim o coach "lembra" de quando você falou de sono, mesmo sem a palavra "sono" aparecer.

📝 texto"dormi mal de novo" 🔢 embedding[0.12, -0.7, …] 🧲 pgvectorguarda o vetor 🔎 similaridadeacha o parecido por isso o coach lembra de "sono ruim" mesmo quando você usa outras palavras

📊 Como ler: o texto vira números (embedding), o pgvector os guarda e depois compara por distância. Quanto mais perto dois vetores, mais parecido o significado — é assim que a memória recupera o passado relevante.

🔌 Você não liga na mão

Não precisa rodar nenhum comando extra: o create extension vector já está dentro da 0001_init.sql. Quando você fez o db push do Tópico 1, o pgvector já ficou ligado. Aqui é só entender por que ele existe.

Conceitos-chave

pgvector

Extensão que guarda vetores no Postgres.

Embedding

Números que representam o significado.

Similaridade

Acha o parecido por distância.

Já vem ligado

A 0001_init.sql faz isso por você.

4

🪣 O storage bucket de fotos

As tabelas guardam números e texto; as fotos (comida, exames, corpo) vão para um bucket de storage. O HealthOS usa um bucket chamado health-assets, criado por um único comando — e ele é privado.

🟢 Novo aqui?

Bucket — é uma "pasta" de armazenamento de arquivos no Supabase, separada das tabelas. Privado significa que ninguém acessa um arquivo pela URL pública; só o servidor, com a chave certa, gera um link temporário pra ler.

🎯 Objetivo: criar o bucket privado health-assets onde as fotos vão morar.
# um comando cria o bucket PRIVADO de fotos
python3 agent/scripts/db.py mkbucket health-assets
✅ Como verificar: no painel do Supabase, em Storage, o bucket health-assets aparece marcado como Private (não público). Rodar de novo é seguro — não duplica.

✓ Bucket privado (o certo)

  • Fotos de saúde não vazam por URL pública.
  • O servidor gera links temporários quando precisa.
  • É o padrão que o mkbucket já aplica.

✗ Bucket público (não faça)

  • Qualquer um com a URL veria a foto do seu exame.
  • Dado de saúde sensível exposto à internet.
  • Não dá pra "despublicar" o que já vazou.

Conceitos-chave

Bucket

Storage de arquivos, fora das tabelas.

health-assets

O bucket de fotos do HealthOS.

Privado

Sem URL pública; só o servidor lê.

mkbucket

Um comando cria tudo certo.

5

🔒 RLS — trancar o banco

O esquema liga a RLS (Row-Level Security) em toda tabela e não cria nenhuma política. O efeito é radical e simples: a chave pública (anon) não lê nada; só o servidor, com a chave service-role, atravessa. É a tranca padrão do HealthOS.

🟢 Novo aqui? Duas chaves, dois mundos

  • RLS — recurso do Postgres que decide, linha a linha, quem pode ler/escrever. Sem política liberando, o padrão é negar.
  • service-role — a chave do servidor. Ela bypassa a RLS (passa por cima), então o agente lê e escreve normalmente. Vive só no ~/.env, nunca no navegador.
  • anon — a chave pública, segura de expor. Com RLS ligada e zero políticas, ela não lê nada.
🔑 service-roleservidor (no ~/.env) 🌐 anon (pública)navegador / fora 🔒 RLS sem políticas 🗄️ 14 tabelasseus dados bypassa → passa ✓ anon é barrada na RLS → não lê nada ✗

📊 Como ler: as duas chaves chegam na mesma porta (a RLS). A service-role (verde) passa por cima e chega às tabelas; a anon (vermelho, tracejado) bate no X e volta. Por isso a chave pública é segura de expor.

✓ service-role (servidor)

  • Lê e escreve em todas as tabelas.
  • Bypassa a RLS (passa por cima).
  • Fica só no ~/.env, no servidor.

✗ anon (pública)

  • Não lê nenhuma linha (RLS sem política).
  • Não escreve nada.
  • Por isso é segura de expor se precisar.

Conceitos-chave

RLS

Ligada em tudo, sem políticas = nega.

service-role

A chave do servidor bypassa a RLS.

anon

A chave pública não lê nada.

Tranca padrão

Privado por desenho, sem configurar.

6

🔌 Testar a conexão

Antes de seguir pro agente, prove que o servidor fala com o banco. O db.py é o utilitário de banco do HealthOS; um select simples confirma que as chaves do ~/.env estão certas e que a RLS deixa o servidor passar.

🎯 Objetivo: confirmar que o servidor conecta e lê uma tabela real (goals).
# lê as linhas da tabela goals usando a chave service-role do ~/.env
python3 agent/scripts/db.py select goals
✅ Como verificar: ele imprime as suas linhas de goals (ou uma lista vazia [] se você ainda não trocou o seed). Sem erro de conexão/autenticação = chaves e RLS OK. Troque goals por <outra-tabela> pra inspecionar qualquer uma das 14.

🧪 Se der erro

  • Falha de autenticação? A SUPABASE_SERVICE_ROLE_KEY ou a SUPABASE_URL no ~/.env está errada.
  • Tabela não existe? O db push do Tópico 1 não rodou completo — refaça.
  • Lista vazia? Isso é sucesso de conexão — só falta o seed (Tópico 7).

✅ Auto-checagem (opcional): por que o db.py select goals consegue ler, se a RLS está ligada?

Conceitos-chave

db.py

O utilitário de banco do HealthOS.

select goals

Teste mínimo de conexão.

Lê = OK

Chaves e RLS funcionando.

[] também é OK

Conexão certa, só falta o seed.

7

🌱 Seed e dados sensíveis

A migration 0002_seed_example.sql planta um seed de exemplo (genérico, sem dados reais) só pra você ver o formato. O passo final é trocar esse exemplo pelas suas metas e contexto — e manter o seu seed real e o seu CLAUDE.md fora do git.

🟢 Novo aqui?

  • Seed — dados iniciais que "semeiam" o banco. O exemplo é genérico; o seu, real, vai nas tabelas goals e context.
  • Fora do git — o repositório é o blueprint limpo. Seus valores reais ficam só na sua máquina/banco; entram no .gitignore e nunca são versionados.

✓ Pode versionar

  • As migrations do esquema (0001_init.sql).
  • O 0002_seed_example.sql genérico.
  • O CLAUDE.md modelo (em branco).

✗ Nunca versionar

  • O seu seed real (goals + context preenchidos).
  • O seu CLAUDE.md com perfil real.
  • O ~/.env e as suas fotos.

⚠️ Dado de saúde é sensível

Um seed real commitado é um vazamento permanente — o histórico do git guarda tudo. Antes de qualquer git add, confirme que goals/context reais, CLAUDE.md preenchido e ~/.env estão no .gitignore. O repositório público deve permanecer o blueprint scrubbed, sem nenhuma informação pessoal.

Conceitos-chave

Seed

Dados iniciais do banco.

Exemplo → seu

Troque 0002 pelas suas metas+context.

Fora do git

Seed real e CLAUDE.md não versionam.

Blueprint limpo

O repo público não tem dado pessoal.

📋 Resumo do módulo

Migrations num comandosupabase db push cria as 14 tabelas e liga o pgvector (0001_init.sql).
14 tabelas, uma por família — comida, treino, peso, vitais, exames, metas, contexto… + a memória semântica em messages.
pgvector é a memória — guarda embeddings e busca por significado; já vem ligado pela migration.
Bucket privado + RLS — fotos em health-assets fechado; RLS ligada sem políticas: só o service-role passa.
Conexão testada e seed seudb.py select goals confirma tudo; seed real e CLAUDE.md ficam fora do git.

Próximo módulo:

2.3 — O agente e o bot: dar vida ao coach no Telegram, conectar o agente ao banco que você acabou de montar e responder à primeira mensagem.