Eliminating food waste by connecting surplus food with communities in need.
- Screenshots
- Problem Statement
- Our Solution
- Key Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Testing
- User Roles & Flows
- AI Integration
- API Reference
- Security
- Performance Optimizations
- Browser Compatibility
- Roadmap
- Troubleshooting
- Contributing
- License
| Landing Page | AI Food Scanner | Volunteer Dashboard |
|---|---|---|
![]() |
AI-powered food analysis with category detection | Browse pickups, claim deliveries, upload proof |
| Donor Dashboard | Admin Panel | Transparency Ledger |
|---|---|---|
| Scan food, list donations, track pickups | Approve volunteers, review deliveries | Public accountability log |
1.3 billion tons of food is wasted globally every year, while 827 million people go hungry. A massive portion of edible food from restaurants, caterers, and households is thrown away simply because there is no efficient system to redistribute it in time.
| Challenge | Impact |
|---|---|
| No real-time visibility into surplus food | Edible food expires before it reaches people |
| Manual coordination between donors & volunteers | Delays cause spoilage |
| No quality verification for food safety | Trust issues prevent participation |
| No accountability in the delivery chain | Donors can't verify food reached the right people |
Vertical: Social Good / Environmental Sustainability (Food Tech)
Problem Statement Alignment: We chose this vertical precisely because the problem of food waste (1.3 billion tons annually) combined with global hunger (827 million people) is an incredibly solvable logistical problem. OpenTable aligns directly with this problem statement by providing a real-time, AI-driven coordination platform that removes the friction from food donation and eliminates the trust barrier for volunteers, ensuring surplus food reaches those in need before it spoils.
Our approach focuses on removing friction for food donors and building trust in the volunteer network.
Logic:
- Donor Friction: Restaurants won't donate if it takes 10 minutes to fill out a form. We use Google Gemini AI to let them just snap a photoβthe AI fills in the category, quantity estimates, and safety tags automatically.
- Trust & Safety: Charities won't accept food from unvetted strangers. We built an identity verification system and a digital "chain of custody" where every pickup and delivery is logged with photo proof.
- Real-time Sync: Food spoils fast. We use Firebase Firestore to ensure the moment a donor lists food, every volunteer's feed updates instantly without refreshing.
OpenTable is an AI-powered, real-time food rescue platform that creates a seamless bridge between food donors (restaurants, caterers, households) and communities in need, coordinated by verified volunteers.
graph LR
A[πͺ Donor uploads food photo] --> B[π€ Gemini AI analyzes & categorizes]
B --> C[π Listed on real-time feed]
C --> D[π Verified volunteer claims pickup]
D --> E[πΈ Volunteer delivers & uploads proof]
E --> F[β
Admin reviews & applauds]
- Donors: Snap a photo of surplus food. Google Gemini AI automatically categorizes it and adds safety context. The donation is broadcasted via Firebase to all nearby volunteers instantly.
- Volunteers: Must submit ID and selfie for admin verification. Once approved, they see an active feed of available pickups, accept a task, get Google Maps directions, and must upload photo proof of the final delivery.
- Admins: Oversee the entire ecosystem. They approve/reject volunteer verifications, audit the delivery proofs, and can "clap" (reward) volunteers for completed drives.
- Internet Access: We assume both donors and volunteers have reliable internet access and smartphone cameras to take photos of the food and delivery proofs.
- Platform Moderation: We assume there is a dedicated Admin team available to review volunteer applications in a timely manner so bottlenecks don't occur.
- Local Geography: Initially, we assume operations are within a single metropolitan area, meaning any volunteer seeing the feed is reasonably close to the donation pickups (Google Maps handles the exact routing).
- Food Safety Norms: We assume donors are following basic local health regulations before deciding an item is fit for donation.
- AI Food Scanner β Snap a photo β Gemini AI identifies the food, category, freshness level, and safety window
- One-Tap Listing β Add quantity, contact, location β donation goes live instantly
- Live Tracking β See when your donation is claimed and delivered in real-time
- GPS Integration β Auto-detect location for faster listing
- Available Pickups Feed β Browse all active food donations nearby
- One-Click Claim β Accept a pickup and get directions via Google Maps
- Delivery Proof β Camera integration to photograph delivery for accountability
- Completed Tab β Track all past deliveries and see admin π recognition
- One-Time Verification β Verify identity once, accept unlimited deliveries
- Approval Dashboard β Review volunteer identity verification requests (ID photo + selfie)
- Trust Scoring β Assign trust scores to volunteers
- Completed Deliveries β View all delivery proof photos
- Clap Recognition β π Applaud volunteers for successful deliveries
- Status Management β Approve, Flag, or Reject volunteer applications
- Food Image Recognition β Category detection (produce, dairy, bakery, prepared meals, etc.)
- Freshness Analysis β AI estimates remaining shelf life and safety parameters
- Smart Categorization β Auto-fill donation details for faster listing
graph TB
subgraph Frontend["React Frontend (Vite + TypeScript)"]
LP[Landing Page] --> Auth[Firebase Auth]
Auth --> RS[Role Selection]
RS --> DD[Donor Dashboard]
RS --> VD[Volunteer Dashboard]
RS --> AD[Admin Dashboard]
end
subgraph Services["External Services"]
Gemini[Google Gemini AI]
Cloud[Cloudinary CDN]
FS[Firebase Firestore]
FA[Firebase Auth]
end
DD -->|"Food Analysis"| Gemini
DD -->|"Image Upload"| Cloud
DD -->|"Save Donation"| FS
VD -->|"Delivery Proof"| Cloud
VD -->|"Update Status"| FS
AD -->|"Read/Write"| FS
style Frontend fill:#1a1a2e,stroke:#16213e,color:#fff
style Services fill:#0f3460,stroke:#16213e,color:#fff
| Collection | Purpose | Key Fields |
|---|---|---|
users |
User profiles & roles | uid, email, role, name |
donations |
Food donation listings | item, status, imageUrl, deliveryProofUrl, clappedByAdmin |
volunteersrequest |
Volunteer verification | idImageUrl, selfieUrl, status, trustScore |
| Layer | Technology | Purpose |
|---|---|---|
| Framework | React 19 + TypeScript | Component-based UI with type safety |
| Build Tool | Vite 6 | Lightning-fast HMR & optimized builds |
| Styling | Tailwind CSS | Utility-first responsive design |
| Database | Firebase Firestore | Real-time NoSQL database |
| Authentication | Firebase Auth | Google OAuth + Email/Password |
| AI | Google Gemini 2.0 Flash | Multimodal food image analysis |
| Image CDN | Cloudinary | Optimized image storage & delivery |
| **Serverless | Image CDN | Cloudinary |
| Icons | Lucide React | Consistent icon system |
| Deployment | Vercel | Edge-optimized hosting |
| PWA | vite-plugin-pwa | Progressive Web App capabilities |
OpenTable/
βββ .github/ # GitHub templates
β βββ ISSUE_TEMPLATE/
β β βββ bug_report.md # Bug report template
β β βββ feature_request.md # Feature request template
β βββ PULL_REQUEST_TEMPLATE.md # PR checklist template
βββ public/ # Static assets (logo, carousel images)
βββ src/
β βββ components/ # Reusable UI components
β β βββ DoodleBackground.tsx # Decorative background component
β β βββ ErrorBoundary.tsx # Global error boundary with retry
β β βββ Layout.tsx # App shell with navigation & footer
β β βββ Toast.tsx # Custom toast notification system
β βββ config/ # Application configuration
β β βββ env.ts # Environment variable validation
β β βββ index.ts # Config barrel exports
β βββ constants/ # App-wide constants & enums
β β βββ index.ts # Routes, roles, API URLs, collections
β βββ contexts/ # React Context providers
β β βββ AdminContext.tsx # Volunteer applications & admin actions
β β βββ AuthContext.tsx # Authentication state & role management
β β βββ DonationContext.tsx # Donation CRUD & real-time sync
β βββ hooks/ # Custom React hooks
β β βββ index.ts # Hook barrel exports
β β βββ useLocalStorage.ts # Persistent state in localStorage
β β βββ useMediaQuery.ts # Responsive breakpoint detection
β β βββ useToast.ts # Toast notification management
β βββ pages/ # Route-level page components
β β βββ AdminDashboard.tsx # Approve volunteers, view deliveries
β β βββ DashboardSelection.tsx # Dashboard type selector
β β βββ DonorDashboard.tsx # AI scan, list donations, track
β β βββ LandingPage.tsx # Hero, features, animated landing
β β βββ LoginPage.tsx # Auth (Google + Email/Password)
β β βββ OnboardingApplication.tsx # Volunteer identity verification
β β βββ RoleSelection.tsx # Post-login role picker
β β βββ TransparencyLedger.tsx # Public donation activity log
β β βββ VolunteerDashboard.tsx # Browse, claim, deliver, proof
β βββ services/ # External service integrations
β β βββ cloudinary.ts # Cloudinary image upload service
β β βββ firebase.ts # Firebase initialization & helpers
β β βββ geminiService.ts # Google Gemini AI integration
β βββ utils/ # Shared utility functions
β β βββ cn.ts # CSS class name combiner
β β βββ date.ts # Date formatting & relative time
β β βββ image.ts # Image processing & compression
β β βββ index.ts # Utility barrel exports
β βββ App.tsx # Route definitions with lazy loading
β βββ index.tsx # React DOM entry point
β βββ types.ts # Shared TypeScript type definitions
βββ .editorconfig # Editor formatting standards
βββ .env.example # Environment variable template
βββ .eslintrc.js # ESLint configuration
βββ .gitignore # Git ignore rules
βββ .prettierrc # Prettier code formatting config
βββ CHANGELOG.md # Version history (Keep a Changelog)
βββ CODE_OF_CONDUCT.md # Contributor Covenant CoC
βββ CONTRIBUTING.md # Contribution guidelines
βββ LICENSE # MIT License
βββ SECURITY.md # Security policy & reporting
βββ firestore.rules # Firebase security rules
βββ package.json # Dependencies & scripts
βββ tsconfig.json # TypeScript configuration (strict)
βββ vercel.json # Deployment config with caching
βββ vite.config.ts # Vite build configuration
- Node.js 18+ (Download)
- npm 9+
- A Firebase project (Create one)
- A Cloudinary account (Sign up)
# 1. Clone the repository
git clone https://github.com/anandhukrishnaas1/OpenTable.git
cd OpenTable
# 2. Install dependencies
npm install
# 3. Set up environment variables (see section below)
cp .env.example .env
# 4. Start the development server
npm run devThe app will be available at http://localhost:5173
npm run build
npm run previewCreate a .env file in the root directory with the following variables:
| Variable | Description | Required |
|---|---|---|
VITE_FIREBASE_API_KEY |
Firebase project API key | β |
VITE_OPENROUTER_API_KEY |
OpenRouter API key for Gemini AI | β |
VITE_CLOUDINARY_CLOUD_NAME |
Cloudinary cloud name | β |
VITE_CLOUDINARY_UPLOAD_PRESET |
Cloudinary unsigned upload preset | β |
VITE_FIREBASE_API_KEY=your_firebase_api_key
VITE_OPENROUTER_API_KEY=your_openrouter_api_key
VITE_CLOUDINARY_CLOUD_NAME=your_cloud_name
VITE_CLOUDINARY_UPLOAD_PRESET=your_upload_preset
β οΈ Security: The.envfile is gitignored. Never commit API keys to version control.
OpenTable uses Vitest for unit and integration testing.
# Run all tests once
npm run test
# Run tests in watch mode (re-runs on file changes)
npm run test:watch
# Run tests with coverage report
npm run test:coveragesrc/__tests__/
βββ setup.ts # Test environment setup (matchMedia & localStorage mocks)
βββ utils.test.ts # Unit tests for date, image, and className utilities
# Run all quality checks (typecheck + lint + format + test)
npm run validategraph TD
U[New User] -->|Sign Up| RS[Role Selection]
RS -->|"I want to donate"| D[Donor]
RS -->|"I want to volunteer"| V[Volunteer]
D -->|"Scan & List Food"| DD[Donor Dashboard]
V -->|"Must verify first"| OB[Onboarding Form]
OB -->|"Submit ID + Selfie"| Admin[Admin Review]
Admin -->|"Approve β
"| VD[Volunteer Dashboard]
Admin -->|"Reject β"| OB
style D fill:#22c55e,color:#fff
style V fill:#3b82f6,color:#fff
style Admin fill:#f97316,color:#fff
- Sign up / Login β Select "Donor" role
- Take a photo of food β AI analyzes it
- Add quantity, contact, address β Submit donation
- Track when volunteer picks it up
- Sign up / Login β Select "Volunteer" role
- Complete identity verification (ID photo + selfie)
- Admin reviews & approves (one-time process)
- Browse available pickups β Claim β Deliver β Upload proof photo
- See completed deliveries & admin recognition
- Login with admin account
- Review pending volunteer verifications
- Approve / Flag / Reject applications
- View completed deliveries & delivery proof photos
- π Clap for outstanding volunteers
OpenTable uses Google's Gemini 2.0 Flash model via OpenRouter for intelligent food analysis:
// Example AI prompt structure
const prompt = `Analyze this food image and provide:
- Food item name
- Category (produce, dairy, bakery, prepared, etc.)
- Estimated freshness condition
- Safe distribution window
- Storage recommendations`;| Feature | Description |
|---|---|
| Food Recognition | Identifies food type from photos |
| Category Detection | Auto-categorizes into food groups |
| Freshness Estimation | AI-assessed quality and safety |
| Smart Pre-fill | Auto-populates donation form fields |
For detailed API documentation of all external service integrations, see docs/API.md.
For architecture diagrams and design decisions, see docs/ARCHITECTURE.md.
| Layer | Implementation |
|---|---|
| Authentication | Firebase Auth (Google OAuth + Email/Password) |
| Authorization | Role-based access (user, volunteer, admin) |
| Database Rules | Firestore rules require request.auth != null for all operations |
| API Keys | Stored in environment variables, never committed to git |
| Image Storage | Cloudinary with unsigned upload presets (no API secret exposed) |
| Identity Verification | ID photo + selfie required for volunteer approval |
| Optimization | Impact |
|---|---|
| React.lazy + Suspense | ~60-70% reduction in initial bundle size via code splitting |
| Preconnect hints | 200-500ms faster first API calls (Firebase, Cloudinary, Fonts) |
| Browser caching (vercel.json) | JS/CSS cached 1 year; images cached 1 day with stale-while-revalidate |
| Cloudinary CDN | Images served from nearest edge node |
| Vite build | Tree-shaking, minification, chunk splitting |
| Firebase onSnapshot | Real-time sync without polling |
| Browser | Supported | Notes |
|---|---|---|
| Chrome 90+ | β | Recommended |
| Firefox 90+ | β | Full support |
| Safari 15+ | β | Full support |
| Edge 90+ | β | Full support |
| Mobile Chrome | β | PWA installable |
| Mobile Safari | β | PWA installable |
- AI-powered food scanning with Gemini
- Volunteer identity verification system
- Admin dashboard with clap recognition
- Real-time donation tracking
- Progressive Web App (PWA) support
- Push notifications for new donations
- Geo-based donation matching (nearest volunteer)
- Multi-language support (i18n)
- Donor impact analytics dashboard
- Mobile-native app (React Native)
Build fails with "Missing environment variables"
Ensure all required variables are set in your .env file. Copy from the template:
cp .env.example .envThen fill in your API keys. See Environment Variables for details.
Firebase Auth not working
- Ensure your Firebase project has Authentication enabled
- Enable the Google and Email/Password sign-in providers
- Add your domain (
localhostfor development) to the authorized domains list in Firebase Console β Authentication β Settings
AI food scanning returns "Unknown Item"
- Verify your
VITE_OPENROUTER_API_KEYis valid - Check that you have sufficient credits on OpenRouter
- Ensure the image is clear and well-lit for best AI results
Cloudinary upload fails
- Verify
VITE_CLOUDINARY_CLOUD_NAMEmatches your Cloudinary account - Ensure the upload preset (
VITE_CLOUDINARY_UPLOAD_PRESET) exists and is set to unsigned - Check your Cloudinary plan's upload limits
Tests failing after fresh clone
# Clean install dependencies
rm -rf node_modules package-lock.json
npm install
# Run tests
npm run testContributions are welcome! Please read our Contributing Guidelines before getting started.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CONTRIBUTING.md for detailed guidelines on code style, commit conventions, and PR requirements.
This project is licensed under the MIT License β see the LICENSE file for details.
- Push your code to GitHub
- Go to vercel.com and import your repository
- Set the environment variables in the Vercel dashboard:
VITE_FIREBASE_API_KEYVITE_OPENROUTER_API_KEYVITE_CLOUDINARY_CLOUD_NAMEVITE_CLOUDINARY_UPLOAD_PRESET
- Deploy β Vercel auto-detects Vite and configures the build
# Build for production
npm run build
# Preview locally
npm run previewThe dist/ folder can be deployed to any static hosting provider (Netlify, AWS S3, Firebase Hosting, etc.).
Q: How do I get a Gemini AI API key?
Sign up at OpenRouter and generate an API key. OpenTable uses the google/gemini-2.5-flash model via OpenRouter's unified API.
Q: Can I run this without AI features?
Yes β the app works without the AI key, but the food scanning feature will be disabled. All other features (listing, claiming, delivery) work independently.
Q: How do I become an admin?
Manually set the role field to "admin" in the user's Firestore document under the users collection.
Q: Is this project PWA-compatible?
Yes! OpenTable is configured as a Progressive Web App via vite-plugin-pwa. Users can install it on mobile and desktop for an app-like experience.
Q: How do I configure Firebase?
- Create a Firebase project at console.firebase.google.com
- Enable Authentication (Google + Email/Password providers)
- Create a Firestore database
- Copy the API key and add it to your
.envfile
- Google Gemini AI β Multimodal AI engine
- Firebase β Backend-as-a-Service
- Cloudinary β Image management platform
- Vercel β Edge deployment platform
- Lucide Icons β Icon library
- Vite β Next-generation build tool
Built with β€οΈ to fight food waste
OpenTable β Every meal matters.
- Code Quality: The project is structured component-by-component in React/TypeScript. Global states are isolated into context hooks (
useDonations,useAuth,useAdmin), and component internals leverage hooks likeuseMemoanduseCallbackto prevent unnecessary re-rendering. - Security: Authentication is firmly walled behind Firebase Auth. Firestore Security Rules enforce document access (only admins can approve volunteers, and only identical donors can edit their donations) which limits common risk vectors.
- Efficiency: The React single-page app utilizes lazy loading for main dashboard routes. Components only fetch data when absolutely necessary. Images are actively compressed and stored efficiently.
- Testing: The test suite provides comprehensive test coverage (
npm run test -- --coverage) covering hooks, services, types, edge cases and integration APIs. - Accessibility: Toast popups include
role="alert"andaria-live="assertive". All image tags use validalttext. The layout utilizes distinct semantic contrast and scaling support for screen readers. - Google Services: The application utilizes Google Services extensively across all workflows:
- Firebase Auth (Google OAuth & Email) for secure user access control.
- Firebase Firestore for real-time NO-SQL database synchronization across all volunteer & donor peers.
- Google Gemini 2.0 (via OpenRouter) for sophisticated AI/ML image processing of food categories and autonomous expiry analysis.
- Google Maps API (Client-side) for location generation and seamless navigation for volunteers claiming deliveries.
This project's code is fully open-source and hosted publicly at: https://github.com/anandhukrishnaas1/OpenTable
