A lightweight, shared web app for research labs to track incoming and outgoing packages so shipments never get lost in email threads again. Anyone in the lab can add a package; everyone can see its status. Perishable and overdue shipments are made impossible to miss.
Built as a zero-dependency static site (plain HTML/CSS/JavaScript) — no build step, no paid services, no login required for the prototype. It runs from a folder and deploys to GitHub Pages in minutes.
- Package entry form — tracking number, carrier, description, vendor, recipient, delivery location, expected date, notes, and a full perishable workflow (details, storage required, action-needed-by, emergency contact).
- Dashboard — card layout showing status, tracking #, carrier, description, recipient, expected delivery, perishable status, and last updated. Perishable packages sort to the top.
- Impossible-to-miss alerts
- Red PERISHABLE badge on perishable packages.
- Orange OVERDUE highlight when the expected date has passed.
- A banner warns when a perishable package is delivered but not yet received (i.e. sitting on a dock warming up).
- Filters — All / Active / Perishable / Overdue / Problem / Delivered.
- Search — by tracking number, person, vendor, or description.
- Auto-generated tracking links — a "Check tracking ↗" button opens the carrier's public tracking page in a new tab (UPS, FedEx, USPS, DHL, Amazon). No API key required.
- Manual status pipeline — Ordered → Shipped → In transit → Out for delivery → Delivered → Received by lab, plus Problem/delayed and Lost/needs-follow-up. Every change is timestamped with an optional note.
- Package history / timeline — see every status change on the Details view.
- Mark received, Report missing, Edit, and per-package QR code for lab signage.
- CSV export of the full package log.
- Notification hooks — placeholder
notifyEmail/notifySlackfunctions (log to console today; wire to a real service later). - Mobile-friendly — usable from the loading dock, hatchery, or field site.
Because the app is fully static, you just need to serve the folder over HTTP
(opening index.html via file:// works too, but a local server avoids
browser quirks).
# clone, then from the project folder:
python3 -m http.server 4173
# open http://localhost:4173Any static server works equally well:
npx serve . # Node
php -S localhost:4173 # PHPOn first load the app seeds four sample packages (see below). Use Reset sample data to restore them at any time.
- Push this repo to GitHub.
- Repo Settings → Pages → Build and deployment.
- Source: Deploy from a branch, branch
main, folder/ (root). - Your app is live at
https://<user>.github.io/<repo>/.
No build step or configuration is needed.
Point the service at this repo and set:
- Build command: (none)
- Publish / output directory:
.(the repo root)
The seed (see js/seed.js) includes exactly the four requested
scenarios, with dates computed relative to today so the demo always looks live:
- Equipment — Benchtop microcentrifuge (UPS, in transit).
- Reagent — Taq polymerase + dNTP mix (FedEx, shipped, store at −20 °C).
- Perishable biological sample — Pacific oyster tissue for RNA extraction (USPS, out for delivery, dry ice, −80 °C, emergency contact).
- Delayed / lost — Custom antibody held at customs (DHL, overdue, flagged as a problem).
lab-package-tracker/
├── index.html # markup + modals
├── css/
│ └── styles.css # clean academic style, mobile-first
└── js/
├── model.js # data model: carriers, statuses, helpers (isOverdue…)
├── carriers.js # tracking-URL builder + live-status API stub
├── notifications.js # email/Slack notification hook placeholders
├── seed.js # sample data
├── store.js # data-access layer (localStorage; swap for a backend)
└── app.js # UI controller: render, filter, search, modals, CSV
Each JS file is wrapped in an IIFE and exposes a single window.LPT_* object,
so the files load in plain <script> tags with no bundler.
A Package (see the header comment in js/model.js):
| Field | Notes |
|---|---|
id |
generated |
tracking_number |
required |
carrier |
UPS | FedEx | USPS | DHL | Amazon | Other |
tracking_url |
derived from carrier + number |
description |
required |
vendor_or_sender, recipient, delivery_location |
free text / preset |
expected_delivery_date |
YYYY-MM-DD |
status |
see status pipeline above |
is_perishable, perishable_details, storage_required, action_needed_by, emergency_contact |
perishable workflow |
notes |
free text |
history |
timeline of {ts, status, note, by} |
last_updated, received_at, problem_flag |
bookkeeping |
The app was designed so the two "prototype shortcuts" can be replaced without touching the UI.
Data currently lives in each browser's localStorage, so it is not shared
between people — fine for a single kiosk/tablet, not for a whole lab. To make
it truly shared, re-implement the six methods in
js/store.js (getAll, get, add, update, remove,
replaceAll) against a backend and await them in app.js. Good no-/low-cost
options:
- Supabase — hosted Postgres + REST/JS client, generous free tier.
- Firebase Firestore — realtime sync, free tier.
- SQLite + a tiny API — e.g. a small Express/FastAPI service on Render.
Because every read/write already flows through store, nothing else changes.
Status is updated manually today. js/carriers.js contains
fetchLiveStatus(pkg) — a documented stub — and each carrier in model.js has
a spot for an api block. Implement the fetch there, add a "Refresh from
carrier" button, and merge the returned status via store.update(). Carrier
API keys must live server-side, never in this client code.
js/notifications.js logs to the console. Point
notifyEmail / notifySlack at a serverless function (SendGrid/SES) or a
Slack Incoming Webhook — keep all secrets server-side.
- No authentication by design (prototype). Add auth when you move to a shared backend.
- The QR code image uses a free public endpoint (
api.qrserver.com) and needs internet; it degrades gracefully to a plain link offline. Bundle a local QR library to remove that dependency. - Amazon has no universal public tracking-by-number page, so its "Check tracking" link points to the orders page.
MIT — use it, adapt it, share it with your lab.