An engineering‑grade platform for real‑time sensor data ingestion, visualization and alerting. Backend: Django + DRF + Channels (ASGI, Redis). Frontend: Nuxt 3 (Vue 3). Local dev via Docker Compose.
Live WebSockets + one‑click Quickstart/Seed — see data flowing in seconds.
Click: docs/
- 🐍 Django 4 + Django REST Framework + Channels (ASGI, WebSocket)
- 🐘 PostgreSQL, 🧰 Redis (Channels layer)
- 🌐 Nuxt 3 / Vue 3
- 🐳 Docker Compose
- 🧪 unittest/pytest, flake8/black/isort
- 🔐 Token‑based authentication (create user, obtain token,
/me
) - 🧩 Domain model: Workspaces → Machines → Sensors → Readings/Events
- 🧪 Simulator that generates live readings and threshold alerts (broadcast via WS)
- 📊 Nuxt dashboard with real‑time readings
- ⚡ Quickstart/Seed endpoints to spin up a demo workspace instantly
.
├─ backend/ # Django project (DRF + Channels)
│ ├─ app/ # settings, urls, ASGI
│ ├─ core/ # models & Workspace API
│ ├─ simulator/ # start/stop + WS broadcast services
│ ├─ docker-compose.yml, Dockerfile
│ └─ requirements*.txt
└─ frontend/ # Nuxt 3 app
├─ app/ (pages, components, composables)
└─ nuxt.config.ts
cd backend
docker compose up
# Django API: http://localhost:8000
# API Docs (Swagger): http://localhost:8000/api/docs/
# OpenAPI schema: http://localhost:8000/api/schema/
Useful commands:
# run tests
docker compose run --rm app python manage.py test
# seed demo user & workspace (optional)
docker compose run --rm app python manage.py seed_demo
# prints: demo credentials and workspace_id
# migrations
docker compose run --rm app python manage.py makemigrations
docker compose run --rm app python manage.py migrate
The stack uses Channels (ASGI) + Redis. The compose is set up to run an ASGI server and a Redis instance.
cd frontend
npm i
npm run dev
# http://localhost:3000 (or 4000 if 3000 is busy)
Optional .env
(defaults are already set in nuxt.config.ts
):
NUXT_PUBLIC_API_BASE=/api
NUXT_PUBLIC_WS_BASE=/ws
# PORT=3000
Nuxt is configured to proxy requests to the backend:
// nuxt.config.ts (excerpt)
nitro: {
routeRules: {
'/api/**': { proxy: 'http://127.0.0.1:8000/api/**' },
'/ws/**' : { proxy: 'http://127.0.0.1:8000/ws/**' }, // WebSockets proxy
},
},
security: {
headers: {
contentSecurityPolicy: {
'connect-src': ["'self'", 'http:', 'https:', 'ws:', 'wss:'], // relaxed for dev
},
},
},
This removes CORS pain and allows WS via the same origin (localhost:3000
).
# register
curl -X POST http://localhost:8000/api/user/create/ \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"demo123","name":"Demo"}'
# obtain token
curl -X POST http://localhost:8000/api/user/token/ \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"demo123"}'
# -> {"token":"..."}
Add the token to subsequent requests:
Authorization: Token <YOUR_TOKEN>
- Open
/dashboard/workspaces
. - Click “Create demo workspace” — it will create & seed a workspace and redirect to its detail view.
- Click Start — if empty, the page seeds sensors and then starts the simulator. Live readings appear immediately.
User
POST /api/user/create/
— registerPOST /api/user/token/
— obtain tokenGET /api/user/me/
— current user
Workspaces
GET /api/workspaces/
— list (current user)POST /api/workspaces/
— createGET /api/workspaces/{id}/
— retrievePOST /api/workspaces/quickstart/
— create a demo workspace for the user (creates & seeds)POST /api/workspaces/{id}/seed/
— seed a workspace (adds machine & sensors if empty)
Simulator
POST /api/sim/start/{id}/
POST /api/sim/stop/{id}/
WebSocket (Channels)
-
ws://localhost:8000/ws/workspaces/{id}/
-
message samples:
{ "type": "reading", "sensor_id": 1, "value": 61.5, "unit": "°C" } { "type": "event", "level": "WARN", "sensor_id": 1, "message": "temperature alert" }
-
# tests
cd backend
docker compose run --rm app python manage.py test
# style/format (if included in image)
docker compose run --rm app flake8
docker compose run --rm app isort --check .
docker compose run --rm app black --check .
-
CSP blocks WebSocket (browser shows
NS_ERROR_CONTENT_BLOCKED
):- Ensure
connect-src
allowsws:
/wss:
in dev (seenuxt.config.ts
). - With proxy (
/ws/**
), the browser connects tows://localhost:3000/ws/...
and Nitro forwards to:8000
.
- Ensure
-
Backend logs:
X of Y channels over capacity in group ws_*
:- The WS client is not actually connected (CSP/CORS/URL). Fix CSP or WS URL.
-
Start clicked, but no data:
- Workspace has no sensors. Use
POST /api/workspaces/{id}/seed/
or the Seed + Start button in the UI.
- Workspace has no sensors. Use
-
404 for
/ws/...
:- Make sure the backend runs an ASGI server (Daphne/Uvicorn) and Channels routing includes the consumer.
- CRUD for machines/sensors (drag‑and‑drop canvas)
- Real‑time charts + history & aggregations
- Multi‑tenant/roles, exports, webhooks
🚧 Work in progress (pre-alpha). Stable enough to explore; expect breaking changes. Screens below use already simulated data.





MIT — feel free to use, modify and share. A credit link is appreciated 🙌