contrato de datos · de Moisés para Jaime

Qué guarda cada pantalla, tabla por tabla

de: moisés (diseño)para: jaime (Supabase + 5 funciones)tarea: J123 jul 2026

Es el plano para tu esquema en Supabase: qué datos guarda cada pantalla, con su tipo, si es obligatorio y cómo se valida. No es SQL — el CREATE TABLE lo decides tú (tipos Postgres, PK/FK, índices, RLS). Sale directo de las pantallas del producto v2, del PRD §6 y de la tabla de inputs de a11y.md §2.4. Cada campo dice de dónde viene para que lo puedas contrastar con la maqueta.

ANTES DE NADA

Los principios que rigen todo el esquema

  1. Mínimo + progresivo. Al alta solo pedimos nombre + teléfono. Todo lo demás se rellena después, así que casi todo es nullable.
  2. El teléfono del usuario es obligatorio y único: así Alma y Mia lo reconocen en WhatsApp. Guardar en E.164 (+34612480315), aunque en pantalla se vea con espacios.
  3. El email viene de Google Auth, no lo pedimos nosotros (login OAuth de Francisco).
  4. Datos del usuario ≠ datos del destino. Los del usuario se reutilizan (SC 3.3.7); los del tercero (restaurante, médico…) viven en cada llamada, no en el perfil.
  5. Las grabaciones se almacenan siempre, con aviso (legal, de Juan José).
  6. Fase 1 por navegador; teléfono real (Zadarma/LiveKit) en fase 3. El esquema no cambia entre fases.
obligatorio opcional (nullable) 🔒 lo pone el sistema, no el usuario

TABLA 1 · FUNCIÓN guardar_perfil

Quién eres usuarios

Origen: pantalla 00 (Alta) y pantalla 10 (Perfil).

CampoTipoObl.ValidaciónOrigen / notas
iduuid🔒El de Supabase Auth (Google). Es la clave.
nombretexto1–80 caracteresAlta. Prellenado desde Google, editable.
telefonotexto (E.164)formato E.164, únicoAlta. Obligatorio; validación suave (acepta espacios y +34, se normaliza).
emailtexto🔒email válidoViene de Google Auth. No editable.
planenum plan🔒ver §7Al registrarse: prueba. Lo gobierna Stripe.
creado_entimestamp🔒Alta.
DNI, dirección y datos bancarios NO van aquí. Los pagos viven en Stripe (Sonia); el DNI era del MVP viejo y se descartó para el alta.

TABLA 2 · FUNCIÓN guardar_perfil

Cómo quieres que trabajemos preferencias

Origen: pantalla 10 (Perfil) → Preferencias. Progresivo: todo nullable, con valores por defecto. Puede ser tabla 1-a-1 o columnas en usuarios, a tu criterio.

CampoTipoObl.ValidaciónOrigen / notas
usuario_iduuid (FK)→ usuarios.id
resumen_whatsappbooleanoToggle. Por defecto: activado.
avisar_antesbooleanoToggle. Por defecto: desactivado.
horario_desdehoraPor defecto 09:00.
horario_hastahorahasta > desdePor defecto 21:00.

TABLA 3 · FUNCIÓN agenda

La agenda contactos

En esta fase el perfil no muestra la agenda todavía (perfil mínimo), pero conviene tener tabla y función listas: las plantillas ya guardan «a quién se llama con qué notas».

CampoTipoObl.ValidaciónOrigen / notas
iduuid🔒
usuario_iduuid (FK)→ usuarios.idCada usuario ve solo los suyos (RLS).
nombretexto1–80«Mamá», «Restaurante La Traviesa».
telefonotexto (E.164)formato E.164Es un tercero: autocomplete=off.
notastexto«mesa tranquila», «mejor por la tarde».
cumpleanosfechaSolo para la felicitación.

TABLA 4 · FUNCIONES crear_llamada · estado_llamada · obtener_resultado

El corazón llamadas

Origen: pantallas 02–07 (crear → estado → resultado) y todo el panel admin.

CampoTipoObl.ValidaciónOrigen / notas
iduuid🔒El ID visible LLX-2026-0142 puede ser aparte o derivado.
usuario_iduuid (FK)→ usuarios.id
plantillaenum plantillaver §7Qué llamada es. La elige la home.
destino_nombretexto1–120Paso 1. «Restaurante La Traviesa».
destino_telefonotexto (E.164)formato E.164Paso 1. Tercero: autocomplete=off.
preguntar_portextoPaso 1, opcional. «Carmen».
variablesJSONschema por plantilla (§5)Los datos de la plantilla; se inyectan al agente.
cuandoenum cuandoahora | programadaPaso 1.
programada_paratimestampfuturo; requerido si programadaPaso 1 («a una hora concreta»).
estadoenum estado_llamada🔒ver §7Lo escribe el worker. Empieza en pendiente.
creada_entimestamp🔒
resumentexto🔒Resultado. Lo genera la IA al colgar.
resultado_datosJSON🔒Datos clave (día, hora, código de reserva…).
transcripcionJSON🔒Turnos (hablante, hora, texto).
grabacion_iduuid (FK)→ grabaciones.idVer §6.

Los límites del paso 2 llamada_limites

Origen: pantalla 03 (paso 2 «Los límites»). Es lo que convierte el paso 2 en instrucciones para el agente. Recomiendo tabla propia porque el panel los pinta uno a uno.

CampoTipoObl.ValidaciónOrigen / notas
iduuid🔒
llamada_iduuid (FK)→ llamadas.id
tipoenumacepta | pregunta | bloqueadoVerde / ámbar / candado.
textotexto«Otra hora entre 21:00 y 22:00».
es_sistemabooleano🔒Pagos/señal/datos bancarios: true y no se pueden quitar.

DENTRO DE llamadas.variables

Las variables por plantilla (JSON)

El campo variables depende de la plantilla. Schema de cada una según el PRD §6 — son las variables que se inyectan al agente de voz. Recomiendo validarlo en la API con un schema por plantilla, no en la base. (El margen y las condiciones aceptables van en llamada_limites, no aquí.)

P1 · Reservar mesa / pedir cita reservar_mesa · pedir_cita

tipo_reserva · dia_preferido (fecha) · hora_preferida (hora) · personas (entero, si aplica) · nombre_reserva (texto) · mensaje_adicional (texto, opcional).

P2 · Cambiar una cita cambiar_cita

cita_actual (texto) · accion (enum: confirmar / cambiar / cancelar / avisar_retraso / reprogramar) · nueva_fecha (fecha, opcional) · mensaje (texto).

P3 · Preguntar precio / info preguntar_precio

pregunta_principal (texto) · preguntas_secundarias (lista) · datos_a_recoger (texto) · no_confirmar (texto) · canal_resumen (enum: whatsapp / app).

P4 · Felicitar cumpleaños felicitar_cumple

relacion (texto) · edad (entero, opcional) · datos_personalizar (texto) · tono (enum tono, §7) · bromas_permitidas · cosas_prohibidas · mensaje_final · decir_quien_encarga (booleano).

P6 · Mensaje divertido mensaje_divertido

personaje (texto) · mensaje (texto) · nivel_picante (entero 1–3) · cosas_prohibidas (texto). Nota: las divertidas pasan por el Revisor del panel antes de salir.

TABLA 5 · FUNCIÓN obtener_resultado

El audio, siempre con aviso grabaciones

Origen: requisito legal + pantalla de Resultado / detalle admin.

CampoTipoObl.ValidaciónOrigen / notas
iduuid🔒
llamada_iduuid (FK)→ llamadas.id
urltexto🔒Supabase Storage con acceso restringido.
duracion_sentero🔒≥ 0Segundos.
creada_entimestamp🔒

LISTAS CERRADAS

Enums

Los valores fijos. Fija los que uses en el panel para que color/estado coincidan con las maquetas.

estado_llamada · los 9 estados del feed, en orden natural

pendientepreparandollamandoen_conversacionrequiere_respuestacompletadasin_respuestafallidacancelada

plan

pruebaminiplusmax

Mini 4,99/3 llam · Plus 9,99/12 · Max 19,99/25 · 1ª gratis. Los pagos los gobierna Stripe, no esta tabla.

plantilla

reservar_mesapedir_citapreguntar_preciocambiar_citafelicitar_cumplemensaje_divertido

Las 6 de la home. reservar_mesa y pedir_cita comparten el schema P1.

cuando

ahoraprogramada

tono · para felicitaciones (PRD P4)

elegantegraciosofamiliargamberro_suaveabueloradioepicoamigo_pesado

TU TAREA J2

Cómo las 5 funciones tocan estas tablas

Del anexo técnico de producto-v2.

FunciónLee / escribe
guardar_perfilusuarios + preferencias
crear_llamadainserta en llamadas (+ llamada_limites, + variables); la mete en la cola
estado_llamadaactualiza llamadas.estado; lo lee el móvil en vivo (WebSocket)
agendacontactos (leer y escribir)
obtener_resultadoescribe resumen, resultado_datos, transcripcion; enlaza grabaciones

PARA QUE NO MONTES DE MÁS

Lo que NO entra en esta fase

Dudas o ajustes: hablémoslo por Telegram antes de fijar el esquema. Esto es diseño; si al implementarlo ves que algo encaja mejor de otra forma, adelante — lo importante es que las pantallas y las tablas cuenten lo mismo.