🧱 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á.
📊 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.
# 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
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
SQL numerado que reconstrói o esquema.
Cria as 14 tabelas e liga o pgvector.
Um comando aplica tudo na nuvem.
Reproduzível em qualquer projeto.
📋 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.
📊 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).
Comida → macros + flags.
Treinos registrados.
Pesagens (tendência).
Composição corporal.
Cafeína ao longo do dia.
Suplementos e horários.
PA, recovery, HRV, RHR, sono.
Marcadores de sangue.
Check-ins diários.
Suas metas.
Perfil e contexto fixo.
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
Cada registro vira uma linha numa tabela.
Uma tabela por tipo de dado.
O coach lê um resumo dessas tabelas.
A única com vetores (memória).
🧲 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.
📊 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
Extensão que guarda vetores no Postgres.
Números que representam o significado.
Acha o parecido por distância.
A 0001_init.sql faz isso por você.
🪣 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.
health-assets onde as fotos vão morar.# um comando cria o bucket PRIVADO de fotos
python3 agent/scripts/db.py mkbucket health-assets
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
mkbucketjá 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
Storage de arquivos, fora das tabelas.
O bucket de fotos do HealthOS.
Sem URL pública; só o servidor lê.
Um comando cria tudo certo.
🔒 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.
📊 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
Ligada em tudo, sem políticas = nega.
A chave do servidor bypassa a RLS.
A chave pública não lê nada.
Privado por desenho, sem configurar.
🔌 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.
goals).# lê as linhas da tabela goals usando a chave service-role do ~/.env
python3 agent/scripts/db.py select goals
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_KEYou aSUPABASE_URLno~/.envestá errada. - •Tabela não existe? O
db pushdo 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
O utilitário de banco do HealthOS.
Teste mínimo de conexão.
Chaves e RLS funcionando.
Conexão certa, só falta o seed.
🌱 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
goalsecontext. - Fora do git — o repositório é o blueprint limpo. Seus valores reais ficam só na sua máquina/banco; entram no
.gitignoree nunca são versionados.
✓ Pode versionar
- ✓As migrations do esquema (
0001_init.sql). - ✓O
0002_seed_example.sqlgenérico. - ✓O
CLAUDE.mdmodelo (em branco).
✗ Nunca versionar
- ✗O seu seed real (goals + context preenchidos).
- ✗O seu
CLAUDE.mdcom perfil real. - ✗O
~/.enve 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
Dados iniciais do banco.
Troque 0002 pelas suas metas+context.
Seed real e CLAUDE.md não versionam.
O repo público não tem dado pessoal.
📋 Resumo do módulo
supabase db push cria as 14 tabelas e liga o pgvector (0001_init.sql).db.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.