Plan meals for the week, save recipes, and automatically generate grocery lists you can share with your whole kitchen.
SmartCart is a full-stack web app built with Next.js (App Router) + Supabase.
- Accounts - email/password auth with server-side sessions (Supabase Auth +
@supabase/ssr), plus an optional open "guest" mode (anonymous sign-in) so you can use the app without an account. Toggle withNEXT_PUBLIC_REQUIRE_AUTH. - Profile preferences - allergies, eating type (all / vegetarian / vegan / …), serving-size multiplier, daily macro nutrition targets, and top 3 favorite meals.
- My Recipes - create, edit and delete recipes with a dynamic list of ingredients.
- Cookbook - mark a recipe public to share it, and clone anyone's public recipe into your own collection.
- Kitchens - shared spaces you create or join with an invite code. Add household people without accounts (kids, guests) with their own diet prefs and favorites. Members plan and shop together.
- Weekly Planner - a Monday-Sunday grid (breakfast / lunch / dinner) scoped to the active kitchen and week.
- Grocery Lists - auto-generated by aggregating the ingredients of the week's planned recipes; items are checkable, addable, and shareable. Because lists live inside a kitchen, every member sees the same list.
- Pantry - track ingredients you already have in the kitchen, then match them against your recipes and the cookbook (ready-to-cook, partial matches, and missing items).
- Next.js 16 (App Router, Server Actions, TypeScript)
- Supabase (Postgres, Auth, Row Level Security)
- Tailwind CSS v4 + a small set of local UI primitives
- lucide-react icons
app/
(auth)/ login, signup pages + auth server actions
(app)/ authenticated app (nav shell + kitchen switcher)
planner/ weekly meal-plan grid
grocery/ grocery list per week
pantry/ kitchen pantry inventory + recipe matches
recipes/ personal recipe CRUD
cookbook/ public community recipes
kitchens/ create/join/manage kitchens
auth/callback/ PKCE code exchange for email links
components/ UI primitives + feature components
lib/
supabase/ browser, server and proxy Supabase clients
kitchen.ts active-kitchen resolution
meal-plan.ts get-or-create weekly meal plan
types.ts DB row types
utils.ts week/date helpers + cn()
proxy.ts session refresh + route protection (Next 16 "proxy")
supabase/migrations/ SQL schema + RLS policies
Create a project at supabase.com. From Project Settings -> API grab:
- Project URL ->
NEXT_PUBLIC_SUPABASE_URL anonpublic key ->NEXT_PUBLIC_SUPABASE_ANON_KEY
Run the two migration files, in order, in the Supabase SQL Editor (or with the Supabase CLI):
supabase/migrations/0001_schema.sql- tables and indexessupabase/migrations/0002_policies.sql- RLS policies, helper functions, and the new-user profile triggersupabase/migrations/0003_profiles_and_household_people.sql- profile diet prefs, favorites, and household people (non-members)supabase/migrations/0004_recipe_timing_difficulty.sql- recipe difficulty, prep time, and cook timesupabase/migrations/0005_recipe_tags.sql- recipe tags (healthy, high protein, etc.)supabase/migrations/0006_recipe_origin.sql- distinguish user-created vs cookbook recipessupabase/migrations/0007_recipe_nutrition.sql- estimated nutrition facts per servingsupabase/migrations/0008_recipe_ratings_comments.sql- ratings and comments on shared cookbook recipessupabase/migrations/0009_recipe_personal_comments.sql- private personal notes on My Recipessupabase/migrations/0010_recipe_image.sql- optional cover image URL for recipessupabase/migrations/0011_profile_macro_targets.sql- daily macro nutrition targets on member profilessupabase/migrations/0012_kitchen_pantry.sql- shared kitchen pantry inventory
Using the Supabase CLI:
supabase link --project-ref <your-project-ref>
supabase db pushTo populate the Cookbook with starter public recipes, run
supabase/seed_cookbook.sql in the SQL Editor.
It creates a system "SmartCart Cookbook" owner and 8 public recipes with
ingredients. Safe to re-run.
cp .env.local.example .env.localFill in the values:
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-or-publishable-key>
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_REQUIRE_AUTH=false
SmartCart can run in two modes, controlled by NEXT_PUBLIC_REQUIRE_AUTH:
- Open mode (
falseor unset, the default): visitors are automatically signed in as an anonymous guest (one per browser) so they can use the whole app without creating an account. Requires enabling Authentication -> Providers -> Anonymous Sign-Ins in Supabase (locally:enable_anonymous_sign_ins = trueinconfig.toml). Guests can still open the Sign in link in the top bar to create a real account. - Required mode (
true): login/signup is mandatory; unauthenticated users are redirected to/login.
To switch back to required accounts later, set NEXT_PUBLIC_REQUIRE_AUTH=true
and restart/redeploy - no code changes. (You may then disable Anonymous
Sign-Ins in Supabase.)
Guest data is per-browser and is not shared across devices (a property of anonymous auth). Sharing between guests still works via kitchen invite codes.
In Supabase Authentication -> URL Configuration, add
http://localhost:3000/auth/callback (and your production URL) to the list of
redirect URLs. For local development you can disable "Confirm email" under
Authentication -> Providers -> Email so sign-up logs you straight in.
npm install
npm run devOpen http://localhost:3000.
- In open mode you're dropped straight into the app as a guest; otherwise sign up first. Either way, create a Kitchen (or join one with an invite code). The active kitchen is stored in a cookie and switched from the top-right dropdown.
- Add Recipes with their ingredients. Toggle "Share to cookbook" to publish, or clone others' recipes from the Cookbook.
- Open the Planner, pick a week, and drop recipes into each day's meal slots.
- Go to Grocery, hit Generate from plan, and SmartCart aggregates every ingredient from that week's recipes (summing quantities by name + unit). Check items off as you shop, or add extras manually. Everyone in the kitchen sees the same list.
- Use Pantry to log what you already have; SmartCart ranks recipes from My Recipes and the Cookbook by how many ingredients you can cover.
Authorization is enforced entirely by Postgres Row Level Security:
- Recipes are readable by their owner, if
is_public, or if used in a meal plan of a kitchen you belong to. - Kitchen data (members, meal plans, entries, grocery items, pantry) is readable/writable only by members, checked via
SECURITY DEFINERhelper functions (is_kitchen_member,recipe_in_my_kitchen) to avoid recursive policy evaluation. - Joining by invite code goes through the
join_kitchen_by_codeRPC so non-members can look up a kitchen by code without exposing the whole table.
Deploy to Vercel:
- Push this repo to GitHub and import it in Vercel.
- Add
NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEY,NEXT_PUBLIC_SITE_URL(your deployed URL), andNEXT_PUBLIC_REQUIRE_AUTHas environment variables. - Add your production
/auth/callbackURL to Supabase's redirect URL allow-list.
npm run dev # start dev server
npm run build # production build
npm run start # run the production build
npm run lint # eslint