Skip to content

SriRammSS/snack-stalker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SnackStalker

Multi-University Campus Vending Machine Management Platform

TypeScript React Express PostgreSQL Redux Toolkit License: MIT


A full-stack TypeScript monorepo simulating an end-to-end smart vending machine network across multiple university campuses — with real-time inventory management, sustainability tracking, and dynamic white-label theming per institution.


Table of Contents


Overview

SnackStalker models a production-grade campus vending machine network across 5 universities (UMD, Georgia Tech, Ohio State, UCLA, UT Austin). It implements three distinct role-based access control tiers, a transactional vend engine with row-level locking, a geospatial campus map, and a carbon-footprint sustainability analytics layer.

Dimension Details
Universities 5 (UMD, Georgia Tech, Ohio State, UCLA, UT Austin)
Buildings seeded ~40 across all campuses
Machines seeded 29 (UMD) + per-university machines
Snack catalog 25 SKUs with carbon footprint data
Vending slots per machine 25 (5×5 grid, A1–E5)
User roles student, admin, super_admin

Feature Matrix

Student

  • JWT-authenticated login/registration by email or directory ID
  • Interactive Leaflet campus map with GeoJSON building polygons
  • Click-through flow: Building → Machine selector → 5×5 vending grid
  • QR payment simulation with countdown dialog
  • Vend animation — tactile CSS snack-drop sequence
  • Personal carbon footprint dashboard (kg CO₂e, tree/miles equivalents)
  • Personalized low-carbon snack suggestions

Admin

  • Batch inventory stock updates with full audit trail (restock_events)
  • Real-time transaction log (last 500 events)
  • Analytics charts: revenue, top-selling SKUs, total dispenses (Recharts)
  • Cross-machine inventory health view

Super-Admin (UMD)

  • Aggregate sustainability leaderboard across all universities
  • Cross-institution carbon metrics and per-student rankings

Platform

  • White-label theming — CSS custom properties injected at runtime per university (colors, mascot, coordinates)
  • Full light/dark mode toggle via ThemeContext
  • RTK Query cache invalidation — UI auto-refreshes after vend or restock

System Architecture

┌─────────────────────────────────────────────────────────────────┐
│ Browser (React 19) │
│ │
│ Redux Store (RTK Query) ←→ React Router v7 ←→ Tailwind CSS │
│ │ │
│ Cache Tags: [Slots, Transactions, Sustainability] │
└────────────────────┬────────────────────────────────────────────┘
 │ /api/v1/* (Vite proxy → :3001)
 ▼
┌─────────────────────────────────────────────────────────────────┐
│ Express 5 (Node.js / ESM) │
│ │
│ /auth /buildings /machines /vend /inventory │
│ /transactions /universities /sustainability │
│ │
│ Vend route: BEGIN → SELECT FOR UPDATE → DECREMENT → COMMIT │
└────────────────────┬────────────────────────────────────────────┘
 │ pg.Pool (no ORM)
 ▼
┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL 15+ │
│ │
│ 8 tables · 4 analytics views · SERIAL + UUID PKs │
│ Row-level locking on vend transactions │
└─────────────────────────────────────────────────────────────────┘

Tech Stack

Layer Technology Notes
Language TypeScript 5.x End-to-end typed (frontend + backend)
Frontend framework React 19 + Vite 7 ESM, HMR
State management Redux Toolkit + RTK Query Cache tags for auto-invalidation
Routing React Router v7 Client-side SPA routing
Styling Tailwind CSS v4 CSS custom props for university theming
Maps Leaflet + React-Leaflet GeoJSON polygon building overlays
Charts Recharts Admin analytics tab
QR codes qrcode.react Simulated payment flow
Backend Express 5 (Node.js, ESM) REST API on port 3001
Database PostgreSQL Raw pg pool — no ORM
Auth bcryptjs Password hashing; session via Redux localStorage
Build Vite (frontend) + tsc (backend) Separate build pipelines
Linting ESLint 9 + typescript-eslint Shared config per workspace

Database Schema

universities ──┬── users
 │ └── (role: student | admin | super_admin)
 └── buildings ──── vending_machines ──── vending_slots
 │
snacks ────────────────────────────────────────────────── slots
 └── carbon_kg_per_unit │
 transactions
 restock_events
Table Description
universities 5 institutions with branding colors, coordinates, zoom
users Role-based accounts linked to a university
buildings GeoJSON polygon per building, linked to university
vending_machines Machine per building with floor location
snacks 25-item catalog with emoji, color, category, and carbon_kg_per_unit
vending_slots 5×5 grid per machine (A1–E5); current/max stock, price
transactions Immutable vend audit log (denormalized for analytics)
restock_events Audit trail for every admin stock change

4 PostgreSQL views: building_inventory_view, snack_summary_view, building_snack_summary_view, building_dispensed_summary_view


API Reference

Method Route Role Description
POST /auth/login All Authenticate user, return university object
POST /auth/register Public Register new student account
GET /buildings All List buildings filtered by universityId
GET /buildings/:id/machines All Get machines in a building
GET /machines/:id/slots All Get 5×5 slot grid for a machine
POST /vend Student Atomic vend: lock slot → decrement stock → log transaction
PATCH /inventory/stock Admin Batch stock update with restock event audit
GET /transactions Admin Last 500 transactions (optionally filtered by userId)
GET /sustainability/leaderboard All Per-university carbon leaderboard
GET /sustainability/campus-stats Admin Campus-wide aggregate carbon metrics
GET /sustainability/all-universities Super-Admin Cross-institution sustainability rollup

Getting Started

Prerequisites

  • Node.js 20+
  • PostgreSQL 15+
  • npm 10+

1. Clone & Install

git clone https://github.com/SriRammSS/snack-stalker.git
cd snack-stalker

# Install server dependencies
cd apps/server && npm install

# Install web dependencies
cd ../web && npm install

2. Database Setup

# Create the database
createdb snack_stalker

# Run migrations in order
psql -d snack_stalker -f database/001_schema.sql
psql -d snack_stalker -f database/002_seed.sql
psql -d snack_stalker -f database/003_views_and_counters.sql
psql -d snack_stalker -f database/004_add_universities.sql
psql -d snack_stalker -f database/005_superadmin_universal.sql
psql -d snack_stalker -f database/006_add_student_seed.sql
psql -d snack_stalker -f database/007_add_carbon_to_snacks.sql

3. Environment Configuration

Create apps/server/.env:

DATABASE_URL=postgresql://postgres:<password>@localhost:5432/snack_stalker
PORT=3001

4. Run Development Servers

# Terminal 1 — Backend
cd apps/server && npm run dev

# Terminal 2 — Frontend
cd apps/web && npm run dev

Frontend available at http://localhost:5173 · API at http://localhost:3001


Project Structure

snack_stocker/
├── apps/
│ ├── server/ # Express 5 REST API
│ │ └── src/
│ │ ├── index.ts # App entry — route registration, server start
│ │ ├── db.ts # pg.Pool singleton
│ │ └── routes/ # auth, buildings, machines, vend, inventory,
│ │ # transactions, universities, sustainability
│ └── web/ # React 19 SPA
│ └── src/
│ ├── routes/ # Login, StudentDashboard, AdminDashboard,
│ │ # MapView, SustainabilityDashboard
│ ├── components/ # CampusMap, VendingMachineModal, VendingGrid,
│ │ # PaymentQRDialog, VendAnimation, admin/*
│ ├── context/ # UniversityContext (CSS theming), ThemeContext
│ └── store/ # Redux store, RTK Query apiSlice, auth/vend slices
└── database/ # Ordered PostgreSQL migration files (001–007)

Architectural Decisions

Decision Rationale
No ORM Raw pg pool gives full control over query shape and enables SELECT FOR UPDATE row locks on the vend path — critical for preventing oversell under concurrent load
RTK Query cache tags Slots, Transactions, Sustainability tags auto-invalidate after a vend or restock, eliminating manual refetch calls
CSS custom properties for theming UniversityContext sets --color-uni-primary etc. on :root at login time — the entire UI re-themes without a rebuild or page reload
Multi-phase vend UX browsing → confirming → QR payment → animation → API commit makes the experience feel physical; the DB write fires only after the animation completes
Denormalized transactions table Analytics queries (revenue, top SKUs, dispense counts) run against a flat log rather than joins across 4 tables — reduces query complexity for read-heavy dashboards

Author

Sri Ramm Sekar Sasirekha

GitHub


Built as a full-stack TypeScript monorepo demonstrating end-to-end product engineering across backend, frontend, and database layers.

About

Multi-university campus vending machine platform — React 19 + Express 5 + PostgreSQL monorepo with RTK Query, Leaflet campus maps, QR payment simulation, and sustainability tracking

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors