407 lines
14 KiB
Markdown
407 lines
14 KiB
Markdown
# 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
|
|
- **Shopping Events**: Record purchases with multiple products and amounts
|
|
- **Price Tracking**: Monitor price changes over time
|
|
- **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 <your-repo-url>
|
|
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
|
|
- Axios - HTTP client for API calls
|
|
|
|
**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)
|
|
|
|
#### Groceries (`groceries` table)
|
|
- `id`: Integer, Primary key, Auto-increment
|
|
- `name`: String, Grocery item name (indexed, required)
|
|
- `category_id`: Integer, Foreign key to grocery_categories (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)
|
|
- `grocery_id`: Integer, Foreign key to groceries (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", "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 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 ┌─────────────────┐ 1:N ┌─────────────────┐
|
|
│ Brands │ ────────→ │ Products │ ←──────── │ Groceries │ ←──────── │ Grocery │
|
|
│ │ │ │ │ │ │ Categories │
|
|
│ • id │ │ • id │ │ • id │ │ • id │
|
|
│ • name │ │ • name │ │ • name │ │ • name │
|
|
│ • created_at │ │ • grocery_id │ │ • category_id │ │ • created_at │
|
|
│ • updated_at │ │ • brand_id │ │ • created_at │ │ • updated_at │
|
|
└─────────────────┘ │ • organic │ │ • updated_at │ │ • updated_at │
|
|
│ • 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 │
|
|
└─────────────────┘
|
|
```
|
|
|
|
### Key Features
|
|
|
|
- **Hierarchical Product Organization**: Products are organized by grocery type and category (e.g., "Apples" → "Fruits" → "Fresh Produce")
|
|
- **Brand Tracking**: Optional brand association for products
|
|
- **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.)
|
|
- **Audit Trail**: All entities have creation timestamps for tracking
|
|
- **Data Integrity**: Foreign key constraints ensure referential integrity
|
|
|
|
## 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
|
|
|
|
### 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
|
|
|
|
### 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
|
|
|
|
### 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 Products**: Create product 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
|
|
|
|
## 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 <your-repo-url>
|
|
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
|