SkillShare Logo
STEP 6 OF 7 · AUTOMATION

Low-Stock Alert Emails

The feature that makes this app useful: when a product’s quantity drops to its minStock, the store owner automatically gets an email — no one has to remember to check.

01 — TWO STRATEGIES

When to Check

There are two complementary ways to catch low stock. Start with the first; add the second later if you like.

A

Event-driven (recommended)

Check right after every create/update. Instant alerts, zero extra infrastructure. This is the checkLowStock() we already call in the CRUD handlers.

B

Scheduled sweep (optional)

A cron job runs daily, finds everything currently below threshold, and sends a digest. A safety net for stock that dropped via other paths.

Add one env var

Decide who receives alerts. Add ALERT_EMAIL="owner@store.com" to server/.env. (For a multi-owner app you’d email the user who owns each product instead.)

02 — THE HELPER

The checkLowStock Function

A tiny function that compares the numbers and emails when needed. It reuses the same sendMail from the Authentication page.

server/src/low-stock.ts
import { sendMail } from "./mailer";
import { Product } from "./entities";

export async function checkLowStock(p: Product) {
  if (p.quantity > p.minStock) return;          // stock is fine

  await sendMail(
    process.env.ALERT_EMAIL!,
    `⚠️ Low stock: ${p.name}`,
    `<p><b>${p.name}</b> (SKU ${p.sku}) is low.</p>
     <p>Only <b>${p.quantity}</b> left (minimum ${p.minStock}). Time to restock.</p>`,
  );
}
Don't spam the inbox

As written, every update at-or-below the threshold sends an email. To send once per dip, add a lowStockNotified boolean to Product: set it true when you alert, and reset to false when a restock pushes quantity back above minStock. Only email when it’s currently false.

03 — OPTIONAL

A Scheduled Daily Sweep

A backstop that emails a digest of everything currently low — runs on a timer, independent of user actions.

server/src/cron.ts — npm i node-cron
import cron from "node-cron";

// every day at 09:00
cron.schedule("0 9 * * *", async () => {
  const low = await repo
    .createQueryBuilder("p")
    .where("p.quantity <= p.minStock")
    .getMany();
  // Mongoose: ProductModel.find({ $expr: { $lte: ["$quantity", "$minStock"] } })

  for (const p of low) await checkLowStock(p);
});
Cron syntax

"0 9 * * *" = minute 0, hour 9, every day. Use crontab.guru to build your own schedule.

04 — CHECKPOINT

Test the Alert

Make a product go low and confirm the email lands in your Mailtrap inbox.

  1. Create a product with quantity: 5, minStock: 5→ an alert should send immediately (5 ≤ 5).
  2. Or update an existing product’s quantity down to its minStock and watch the inbox.
  3. Open Mailtrapand read the “⚠️ Low stock” email.
  • ALERT_EMAIL set in .env
  • checkLowStock() imported and called in create + update
  • Email arrives when quantity ≤ minStock
  • No email when stock is healthy