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