perfiles, recetas, and favoritos.
Tables
perfiles
Stores user profile information. Each row is linked to a Supabase Auth user via theid column.
| Column | Type | Description |
|---|---|---|
id | uuid | Primary key. References auth.users(id). Populated on registration. |
nombre | varchar(30) | Display name chosen by the user. Must be unique (case-insensitive). |
sobre_mi | text | Short biography. Maximum 300 characters. Nullable. |
avatar_url | text | Public URL of the user’s avatar image stored in Supabase Storage. Nullable. |
is_admin | boolean | Whether the user has administrator privileges. Defaults to false. |
bloqueado | boolean | Whether 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.| Column | Type | Description |
|---|---|---|
id | uuid | Primary key. Generated by the database. |
autor_id | uuid | Foreign key referencing perfiles(id). The user who created the recipe. |
titulo | varchar(60) | Recipe title. Required. Maximum 60 characters. |
descripcion | text | Short description of the recipe. Required. Maximum 300 characters. |
tiempo | text | Preparation/cooking time as a free-form string (e.g. “30 min”). Required. |
dificultad | text | Difficulty level as a free-form string (e.g. “Fácil”, “Media”, “Difícil”). |
ingredientes | jsonb | JSON array of ingredient strings. Must contain at least one entry. |
pasos | jsonb | JSON array of instruction step strings. Must contain at least one entry. |
imagen_url | text | Public URL of the recipe image stored in Supabase Storage. Nullable. |
oculta | boolean | Whether the recipe is hidden from public listings. Defaults to false. |
fecha_creacion | timestamp | Timestamp 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.| Column | Type | Description |
|---|---|---|
id | uuid | Primary key. Generated by the database. |
usuario_id | uuid | Foreign key referencing perfiles(id). The user who saved the recipe. |
receta_id | uuid | Foreign key referencing recetas(id). The saved recipe. |
fecha_guardado | timestamp | Timestamp of when the favorite was saved. Used to sort the favorites list by most recent. |
Relationships
The three tables are connected as follows:perfiles→auth.users: Each profile row maps one-to-one to a Supabase Auth user. Theperfiles.idcolumn referencesauth.users.id.recetas→perfiles: Each recipe has one author.recetas.autor_idreferencesperfiles.id. A single user can have many recipes (one-to-many).favoritos→perfilesandrecetas: Thefavoritostable is a many-to-many junction between users and recipes.favoritos.usuario_idreferencesperfiles.idandfavoritos.receta_idreferencesrecetas.id.
Key constraints and notes
Public recipe visibility
Public recipe visibility
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.User account blocking
User account blocking
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.Unique display names
Unique display names
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.JSON storage for ingredientes and pasos
JSON storage for ingredientes and pasos
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.Ownership checks
Ownership checks
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.