A Node.js web application to track shrinkflation, price changes, and nutrition modifications in consumer products.
- Product Management: Enter or select product name, package size, form factor, flavor, and price
- Image Upload: Upload photos of nutrition facts, products, and packaging (5MB limit per image)
- AI-Powered Parsing: Use Azure Computer Vision AI to automatically extract nutrition information from images
- Version Control: Automatically detect changes and save new versions when nutrition, size, or price differs
- Analytics Dashboard: Track price changes, size reductions (shrinkflation), and nutrition modifications
- Product Search: Easily find and filter products
- MongoDB Support: Works with MongoDB or Azure Cosmos DB (MongoDB API)
- Dark Mode: Automatic dark mode support based on device preference
- Containerized: Ready to deploy with Docker
- Backend: Node.js, Express.js
- Frontend: Preact, Vite
- Database: MongoDB / Azure Cosmos DB
- AI: Azure Computer Vision API (OCR)
- Styling: CSS with dark mode support
- File Upload: Multer 2.x
- Deployment: Docker & Docker Compose
The easiest way to run ShrinkWatch is using Docker:
# Clone the repository
git clone https://github.com/zeroClearAmerican/shrinkwatch.git
cd shrinkwatch
# Start the application with Docker Compose
docker-compose up -d
# Access the application
# Open http://localhost:3000 in your browserThis will start both the application and MongoDB automatically.
To stop the application:
docker-compose down- Node.js (v20 or higher)
- MongoDB (local installation or MongoDB Atlas account)
- Azure Computer Vision API key (optional, for AI parsing)
- Clone the repository
git clone https://github.com/zeroClearAmerican/shrinkwatch.git
cd shrinkwatch- Install dependencies
npm install- Configure environment variables
Copy the example environment file:
cp .env.example .envEdit .env and configure:
# Server Configuration
PORT=3000
# MongoDB Configuration
# For local MongoDB:
MONGODB_URI=mongodb://localhost:27017/shrinkwatch
# For MongoDB Atlas:
# MONGODB_URI=mongodb+srv://<username>:<password>@cluster.mongodb.net/shrinkwatch
# For Azure Cosmos DB with MongoDB API:
# MONGODB_URI=mongodb://<account-name>:<password>@<account-name>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000
# Azure AI Vision Configuration (Optional - for OCR nutrition parsing)
AZURE_VISION_ENDPOINT=https://your-resource.cognitiveservices.azure.com/
AZURE_VISION_KEY=your-api-key-here
# File Upload Configuration
MAX_FILE_SIZE=5242880- Set up MongoDB
Option A: Local MongoDB
- Install MongoDB Community Edition
- Start MongoDB service:
mongod
Option B: MongoDB Atlas (Cloud)
- Create a free account at MongoDB Atlas
- Create a cluster and get the connection string
- Update
MONGODB_URIin.env
Option C: Azure Cosmos DB
- Create a Cosmos DB account with MongoDB API
- Get the connection string from Azure Portal
- Update
MONGODB_URIin.env
- Set up Azure Computer Vision (Optional)
If you want AI-powered nutrition parsing:
- Create an Azure account at Azure Portal
- Create a Computer Vision resource
- Copy the endpoint and API key to
.env
Note: The app will work without Azure Vision using mock OCR results for testing.
For development, you'll need to run both the backend server and the Vite dev server:
Terminal 1 - Backend API Server:
npm run devTerminal 2 - Vite Frontend Dev Server:
npm run dev:viteThen open http://localhost:5173 in your browser (Vite dev server with HMR).
Build the frontend and run the backend:
npm run build
npm startThe application will be available at http://localhost:3000
Build the Docker image:
docker build -t shrinkwatch .Run the container:
docker run -d -p 3000:3000 \
-e MONGODB_URI=mongodb://your-mongo-host:27017/shrinkwatch \
-v $(pwd)/public/img:/app/public/img \
shrinkwatchDocker Compose will start both the app and MongoDB:
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -vThe containerized app can be directly exposed to web traffic behind Cloudflare:
- Configure your Cloudflare DNS to point to your server
- Set up Cloudflare SSL/TLS (Flexible or Full)
- Enable Cloudflare features (DDoS protection, WAF, caching)
- Run the container on port 3000 (or configure as needed)
- Cloudflare will handle SSL termination and security
The app includes rate limiting and security best practices for production use.
The frontend is built with Preact for a lightweight, performant user experience:
- Component-Based: Modular Preact components for each feature
- State Management: React hooks (useState, useEffect) for component state
- Fast Refresh: Vite HMR for instant updates during development
- Optimized Build: Vite produces highly optimized production bundles
- Dark Mode: CSS custom properties with
prefers-color-schemesupport
Component Structure:
src/
├── components/
│ ├── App.jsx # Main app container
│ ├── Header.jsx # Header with branding
│ ├── TabNavigation.jsx # Tab switching interface
│ ├── AddProductForm.jsx # Product entry form
│ ├── ViewProducts.jsx # Product listing and search
│ └── Analytics.jsx # Analytics dashboard
└── main.jsx # App entry point
RESTful API server with:
- Express.js for routing and middleware
- MongoDB with Mongoose ODM for data persistence
- Rate limiting for API protection
- Multer for file upload handling
- Azure Computer Vision integration for OCR
The backend serves the compiled Vite build in production and provides API endpoints for all data operations.
- Navigate to the "Add/Update Product" tab
- Fill in product information (name, brand, category, etc.)
- Upload a photo of the nutrition facts label
- Optionally click "Preview AI Parsing" to see extracted nutrition data
- Add additional product/packaging images if desired
- Click "Submit Product"
The system automatically creates new versions when it detects:
- Changes in nutrition facts (calories, fat, sodium, etc.)
- Changes in package size
- Changes in price
- Changes in form factor or flavor
- Click the "View Products" tab to see all tracked products
- Use the search box to filter products
- Products with multiple versions will show a warning indicator
The analytics tab provides insights:
- Overview: Total products, versions, and products with changes
- Price Changes: Products with price increases/decreases
- Size Changes: Products affected by shrinkflation
- Top Offenders: Products with the most detected changes
GET /api/products- Get all productsGET /api/products/:id- Get a specific productGET /api/products/:id/versions- Get all versions of a productPOST /api/products- Create or update a product (with file upload)POST /api/products/parse-nutrition- Parse nutrition from imageDELETE /api/products/:id- Delete a productGET /api/products/search/:query- Search products
GET /api/analytics/overview- Get overview statisticsGET /api/analytics/price-changes- Get price change dataGET /api/analytics/size-changes- Get size change data (shrinkflation)GET /api/analytics/nutrition-changes- Get nutrition change dataGET /api/analytics/top-offenders- Get products with most changes
shrinkwatch/
├── models/
│ └── Product.js # MongoDB schemas
├── routes/
│ ├── products.js # Product API routes
│ └── analytics.js # Analytics API routes
├── services/
│ └── nutritionParser.js # AI nutrition parsing service
├── public/
│ ├── css/
│ │ └── style.css # Styles
│ └── js/
│ └── app.js # Frontend JavaScript
├── views/
│ └── index.ejs # Main HTML template
├── uploads/ # Uploaded images
├── server.js # Express server
├── package.json
└── .env # Environment variables
Contributions are welcome! Please feel free to submit a Pull Request.
ISC
For issues and questions, please open an issue on GitHub.