Skip to main content
The database is hosted on Supabase and uses PostgreSQL. It consists of three core tables: perfiles, recetas, and favoritos.

Tables

perfiles

Stores user profile information. Each row is linked to a Supabase Auth user via the id column.
ColumnTypeDescription
iduuidPrimary key. References auth.users(id). Populated on registration.
nombrevarchar(30)Display name chosen by the user. Must be unique (case-insensitive).
sobre_mitextShort biography. Maximum 300 characters. Nullable.
avatar_urltextPublic URL of the user’s avatar image stored in Supabase Storage. Nullable.
is_adminbooleanWhether the user has administrator privileges. Defaults to false.
bloqueadobooleanWhether the account is blocked. Blocked users cannot log in. Defaults to false.
A profile row is created automatically when a user registers via POST /api/auth/register. The id is set to authData.user.id so it always matches the Supabase Auth identity.

recetas

Stores all recipe data submitted by users.
ColumnTypeDescription
iduuidPrimary key. Generated by the database.
autor_iduuidForeign key referencing perfiles(id). The user who created the recipe.
titulovarchar(60)Recipe title. Required. Maximum 60 characters.
descripciontextShort description of the recipe. Required. Maximum 300 characters.
tiempotextPreparation/cooking time as a free-form string (e.g. “30 min”). Required.
dificultadtextDifficulty level as a free-form string (e.g. “Fácil”, “Media”, “Difícil”).
ingredientesjsonbJSON array of ingredient strings. Must contain at least one entry.
pasosjsonbJSON array of instruction step strings. Must contain at least one entry.
imagen_urltextPublic URL of the recipe image stored in Supabase Storage. Nullable.
ocultabooleanWhether the recipe is hidden from public listings. Defaults to false.
fecha_creaciontimestampTimestamp of when the recipe was created. Set automatically by the database.
Only recipes where oculta = false are returned by the public listing endpoint (GET /api/recetas). Administrators can toggle visibility using PATCH /api/recetas/[id].

favoritos

Junction table that tracks which recipes each user has saved as favorites.
ColumnTypeDescription
iduuidPrimary key. Generated by the database.
usuario_iduuidForeign key referencing perfiles(id). The user who saved the recipe.
receta_iduuidForeign key referencing recetas(id). The saved recipe.
fecha_guardadotimestampTimestamp of when the favorite was saved. Used to sort the favorites list by most recent.

Relationships

The three tables are connected as follows:
  • perfilesauth.users: Each profile row maps one-to-one to a Supabase Auth user. The perfiles.id column references auth.users.id.
  • recetasperfiles: Each recipe has one author. recetas.autor_id references perfiles.id. A single user can have many recipes (one-to-many).
  • favoritosperfiles and recetas: The favoritos table is a many-to-many junction between users and recipes. favoritos.usuario_id references perfiles.id and favoritos.receta_id references recetas.id.
auth.users

    │ id = perfiles.id

perfiles ◄──────────────────── favoritos
    │          usuario_id            │
    │                                │
    │          receta_id             │
    └──────────────────────────────► recetas
            autor_id

Key constraints and notes

The oculta column on the recetas table controls public visibility. When oculta = false, the recipe appears in public search results and listings. When oculta = true, the recipe is hidden from all public endpoints but still exists in the database. Only administrators (users where is_admin = true) can change this flag.
The bloqueado column on the perfiles table controls whether a user can log in. When bloqueado = true, the login endpoint signs the user out immediately and returns a 403 error. Only administrators can toggle this field via PATCH /api/perfil/bloquear.
The nombre column is checked for uniqueness using a case-insensitive ilike query during registration. Two users cannot share the same display name regardless of letter casing.
The ingredientes and pasos columns store JSON arrays serialized as strings via JSON.stringify() before insertion. Empty strings within the arrays are filtered out before saving. Each array must contain at least one valid entry.
Write operations on recetas (PUT, DELETE) filter by both id and autor_id = user.id, ensuring users can only modify or delete their own recipes. Profile updates (PUT) filter by id = user.id for the same reason.

Build docs developers (and LLMs) love