# Costco Grocery List

A full-stack web application for managing grocery shopping lists with role-based access control, image support, and intelligent item classification.

![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Node](https://img.shields.io/badge/node-20.x-green.svg)
![React](https://img.shields.io/badge/react-19.2.0-blue.svg)
![Express](https://img.shields.io/badge/express-5.1.0-lightgrey.svg)

## 📋 Table of Contents
- [Overview](#overview)
- [System Architecture](#system-architecture)
- [Key Features](#key-features)
- [Technology Stack](#technology-stack)
- [Data Flow](#data-flow)
- [Role-Based Access Control](#role-based-access-control)
- [Getting Started](#getting-started)
- [API Documentation](#api-documentation)
- [Project Structure](#project-structure)
- [Development Workflow](#development-workflow)
- [Deployment](#deployment)

---

## 🎯 Overview

The Costco Grocery List application provides a collaborative platform for managing household grocery shopping. Users can add items with photos, track quantities, mark items as purchased, and organize items by store zones. The system supports multiple users with different permission levels, making it ideal for families or shared households.

**Live Demo:** [https://costco.nicosaya.com](https://costco.nicosaya.com)

---

## 🏗️ System Architecture

```mermaid
graph TB
    subgraph "Client Layer"
        A[React 19 SPA]
        B[Vite Dev Server]
    end
    
    subgraph "Application Layer"
        C[Express 5 API]
        D[JWT Auth Middleware]
        E[RBAC Middleware]
        F[Image Processing]
    end
    
    subgraph "Data Layer"
        G[(PostgreSQL)]
        H[grocery_list]
        I[users]
        J[item_classification]
        K[grocery_history]
    end
    
    A -->|HTTP/REST| C
    C --> D
    D --> E
    E --> F
    C --> G
    G --> H
    G --> I
    G --> J
    G --> K
    
    style A fill:#61dafb
    style C fill:#259dff
    style G fill:#336791
```

### Architecture Layers

1. **Presentation Layer (Frontend)**
   - React 19 with modern hooks (useState, useEffect, useContext)
   - Component-based architecture organized by feature
   - CSS custom properties for theming
   - Axios for HTTP requests with interceptors

2. **Business Logic Layer (Backend)**
   - Express.js REST API
   - JWT-based authentication
   - Role-based access control (RBAC)
   - Image optimization middleware (Sharp)
   - Centralized error handling

3. **Data Persistence Layer**
   - PostgreSQL relational database
   - Normalized schema with foreign key constraints
   - Junction table for item history tracking
   - Binary storage for optimized images

---

## ✨ Key Features

### 🔐 Authentication & Authorization
- JWT token-based authentication (1 year expiration)
- Three-tier role system (Viewer, Editor, Admin)
- Secure password hashing with bcrypt
- Token-based session management

### 📝 Grocery List Management
- Add items with optional images
- Update item quantities
- Mark items as bought/unbought
- View recently bought items (24-hour window)
- Long-press to edit items (mobile-friendly)

### 🖼️ Image Support
- Upload product images
- Automatic image optimization (800x800px, JPEG 85%)
- Base64 encoding for efficient storage
- 5MB maximum file size
- Support for JPEG, PNG, GIF, WebP

### 🏪 Smart Organization
- Item classification system (type, group, zone)
- 13 predefined store zones
- Sort by zone, alphabetically, or quantity
- Visual grouping by store location
- Intelligent item suggestions

### 🔍 Search & Suggestions
- Real-time autocomplete suggestions
- Fuzzy string matching (80% similarity threshold)
- Substring detection for partial matches
- Case-insensitive search

### 👥 User Management (Admin)
- View all registered users
- Update user roles
- Delete user accounts
- User activity tracking

---

## 🛠️ Technology Stack

### Frontend
| Technology | Version | Purpose |
|------------|---------|---------|
| React | 19.2.0 | UI framework |
| React Router | 7.9.6 | Client-side routing |
| Axios | 1.13.2 | HTTP client |
| Vite | 7.2.2 | Build tool & dev server |
| TypeScript | 5.9.3 | Type safety |

### Backend
| Technology | Version | Purpose |
|------------|---------|---------|
| Node.js | 20.x | Runtime environment |
| Express | 5.1.0 | Web framework |
| PostgreSQL | 8.16.0 | Database |
| JWT | 9.0.2 | Authentication |
| Bcrypt | 3.0.3 | Password hashing |
| Sharp | 0.34.5 | Image processing |
| Multer | 2.0.2 | File upload handling |

### DevOps
| Technology | Purpose |
|------------|---------|
| Docker | Containerization |
| Docker Compose | Multi-container orchestration |
| Gitea Actions | CI/CD pipeline |
| Nginx | Production static file serving |
| Nodemon | Development hot-reload |

---

## 🔄 Data Flow

### Adding an Item

```mermaid
sequenceDiagram
    participant User
    participant Frontend
    participant API
    participant Auth
    participant RBAC
    participant Database
    
    User->>Frontend: Enter item name & quantity
    User->>Frontend: Upload image (optional)
    Frontend->>API: POST /list/add (FormData)
    API->>Auth: Verify JWT token
    Auth->>RBAC: Check role (Editor/Admin)
    RBAC->>API: Authorization granted
    API->>API: Process & optimize image
    API->>Database: Check if item exists
    alt Item exists & unbought
        Database-->>API: Return existing item
        API->>Database: UPDATE quantity
    else Item exists & bought
        Database-->>API: Return existing item
        API->>Database: SET bought=false, UPDATE quantity
    else Item doesn't exist
        API->>Database: INSERT new item
    end
    API->>Database: INSERT grocery_history record
    Database-->>API: Success
    API-->>Frontend: 200 OK {message, addedBy}
    Frontend-->>User: Show success message
    Frontend->>API: GET /list (refresh)
    API->>Database: SELECT unbought items
    Database-->>API: Return items
    API-->>Frontend: Item list
    Frontend-->>User: Update UI
```

### Authentication Flow

```mermaid
sequenceDiagram
    participant User
    participant Frontend
    participant API
    participant Database
    
    User->>Frontend: Enter credentials
    Frontend->>API: POST /auth/login
    API->>Database: SELECT user WHERE username
    Database-->>API: User record
    API->>API: Compare password hash
    alt Valid credentials
        API->>API: Generate JWT token
        API-->>Frontend: {token, role, username}
        Frontend->>Frontend: Store token in localStorage
        Frontend->>Frontend: Store role in AuthContext
        Frontend->>API: GET /list (with token)
        API->>API: Verify token
        API-->>Frontend: Protected data
    else Invalid credentials
        API-->>Frontend: 401 Unauthorized
        Frontend-->>User: Show error message
    end
```

### Item Classification Flow

```mermaid
graph LR
    A[Add/Edit Item] --> B{Classification Exists?}
    B -->|Yes| C[Display Existing]
    B -->|No| D[Show Empty Form]
    C --> E[User Edits]
    D --> E
    E --> F{Validate Classification}
    F -->|Valid| G[Upsert to DB]
    F -->|Invalid| H[Show Error]
    G --> I[confidence=1.0, source='user']
    I --> J[Update Item List]
    H --> E
    
    style G fill:#90EE90
    style H fill:#FFB6C1
```

---

## 🔒 Role-Based Access Control

### Role Hierarchy

```
Admin (Full Access)
  ├── User Management
  ├── Item Management
  └── View Access
      
Editor (Modify Access)
  ├── Add Items
  ├── Edit Items
  ├── Mark as Bought
  └── View Access
      
Viewer (Read-Only)
  └── View Lists Only
```

### Permission Matrix

| Feature | Viewer | Editor | Admin |
|---------|--------|--------|-------|
| View grocery list | ✅ | ✅ | ✅ |
| View recently bought | ✅ | ✅ | ✅ |
| Get suggestions | ✅ | ✅ | ✅ |
| View classifications | ✅ | ✅ | ✅ |
| Add items | ❌ | ✅ | ✅ |
| Edit items | ❌ | ✅ | ✅ |
| Upload images | ❌ | ✅ | ✅ |
| Mark items bought | ❌ | ✅ | ✅ |
| Update classifications | ❌ | ✅ | ✅ |
| View all users | ❌ | ❌ | ✅ |
| Update user roles | ❌ | ❌ | ✅ |
| Delete users | ❌ | ❌ | ✅ |

### Middleware Chain

Protected routes use a middleware chain pattern:

```javascript
router.post("/add", 
  auth,                              // Verify JWT token
  requireRole(ROLES.EDITOR, ROLES.ADMIN),  // Check role
  upload.single("image"),            // Handle file upload
  processImage,                      // Optimize image
  controller.addItem                 // Execute business logic
);
```

---

## 🚀 Getting Started

### Prerequisites
- **Node.js** 20.x or higher
- **PostgreSQL** 8.x or higher
- **Docker** (optional, recommended)
- **Git** for version control

### Local Development Setup

1. **Clone the repository**
   ```bash
   git clone https://github.com/your-org/costco-grocery-list.git
   cd costco-grocery-list
   ```

2. **Configure environment variables**
   
   Create `backend/.env`:
   ```env
   # Database Configuration
   DB_HOST=localhost
   DB_USER=postgres
   DB_PASSWORD=your_password
   DB_DATABASE=grocery_list
   DB_PORT=5432
   
   # Authentication
   JWT_SECRET=your_secret_key_here
   
   # CORS Configuration
   ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
   
   # Server
   PORT=5000
   ```

3. **Start with Docker (Recommended)**
   ```bash
   # Development mode with hot-reload
   docker-compose -f docker-compose.dev.yml up
   
   # Access application:
   # Frontend: http://localhost:3000
   # Backend: http://localhost:5000
   ```

4. **Manual Setup (Alternative)**
   
   **Backend:**
   ```bash
   cd backend
   npm install
   npm run dev
   ```
   
   **Frontend:**
   ```bash
   cd frontend
   npm install
   npm run dev
   ```

5. **Database Setup**
   
   Create PostgreSQL database and tables:
   ```sql
   CREATE DATABASE grocery_list;
   
   -- See backend/models/*.js for table schemas
   ```

### First User Registration

The first registered user should be manually promoted to admin:
```sql
UPDATE users SET role = 'admin' WHERE username = 'your_username';
```

---

## 📚 API Documentation

For detailed API documentation including all endpoints, request/response formats, and examples, see [API_DOCUMENTATION.md](./API_DOCUMENTATION.md).

### Quick Reference

**Base URL:** `http://localhost:5000/api`

**Common Endpoints:**
- `POST /auth/register` - Register new user
- `POST /auth/login` - Authenticate user
- `GET /list` - Get all unbought items
- `POST /list/add` - Add or update item
- `POST /list/mark-bought` - Mark item as bought
- `GET /list/recently-bought` - Get items bought in last 24h
- `GET /admin/users` - Get all users (Admin only)

**Authentication:**
All protected endpoints require a JWT token in the Authorization header:
```
Authorization: Bearer <your_jwt_token>
```

---

## 📁 Project Structure

```
costco-grocery-list/
├── .gitea/
│   └── workflows/
│       └── deploy.yml              # CI/CD pipeline configuration
├── backend/
│   ├── constants/
│   │   └── classifications.js      # Item type/zone definitions
│   ├── controllers/
│   │   ├── auth.controller.js      # Authentication logic
│   │   ├── lists.controller.js     # Grocery list logic
│   │   └── users.controller.js     # User management logic
│   ├── db/
│   │   └── pool.js                 # PostgreSQL connection pool
│   ├── middleware/
│   │   ├── auth.js                 # JWT verification
│   │   ├── rbac.js                 # Role-based access control
│   │   └── image.js                # Image upload & processing
│   ├── models/
│   │   ├── list.model.js           # Grocery list database queries
│   │   └── user.model.js           # User database queries
│   ├── routes/
│   │   ├── auth.routes.js          # Authentication routes
│   │   ├── list.routes.js          # Grocery list routes
│   │   ├── admin.routes.js         # Admin routes
│   │   └── users.routes.js         # User routes
│   ├── app.js                      # Express app configuration
│   ├── server.js                   # Server entry point
│   ├── Dockerfile                  # Backend container config
│   └── package.json
├── frontend/
│   ├── public/                     # Static assets
│   ├── src/
│   │   ├── api/
│   │   │   ├── axios.js            # Axios instance with interceptors
│   │   │   ├── auth.js             # Auth API calls
│   │   │   ├── list.js             # List API calls
│   │   │   └── users.js            # User API calls
│   │   ├── components/
│   │   │   ├── common/             # Reusable components
│   │   │   ├── forms/              # Form components
│   │   │   ├── items/              # Item-related components
│   │   │   ├── layout/             # Layout components
│   │   │   └── modals/             # Modal dialogs
│   │   ├── constants/
│   │   │   └── roles.js            # Role constants
│   │   ├── context/
│   │   │   └── AuthContext.jsx     # Authentication context
│   │   ├── pages/
│   │   │   ├── AdminPanel.jsx      # Admin user management
│   │   │   ├── GroceryList.jsx     # Main grocery list page
│   │   │   ├── Login.jsx           # Login page
│   │   │   └── Register.jsx        # Registration page
│   │   ├── styles/
│   │   │   ├── theme.css           # CSS custom properties
│   │   │   ├── components/         # Component-specific styles
│   │   │   └── pages/              # Page-specific styles
│   │   ├── utils/
│   │   │   ├── PrivateRoute.jsx    # Route protection
│   │   │   ├── RoleGuard.jsx       # Role-based component guard
│   │   │   └── stringSimilarity.js # Fuzzy matching algorithm
│   │   ├── App.jsx                 # Root component with routing
│   │   └── main.tsx                # Application entry point
│   ├── Dockerfile                  # Production build (nginx)
│   ├── Dockerfile.dev              # Development build (Vite)
│   └── package.json
├── docker-compose.yml              # Production compose file
├── docker-compose.dev.yml          # Development compose file
├── docker-compose.prod.yml         # Local production testing
├── API_DOCUMENTATION.md            # Detailed API reference
└── README.md                       # This file
```

### Key Directories

- **`backend/constants/`** - Classification definitions (item types, groups, zones)
- **`backend/middleware/`** - Authentication, authorization, and image processing
- **`frontend/src/components/`** - Organized into 5 categories (common, forms, items, layout, modals)
- **`frontend/src/styles/`** - Theme system with CSS custom properties
- **`.gitea/workflows/`** - CI/CD pipeline for automated deployment

---

## 🔨 Development Workflow

### Component Organization

Frontend components are organized by feature:

```
components/
├── common/          # Reusable UI components
│   ├── ErrorMessage.jsx
│   ├── FloatingActionButton.jsx
│   ├── FormInput.jsx
│   ├── SortDropdown.jsx
│   └── UserRoleCard.jsx
├── forms/           # Form components
│   ├── AddItemForm.jsx
│   ├── ClassificationSection.jsx
│   └── ImageUploadSection.jsx
├── items/           # Item-related components
│   ├── GroceryItem.tsx
│   ├── GroceryListItem.jsx
│   └── SuggestionList.tsx
├── layout/          # Layout components
│   ├── AppLayout.jsx
│   └── Navbar.jsx
└── modals/          # Modal dialogs
    ├── AddImageModal.jsx
    ├── AddItemWithDetailsModal.jsx
    ├── ConfirmBuyModal.jsx
    ├── EditItemModal.jsx
    ├── ImageModal.jsx
    ├── ImageUploadModal.jsx
    ├── ItemClassificationModal.jsx
    └── SimilarItemModal.jsx
```

Each subdirectory has an `index.js` barrel export for cleaner imports.

### Theme System

The application uses CSS custom properties for consistent theming:

```css
/* Theme variables defined in frontend/src/styles/theme.css */
:root {
  /* Colors */
  --color-primary: #0066cc;
  --color-secondary: #6c757d;
  --color-success: #28a745;
  --color-danger: #dc3545;
  
  /* Spacing */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  
  /* Typography */
  --font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', ...;
  --font-size-base: 1rem;
  
  /* And many more... */
}
```

### Code Standards

- **Backend**: CommonJS modules, async/await for asynchronous operations
- **Frontend**: ES6 modules, functional components with hooks
- **TypeScript**: Used for type-safe components (gradually migrating)
- **Naming**: camelCase for functions/variables, PascalCase for components
- **File Structure**: Feature-based organization over type-based

### Testing

Currently, the project uses manual testing. Automated testing infrastructure is planned for future development.

---

## 🚢 Deployment

### CI/CD Pipeline

The application uses Gitea Actions for automated deployment:

```yaml
# .gitea/workflows/deploy.yml

Workflow:
1. Build Stage:
   - Install dependencies
   - Run tests (if present)
   - Build Docker images
   - Tag with :latest and :<commit-sha>
   - Push to private registry

2. Deploy Stage:
   - SSH to production server
   - Upload docker-compose.yml
   - Pull latest images
   - Restart containers
   - Prune old images

3. Notify Stage:
   - Send deployment status via webhook
```

### Production Architecture

```
Production Server
├── Nginx Reverse Proxy (Port 80/443)
│   ├── /api → Backend Container (Port 5000)
│   └── /* → Frontend Container (Port 3000)
├── Docker Compose
│   ├── backend:latest (from registry)
│   └── frontend:latest (from registry)
└── PostgreSQL (External, not containerized)
```

### Environment Configuration

**Production (`docker-compose.yml`):**
- Pulls pre-built images from registry
- Uses external PostgreSQL database
- Environment configured via `backend.env` and `frontend.env`
- Automatic restart on failure

**Development (`docker-compose.dev.yml`):**
- Builds images locally
- Volume mounts for hot-reload
- Uses local `.env` files
- Nodemon for backend, Vite HMR for frontend

### Deployment Process

1. **Commit and push to `main` branch**
   ```bash
   git add .
   git commit -m "Your commit message"
   git push origin main
   ```

2. **CI/CD automatically:**
   - Runs tests
   - Builds Docker images
   - Pushes to registry
   - Deploys to production

3. **Manual deployment (if needed):**
   ```bash
   ssh user@production-server
   cd /opt/costco-app
   docker compose pull
   docker compose up -d --remove-orphans
   ```

---

## 🗄️ Database Schema

### Entity Relationship Diagram

```mermaid
erDiagram
    users ||--o{ grocery_list : creates
    users ||--o{ grocery_history : adds
    grocery_list ||--o{ grocery_history : tracks
    grocery_list ||--o| item_classification : has
    
    users {
        int id PK
        string username UK
        string password
        string name
        string role
    }
    
    grocery_list {
        int id PK
        string item_name
        int quantity
        boolean bought
        bytea item_image
        string image_mime_type
        int added_by FK
        timestamp modified_on
    }
    
    item_classification {
        int id PK,FK
        string item_type
        string item_group
        string zone
        float confidence
        string source
    }
    
    grocery_history {
        int id PK
        int list_item_id FK
        int quantity
        int added_by FK
        timestamp added_on
    }
```

### Key Relationships

- **users → grocery_list**: One-to-many (creator relationship)
- **users → grocery_history**: One-to-many (contributor relationship)
- **grocery_list → grocery_history**: One-to-many (tracks all additions/modifications)
- **grocery_list → item_classification**: One-to-one (optional classification data)

---

## 🤝 Contributing

Contributions are welcome! Please follow these guidelines:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

### Development Guidelines

- Follow existing code style and structure
- Add comments for complex logic
- Update documentation for new features
- Test thoroughly before submitting PR

---

## 📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

---

## 👤 Author

**Nico Saya**
- Repository: [git.nicosaya.com/nalalangan/costco-grocery-list](https://git.nicosaya.com/nalalangan/costco-grocery-list)

---

## 🙏 Acknowledgments

- React team for the excellent framework
- Express.js community for robust server framework
- PostgreSQL for reliable data persistence
- Sharp for efficient image processing
- All contributors and users of this application

---

## 📞 Support

For issues, questions, or feature requests, please:
1. Check existing issues in the repository
2. Create a new issue with detailed description
3. Include steps to reproduce (for bugs)
4. Tag appropriately (bug, enhancement, question, etc.)

---

**Last Updated:** January 4, 2026
