# Grocery Tracker A web application for tracking grocery prices and shopping events. Built with FastAPI (Python) backend and React (TypeScript) frontend. ## Features - **Grocery Management**: Add, edit, and track grocery items with prices, categories, and organic status - **Shop Management**: Manage different shops with locations - **Shopping Events**: Record purchases with multiple groceries and amounts - **Price Tracking**: Monitor price changes over time - **Modern UI**: Clean, responsive interface built with React and Tailwind CSS ## Architecture ### Technology Stack **Backend (Python):** - FastAPI - Modern, fast web framework - SQLAlchemy - SQL toolkit and ORM - PostgreSQL - Relational database - Pydantic - Data validation and settings management - Alembic - Database migrations **Frontend (React):** - React 18 with TypeScript - React Router - Client-side routing - Tailwind CSS - Utility-first CSS framework - Axios - HTTP client for API calls - React Hook Form - Form handling ### Component Communication ``` ┌─────────────────┐ HTTP/REST API ┌─────────────────┐ SQL Queries ┌─────────────────┐ │ React │ ←─────────────────→ │ FastAPI │ ←───────────────→ │ PostgreSQL │ │ Frontend │ JSON requests │ Backend │ SQLAlchemy ORM │ Database │ │ (Port 3000) │ JSON responses │ (Port 8000) │ │ (Port 5432) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ## Data Model ### Core Entities #### Groceries (`groceries` table) - `id`: Integer, Primary key, Auto-increment - `name`: String, Grocery name (indexed, required) - `category`: String, Food category (required) - `organic`: Boolean, Organic flag (default: false) - `weight`: Float, Weight/volume (optional) - `weight_unit`: String, Unit of measurement (default: "piece") - Supported units: "g", "kg", "ml", "l", "piece" - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) #### Shops (`shops` table) - `id`: Integer, Primary key, Auto-increment - `name`: String, Shop name (indexed, required) - `city`: String, Location city (required) - `address`: String, Full address (optional) - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) #### Shopping Events (`shopping_events` table) - `id`: Integer, Primary key, Auto-increment - `shop_id`: Integer, Foreign key to shops (required) - `date`: DateTime, Purchase date (required, default: current time) - `total_amount`: Float, Total cost of shopping event (optional, auto-calculated) - `notes`: String, Optional notes about the purchase - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) ### Association Table #### Shopping Event Groceries (`shopping_event_groceries` table) Many-to-many relationship between shopping events and groceries with additional data: - `id`: Integer, Primary key, Auto-increment - `shopping_event_id`: Integer, Foreign key to shopping_events (required) - `grocery_id`: Integer, Foreign key to groceries (required) - `amount`: Float, Quantity purchased in this event (required, > 0) - `price`: Float, Price at time of purchase (required, ≥ 0) ### Relationships ``` ┌─────────────────┐ ┌─────────────────────────────┐ ┌─────────────────┐ │ Shops │ │ Shopping Event Groceries │ │ Groceries │ │ │ │ (Association Table) │ │ │ │ • id │ ←──────→│ • shopping_event_id │ ←──────→│ • id │ │ • name │ 1:N │ • grocery_id │ N:M │ • name │ │ • city │ │ • amount │ │ • category │ │ • address │ │ • price │ │ • organic │ │ • created_at │ │ │ │ • weight │ └─────────────────┘ └─────────────────────────────┘ │ • weight_unit │ │ │ │ • created_at │ │ │ │ • updated_at │ │ 1:N │ └─────────────────┘ ▼ │ ┌─────────────────┐ │ │ Shopping Events │ ←───────────────────────┘ │ │ 1:N │ • id │ │ • shop_id │ │ • date │ │ • total_amount │ │ • notes │ │ • created_at │ └─────────────────┘ ``` ### Key Features - **Price History**: Each grocery purchase stores the price at that time, enabling price tracking - **Flexible Quantities**: Support for decimal amounts (e.g., 1.5 kg of apples) - **Auto-calculation**: Total amount can be automatically calculated from individual items - **Free Items**: Supports items with price 0 (samples, promotions, etc.) - **Audit Trail**: All entities have creation timestamps for tracking - **Data Integrity**: Foreign key constraints ensure referential integrity ## Setup Instructions ### Prerequisites 1. **Python 3.8+** - For the backend 2. **Node.js 16+** - For the frontend 3. **PostgreSQL** - Database ### Backend Setup 1. **Navigate to backend directory:** ```bash cd backend ``` 2. **Create virtual environment:** ```bash python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` 3. **Install dependencies:** ```bash pip install -r requirements.txt ``` 4. **Setup database:** ```bash # Create PostgreSQL database createdb grocery_tracker # Copy environment variables cp env.example .env # Edit .env with your database credentials nano .env ``` 5. **Run database migrations:** ```bash alembic upgrade head # After setting up alembic ``` 6. **Start the backend server:** ```bash uvicorn main:app --reload ``` The API will be available at `http://localhost:8000` API docs at `http://localhost:8000/docs` ### Frontend Setup 1. **Navigate to frontend directory:** ```bash cd frontend ``` 2. **Install dependencies:** ```bash npm install ``` 3. **Start the development server:** ```bash npm start ``` The app will be available at `http://localhost:3000` ## API Endpoints ### Groceries - `GET /groceries/` - List all groceries - `POST /groceries/` - Create new grocery - `GET /groceries/{id}` - Get specific grocery - `PUT /groceries/{id}` - Update grocery - `DELETE /groceries/{id}` - Delete grocery ### Shops - `GET /shops/` - List all shops - `POST /shops/` - Create new shop - `GET /shops/{id}` - Get specific shop ### Shopping Events - `GET /shopping-events/` - List all shopping events - `POST /shopping-events/` - Create new shopping event - `GET /shopping-events/{id}` - Get specific shopping event ### Statistics - `GET /stats/categories` - Category spending statistics - `GET /stats/shops` - Shop visit statistics ## Usage 1. **Add Shops**: Start by adding shops where you buy groceries 2. **Add Groceries**: Create grocery items with prices and categories 3. **Record Purchases**: Use the "Add Purchase" form to record shopping events 4. **Track Prices**: Monitor how prices change over time 5. **View Statistics**: Analyze spending patterns by category and shop ## Development ### Running Tests **Backend:** ```bash cd backend pytest ``` **Frontend:** ```bash cd frontend npm test ``` ### Database Migrations ```bash cd backend alembic revision --autogenerate -m "Description" alembic upgrade head ``` ## Docker Deployment Create `docker-compose.yml` for easy deployment: ```yaml version: '3.8' services: db: image: postgres:15 environment: POSTGRES_DB: grocery_tracker POSTGRES_USER: grocery_user POSTGRES_PASSWORD: your_password volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" backend: build: ./backend ports: - "8000:8000" depends_on: - db environment: DATABASE_URL: postgresql://grocery_user:your_password@db:5432/grocery_tracker frontend: build: ./frontend ports: - "3000:3000" depends_on: - backend volumes: postgres_data: ``` ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make changes 4. Add tests 5. Submit a pull request ## License MIT License