# Product Tracker A web application for tracking product prices and shopping events. Built with FastAPI (Python) backend and React (TypeScript) frontend. ## Table of Contents - [Features](#features) - [Quick Start with Docker](#quick-start-with-docker) - [Architecture](#architecture) - [Data Model](#data-model) - [Development Setup](#development-setup) - [API Endpoints](#api-endpoints) - [Usage](#usage) - [Deployment](#deployment) - [Development](#development) - [Contributing](#contributing) ## Features - **Product Management**: Add, edit, and track product items with prices, categories, and organic status - **Shop Management**: Manage different shops with locations - **Brand Management**: Track product brands and their availability in different shops - **Shopping Events**: Record purchases with multiple products and amounts - **Price Tracking**: Monitor price changes over time - **Import/Export**: Bulk import and export data via CSV files - **Modern UI**: Clean, responsive interface built with React and Tailwind CSS ## Quick Start with Docker The fastest way to get the application running is with Docker Compose: ### Prerequisites - Docker Engine 20.10+ - Docker Compose 2.0+ ### Deploy in 3 Steps 1. **Clone and setup:** ```bash git clone cd groceries cp docker.env.example .env # Edit .env with your secure passwords ``` 2. **Start all services:** ```bash docker-compose up -d ``` 3. **Initialize database:** ```bash docker-compose exec backend alembic upgrade head ``` ### Access Your Application - **Frontend**: http://localhost - **Backend API**: http://localhost:8000 - **API Documentation**: http://localhost:8000/docs For detailed Docker deployment instructions, see [DOCKER_DEPLOYMENT.md](DOCKER_DEPLOYMENT.md). ## 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 - PapaParse - CSV parsing for import/export **Deployment:** - Docker & Docker Compose - Nginx - Web server and reverse proxy - PostgreSQL - Production database ### Component Communication ``` ┌─────────────────┐ HTTP/REST API ┌─────────────────┐ SQL Queries ┌─────────────────┐ │ React │ ←─────────────────→ │ FastAPI │ ←───────────────→ │ PostgreSQL │ │ Frontend │ JSON requests │ Backend │ SQLAlchemy ORM │ Database │ │ (Port 80) │ JSON responses │ (Port 8000) │ │ (Port 5432) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ## Data Model ### Core Entities #### Brands (`brands` table) - `id`: Integer, Primary key, Auto-increment - `name`: String, Brand name (indexed, required) - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) #### Grocery Categories (`grocery_categories` table) - `id`: Integer, Primary key, Auto-increment - `name`: String, Category name (indexed, required) - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) #### Products (`products` table) - `id`: Integer, Primary key, Auto-increment - `name`: String, Product name (indexed, required) - `category_id`: Integer, Foreign key to grocery_categories (required) - `brand_id`: Integer, Foreign key to brands (optional) - `organic`: Boolean, Organic flag (default: false) - `weight`: Float, Weight/volume (optional) - `weight_unit`: String, Unit of measurement (default: "piece") - Supported units: "g", "kg", "lb", "oz", "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) #### Brands in Shops (`brands_in_shops` table) Association table tracking which brands are available in which shops: - `id`: Integer, Primary key, Auto-increment - `shop_id`: Integer, Foreign key to shops (required) - `brand_id`: Integer, Foreign key to brands (required) - `created_at`: DateTime, Creation timestamp (auto-generated) - `updated_at`: DateTime, Last update timestamp (auto-updated) ### Association Table #### Shopping Event Products (`shopping_event_products` table) Many-to-many relationship between shopping events and products with additional data: - `id`: Integer, Primary key, Auto-increment - `shopping_event_id`: Integer, Foreign key to shopping_events (required) - `product_id`: Integer, Foreign key to products (required) - `amount`: Float, Quantity purchased in this event (required, > 0) - `price`: Float, Price at time of purchase (required, ≥ 0) ### Relationships ``` ┌─────────────────┐ 1:N ┌─────────────────┐ 1:N ┌─────────────────┐ │ Brands │ ────────→ │ Products │ ←──────── │ Grocery │ │ │ │ │ │ Categories │ │ • id │ │ • id │ │ • id │ │ • name │ │ • name │ │ • name │ │ • created_at │ │ • category_id │ │ • created_at │ │ • updated_at │ │ • brand_id │ │ • updated_at │ └─────────────────┘ │ • organic │ └─────────────────┘ │ │ • weight │ │ │ • weight_unit │ │ │ • created_at │ │ │ • updated_at │ │ └─────────────────┘ │ │ │ │ N:M │ ▼ │ ┌─────────────────────────────┐ │ │ Shopping Event Products │ │ │ (Association Table) │ │ │ │ │ │ • id │ │ │ • shopping_event_id │ │ │ • product_id │ │ │ • amount │ │ │ • price │ │ └─────────────────────────────┘ │ │ │ │ N:1 │ ▼ │ ┌─────────────────┐ 1:N ┌─────────────────┐ │ │ Shops │ ────────→ │ Shopping Events │ │ │ │ │ │ │ │ • id │ │ • id │ │ │ • name │ │ • shop_id │ │ │ • city │ │ • date │ │ │ • address │ │ • total_amount │ │ │ • created_at │ │ • notes │ │ │ • updated_at │ │ • created_at │ │ └─────────────────┘ │ • updated_at │ │ │ └─────────────────┘ │ │ │ │ N:M │ ▼ │ ┌─────────────────────────────┐ └────────────→ │ Brands in Shops │ │ (Association Table) │ │ │ │ • id │ │ • shop_id │ │ • brand_id │ │ • created_at │ │ • updated_at │ └─────────────────────────────┘ ``` ### Key Features - **Direct Product-Category Relationship**: Products are directly linked to categories for simplified organization - **Brand Tracking**: Optional brand association for products with shop availability tracking - **Price History**: Each product 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.) - **Shop-Brand Filtering**: Products can be filtered by brands available in specific shops - **Audit Trail**: All entities have creation timestamps for tracking - **Data Integrity**: Foreign key constraints ensure referential integrity - **Import/Export**: CSV-based bulk data operations for all entity types ## Development Setup ### 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 product_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 ### Brands - `GET /brands/` - List all brands - `POST /brands/` - Create new brand - `GET /brands/{id}` - Get specific brand - `PUT /brands/{id}` - Update brand - `DELETE /brands/{id}` - Delete brand ### Grocery Categories - `GET /grocery-categories/` - List all grocery categories - `POST /grocery-categories/` - Create new grocery category - `GET /grocery-categories/{id}` - Get specific grocery category - `PUT /grocery-categories/{id}` - Update grocery category - `DELETE /grocery-categories/{id}` - Delete grocery category ### Products - `GET /products/` - List all products - `POST /products/` - Create new product - `GET /products/{id}` - Get specific product - `PUT /products/{id}` - Update product - `DELETE /products/{id}` - Delete product ### Shops - `GET /shops/` - List all shops - `POST /shops/` - Create new shop - `GET /shops/{id}` - Get specific shop - `PUT /shops/{id}` - Update shop - `DELETE /shops/{id}` - Delete shop ### Brands in Shops - `GET /brands-in-shops/` - List all brand-shop associations - `POST /brands-in-shops/` - Create new brand-shop association - `GET /brands-in-shops/{id}` - Get specific brand-shop association - `GET /brands-in-shops/shop/{shop_id}` - Get brands available in specific shop - `GET /brands-in-shops/brand/{brand_id}` - Get shops that carry specific brand - `DELETE /brands-in-shops/{id}` - Delete brand-shop association ### Shopping Events - `GET /shopping-events/` - List all shopping events - `POST /shopping-events/` - Create new shopping event - `GET /shopping-events/{id}` - Get specific shopping event - `PUT /shopping-events/{id}` - Update shopping event - `DELETE /shopping-events/{id}` - Delete 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 products 2. **Add Categories**: Create grocery categories (e.g., "Dairy", "Produce", "Meat") 3. **Add Brands**: Create brands for your products (optional) 4. **Configure Shop-Brand Availability**: Associate brands with shops where they're available 5. **Add Products**: Create product items linked directly to categories and optionally to brands 6. **Record Purchases**: Use the "Add Shopping Event" form to record purchases with multiple products 7. **Track Prices**: Monitor how prices change over time for the same products 8. **Import/Export Data**: Use CSV files to bulk import or export your data 9. **View Statistics**: Analyze spending patterns by category and shop ## Deployment ### Docker Deployment (Recommended) The application includes a complete Docker Compose setup for easy deployment. This is the recommended way to deploy the application in production. **Quick deployment:** ```bash # Clone repository git clone cd groceries # Setup environment cp docker.env.example .env # Edit .env with your production values # Deploy docker-compose up -d # Initialize database docker-compose exec backend alembic upgrade head ``` **Services included:** - PostgreSQL database with persistent storage - FastAPI backend with health checks - React frontend served by Nginx - Automatic service restart and dependency management For comprehensive deployment instructions, troubleshooting, and production considerations, see **[DOCKER_DEPLOYMENT.md](DOCKER_DEPLOYMENT.md)**. ### Manual Deployment For development or custom deployments, you can also run the services manually using the [Development Setup](#development-setup) instructions above. ## 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 ``` ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make changes 4. Add tests 5. Submit a pull request ## License MIT License