尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證AI-powered memory tracking app
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Larder is an AI-powered inventory tracker that turns grocery receipts into a smart kitchen. Upload a photo of any receipt and Claude AI extracts every item — name, quantity, category, price, and estimated shelf life — into a pantry view that warns you before things expire. The average US household wastes ~$1,500 of food a year; Larder helps you fix that.檢視完整 README ↗Larder is an AI-powered inventory tracker that turns grocery receipts into a smart kitchen. Upload a photo of any receipt and Claude AI extracts every item — name, quantity, category, price, and estimated shelf life — into a pantry view that warns you before things expire. The average US household wastes ~$1,500 of food a year; Larder helps you fix that.
A production full-stack application built with Next.js 16 + React 19 on the frontend, FastAPI + Python on the backend, Supabase (Postgres + JWT auth) for data and identity, and Anthropic Claude for AI-powered receipt parsing. Deployed across Vercel and Render with GitHub Actions CI/CD.
Screenshots are checked into docs/screenshots and captured from the local production builds with a seeded demo pantry session.
| Pantry dashboard | Expiring soon |
|---|---|
| Scan receipt | Settings |
|---|---|
| Marketing landing page |
|---|
A complete end-to-end product built solo — frontend, backend, database, auth, AI integration, DevOps, and design.
| Area | Where it lives |
|---|---|
| Frontend engineering | 3 Next.js 16 App Router apps (web + marketing + docs), 11 routes, ~3,500 LOC of TypeScript/React |
| Backend engineering | FastAPI service with 10 endpoints, Pydantic v2 validation, dependency injection, lifespan hooks |
| Authentication & security | Supabase JWT (ES256) verification with JWKS, key-rotation fallback, type-email-to-confirm flows for destructive actions |
| Database design | Postgres schema with soft deletes, status state machine, re-purchase inference, indexed queries |
| AI / ML integration | Claude vision API for receipt parsing, structured JSON extraction, shelf-life estimation |
| DevOps & deployment | Three independent deploy targets (2× Vercel, 1× Render), explicit CORS allowlist via FRONTEND_URL, env-var-driven config |
| CI/CD | GitHub Actions: ruff lint, Next.js typecheck, auto-merge on green with retry loop |
| Product & UX design | Warm earthy design system, Notion-style sidebar, Headspace-inspired marketing site, animated mockups |
| Compliance | GDPR-friendly account deletion (cascades pantry + receipts + auth user), public privacy policy |
| URL | |
|---|---|
| 🏠 Marketing site | https://larder-website.vercel.app |
| 📱 Web app | https://larder-theta.vercel.app |
| 📖 Docs | https://larder-website.vercel.app/docs |
| 🔒 Privacy policy | https://larder-website.vercel.app/privacy |
| ⚙️ Backend API | https://larder.onrender.com |
| ❤️ Health check | https://larder.onrender.com/health |
| 💻 Source | https://github.com/Chinmay1220/Larder |
/expiring page grouped into Expired / Today / Next 3 daysPASSWORD_RECOVERY event handlingrequestAnimationFrame-based count-up stats@keyframes marquee ticker stripLarder treats Claude as a first-class component, not a wrapper.
canonical_name, category, quantity, unit, price, shelf_life_days); responses are then parsed and validated through Pydantic v2 before insertCode: backend/app/services/vision.py and backend/app/api/receipts.py
| Layer | Tech |
|---|---|
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind v4 |
| Backend | FastAPI, Pydantic v2, Uvicorn |
| Database & auth | Supabase (PostgreSQL, Row-Level Security, JWT) |
| AI | Anthropic Claude (claude-sonnet) — vision + structured extraction |
| File processing | Pillow (images), python-docx (Word), openpyxl (Excel), pdf parsing |
| Rate limiting | slowapi |
| Hosting | Vercel (frontend × 2), Render (Python backend) |
| CI/CD | GitHub Actions — ruff lint, Next.js typecheck, auto-merge on green |
┌────────────────────┐ ┌────────────────────┐
│ Marketing site │ │ Web app │
│ larder-website │ │ larder-theta │
│ (Next.js / SSG) │ │ (Next.js / CSR) │
└────────────────────┘ └─────────┬──────────┘
│ JWT (ES256)
▼
┌────────────────────┐
│ FastAPI backend │
│ larder.onrender │
│ │
│ ┌──────────────┐ │
│ │ /receipts │──┼──▶ Anthropic Claude
│ │ /pantry │ │
│ │ /account │ │
│ └──────┬───────┘ │
└─────────┼──────────┘
▼
┌────────────────────┐
│ Supabase │
│ • auth.users │
│ • pantry_items │
│ • receipts │
└────────────────────┘
status field (active, consumed_manual, consumed_inferred, expired, deleted) for full audit history. Re-purchase inference auto-marks duplicate active items as consumed_inferred when a new receipt adds the same canonical name.localhost plus the exact origins listed in FRONTEND_URL (comma-separated). There is deliberately no wildcard *.vercel.app regex, so arbitrary preview origins can't call the API; add a new front-end origin by setting the env var./decrement endpoint reads and updates quantity in one round-trip, marking the item consumed if it drops below 1.pantry-poc/
├── backend/ # FastAPI backend
│ ├── app/
│ │ ├── api/ # Route handlers (receipts, pantry, account)
│ │ ├── services/ # Business logic (vision, pantry_state)
│ │ ├── auth.py # JWT verification (ES256 + HS256 fallback)
│ │ ├── db.py # Supabase client
│ │ ├── limiter.py # Rate limiter config
│ │ └── main.py # FastAPI app + CORS + lifespan
│ ├── scripts/
│ │ └── nightly_expiry.py
│ └── requirements.txt
│
├── web/ # Next.js consumer app (auth-gated)
│ ├── app/
│ │ ├── page.tsx # Pantry dashboard
│ │ ├── scan/ # Receipt upload page
│ │ ├── login/ signup/ forgot-password/ reset-password/
│ │ ├── settings/ # Profile, password, account deletion
│ │ ├── expiring/ # Items expiring within 3 days
│ │ └── AppShell.tsx # Sidebar + mobile nav wrapper
│ └── lib/supabase.ts
│
├── website/ # Next.js marketing site
│ ├── app/
│ │ ├── page.tsx # Landing page
│ │ ├── docs/
│ │ └── privacy/
│ └── components/ # Nav, Footer, animated sections, FAQ, etc.
│
├── render.yaml # Render deployment config
├── .github/workflows/ # CI: lint, build, auto-merge
└── README.md
cd backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
Required env vars (backend/.env):
SUPABASE_URL=https://<project>.supabase.co
SUPABASE_SERVICE_KEY=<service role key>
ANTHROPIC_API_KEY=<key from console.anthropic.com>
FRONTEND_URL=http://localhost:3000
DEV_MODE=true
cd web && npm install && npm run dev
Required env vars (web/.env.local):
NEXT_PUBLIC_SUPABASE_URL=https://<project>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key>
NEXT_PUBLIC_API_URL=http://localhost:8000
cd website && npm install && npm run dev
All authenticated endpoints expect Authorization: Bearer <Supabase JWT>.
| Method | Path | Purpose |
|---|---|---|
POST | /receipts | Upload a receipt; returns extracted items |
GET | /pantry | List all active items |
GET | /pantry/expiring?days=3 | Items expiring within N days |
POST | /pantry | Manually add an item |
PATCH | /pantry/{id} | Edit an item |
PATCH | /pantry/{id}/consumed | Mark fully used |
PATCH | /pantry/{id}/decrement | Atomic quantity −1 |
DELETE | /pantry/{id} | Soft delete |
DELETE | /account | Hard delete account + cascade |
GET | /health | Liveness probe |
pantry_items| Column | Type | Notes |
|---|---|---|
id | uuid | PK |
user_id | uuid | FK → auth.users |
canonical_name | text | lowercased on insert |
category | text | enum-checked at API layer |
quantity | numeric | |
unit | text | |
price | numeric | nullable |
purchased_at | timestamptz | |
est_expiry | timestamptz | indexed |
consumed_at | timestamptz | nullable |
shelf_life_days | int | Claude estimate |
source_receipt_id | uuid | nullable, FK → receipts |
status | text | active, consumed_manual, consumed_inferred, expired, deleted |
receipts| Column | Type |
|---|---|
id | uuid (PK) |
user_id | uuid (FK → auth.users) |
uploaded_at | timestamptz |
item_count | int |
larder-website, deploys from mainlarder-theta, deploys from mainlarder, deploys from mainA merge to main triggers all three deploys via webhook.
Two scheduled GitHub Actions keep the free-tier services warm:
keepalive.yml — pings the Render /health endpoint every ~14 min so the backend never cold-starts (Render sleeps after 15 min idle).nightly.yml — runs the expiry sweep daily, which doubles as Supabase traffic so the database never pauses (Supabase free tier pauses after ~7 days idle).⚠️ Gotcha: GitHub auto-disables scheduled workflows after 60 days with no repo commits — which would silently stop the keepalive and pause Supabase. A commit to
mainresets that clock. Services last verified active: 2026-08-10.
MIT — built by Chinmay Sawant.