Go to file
Nico dfaab1dfcb
All checks were successful
Build & Deploy Costco Grocery List / build (push) Successful in 11s
Build & Deploy Costco Grocery List / verify-images (push) Successful in 2s
Build & Deploy Costco Grocery List / deploy (push) Successful in 5s
Build & Deploy Costco Grocery List / notify (push) Successful in 1s
add handling of no stores and fix app naming
2026-01-28 01:06:19 -08:00
.gitea/workflows revert registry 2026-01-28 00:54:08 -08:00
.github styling fix and readme files reorg 2026-01-27 00:03:58 -08:00
.vscode update frontend docker deploy 2025-11-26 14:55:05 -08:00
backend styling fix and readme files reorg 2026-01-27 00:03:58 -08:00
docs styling fix and readme files reorg 2026-01-27 00:03:58 -08:00
frontend add handling of no stores and fix app naming 2026-01-28 01:06:19 -08:00
.copilotignore wip 2026-01-01 22:55:39 -08:00
.editorconfig update frontend docker deploy 2025-11-26 14:55:05 -08:00
.gitignore Update backend for RBAC 2025-11-21 18:09:33 -08:00
dev-rebuild.sh wip 2026-01-01 22:55:39 -08:00
docker wip 2025-11-22 00:42:15 -08:00
docker-compose.dev.yml wip 2026-01-01 22:55:39 -08:00
docker-compose.new.yml revert registry 2026-01-28 00:54:08 -08:00
docker-compose.yml potential fix 2026-01-02 17:49:26 -08:00
package-lock.json wip 2026-01-01 22:55:39 -08:00
package.json Instal dev dependencies for tests 2025-11-27 16:39:52 -08:00
README.md update readme 2026-01-04 16:02:19 -08:00
run-migration.bat phase1 - implement database foundation 2026-01-25 00:18:04 -08:00
run-migration.sh phase1 - implement database foundation 2026-01-25 00:18:04 -08:00

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 Node React Express

📋 Table of Contents


🎯 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


🏗️ System Architecture

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

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

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

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:

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

    git clone https://github.com/your-org/costco-grocery-list.git
    cd costco-grocery-list
    
  2. Configure environment variables

    Create backend/.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)

    # 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:

    cd backend
    npm install
    npm run dev
    

    Frontend:

    cd frontend
    npm install
    npm run dev
    
  5. Database Setup

    Create PostgreSQL database and tables:

    CREATE DATABASE grocery_list;
    
    -- See backend/models/*.js for table schemas
    

First User Registration

The first registered user should be manually promoted to admin:

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.

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:

/* 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:

# .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

    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):

    ssh user@production-server
    cd /opt/costco-app
    docker compose pull
    docker compose up -d --remove-orphans
    

🗄️ Database Schema

Entity Relationship Diagram

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


🙏 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