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 migrateThe 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=3000Nuxt 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-srcallowsws:/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 π