FactoryPulse AI is a full-stack manufacturing productivity dashboard for AI-powered CCTV events. Edge/computer-vision systems emit structured events such as working, idle, absent, and product_count; this app ingests them, stores them in MongoDB, deduplicates retries, computes productivity metrics, and exposes both REST APIs and a React dashboard.
The backend is the source of truth. The frontend consumes live backend APIs for factory, worker, workstation, and event data.
This README directly addresses the required written sections:
| Requirement | Where to read |
|---|---|
| Edge -> Backend -> Dashboard architecture | Architecture Overview |
| Database schema | Database Schema and Duplicate Strategy |
| Metric definitions | Metric Definitions |
| Assumptions and tradeoffs | Assumptions and Tradeoffs |
| Intermittent connectivity | Real-World Event Handling |
| Duplicate events | Real-World Event Handling |
| Out-of-order timestamps | Real-World Event Handling |
| Model versioning, drift, retraining | Model Lifecycle Extension Answers |
| Scaling from 5 cameras to 100+ cameras to multi-site | Scaling Plan |
| GitHub repository and web application | Deliverables |
- Single and batch event ingestion with Zod validation.
- MongoDB persistence through Mongoose models.
- Duplicate-event protection through deterministic event fingerprints.
- Worker, workstation, and factory-level metrics.
- Timestamp-based calculations that tolerate out-of-order event arrival.
- Seed/reset utilities with 6 workers, 6 workstations, and realistic shift events.
- Swagger/OpenAPI docs at
/docs. - React dashboard served by Express at
/. - Tests for validation, ingestion, duplicates, out-of-order events, and metrics.
- GitHub repository:
https://github.com/abhey8/Factory_Pulse - Web application:
https://factory-pulse-2.onrender.com/ - API docs:
https://factory-pulse-2.onrender.com/docs/
flowchart LR
A["AI CCTV / Edge Model"] -->|"structured events"| B["Express API"]
B --> C["Zod Validation"]
C --> D["Mongoose Services"]
D --> E[("MongoDB")]
E --> F["Metrics Engine"]
F --> G["REST API"]
G --> H["React Dashboard"]
G --> I["Swagger Docs"]
Flow:
- Edge/CCTV layer emits structured JSON events with worker, station, event type, timestamp, confidence, and optional production count.
- Backend ingestion API validates payloads, checks worker/station references, computes duplicate fingerprints, and persists accepted events.
- MongoDB stores workers, workstations, and raw AI events.
- Metrics engine sorts events by timestamp and computes worker, workstation, and factory metrics.
- Dashboard/API layer exposes metrics through REST endpoints, Swagger docs, and the React dashboard.
classDiagram
class Worker {
+String workerId
+String name
+Date createdAt
+Date updatedAt
}
class Workstation {
+String stationId
+String name
+String type
+Date createdAt
+Date updatedAt
}
class AIEvent {
+Date occurredAt
+String workerExternalId
+String stationExternalId
+EventType eventType
+Number confidence
+Number count
+String eventFingerprint
+ObjectId workerRef
+ObjectId workstationRef
}
Worker "1" --> "many" AIEvent
Workstation "1" --> "many" AIEvent
- Node.js, TypeScript, Express
- MongoDB, Mongoose
- Zod
- Swagger/OpenAPI
- React + Vite
- Recharts
- Vitest, Supertest,
mongodb-memory-server - Docker and Docker Compose support
src/
app.ts, server.ts
config/
controllers/
docs/
lib/
models/
routes/
services/
validators/
frontend/
src/app/App.tsx
src/app/services/api.ts
src/app/components/
scripts/
seed.ts
seed-if-empty.ts
tests/
docs/screenshots/
Key files:
src/services/event.service.ts: ingestion, validation orchestration, duplicate handling, event listing.src/services/metrics.service.ts: worker, workstation, and factory metric calculations.src/services/seedData.ts: deterministic factory seed dataset.frontend/src/app/services/api.ts: central frontend API client.src/docs/openapi.ts: Swagger/OpenAPI document.
Collections:
Worker:workerId,name, timestamps.Workstation:stationId,name,type, timestamps.AIEvent: event timestamp, worker/station IDs, event type, confidence, count, references, and fingerprint.
Duplicate protection uses a deterministic fingerprint:
normalized timestamp | worker_id | workstation_id | event_type | count
This prevents retry submissions from double-counting production. confidence is excluded because the same source event may be resent with a slightly different confidence score.
All duration calculations use event timestamps, not insertion order.
working,idle, andabsentare state transitions.- A state starts at its timestamp and lasts until the next state event for the same worker/workstation grouping.
product_countevents are production increments. They affect totals/rates but do not create active time.- A final open state interval closes at the explicit
toquery parameter when provided; otherwise it closes at the max event timestamp in the filtered dataset.
Definitions:
- Worker active time: time in
working. - Worker idle time: time in
idle. - Worker utilization:
active_time_seconds / tracked_time_seconds * 100. - Workstation occupancy:
workingtime associated with that station. - Workstation throughput:
total_units_produced / tracked_hours. - Factory productive time: sum of worker active time.
- Factory production count: sum of all production counts.
Assumptions:
- The AI/CCTV system emits structured events; this app does not run computer vision itself.
working,idle, andabsentare state transitions, not durations.product_countis an increment event and does not create active time.- Final open intervals close at the explicit
tofilter when supplied, otherwise at the max timestamp in the filtered dataset. - Seed data is deterministic so evaluators see repeatable metrics on first run.
Tradeoffs:
- No authentication or authorization because the assignment focuses on ingestion, metrics, and dashboard integration.
- No queue/streaming layer yet; direct HTTP ingestion is enough for the assessment scope.
- No background aggregation jobs; metrics are computed from persisted events for clarity.
- No model registry implementation yet; model lifecycle support is documented below as an extension path.
Swagger UI:
GET /docs/
Core endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/ |
Dashboard |
GET |
/health |
Health check |
GET |
/api/bootstrap |
Workers, workstations, and factory summary |
GET |
/api/workers |
List workers |
GET |
/api/workstations |
List workstations |
POST |
/api/events/ingest |
Ingest one event or a batch |
GET |
/api/events |
List persisted events |
GET |
/api/metrics/factory |
Factory metrics |
GET |
/api/metrics/workers |
All worker metrics |
GET |
/api/metrics/workers/:workerId |
One worker's metrics |
GET |
/api/metrics/workstations |
All workstation metrics |
GET |
/api/metrics/workstations/:stationId |
One workstation's metrics |
POST |
/api/admin/seed |
Upsert seed data |
POST |
/api/admin/reset-and-seed |
Reset and recreate seed data |
DELETE |
/api/admin/events |
Delete events for testing |
Supported filters where relevant: from, to, worker_id, workstation_id, event_type, limit.
Create environment file:
cp .env.example .envRequired/manual values:
MONGODB_URI=<your MongoDB URI>
PORT=3000
NODE_ENV=development
CORS_ORIGIN=*Keep real credentials in .env, not .env.example.
Install, seed, and run:
npm install
npm run frontend:install
npm run seed
npm run build
npm run devOpen:
- Dashboard: http://localhost:3000/
- Swagger: http://localhost:3000/docs/
- Health: http://localhost:3000/health
Frontend hot reload:
npm run dev:backend
npm run dev:frontendnpm run build
npm run testCurrent verification:
- Build passes.
- Tests pass: 4 files, 17 tests.
- Docker files are included, but Docker was not installed on the development machine for local verification.
If Docker is installed:
docker compose up --buildThis starts the API and a MongoDB container with a persistent volume.
Reset Docker data:
docker compose down -v
docker compose up --buildThe app can deploy as a single Node service. Express serves the compiled React frontend from public/ and the API from the same origin.
Build command:
npm install && npm run frontend:install && npm run buildStart command:
npm run deploy:startDeployment env vars:
MONGODB_URI=<MongoDB Atlas or managed MongoDB URI>
PORT=3000
NODE_ENV=production
CORS_ORIGIN=*deploy:start seeds only if the database is empty/incomplete, then starts the server.
curl http://localhost:3000/health
curl http://localhost:3000/api/bootstrap
curl http://localhost:3000/api/metrics/factory
curl "http://localhost:3000/api/metrics/workers/W001"
curl "http://localhost:3000/api/events?worker_id=W001&limit=10"Ingest one event:
curl -X POST http://localhost:3000/api/events/ingest \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2026-04-21T10:30:00.000Z",
"worker_id": "W001",
"workstation_id": "S001",
"event_type": "product_count",
"confidence": 0.94,
"count": 12
}'Cameras or edge devices may temporarily lose connectivity. The ingestion endpoint accepts batches, so a device can buffer events locally and send them later. The backend does not reject late timestamps.
Retries are safe because each event receives a deterministic fingerprint from timestamp, worker, workstation, event type, and count. If the same event is sent again, it is reported as a duplicate and not inserted again.
Events are persisted even if they arrive late or out of order. Metrics sort by occurredAt, not insertion order, before calculating state durations.
Add fields such as model_version, camera_id, site_id, and optional pipeline_version to AIEvent. For a larger system, add a ModelVersion collection with training date, dataset notes, evaluation metrics, and deployment status.
Monitor confidence distributions, event frequency by camera, worker state mix, sudden station-level changes, and production count mismatch against trusted manual/ERP totals. Drift alerts can be generated by comparing these signals against rolling baselines.
Retraining should be triggered by evidence: drift alerts, repeated manual audit failures, layout/camera changes, new product types, or sustained confidence degradation. A practical loop would collect reviewed examples, retrain a candidate model, evaluate it against held-out shifts, then roll it out gradually.
The current direct HTTP ingestion API is sufficient. Add camera IDs, basic auth, request logging, and monitoring.
Add a queue or streaming layer between cameras and the API, such as Kafka, RabbitMQ, SQS, or a durable edge gateway. Add backpressure, dead-letter handling, stronger timestamp/camera/site indexes, and precomputed hourly or shift aggregates.
Add site_id across workers, workstations, cameras, and events. Add site-aware authorization, site time zones, shift definitions, regional ingestion gateways, and per-site aggregation/reporting.







