Construir una web app de recetas con Next.js que permita crear recetas manualmente y parsear recetas desde URLs usando AI. Desplegada en Vercel, accesible públicamente para uso familiar.
- Frontend/Backend: Next.js 14 (App Router) + TypeScript
- Estilos: Tailwind CSS + shadcn/ui
- Base de datos + Auth + Storage: Supabase
- AI parsing: Anthropic Claude API (claude-sonnet-4-5)
- Scraping: Jina AI Reader (fetch de
https://r.jina.ai/{url}) - Deploy: Vercel
Crear las siguientes tablas en Supabase:
-- Usuarios manejados por Supabase Auth
create table recipes (
id uuid primary key default gen_random_uuid(),
user_id uuid references auth.users(id) on delete cascade,
title text not null,
description text,
servings integer default 4,
prep_time_minutes integer,
cook_time_minutes integer,
image_url text,
source_url text,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
create table ingredients (
id uuid primary key default gen_random_uuid(),
recipe_id uuid references recipes(id) on delete cascade,
name text not null,
amount numeric,
unit text,
order_index integer default 0
);
create table steps (
id uuid primary key default gen_random_uuid(),
recipe_id uuid references recipes(id) on delete cascade,
description text not null,
order_index integer default 0
);
-- RLS: cada usuario solo ve sus recetas
alter table recipes enable row level security;
alter table ingredients enable row level security;
alter table steps enable row level security;
create policy "Users can manage own recipes" on recipes
for all using (auth.uid() = user_id);
create policy "Users can manage own ingredients" on ingredients
for all using (
recipe_id in (select id from recipes where user_id = auth.uid())
);
create policy "Users can manage own steps" on steps
for all using (
recipe_id in (select id from recipes where user_id = auth.uid())
);/app
/auth
/login/page.tsx
/signup/page.tsx
/recipes
/page.tsx ← listado
/new/page.tsx ← crear manual
/[id]/page.tsx ← detalle
/[id]/edit/page.tsx ← editar
/api
/parse-url/route.ts ← endpoint de parsing
/components
/RecipeForm.tsx
/RecipeCard.tsx
/IngredientList.tsx
/StepList.tsx
/lib
/supabase.ts
/anthropic.ts
- Auth completo: login, signup, logout con Supabase Auth (magic link o email+password)
- Listado de recetas del usuario autenticado
- Formulario de creación/edición manual con:
- Campos básicos: título, descripción, porciones, tiempos
- Lista dinámica de ingredientes (agregar/quitar/reordenar)
- Lista dinámica de pasos (agregar/quitar/reordenar)
- Upload de imagen a Supabase Storage
- Página de detalle de receta
- Eliminar receta
- Deploy en Vercel con variables de entorno configuradas
// Flujo:
// 1. Recibe { url: string }
// 2. Fetch a https://r.jina.ai/{url} → markdown limpio
// 3. Manda el markdown a Claude con este system prompt:
// 4. Devuelve el JSON estructurado
const SYSTEM_PROMPT = `
Eres un extractor de recetas. Se te dará el contenido de una página web en markdown.
Tu tarea es extraer la receta y devolverla ÚNICAMENTE como JSON válido con esta estructura exacta:
{
"title": "string",
"description": "string o null",
"servings": number o null,
"prep_time_minutes": number o null,
"cook_time_minutes": number o null,
"ingredients": [
{ "name": "string", "amount": number o null, "unit": "string o null" }
],
"steps": [
{ "description": "string" }
]
}
Si no encontrás una receta en el contenido, devuelve: { "error": "No se encontró una receta en esta URL" }
No incluyas texto fuera del JSON.
`;- Input de URL en la página de creación (botón "Importar desde URL")
- Loading state mientras procesa
- El JSON resultante pre-llena el formulario de edición
- El usuario puede modificar cualquier campo antes de guardar
- Guardar
source_urlen la receta para referencia
- Colecciones/categorías: tabla
collectionscon relación many-to-many a recetas - Búsqueda: full-text search con Postgres
tsvectoro simplementeilike - Escalar porciones: multiplicar cantidades de ingredientes dinámicamente en el detalle
- Tags: desayuno, almuerzo, cena, postre, vegano, etc.
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
ANTHROPIC_API_KEY=- Usar
@supabase/ssrpara el cliente de Supabase en Next.js App Router (no el legacy@supabase/auth-helpers-nextjs) - shadcn/ui components sugeridos:
Card,Button,Input,Textarea,Dialog,Toast,Skeleton - Para el drag-and-drop de ingredientes/pasos usar
@dnd-kit/core - El modelo de Claude a usar:
claude-sonnet-4-5(balance costo/calidad para parsing) - Manejar rate limiting en el endpoint de parsing: máximo 1 request cada 3 segundos por usuario
- Jina Reader es gratuito, sin API key necesaria para empezar
- Setup Next.js + Tailwind + shadcn
- Conectar Supabase + crear tablas + configurar RLS
- Auth (login/signup/logout)
- CRUD de recetas (sin imágenes primero)
- Deploy en Vercel + verificar que funciona en producción
- Upload de imágenes
- Parser de URLs
- Colecciones y búsqueda