尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Scan it, know it, use it up. A smart kitchen app that tells you what's in your food, tracks what's in your pantry, and makes sure you eat it before it expires. India-first (₹, vegetarian / Jain / vegan diets, IST), works anywhere.
All authentication code is commented out and marked AUTH DISABLED (search for it to find every spot). Instead, the server treats every visitor as one guest user — GUEST_EMAIL, default [email protected], the seeded "Demo Flat 4B" household — and talks to the database with the service-role key. Households are still kept apart in code, and the database's row-level security is unchanged, but anyone who can reach the server can read and change the guest household. Don't deploy this publicly.
To turn sign-in back on: uncomment every AUTH DISABLED block (and delete the small replacement code next to each), switch src/lib/session.ts back to supabaseServer() + auth.getUser(), and swap src/lib/household.ts calls back to the create_household / join_household / leave_household RPCs.
| Home | Health Score | Pantry | Cook mode |
|---|---|---|---|
add docs/home.png | add docs/product.png | add docs/pantry.png | add docs/cook.png |
flowchart LR
subgraph Browser["Browser / installed PWA"]
UI["Next.js App Router UI<br/>TanStack Query (persisted)"]
SW["sw.js<br/>app shell + push"]
end
subgraph Server["Next.js on Vercel"]
Proxy["proxy.ts<br/>session refresh + gating"]
API["/api/* route handlers"]
GW["API gateway<br/>cachedFetch · retry/backoff · Zod · quota guard"]
Canon["canon resolver<br/>~165 base ingredients"]
Cron["/api/cron/expiry<br/>Vercel Cron 03:30 UTC"]
end
subgraph Supabase
DB[("Postgres + RLS<br/>pantry, shop, scans, cook_logs,<br/>products, api_cache, quota_log")]
Auth["Auth<br/>magic link + Google"]
end
OFF["Open Food Facts<br/>products + swaps"]
FV["Fruityvice<br/>fruit nutrition"]
SP["Spoonacular<br/>pantry recipes + cost"]
MDB["TheMealDB<br/>explore + fallback + video"]
CDB["TheCocktailDB<br/>drinks from leftovers"]
UI -->|fetch /api| API
UI --> Auth
Proxy --> Auth
API --> DB
API --> Canon
API --> GW
GW --> DB
GW --> OFF & FV & SP & MDB & CDB
Cron --> DB
Cron -->|web push| SW
No secret ever reaches the browser: the five APIs are only called from src/lib/apis/* (all server-only), behind our own /api routes.
| API | Used for | Where |
|---|---|---|
| Open Food Facts | Product by barcode (limited fields, custom User-Agent), better swaps from the same category | src/lib/apis/off.ts |
| Fruityvice | Fruit autocomplete (/all, cached a week), fruit card, real-fruit sugar comparison. Server-only because CORS is off | src/lib/apis/fruityvice.ts |
| Spoonacular | "Use it up" (findByIngredients, expiring first, ranking=1), recipe detail, shopping cost (parseIngredients, US cents → ₹). Guarded by a daily points budget | src/lib/apis/spoonacular.ts, src/lib/quota.ts |
| TheMealDB | Explore (cuisine, category, search, random), cook mode YouTube video, automatic "Use it up" fallback | src/lib/apis/mealdb.ts, src/lib/useitup.ts |
| TheCocktailDB | Drinks from leftovers, non-alcoholic unless every member opts in | src/lib/apis/cocktaildb.ts, src/lib/drinks.ts |
Endpoint-by-endpoint table with cache TTLs: API_USAGE.md. Design calls and deviations: DECISIONS.md.
Needs Node 20.9+ (developed on Node 24) and a free Supabase project.
Install
npm install
Create a Supabase project at supabase.com → New project. Then go to Project Settings → API and copy the URL, the anon key and the service_role key.
Environment
cp .env.example .env.local
Fill in the three Supabase values. Optional extras: a SPOONACULAR_KEY (free at spoonacular.com/food-api/console; without it "Use it up" uses TheMealDB), and VAPID keys for push (npm run gen:vapid prints them).
Run the migration. Either paste supabase/migrations/20261027000000_init.sql into the Supabase dashboard → SQL Editor → Run, or use the CLI:
npx supabase link --project-ref <your-project-ref>
npx supabase db push
Auth settings (dashboard → Authentication):
http://localhost:3000, and add http://localhost:3000/** to Redirect URLs.{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email&next=/homeSeed the demo data
npm run seed
This creates the household Demo Flat 4B (invite code de30f1a7) with ~17 pantry items (some expiring today/tomorrow), 6 months of used/wasted history, scans, a cook log and a shopping list. Users: [email protected] (Riya, vegetarian) and [email protected] (nut allergy, so the seeded Nutella turns red), plus [email protected] for tests.
To look around as the demo user without an inbox, sign in with your own email, then open the invite link http://localhost:3000/join/de30f1a7 to join the demo household.
Email limit: Supabase's built-in mailer sends only 2 sign-in emails per hour per project. While developing, skip email entirely with npm run dev:login -- [email protected] and open the link it prints. For real users, set up custom SMTP (e.g. Resend's free tier) in Authentication → Emails → SMTP Settings, then raise the limit in Authentication → Rate Limits.
| Command | What it does |
|---|---|
npm run dev | Dev server |
npm run typecheck | next typegen + tsc --noEmit |
npm run lint | ESLint |
npm run test | Vitest unit tests (recorded fixtures, no live calls) |
npm run build / npm start | Production build / serve |
npm run test:e2e | Playwright smoke test (needs a seeded Supabase + a running build; run npx playwright install chromium once) |
npm run seed | Rebuild the demo + e2e households |
npm run dev:login -- [email protected] | Print a one-time sign-in link without sending an email (local only, uses the service role key) |
npm run gen:vapid | Print a VAPID key pair for push |
npm run gen:icons | Regenerate the PWA icons from the SVG |
Live RLS test (optional): set RLS_TEST_SUPABASE_URL, RLS_TEST_ANON_KEY and RLS_TEST_SERVICE_KEY (use a dev project — it creates and deletes two throwaway users), then npm test. It checks that one household can't read or write another's pantry. Without them, only the static migration checks run.
.env.example in Vercel → Settings → Environment Variables. Set NEXT_PUBLIC_APP_URL to your production URL and CRON_SECRET to a long random string.https://<your-app>.vercel.app/** to Redirect URLs. If you use Google, add the same callback to the Google OAuth client.vercel.json registers the daily cron (30 3 * * * UTC = 09:00 IST) for /api/cron/expiry; Vercel sends Authorization: Bearer $CRON_SECRET automatically.src/app routes (pages + /api route handlers), proxy.ts
src/components ui (shadcn) + feature components
src/lib/apis one client per external API (server-only)
src/lib canon resolver, cache, quota, http, supabase, domain logic
src/types db + domain + api response types
supabase/ migration (schema, RLS, RPCs)
scripts/ seed, VAPID + icon generators
tests/unit Vitest + recorded fixtures in tests/fixtures
tests/e2e Playwright smoke test
public/sw.js service worker
Data credits: product data © Open Food Facts contributors (ODbL).
Start
npm run dev
Open http://localhost:3000. Camera scanning needs localhost or HTTPS. On a phone on the same Wi-Fi, use a tunnel such as npx localtunnel --port 3000, or type barcodes manually (try 8902579000370 Frooti, 3017624010701 Nutella).