Case study · 01 / 08
PPE Safety Platform
A local-first, offline-capable PPE compliance platform that runs on one on-site server — it watches existing RTSP cameras, tracks every person, checks the PPE their zone requires over seconds rather than single frames, keeps snapshot-and-clip evidence for every confirmed miss, and learns from what the safety team reviews.
- Missing before a violation opens — never one frame
- 3 s
- Video, evidence and models stay on the site server
- 0 cloud
- Helmet to harness, plus custom site types
- 10 PPE types
- No model goes live without a golden-set check
- Human-gated

Context
Industrial sites need to know who is on the floor without a helmet or vest, but cloud video analytics means streaming CCTV off-site, and naive detectors raise an alarm on every flickering frame until people stop looking. Off-the-shelf PPE models also confuse cloth caps with helmets and miss small items seen from high, wide camera angles. The brief: run entirely on one local server, never decide from a single frame, attach proof to every event, and get better on each site's own footage — without a model ever being swapped in behind a person's back.
I lead the platform at Alta Vision as its architect and decision-maker — I set the product brief and requirements, signed off the architecture (Python vision and trainer services, a Bun + Hono API, a Next.js console, one-server deployment), and I make the product calls and own the milestone roadmap from the first client go-live to a white-label product.
01
Tracks, not frames — violations confirmed over seconds
Each camera's light sub-stream runs person detection, ByteTrack tracking, then a PPE detector on batched person crops; an associator assigns every item to the right body region of the right track. Presence is smoothed per track and PPE type, and a person is judged by the smallest zone their feet stand in, after an entry grace period. A violation opens only after an item stays missing for 3 seconds and clears after 2 seconds of being seen, with one event per episode, a 60-second cooldown and an 80 px minimum person height — so a flicker never raises an alarm. Rules are a matrix of zone × PPE type, each with a severity and optional hours and weekdays.
02
Evidence with every event
The main stream is recorded continuously to local SSD as 60-second ffmpeg segments, stream-copied and never re-encoded. When an event closes, the recorder cuts a clip from 5 seconds before to 5 seconds after it, and annotated and raw snapshots come from a per-camera ring buffer of the last 3 seconds. Reviewers mark each event true or false positive, and false positives flow straight into the training queue. If the API is unreachable, events spool to disk and replay when it is back — detection never stops.
03
A learning loop with a human at the gate
The miner saves hard examples — PPE probabilities stuck in the uncertain band, low-confidence people, unusual-looking frames — rate-limited per person and camera. Reviewers correct boxes in a label editor and approve samples into immutable dataset versions. Training fine-tunes the active model during configured idle windows and pauses whenever live cameras need the GPU. Every candidate is scored against a permanent golden set it is never trained on, and activation stays manual: a passing score or a written reason, with one-click rollback.
04
People across cameras, privacy by default
Each confirmed track gets an appearance embedding, which re-attaches people after occlusion on the same camera and links them across cameras into a stable id such as P-1A2B3C4D with a journey of where they were seen. Face recognition is opt-in and matches only people an admin has named; face data of unnamed people is deleted after 7 days by default. PPE checking can be switched off per camera, which unloads the model and frees the GPU for security-only use.
05
One codebase from a MacBook to a GPU server
An InferenceProvider abstraction hides the backend behind one Detections contract — PyTorch on Apple Silicon MPS or CUDA, ONNX Runtime on CPU, CUDA or TensorRT — so it is developed on a Mac and deployed on Linux + NVIDIA with no code changes. Class maps let any model's vocabulary drive the configured PPE types, including "no helmet" classes counted as evidence of absence. Rule and setting changes hot-reload to every camera within 15 seconds, and go2rtc gives sub-second WebRTC live view with an annotated MJPEG fallback.
Stack & architecture
- Next.js 16 operator console: monitor wall with kiosk mode, zone editor, rules matrix, events, datasets, training, models, analytics, ⌘K palette
- Bun + Hono + Drizzle API: auth, four-role RBAC, audit log, WebSocket events, WebRTC signalling proxy, idle-training scheduler
- Zod contract package shared by the web app and the API
- Python vision service: decode → detect → ByteTrack → PPE association → temporal rules → events, plus recorder and hard-example miner
- Python trainer service: immutable dataset versions, idle-aware fine-tuning, golden-set evaluation, candidate registration
- Inference providers: PyTorch (MPS / CUDA), ONNX Runtime (CPU / CUDA / TensorRT), and a DeepStream integration point
- PostgreSQL 17 — or embedded, file-backed PGlite for single-box installs — with Redis for heartbeats, live frames and the training queue
- go2rtc for sub-second WebRTC live view; ffmpeg stream-copy recording to local SSD with retention by free space and age
- Caddy HTTPS (Let's Encrypt or an internal CA for offline sites), Docker Compose with the NVIDIA runtime, systemd units, one-click Windows and macOS installers
- Python
- PyTorch
- ONNX Runtime
- TensorRT
- ByteTrack
- Next.js 16
- Bun + Hono
- PostgreSQL
- Redis
- go2rtc
- Docker
What's next
01 · In progress
Accounts
Request access from the sign-in page with admin approval, password reset that works offline through one-time admin links, invitations and change password. The server side is done; the screens are being built.
02 · Next
Client go-live
Camera presets, NVR bulk add and areas; one event for a person seen by overlapping cameras; visits and incidents with evidence packs; a storage view with disk forecast and 90-day retention; Test bench A/B compare; branded PDF and CSV reports; a load test and handover documents.
03 · Planned
Sell-ready white label
Signed licences with modules and camera limits, an Apps page that switches products on and off, and compiled releases with a licence server. The default model stack moves to licence-safe Apache-2.0 detectors such as RF-DETR, with every model's licence and provenance on record, plus a hygiene and food-safety PPE preset.
04 · Later
Security system
No-go zones with schedules, watchlist alerts, camera tamper, alarms and a site map — plus safety checks: fire and smoke early warning, person down, phone use, forklift proximity, safe corridors and occupancy limits.
05 · Later
More apps
A CCTV playback timeline with export and PTZ; people counting and area analytics with line counts, occupancy, heatmaps and dwell; vehicles and number plates; video search by text description; and time and attendance.