Skip to content

NotYuSheng/How-Much

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

How Much?

A grocery price guessing game that tests how in touch you are with the cost of everyday goods

FeaturesQuick StartUsageDeployment

React Node.js AWS Lambda DynamoDB Terraform Docker License


Note

This project is currently in active development. Only Singapore (SG) is supported at this time. More regions are on the roadmap — see Supported Countries.

Guess the real prices of common household items in your country and find out if you're down to earth or living in a bubble. Scored against crowd-sourced averages from real shoppers. 10 fixed items, every region, no sign-up required.

Features

Feature Description
10 fixed items Same 10 everyday items across every country — only the prices change
Denomination support Items like eggs, milk, and rice let you pick a pack size before guessing
Multi-country support Items are universal; prices, brands, and leaderboards are country-scoped
Scoring system Points based on accuracy — closer guess = higher score, +50 bonus for guessing under
Crowd-sourced prices Answers are running averages of real user submissions
Leaderboard Country + period-based leaderboard to compete against other players
Anonymous play No sign-up required — anonymous user ID stored in localStorage
Nightly catalog sync EventBridge cron updates brand names and images for the fixed items per country via Open Food Facts
Mobile-first UI Game-show aesthetic with dark navy + gold theme, fully responsive

Quick Start

Prerequisites

Software Version Purpose
Docker Latest Local DynamoDB
Node.js 20.x Backend + frontend dev servers
npm Latest Package management

Installation

1. Clone the repository:

git clone https://github.com/NotYuSheng/How-Much.git
cd How-Much

2. Install dependencies:

cd frontend && npm install && cd ..
cd backend && npm install && cd ..

3. Start local DynamoDB:

docker compose up -d

4. Bootstrap tables and seed data (first time only):

./scripts/bootstrap-local.sh

Data is persisted in a Docker volume — you only need to run this once. Tables survive container restarts.

5. Start the dev servers:

# Terminal 1 — API server
cd backend && npm run dev

# Terminal 2 — React frontend
cd frontend && npm run dev

6. Open the game:

Visit http://localhost:5173 in your browser.

Usage

Game Flow

graph LR
    A[Select Region] --> B[Start Game]
    B --> C[Guess Item Price]
    C --> D[See Score & Reveal]
    D --> E{More Items?}
    E -- Yes --> C
    E -- No --> F[Final Score]
    F --> G[Submit to Leaderboard]
Loading
  1. Select Region — Pick your country on the start screen (Singapore live, more coming soon)
  2. Start — Click "Start Game" to begin a new session — all 10 items appear in a randomised order
  3. Guess — For denomination items, pick a pack size first, then enter your price guess
  4. Reveal — See the actual crowd-sourced price and your score for that round
  5. Repeat — Continue through all 10 items
  6. Final Score — See your total out of 10,000 and submit a nickname to the leaderboard

Scoring Algorithm

Accuracy Points
Exact (0%) 1000
Within 2% 950
Within 5% 850
Within 10% 700
Within 20% 500
Within 35% 300
Within 50% 100
Off by >50% 0
Guess ≤ actual +50 bonus

Maximum score per round: 1,000 pts — Maximum per game (10 rounds): 10,000 pts

Tech Stack

Component Technology
Frontend React 19, Tailwind CSS v4, Vite
Backend Node.js 20.x Lambda functions (ESM), esbuild
Database DynamoDB on-demand (integer cents to avoid float bugs)
Infrastructure Terraform, AWS ap-southeast-1
Local Dev DynamoDB Local via Docker Compose
Catalog Sync EventBridge nightly cron → Open Food Facts API

Multi-Country Support

The data model is fully country-aware from the ground up — no infrastructure changes needed to add a new country:

  • Items have a countries StringSet (e.g. ["SG", "MY"])
  • Prices store country + currency per submission
  • Leaderboard PK includes country, so rankings are always country-scoped
  • Catalog sync runs per country, pulling locally relevant products from Open Food Facts

To add a new country, run catalog sync with the new country code — no item changes needed.

Supported Countries

Asia-Pacific

  • Singapore (SG)
  • China (CN)
  • India (IN)
  • Japan (JP)
  • South Korea (KR)
  • Indonesia (ID)
  • Philippines (PH)
  • Malaysia (MY)
  • Australia (AU)

Europe

  • United Kingdom (GB)
  • Germany (DE)
  • France (FR)
  • Spain (ES)
  • Italy (IT)
  • Russia (RU)

Americas

  • United States (US)
  • Brazil (BR)
  • Mexico (MX)

Project Structure

How-Much/
├── frontend/               # React + Tailwind (Vite)
│   └── src/
│       ├── components/     # StartScreen, Header, ItemCard, PriceInput,
│       │                   # DenominationPicker, RevealOverlay, ProgressDots, FinalScore
│       ├── lib/
│       │   ├── api.js      # All API calls + anonymous user ID
│       │   └── scoring.js  # Score calculation + labels
│       └── App.jsx         # Game state machine
├── backend/
│   ├── functions/
│   │   ├── game/           # POST /sessions, POST /sessions/:id/guess,
│   │   │                   # POST /sessions/:id/complete, GET /sessions/:id
│   │   ├── items/          # GET /items, GET /items/:id
│   │   ├── prices/         # GET /prices/:itemId
│   │   ├── leaderboard/    # GET /leaderboard
│   │   └── catalog-sync/   # Nightly Open Food Facts → DynamoDB sync
│   ├── shared/
│   │   ├── dynamo.js       # DynamoDB client
│   │   └── scoring.js      # Scoring algorithm + HTTP helpers
│   └── scripts/
│       └── build.js        # esbuild bundler
├── scripts/
│   ├── bootstrap-local.sh  # Creates tables and seeds data locally
│   └── seed.js             # Seeds curated items
├── terraform/              # Full AWS infrastructure as code
└── docker-compose.yml      # DynamoDB Local for dev

API Reference

POST   /sessions                         # Start game, picks 10 random items by country
POST   /sessions/{id}/guess              # Submit guess (cents) → returns score + reveal
GET    /sessions/{id}                    # Recover state on page refresh
POST   /sessions/{id}/complete           # Finalise session → submit to leaderboard
GET    /items?country=SG
GET    /items/{id}
GET    /prices/{itemId}?country=SG
GET    /leaderboard?country=SG&period=alltime

Deployment

Prerequisites

  • AWS account with CLI configured
  • Terraform installed

Steps

1. Bootstrap Terraform state backend (once):

aws s3 mb s3://howmuch-tfstate-<account-id> --region ap-southeast-1
aws dynamodb create-table --table-name howmuch-tfstate-lock \
  --attribute-definitions AttributeName=LockID,AttributeType=S \
  --key-schema AttributeName=LockID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST --region ap-southeast-1

Update terraform/backend.tf with your bucket name.

2. Build and deploy backend:

cd backend && npm run build
cd terraform && terraform init && terraform apply

3. Build and deploy frontend:

cd frontend && npm run build
aws s3 sync dist/ s3://howmuch-frontend/ --delete
aws cloudfront create-invalidation --distribution-id <id> --paths "/*"

4. Seed production data:

node scripts/seed.js

Common Tasks

View logs

docker compose logs -f

Rebuild backend bundles

cd backend && npm run build

Re-seed local data

node scripts/seed.js

Reset local DynamoDB

docker compose down -v && docker compose up -d
./scripts/bootstrap-local.sh

Security

  • Anonymous auth — No user accounts; identity is a UUID in localStorage
  • No secrets in code — AWS credentials via IAM roles; environment variables for config
  • DynamoDB not public — Only accessible via Lambda functions behind API Gateway
  • Sessions expire — Session TTL is 24 hours for abandoned games

License

This project is licensed under the MIT License. See LICENSE for details.

About

Guess the real prices of common household items in your country and find out if you're down to earth or living in a bubble. Scored against crowd-sourced averages from real shoppers. 10 fixed items, every region, no sign-up required.

Topics

Resources

License

Stars

Watchers

Forks

Contributors