Skip to content

adityashaw2/amul-restock

Repository files navigation

Amul Restock 🟢

Get notified when Amul products are back in stock for your pincode.

How It Works

  1. Scraper fetches product catalog from shop.amul.com (StoreHippo platform)
  2. Users subscribe with email + pincode + products they want
  3. Stock checker runs every 15 min, checking availability per pincode
  4. Email notification fires when a product goes from out-of-stock → in-stock

Architecture

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Scraper     │────▶│  SQLite DB  │◀────│  tRPC API   │
│  (Playwright │     │  (products, │     │  (Hono)     │
│   or HTTP)   │     │   subs,     │     │             │
└─────────────┘     │   stock)    │     └──────┬──────┘
                    └──────┬──────┘            │
                           │              ┌────▼──────┐
                    ┌──────▼──────┐       │  Frontend  │
                    │ Stock Check │       │  (React)   │
                    │   (Cron)    │       └───────────┘
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │   Resend    │
                    │  (Email)    │
                    └─────────────┘

Tech Stack

  • Runtime: Bun
  • API: Hono + tRPC
  • Database: SQLite (better-sqlite3 + Drizzle ORM)
  • Scraping: Playwright (fallback) / HTTP + StoreHippo session
  • Email: Resend
  • Language: TypeScript

Setup

# Install dependencies
bun install

# Install Playwright browsers (needed for scraper fallback)
bunx playwright install chromium

# Copy env and configure
cp .env.example .env

# Create database tables
bun run db:push

# Scrape products from Amul
bun run scrape

# Start the server (includes stock check cron)
bun run dev

API Routes (tRPC)

Products

  • product.getProducts({ query?, category? }) — Search/filter products
  • product.getProductAggregation() — Categories with counts
  • product.getProduct({ id }) — Single product

Subscriptions

  • subscription.createSubscription({ email, pincode, products[] }) — Subscribe
  • subscription.cancelSubscriptions({ email }) — Unsubscribe all
  • subscription.getSubscriptions({ email }) — List active subscriptions

Admin

  • POST /admin/check-stock — Manually trigger stock check

How Amul's Stock System Works

Amul's shop runs on StoreHippo, a headless e-commerce platform. Key details:

  • Products are stored as ms.products entities with internal _ids
  • Stock is pincode-specific — different Amul distributors serve different areas
  • Availability is determined via ms.linked_products which maps products to substores (distributors)
  • When you enter a pincode, StoreHippo finds the matching substore and checks inventory

This means a product can be in stock in Mumbai (400001) but out of stock in Delhi (110001).

Scraping Strategy

  1. Primary: HTTP requests with a StoreHippo session token (fast, no browser needed)
  2. Fallback: Playwright headless browser — intercepts XHR responses to /api/ms.products

The session token expires every ~30 min and is auto-refreshed.

Deployment

Fly.io

fly launch
fly secrets set RESEND_API_KEY=re_xxxx
fly deploy

Docker

FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --production
COPY . .
RUN bun run db:push
CMD ["bun", "run", "start"]

Cron-only (no server)

# Run stock check as a cron job instead of built-in interval
*/15 * * * * cd /path/to/amul-restock && bun src/cron/check-stock.ts >> /tmp/amul-restock.log 2>&1

License

MIT

About

Amul product restock notification service - get alerted when products are back in stock for your pincode

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages