NoWaste is a Next.js app for reducing food waste by connecting surplus restaurant inventory to customers.
- Marketplace browse + listing detail + checkout entry
- Restaurant listings operations hub:
- create listings
- search/filter listings
- inline edit pricing and inventory
- pause / activate / archive / delete listing lifecycle actions
- Orders center:
- API-backed order history
- status filters and search
- cancellation action with server updates
- pickup code confirmation flow
- Restaurant reservations queue (
/reservations):- lists persisted checkouts for the scoped restaurant (staff) or a selected restaurant (admin via
?restaurantId=) - mark Picked up or No-show (
PATCH /api/orders/{orderId}/fulfillmentwith{ "status": "picked_up" | "missed_pickup" }) - new reservations store
restaurantId/restaurantNameon the order at checkout time
- lists persisted checkouts for the scoped restaurant (staff) or a selected restaurant (admin via
| Method | Path | Notes |
|---|---|---|
GET |
/api/orders/restaurant |
Staff: restaurant scope comes from the signed session (nw-session-sig covers nw-restaurant-id). Admin: requires ?restaurantId=<id>. |
PATCH |
/api/orders/{orderId}/fulfillment |
Body: { "status": "picked_up" } or { "status": "missed_pickup" }. Only while fulfillment is reserved. |
Signed session cookies (nw-authenticated, nw-role, optional nw-restaurant-id, and nw-session-sig) use AUTH_SESSION_SECRET. Staff cannot change nw-restaurant-id without invalidating the signature.
For local demos, POST /api/auth/nw-session with JSON such as { "role": "restaurant_staff", "restaurantId": "r1" } sets matching cookies. In production the route requires ALLOW_NW_SESSION_ISSUE=1 and header x-nw-session-issue-secret matching NW_SESSION_ISSUE_SECRET. Prefer issuing scope from your auth provider when user profiles store restaurantId.
npm install
npm run devOpen http://localhost:3000.
Use this when you want the real native shell (not only the browser). Full detail is in CONTRIBUTING.md.
Prerequisites
- iOS: Mac with Xcode and iOS Simulator. CocoaPods if the iOS project prompts you.
- Android: Android Studio with an emulator, after a one-time
npm run mobile:android:add(see below).
First time only (iOS)
npm install
npm run mobile:ios:add
npm run mobile:syncFirst time only (Android)
npm install
npm run mobile:android:add
npm run mobile:syncEvery day — one command (starts Next on MOBILE_DEV_PORT / MOBILE_PORT, default 3000, waits until that URL responds, then opens the simulator)
| Platform | Command |
|---|---|
| iOS | npm run mobile:ios:dev (shorthand: npm run sim:ios) |
| Android | npm run mobile:android:dev (shorthand: npm run sim:android) |
Custom port (e.g. 3000 already in use): MOBILE_DEV_PORT=3001 npm run sim:ios — use the same port in CAP_SERVER_URL on a physical device (see Contributing).
If Capacitor or Xcode misbehave, run npm run mobile:doctor.
Physical phone on Wi‑Fi: keep npm run dev:mobile running, then run Capacitor with your computer’s LAN IP and the same port (see CONTRIBUTING.md).
npm run lint
npm run typecheck
npm test
npm run buildNoWaste ships as a Next.js app with optional Capacitor native shells. It is not Expo: npm run dev does not show i / a / w shortcuts (that is Expo CLI). Use the flows in CONTRIBUTING.md instead.
| Goal | Command / flow |
|---|---|
| Web (any OS) | npm run dev → open http://localhost:3000 |
| iOS Simulator (Mac + Xcode) | One command: npm run mobile:ios:dev — or two terminals: npm run dev:mobile + npm run ios |
| Android emulator | One-time npm run mobile:android:add, then npm run mobile:android:dev (or dev:mobile + npm run android) |
| Physical device | npm run dev:mobile plus CAP_SERVER_URL=http://<your-LAN-IP>:<port> matching MOBILE_DEV_PORT (default 3000; see Contributing) |
Short merge-friendly workflow tips for larger features are also in CONTRIBUTING.md.
Next.js(App Router, route handlers)TypeScriptReactTailwind CSS(v4 via@tailwindcss/postcss)Zod+react-hook-formVitestfor testsSupabase(auth/data integration points)Stripe(checkout session integration)
npm installCopy .env.example to .env.local and set values:
cp .env.example .env.localRequired keys:
NEXT_PUBLIC_APP_URLNEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSTRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRETAUTH_SESSION_SECRETEXPIRE_RESERVATIONS_SECRET
-
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEY- Create/select a project in Supabase.
- Go to Project Settings -> API.
- Use Project URL for
NEXT_PUBLIC_SUPABASE_URL. - Use anon/public key for
NEXT_PUBLIC_SUPABASE_ANON_KEY.
-
STRIPE_SECRET_KEY- Create/login to Stripe.
- Use Developers -> API keys -> Secret key (test key for local).
-
STRIPE_WEBHOOK_SECRET- In Stripe Dashboard: Developers -> Webhooks, create an endpoint for
/api/stripe/webhook. - Copy the endpoint signing secret into
STRIPE_WEBHOOK_SECRET. - Local development: run
stripe listen --forward-to localhost:3000/api/stripe/webhookand use the displayed signing secret.
- In Stripe Dashboard: Developers -> Webhooks, create an endpoint for
-
AUTH_SESSION_SECRET- Random 32+ byte secret used for server-side session signature checks.
- Example generation:
openssl rand -hex 32.
-
EXPIRE_RESERVATIONS_SECRET- Random secret for the reservation expiration job endpoint auth header.
- Example generation:
openssl rand -hex 32.
Default (stabilized) dev mode:
npm run devOptional Turbopack regression mode:
npm run dev:turboApp runs at http://localhost:3000.
npm run dev- start local dev server (Webpack mode)npm run dev:mobile- dev server on0.0.0.0andMOBILE_DEV_PORT(default 3000; aliasMOBILE_PORT)npm run dev:turbo- start local dev server in Turbopack modenpm run mobile:ios:dev/npm run mobile:android:dev- start dev server, wait for HTTP on the chosen port, then open simulator (180s wait budget for slow compiles)npm run sim:ios/npm run sim:android- aliases for the abovenpm run mobile:doctor- Capacitor environment check (cap doctor)npm run ios/npm run android- Capacitor only (runnpm run dev:mobilein another terminal; see CONTRIBUTING.md)npm run mobile:sync- production build +cap sync(all added platforms)npm run build- production buildnpm run start- run production servernpm run lint- lint codebasenpm run typecheck- TypeScript checksnpm test- run all testsnpm run test:unit- unit tests (src/lib)npm run test:component- component tests (src/components)npm run test:integration- API/integration tests (src/app/api)npm run test:ci- CI-oriented test run
- Restaurant operations
- Dashboard
- Create/manage listings
- Pickup verification and audit views
- Customer marketplace
- Browse/filter listings
- Listing and restaurant detail pages
- Checkout and order confirmation
- Donation fallback
- Convert unsold listings to donation flow
- Partner claim and handoff lifecycle
- Admin/reporting
- Admin guarded pages
- CSV export route for reporting
POST /api/listings- create listing (auth + role scoped)POST /api/checkout/session- create Stripe checkout sessionPOST /api/jobs/expire-reservations- secure expiration job endpointPOST /api/stripe/webhook- Stripe event finalization for payment statusGET /api/orders/me- customer-scoped order history fromnw-user-idcookieGET /api/admin/reports/csv- admin-only CSV export
- Branch protection on
mainrequires PR review. - Use feature/fix branches and open PRs into
main. - Larger features: follow CONTRIBUTING.md to reduce merge pain on shared files and native projects.
- Keep secrets only in
.env.local; never commit secrets.
-
Dev server hangs or logs repeated
Can't resolve 'tailwindcss'- Use the stabilized default:
npm run dev(Webpack mode). - Turbopack remains available via
npm run dev:turbofor regression checks. - Stop runaway dev processes before retrying:
pkill -f "next dev"
- Use the stabilized default:
-
Env-related startup/runtime errors
- Confirm
.env.localincludes all required keys from this README. - Re-check variable names exactly (for example,
NEXT_PUBLIC_SUPABASE_ANON_KEY).
- Confirm
-
API routes returning
401/403locally- Some routes are intentionally protected (admin/job endpoints).
- Confirm required auth cookies/headers and secrets are set before testing those routes.
-
Build/test drift
- Run full local validation:
npm run lint && npm test && npm run typecheck && npm run build
- Run full local validation:
-
npm run mobile:syncfails onpod install/xcodebuild/ “CommandLineTools”- iOS sync requires the full Xcode app, not only Apple Command Line Tools.
- Run:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developerthensudo xcodebuild -runFirstLaunch, open Xcode once, and retrymobile:sync. - More detail: CONTRIBUTING.md (macOS + Xcode section).
Before opening a PR:
npm run lint
npm test
npm run typecheck
npm run build