# Project export: Grocify

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Track your pantry, ensure dietary restrictions, craft personalized recipes—ensuring zero waste, smart shopping, and efficient cooking.
- Devpost: https://devpost.com/software/grocify
- GitHub: https://github.com/Sachin-dot-py/Grocify
- Demo: https://grocify.co/
- Video: https://www.youtube.com/embed/3mnrfpyawdU?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner ([MLH] Best Domain Name from GoDaddy Registry)
- Team: 2 GitHub contributor(s) — Sachin Ramanathan (34 commits), SujalGour (7 commits)

## Devpost submission (written by the team)

### Inspiration

The idea for Grocify came from a small but frustrating moment in our busy college lives. We bought a perfect avocado, full of possibilities. But in the loop of classes and assignments, it sat there, forgotten. By the time we remembered, it was too late—a sad, mushy reminder of how hard it can be to keep track of fresh groceries and how much food we waste. That moment made us wonder—how many others face the same problem? Wasting food isn’t just annoying; it’s wasteful and bad for the environment. We wanted a way to avoid these moments, save money, and make our busy lives a bit more organized. That’s how Grocify was born: a simple, intuitive tool to help manage groceries, track expiry dates, and reduce food waste, all while making it easier to use what we buy. What It Does Grocify is like having a personal grocery assistant in your pocket, making food management easy. From keeping track of what’s in your pantry to ensuring nothing goes to waste, Grocify helps you stay on top of your groceries without the hassle. Using barcode and image scanning, adding items is quick and painless—just scan the barcode or click the photo. Once items are in the inventory, Grocify takes care of tracking expiry dates and helping you avoid the mess. Grocify can suggest recipes based on what you have, prioritizing ingredients nearing expiration. It even considers your dietary preferences, so the recipes are not just convenient but fit your needs. And if you get stuck while cooking, our helpful assistant is just a tap away to guide you through the steps. How We Built It Building Grocify was an iterative process that began with understanding how to simplify grocery management for users. We started by prototyping a user journey that made adding items effortless—leading us to integrate barcode scanning using an API and advanced image recognition powered by Llama. Once core features were established, we added an inventory page to track product statuses in real time. Next, we introduced a Recipes page that curates personalized recipes tailored to the ingredients users already have, utilizing the mixtral and gemma models through Groq to deliver optimal suggestions. To enhance the experience, we integrated a chatbot that offers step-by-step cooking guidance, understanding that many college students may need extra support in the kitchen. We also included options for specifying dietary preferences and special requests, allowing the app to generate customized recipes that fit users' needs. Overall, Grocify aims to take the hassle out of grocery management and make cooking approachable and enjoyable. Challenges We Ran Into As with any ambitious project, building Grocify came with its fair share of challenges—some of which were quite unexpected! One of the first major hurdles was getting the barcode scanner to correctly identify individual products, especially when they were originally part of a larger package. We had a particularly amusing incident where we scanned a single granola bar, and it read as a 24-pack—likely because it was originally part of a larger box. Another challenge was integrating the expiry date feature. We thought it would be simple enough to estimate how long items would stay fresh—until we realized our initial model displayed expiry dates for ripe bananas as being three weeks later. After plenty of trial and error, we fine-tuned the system to provide realistic expiry estimates, even for tricky produce. The chatbot also posed an interesting problem. Initially, it answered simple cooking questions, but we quickly found users asking wild inquiries—like substituting pancake mix for flour in every recipe. The chatbot ended up giving overly confident (and wrong) advice, so we had to add extra checks to prevent it from turning into a rogue chef. Through all these challenges, we learned to stay adaptable. Every hurdle helped us refine Grocify, ensuring users would have an intuitive and reliable experience. Accomplishments That We're Proud Of We are especially proud of how Grocify makes sustainable living effortless. It’s not just about managing groceries—it’s about reducing food waste, saving money, and making it all incredibly easy. The convenience is unmatched: you can check what’s in your pantry on your way home, plan a recipe, and know exactly what to cook before stepping through the door. One of our biggest wins is making sustainability accessible. As a vegetarian, I love how easy it is to see if a product fits my dietary restrictions just by scanning it. Grocify takes the guesswork out of managing groceries, ensuring everyone can make choices that are good for them and for the planet. Although working with personalized dietary restrictions added complexity, there were moments where we were surprised by how aware the system was about common allergens in products. For example, we learned through the app's warning that Cheetos contain milk and aren't vegan—a detail we would never have guessed. Seeing the system catch these details made us incredibly proud. Another highlight was realizing our image recognition feature could distinguish even the most visually similar produce items. During testing, we saw the app correctly identify subtle differences between items like mandarins and oranges, which felt like a major leap forward. We're also proud of how Grocify estimates expiry dates. Though we initially had some hiccups, refining that system into something accurate and reliable took a lot of work, and the payoff was worth it. What We Learned Building Grocify taught us the importance of empathy and thoughtful design. Small features like barcode scanning and personalized recipes can make managing groceries easier and reduce waste. The vision of integrating with stores for automatic syncing showed us how to reach a broader audience, making things effortless for users. Sustainability doesn't have to be complicated with the right tools, and these insights will guide us as we continue improving Grocify. We also learned how to effectively leverage generative AI and LLM (Large Language Model) APIs. Integrating these technologies allowed us to build features far more sophisticated than we imagined. The chatbot, powered by an LLM, evolved into an intelligent assistant capable of answering complex cooking questions, generating custom recipes, and offering helpful substitutions. Working with generative AI taught us about prompt engineering—how to structure inputs to get useful outputs, and how to refine responses for user-friendliness. What's Next for Grocify Moving forward, we want Grocify to empower users even more when it comes to choosing what they bring into their homes. By expanding our barcode scanning feature, we aim to give users the ability to quickly evaluate products based on their ingredient lists, helping them avoid items with excessive chemicals or preservatives and make healthier choices. We also plan to enhance our recipe generator by incorporating even more personalization, so users can discover meals that align perfectly with their health goals and preferences. Our mission is to make grocery management smarter and healthier for everyone—while keeping it simple, intuitive, and focused on sustainability. Additionally, we want to integrate Grocify with popular stores like Trader Joe's, allowing users to sync purchases directly with the app. This means items bought in-store can be automatically added to their inventory, making the process seamless. By leveraging our barcode scanning feature, users will also be able to access detailed nutritional facts, enabling more informed dietary decisions.

## README (from the GitHub repository)

# Grocify: Your Personal Grocery Assistant

Grocify is an all-in-one food tracking, grocery management, and cooking assistant platform designed to help users efficiently manage their kitchen inventory. It provides features such as barcode scanning, personalized recipe suggestions, dietary-specific custom recipe generation, and more, making it easier to manage ingredients, minimize food waste, and explore new recipes.

## Built for Cal Hacks 11.0

Grocify was created as part of Cal Hacks 11.0 in San Francisco. We wanted to challenge ourselves to solve a real-world problem within the hackathon's time constraints, and food waste felt like an issue that resonated with many of us. Over an intense weekend of brainstorming, coding, and testing, we brought Grocify to life, aiming to make grocery management smarter, more sustainable, and accessible to everyone.

Demo Video: https://www.youtube.com/watch?v=3mnrfpyawdU

## Tech Stack

- **Frontend**: React.js with Bootstrap for styling.
- **Backend**: Flask (Python) for API and backend functionality.
- **Database**: MongoDB Atlas for storing inventory items and user information.
- **Web Server**: Nginx used for serving frontend and acting as a reverse proxy for the backend.
- **Deployment**: DigitalOcean Droplet.

## Description
### Inspiration
The idea for Grocify came from a small but frustrating moment in our busy college lives. We bought a perfect avocado, full of possibilities. But in the loop of classes and assignments, it sat there, forgotten. By the time we remembered, it was too late—a sad, mushy reminder of how hard it can be to keep track of fresh groceries and how much food we waste.

That moment made us wonder—how many others face the same problem? Wasting food isn’t just annoying; it’s wasteful and bad for the environment. We wanted a way to avoid these moments, save money, and make our busy lives a bit more organized. That’s how Grocify was born: a simple, intuitive tool to help manage groceries, track expiry dates, and reduce food waste, all while making it easier to use what we buy.

### What It Does
Grocify is like having a personal grocery assistant in your pocket, making food management easy. From keeping track of what’s in your pantry to ensuring nothing goes to waste, Grocify helps you stay on top of your groceries without the hassle.

Using barcode and image scanning, adding items is quick and painless—just scan the barcode or click the photo. Once items are in the inventory, Grocify takes care of tracking expiry dates and helping you avoid the mess.

Grocify can suggest recipes based on what you have, prioritizing ingredients nearing expiration. It even considers your dietary preferences, so the recipes are not just convenient but fit your needs. And if you get stuck while cooking, our helpful assistant is just a tap away to guide you through the steps.

### How We Built It
Building Grocify was an iterative process that began with understanding how to simplify grocery management for users. We started by prototyping a user journey that made adding items effortless—leading us to integrate barcode scanning using an API and advanced image recognition powered by Llama. Once core features were established, we added an inventory page to track product statuses in real time. Next, we introduced a Recipes page that curates personalized recipes tailored to the ingredients users already have, utilizing the mixtral and gemma models through Groq to deliver optimal suggestions.

To enhance the experience, we integrated a chatbot that offers step-by-step cooking guidance, understanding that many college students may need extra support in the kitchen. We also included options for specifying dietary preferences and special requests, allowing the app to generate customized recipes that fit users' needs. Overall, Grocify aims to take the hassle out of grocery management and make cooking approachable and enjoyable.

### Challenges We Ran Into
As with any ambitious project, building Grocify came with its fair share of challenges—some of which were quite unexpected! One of the first major hurdles was getting the barcode scanner to correctly identify individual products, especially when they were originally part of a larger package. We had a particularly amusing incident where we scanned a single granola bar, and it read as a 24-pack—likely because it was originally part of a larger box.

Another challenge was integrating the expiry date feature. We thought it would be simple enough to estimate how long items would stay fresh—until we realized our initial model displayed expiry dates for ripe bananas as being three weeks later. After plenty of trial and error, we fine-tuned the system to provide realistic expiry estimates, even for tricky produce.

The chatbot also posed an interesting problem. Initially, it answered simple cooking questions, but we quickly found users asking wild inquiries—like substituting pancake mix for flour in every recipe. The chatbot ended up giving overly confident (and wrong) advice, so we had to add extra checks to prevent it from turning into a rogue chef.

Through all these challenges, we learned to stay adaptable. Every hurdle helped us refine Grocify, ensuring users would have an intuitive and reliable experience.

### Accomplishments That We're Proud Of
We are especially proud of how Grocify makes sustainable living effortless. It’s not just about managing groceries—it’s about reducing food waste, saving money, and making it all incredibly easy. The convenience is unmatched: you can check what’s in your pantry on your way home, plan a recipe, and know exactly what to cook before stepping through the door.

One of our biggest wins is making sustainability accessible. As a vegetarian, I love how easy it is to see if a product fits my dietary restrictions just by scanning it. Grocify takes the guesswork out of managing groceries, ensuring everyone can make choices that are good for them and for the planet. Although working with personalized dietary restrictions added complexity, there were moments where we were surprised by how aware the system was about common allergens in products. For example, we learned through the app's warning that Cheetos contain milk and aren't vegan—a detail we would never have guessed. Seeing the system catch these details made us incredibly proud.

Another highlight was realizing our image recognition feature could distinguish even the most visually similar produce items. During testing, we saw the app correctly identify subtle differences between items like mandarins and oranges, which felt like a major leap forward. We're also proud of how Grocify estimates expiry dates. Though we initially had some hiccups, refining that system into something accurate and reliable took a lot of work, and the payoff was worth it.

### What We Learned
Building Grocify taught us the importance of empathy and thoughtful design. Small features like barcode scanning and personalized recipes can make managing groceries easier and reduce waste. The vision of integrating with stores for automatic syncing showed us how to reach a broader audience, making things effortless for users. Sustainability doesn't have to be complicated with the right tools, and these insights will guide us as we continue improving Grocify.

We also learned how to effectively leverage generative AI and LLM (Large Language Model) APIs. Integrating these technologies allowed us to build features far more sophisticated than we imagined. The chatbot, powered by an LLM, evolved into an intelligent assistant capable of answering complex cooking questions, generating custom recipes, and offering helpful substitutions. Working with generative AI taught us about prompt engineering—how to structure inputs to get useful outputs, and how to refine responses for user-friendliness.

### What's Next for Grocify
Moving forward, we want Grocify to empower users even more when it comes to choosing what they bring into 

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 23 recognized source files, 92 KB.
- CSS (language) — detected in the code
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- MongoDB (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (30 of 30)

```
backend/.gitignore
backend/app.py
backend/requirements.txt
frontend/.gitignore
frontend/package.json
frontend/public/index.html
frontend/public/manifest.json
frontend/public/robots.txt
frontend/public/site.webmanifest
frontend/src/App.css
frontend/src/App.js
frontend/src/App.test.js
frontend/src/components/Header.js
frontend/src/index.css
frontend/src/index.js
frontend/src/pages/AddItem.css
frontend/src/pages/AddItem.js
frontend/src/pages/Home.css
frontend/src/pages/Home.js
frontend/src/pages/Inventory.css
frontend/src/pages/Inventory.js
frontend/src/pages/Login.css
frontend/src/pages/Login.js
frontend/src/pages/Recipes.css
frontend/src/pages/Recipes.js
frontend/src/reportWebVitals.js
frontend/src/setupTests.js
README.md
setup.sh
update.sh
```

### Dependencies

- backend/requirements.txt: flask, flask_bcrypt, flask_jwt_extended, flask-cors, openai, pymongo, python-dotenv, requests
- frontend/package.json: @testing-library/jest-dom@^5.14.1, @testing-library/react@^13.0.0, @testing-library/user-event@^13.2.1, axios@^1.7.7, bootstrap@^5.3.3, quagga@^0.12.1, react@^18.3.1, react-bootstrap@^2.10.5, react-dom@^18.3.1, react-icons@^5.3.0, react-markdown@^9.0.1, react-router-dom@^6.27.0, react-scripts@5.0.1, react-webcam@^7.2.0, web-vitals@^2.1.0

### Recent commits (newest first)

- Add demo video and screenshots
- Edit README
- Update README
- Add error handling for barcode scanning
- Remove Edit button
- Improve prompt for Recipe Chat and improve design
- Add "Chat with the Head Chef"
- Add README
- Rewrite error message
- Add Dietary Restrictions and Estimated Expiry Dates
- Foundation for dietary restriction warnings
- Fix bug fix for barcode scanning on desktop
- Align Login/Logout buttons to the right
- Fix NavBar alignment to make it mobile friendly
- Format NavBar
- Use rear camera on phone
- Update logo and favicon
- Egde for Login
- Re-add backend recipe generation code
- Updated Edge cases

## Key source files (fetched from GitHub, selected and truncated for size)

### backend/requirements.txt

```
flask
pymongo
flask_bcrypt
flask_jwt_extended
requests
openai
python-dotenv
flask-cors
```

### frontend/package.json

```
{
  "name": "grocify-frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "axios": "^1.7.7",
    "bootstrap": "^5.3.3",
    "quagga": "^0.12.1",
    "react": "^18.3.1",
    "react-bootstrap": "^2.10.5",
    "react-dom": "^18.3.1",
    "react-icons": "^5.3.0",
    "react-markdown": "^9.0.1",
    "react-router-dom": "^6.27.0",
    "react-scripts": "5.0.1",
    "react-webcam": "^7.2.0",
    "web-vitals": "^2.1.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### frontend/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### frontend/src/App.js

```javascript
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Header from './components/Header';
import Home from './pages/Home';
import Inventory from './pages/Inventory';
import Recipes from './pages/Recipes';
import AddItem from './pages/AddItem';
import Login from './pages/Login';

function App() {
  return (
    <Router>
      <div className="App">
        <Header />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/inventory" element={<Inventory />} />
          <Route path="/recipes" element={<Recipes />} />
          <Route path="/add-item" element={<AddItem />} />
          <Route path="/login" element={<Login />} />
        </Routes>
      </div>
    </Router>
  );
}

export default App;

```

### backend/app.py

```python
from flask import Flask, request, jsonify
from datetime import timedelta
import os
import requests
from pymongo import MongoClient
from flask_bcrypt import Bcrypt
from flask_jwt_extended import JWTManager, create_access_token, create_refresh_token, jwt_required, get_jwt_identity
import base64
import json
from openai import OpenAI
from dotenv import load_dotenv
from bson import ObjectId
from flask_cors import CORS
import datetime

load_dotenv()
app = Flask(__name__)
CORS(app)
app.config["JWT_SECRET_KEY"] = os.getenv("JWT_SECRET_KEY")
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(days=7)  # Extend token validity to 7 days

# Custom JSON encoder to handle ObjectId
class JSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ObjectId):
            return str(o)
        return super().default(o)

app.json_encoder = JSONEncoder

# MongoDB setup
client = MongoClient(os.getenv("MONGO_URI"))  # Add your MongoDB Atlas URI
db = client.grocify
items_collection = db.items
users_collection = db.users
bcrypt = Bcrypt(app)
jwt = JWTManager(app)
gpt_client = OpenAI(base_url="https://api.groq.com/openai/v1", api_key=os.getenv("GROK_API_KEY"))

# BarcodeLookup API credentials
BARCODE_LOOKUP_API_KEY = os.getenv("BARCODE_API_KEY")
BARCODE_LOOKUP_API_URL = "https://api.barcodelookup.com/v3/products"

# For CORS
@app.after_request
def after_request(response):
    response.headers.add('Access-Control-Allow-Origin', '*')
    response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
    response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
    return response

# User registration
@app.route('/api/register', methods=['POST'])
def register():
    data = request.json
    username = data.get('username')
    password = data.get('password')

    if not username or not password:
        return jsonify({'error': 'Missing username or password'}), 400

    # Check if the username already exists
    if users_collection.find_one({'username': username}):
        return jsonify({'error': 'Username already exists'}), 400

    hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
    user = {
        'username': username,
        'password': hashed_password,
        'dietary_restrictions': None  # Initialize dietary restrictions as None
    }
    users_collection.insert_one(user)

    return jsonify({'message': 'User registered successfully'}), 201

# User login
@app.route('/api/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')

    if not username or not password:
        return jsonify({'error': 'Missing username or password'}), 400

    user = users_collection.find_one({'username': username})
    if user and bcrypt.check_password_hash(user['password'], password):
        access_token = create_access_token(identity=username)
        refresh_token = create_refresh_token(identity=username)
        return jsonify({'access_token': access_token, 'refresh_token': refresh_token}), 200
    elif user:
        return jsonify({'error': 'Incorrect password'}), 401
    else:
        return jsonify({'error': 'Username does not exist'}), 401

# Refresh token route
@app.route('/api/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
    current_user = get_jwt_identity()
    new_access_token = create_access_token(identity=current_user)
    return jsonify({'access_token': new_access_token}), 200

# Update dietary restrictions
@app.route('/api/user-info', methods=['PUT'])
@jwt_required()
def update_user_info():
    try:
        current_user = get_jwt_identity()
        data = request.json
        dietary_restrictions = data.get('dietary_restrictions')

        # Update dietary restrictions in the user's document
        result = users_collection.update_one(
            {'username': current_user},
            {'$set': {'dietary_restrictions': dietary_restrictions}}
        )

        if result.matched_count == 1:
            return jsonify({'message': 'Dietary restrictions updated successfully'}), 200
        else:
            return jsonify({'error': 'Failed to update dietary restrictions'}), 400
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# Route to fetch user information
@app.route('/api/user-info', methods=['GET'])
@jwt_required()
def user_info():
    try:
        current_user = get_jwt_identity()
        user = users_collection.find_one({'username': current_user})

        if not user:
            return jsonify({'error': 'User not found'}), 404

        return jsonify({
            'username': user['username'],
            'dietary_restrictions': user.get('dietary_restrictions')
        }), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# Route to handle barcode lookup
@app.route('/api/barcode/<barcode>', methods=['GET'])
@jwt_required()
def lookup_barcode(barcode):
    try:
        # Make the API call to BarcodeLookup.com
        params = {
            'barcode': barcode,
            'key': BARCODE_LOOKUP_API_KEY
        }
        response = requests.get(BARCODE_LOOKUP_API_URL, params=params)
        
        # Check if the response status is OK (200)
        if response.status_code != 200:
            return jsonify({'error': f'API request failed with status code {response.status_code}'}), 500
        
        # Parse the response as JSON
        data = response.json()

        # Check if data was found
        if 'products' in data and len(data['products']) > 0:
            product = data['products'][0]  # Get the first product match
            product_name = product.get('title', 'Unknown Product')
            product_image = product['images'][0] if 'images' in product and len(product['images']) > 0 else None

            return jsonify({
                'name': product_name,
                'image': product_image
            })
        else:
            return jsonify({'erro
[truncated — 16680 more characters]
```

### update.sh

```shell
#!/bin/bash

# Navigate to project directory
cd ~/Grocify

# Pull the latest changes from the Git repository
git pull origin main

# Rebuild the React frontend
cd frontend
npm install
npm run build

# Deploy updated frontend with Nginx
sudo cp -r build/* /var/www/html/

# Restart Nginx
sudo systemctl restart nginx

# Restart the backend Gunicorn service
sudo systemctl restart Grocify

# Final Message
echo "Update and deployment completed."

```

### setup.sh

```shell
#!/bin/bash

# Update and Install Essentials
sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl nginx python3-pip python3-venv ufw certbot python3-certbot-nginx
sudo apt install npm

# Clone Project Repository
mkdir -p ~/Grocify
cd ~/Grocify
git clone https://github.com/Sachin-dot-py/Grocify .

# Set Up Python Flask Backend
python3 -m venv venv
source venv/bin/activate
pip install -r backend/requirements.txt

# Install Gunicorn
pip install gunicorn

# Create Gunicorn Systemd Service
cat <<EOL | sudo tee /etc/systemd/system/Grocify.service
[Unit]
Description=Gunicorn instance to serve your Flask app
After=network.target

[Service]
User=root
Group=www-data
WorkingDirectory=/root/Grocify/backend
Environment="PATH=/root/Grocify/venv/bin"
ExecStart=/root/Grocify/venv/bin/gunicorn --workers 4 --bind 0.0.0.0:8000 app:app

[Install]
WantedBy=multi-user.target
EOL

# Enable and Start Backend Service
sudo systemctl enable Grocify
sudo systemctl start Grocify

# Set Up React Frontend
cd ~/Grocify/frontend
npm install
# TODO: .env file for frontend should be added here (.env for backend should be added at anytime)
npm run build

# Deploy Frontend with Nginx
sudo cp -r build/* /var/www/html/

# Configure Nginx
cat <<EOL | sudo tee /etc/nginx/sites-available/default
server {
    listen 80;
    server_name _;

    location / {
        root /var/www/html;
        index index.html index.htm;
        try_files \$uri \$uri/ /index.html;
    }

    location /api {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOL

# Restart Nginx
sudo nginx -t && sudo systemctl restart nginx

# Do yourself: Create .env files manually

# Final Message
echo "Deployment script completed."

```

### frontend/src/setupTests.js

```javascript
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

```

### frontend/src/App.test.js

```javascript
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

```

### frontend/src/reportWebVitals.js

```javascript
const reportWebVitals = onPerfEntry => {
  if (onPerfEntry && onPerfEntry instanceof Function) {
    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
      getCLS(onPerfEntry);
      getFID(onPerfEntry);
      getFCP(onPerfEntry);
      getLCP(onPerfEntry);
      getTTFB(onPerfEntry);
    });
  }
};

export default reportWebVitals;

```

[14 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]