PTENES
MÓDULO 2.2

🗄️ La base de datos (Supabase)

Sube el esquema: ejecuta las migrations, conocer las 14 tablas, conectar el pgvector (memoria), crear el bucket de fotos, protegerlo con RLS y probar la conexión. Al final de este módulo, la base de datos está lista y el coach ya tendría dónde guardar todo.

7
Temas
~35
Minutos
Intermedio
Nivel
Práctico
Tipo
Tu progreso en este módulo 0% · 0 de 7
1

🧱 Ejecutar las migrations

Las migrations son archivos .sql versionados en agent/supabase/migrations/ que describen toda la base de datos. Llevarlas a tu proyecto Supabase crea, de una vez, las 14 tablas y activa la extensión pgvector — todo mediante la primera migración, la 0001_init.sql. No creas las tablas manualmente: el esquema ya viene listo en el blueprint.

🟢 ¿Nuevo por aquí?

  • Migration — un archivo SQL numerado que aplica un cambio en la base de datos. Ejecutarlos todos, en orden, reconstruye el esquema desde cero en cualquier proyecto.
  • Supabase CLI — la herramienta de línea de comandos de Supabase. Ella conecta tu carpeta local con tu proyecto en la nube y impulsa las migrations para allá.
📁 migrations/ (.sql)0001_init · 0002_seed ⚙️ supabase CLIdb push ☁️ Postgres (nube)tu proyecto privado 🗄️ 14 tablas+ pgvector activado un único `db push` reconstruye toda la base de datos: nunca creas tablas a mano

📊 Cómo leer: de izquierda a derecha, los archivos SQL se convierten en la base de datos real. Los cuadros azules con brillo son donde ocurre la acción (la CLI y el resultado); los cian son el origen y el destino. El secreto es que el esquema está en un archivo, no en tu memoria.

🎯 Objetivo: conectar tu carpeta al proyecto Supabase y aplicar las migraciones (crea las 14 tablas + 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
✅ Cómo verificar: la CLI muestra las migraciones aplicadas (incluyendo 0001_init.sql) sin errores. En el panel de Supabase, en Table Editor, aparecen las 14 tablas; en Database → Extensions, vector está habilitada.

💡 De dónde viene la contraseña

O supabase link usa la SUPABASE_DB_PASSWORD que guardaste en el ~/.env (Módulo 2.1). El <seu-project-ref> es el identificador del proyecto —aparece en la URL https://<ref>.supabase.co y en Settings.

Conceptos clave

Migration

SQL numerado que reconstruye el esquema.

0001_init.sql

Crea las 14 tablas y activa pgvector.

db push

Un comando aplica todo en la nube.

Esquema en archivo

Reproducible en cualquier proyecto.

2

📋 Las 14 tablas — descripción general

Cada cosa que registras se convierte en fila en una tabla. El esquema abarca las familias de datos de salud — comida, entrenamiento, peso, composición corporal, cafeína, suplementos, signos vitales, exámenes, check-ins, metas y contexto — además de la memoria semántica de los mensajes. El diagrama muestra cómo las fuentes alimentan las tablas y cómo el coach vuelve a leerlas.

⌚ wearable 📷 fotos 💬 mensajes vitals food_log workouts weigh_ins lab_results goals · context messages (vector) …y más: body_comp, caffeine, supplements, checkins, coach_summary (14 en total) 🤖 Coach lee el snapshot 💬 respuesta con contexto

📊 Cómo leer: las fuentes (cian, a la izquierda) escriben en las tablas (centro); el coach (azul) lee la instantánea de esas tablas y responde. La tabla messages se destaca porque es la única que guarda vectores (la memoria semántica — Tema 3).

food_log

Comida → macros + flags.

workouts

Entrenamientos registrados.

weigh_ins

Pesajes (tendencia).

body_comp

Composición corporal.

caffeine

Cafeína a lo largo del día.

supplements

Suplementos y horarios.

vitals

PA, recovery, HRV, RHR, sueño.

lab_results

Marcadores de sangre.

checkins

Registros diarios.

goals

Tus metas.

context

Perfil y contexto fijo.

messages 🧲

Memoria semántica (vector).

Estas 12 familias de datos + tablas de apoyo (como coach_summary, que guarda la recuperación y su causa) completan las 14 tablas que crea la migration.

Conceptos clave

Todo es una línea

Cada registro se convierte en una fila de una tabla.

Familias

Una tabla por tipo de dato.

Snapshot

El coach lee un resumen de esas tablas.

messages

La única con vectores (memoria).

3

🧲 pgvector — la memoria

La migration 0001_init.sql conecta el pgvector antes de crear las tablas. Es lo que le da a la base de datos la capacidad de guardar la memoria semántica — buscar mensajes anteriores por significado, no por una palabra exacta.

🟢 ¿Nuevo por aquí? Qué es pgvector

pgvector es una extensión de PostgreSQL que agrega un nuevo tipo de columna: vector. Cada mensaje se convierte en un embedding (una lista de números que representa el significado del texto). pgvector compara estos vectores y encuentra lo que es parecido en significado — así el coach «recuerda» cuando hablaste del sueño, aunque no aparezca la palabra «sueño».

📝 texto"dormí mal de nuevo" 🔢 embedding[0.12, -0.7, …] 🧲 pgvectorguarda el vector 🔎 similitudencuentra el parecido por eso el coach recuerda «mal sueño» incluso cuando usas otras palabras

📊 Cómo leer: el texto se convierte en números (embedding), pgvector los guarda y luego los compara por distancia. Cuanto más cerca están dos vectores, más parecido es su significado: así es como la memoria recupera el pasado relevante.

🔌 No conectas manualmente

No necesitas ejecutar ningún comando extra: el create extension vector ya está dentro de la 0001_init.sql. Cuando hiciste el db push del Tema 1, pgvector ya quedó habilitado. Aquí solo tienes que entender por qué existe.

Conceptos clave

pgvector

Extensión que almacena vectores en Postgres.

Embedding

Números que representan el significado.

Similitud

Encuentra lo parecido por distancia.

Ya viene activado

La 0001_init.sql hace eso por ti.

4

🪣 El bucket de almacenamiento de fotos

Las tablas guardan números y texto; las fotos (comida, análisis, cuerpo) van a un bucket de storage. HealthOS usa un bucket llamado health-assets, creado con un solo comando —y él es privado.

🟢 ¿Nuevo por aquí?

Bucket — es una "carpeta" de almacenamiento de archivos en Supabase, separada de las tablas. Privado significa que nadie accede a un archivo mediante la URL pública; solo el servidor, con la clave correcta, genera un enlace temporal para leerlo.

🎯 Objetivo: crear el bucket privado health-assets dónde se guardarán las fotos.
# um comando cria o bucket PRIVADO de fotos
python3 agent/scripts/db.py mkbucket health-assets
✅ Cómo verificar: en el panel de Supabase, en Almacenamiento, el bucket health-assets aparece marcado como Private (no público). Puedes volver a ejecutarlo sin problema: no duplica.

✓ Bucket privado (el correcto)

  • ✓Las fotos de salud no se filtran mediante URL públicas.
  • ✓El servidor genera enlaces temporales cuando hace falta.
  • ✓Es el patrón que el mkbucket ya lo aplica.

✗ Bucket público (no lo hagas)

  • ✗Cualquiera con la URL podría ver la foto de tu examen.
  • ✗Datos de salud sensibles expuestos a internet.
  • ✗No se puede «despublicar» lo que ya se filtró.

Conceptos clave

Bucket

Almacenamiento de archivos, fuera de las tablas.

health-assets

El bucket de fotos de HealthOS.

Privado

Sin URL pública; solo el servidor lo lee.

mkbucket

Un comando crea todo correctamente.

5

🔒 RLS — bloquear la base de datos

El esquema conecta el RLS (Row-Level Security) en cada tabla y no crea ninguna política. El efecto es radical y sencillo: la clave pública (anon) no lee nada; solo el servidor, con la clave service-role, atraviesa. Es el bloqueo estándar de HealthOS.

🟢 ¿Nuevo por aquí? Dos claves, dos mundos

  • RLS — recurso de Postgres que decide, fila por fila, quién puede leer/escribir. Sin una política que lo permita, el comportamiento predeterminado es denegar.
  • service-role — la clave de servidor. Ella elude la RLS (la omite), así que el agente lee y escribe con normalidad. Solo vive en ~/.env, nunca en el navegador.
  • anon — la clave pública, segura de exponer. Con RLS activada y cero políticas, esta no lee nada.
🔑 service-roleservidor (en el ~/.env) 🌐 anon (pública)navegador / fuera 🔒 RLS sin políticas 🗄️ 14 tablastus datos elude → pasa ✓ anon queda bloqueado por la RLS → no lee nada ✗

📊 Cómo leer: las dos claves llegan a la misma puerta (la RLS). La service-role (verde) pasa por encima y llega a las tablas; la anon (rojo, discontinuo) choca con la X y vuelve. Por eso es seguro exponer la clave pública.

✓ service-role (servidor)

  • ✓Lee y escribe en todas las tablas.
  • ✓Omite la RLS (pasa por encima).
  • ✓Se limita a ~/.env, en el servidor.

✗ anon (pública)

  • ✗No lee ninguna línea (RLS sin política).
  • ✗No escribe nada.
  • ✓Por eso es segura de exponer si hace falta.

Conceptos clave

RLS

Activada para todo, sin políticas = deniega.

service-role

La clave del servidor omite la RLS.

anon

La clave pública no lee nada.

Bloqueo predeterminado

Privado por diseño, sin necesidad de configurar nada.

6

🔌 Probar la conexión

Antes de seguir con el agente, comprueba que el servidor se comunica con la base de datos. El db.py es la utilidad de base de datos de HealthOS; un select simple confirma que las claves del ~/.env están correctas y que la RLS permite el acceso del servidor.

🎯 Objetivo: confirmar que el servidor se conecta y lee una tabla real (goals).
# lê as linhas da tabela goals usando a chave service-role do ~/.env
python3 agent/scripts/db.py select goals
✅ Cómo verificar: imprime tus líneas de goals (o una lista vacía [] si todavía no cambiaste el seed de ejemplo). Sin errores de conexión/autenticación = claves y RLS OK. Cambia goals por <outra-tabela> para inspeccionar cualquiera de las 14.

🧪 Si da error

  • •¿Falló la autenticación? A SUPABASE_SERVICE_ROLE_KEY o la SUPABASE_URL en el ~/.env está equivocada.
  • •¿No existe la tabla? O db push del Tema 1 no se ejecutó por completo — repítelo.
  • •¿La lista está vacía? Esto es un éxito de conexión: solo falta el seed (Tema 7).

✅ Autoevaluación (opcional): por qué el db.py select goals puede leer, si RLS está habilitada?

Conceptos clave

db.py

La utilidad de base de datos de HealthOS.

select goals

Prueba mínima de conexión.

Lee = OK

Claves y RLS en funcionamiento.

[] también está bien

Conexión correcta, solo falta el seed.

7

🌱 Seed y datos sensibles

La migration 0002_seed_example.sql planta uno seed de ejemplo (genérico, sin datos reales), solo para que veas el formato. El último paso es reemplazar este ejemplo por tus tus metas y contexto — y conserva tu seed real y tu CLAUDE.md fuera de git.

🟢 ¿Nuevo por aquí?

  • Seed — datos iniciales que «siembran» la base de datos. El ejemplo es genérico; el tuyo, el real, va en las tablas goals e context.
  • Fuera de Git — el repositorio es el plano limpio. Tus valores reales quedan solo en tu máquina/base de datos; se incluyen en el .gitignore y nunca se versionan.

✓ Puedes versionar

  • ✓Las migrations del esquema (0001_init.sql).
  • ✓O 0002_seed_example.sql genérico.
  • ✓O CLAUDE.md modelo (en blanco).

✗ Nunca versionar

  • ✗Tu seed real (goals + context completados).
  • ✗Tu CLAUDE.md con un perfil real.
  • ✗O ~/.env y tus fotos.

⚠️ Los datos de salud son sensibles

Un seed real en un commit es una filtración permanente: el historial de git lo guarda todo. Antes de cualquier git add, confirma que los goals/context reales, CLAUDE.md completado y ~/.env están en el .gitignore. El repositorio público debe conservarse como el blueprint scrubbed, sin información personal.

Conceptos clave

Seed

Datos iniciales de la base de datos.

Ejemplo → el tuyo

Reemplaza 0002 por tus metas+context.

Fuera de Git

El Seed real y CLAUDE.md no se versionan.

Blueprint limpio

El repo público no contiene datos personales.

📋 Resumen del módulo

✓
Migraciones con un comando — supabase db push crea las 14 tablas y conecta pgvector (0001_init.sql).
✓
14 tablas, una por familia — comida, entrenamiento, peso, signos vitales, análisis, metas, contexto… + la memoria semántica en messages.
✓
pgvector es la memoria — guarda embeddings y busca por significado; ya viene activado por la migration.
✓
Bucket privado + RLS — fotos en health-assets cerrado; RLS activada sin políticas: solo pasa el service-role.
✓
Conexión probada y seed tuyo — db.py select goals confirma todo; el seed real y CLAUDE.md quedan fuera de git.

Próximo módulo:

2.3 — El agente y el bot: darle vida al coach en Telegram, conectar el agente a la base de datos que acabas de configurar y responder al primer mensaje.