Sentinel is built with defence-in-depth security from the ground up. Every component \u2014 from the agent on your devices to the database that stores your data \u2014 is designed to protect your school's infrastructure.
🔒
Encryption in Transit
All API and dashboard traffic encrypted via HTTPS (TLS 1.2+) with auto-renewed Let’s Encrypt certificates managed by Caddy reverse proxy.
Agent-to-server communication uses MQTTS (MQTT over TLS) on port 8883 — no plaintext MQTT is exposed to the internet.
Dashboard real-time feeds use WSS (WebSocket Secure) for live device telemetry.
Internal service communication (server → database, server → Redis, server → MQTT broker) is bound to localhost only and never exposed externally.
🛡️
Authentication & Authorization
Admin authentication via Supabase Auth with JWTs and automatic refresh token rotation.
Role-based access control (RBAC): owner, admin, and readonly roles enforced at the API level. Read-only users cannot create, modify, or delete any resources.
Device authentication uses unique per-device bearer tokens generated at enrollment. Tokens are SHA-256 hashed before storage — raw tokens never persist in the database.
API rate limiting enforced globally (100 req/min) with stricter limits on sensitive endpoints: enrollment (10/min), billing (10/min), org creation (5/min).
🏢
Tenant Isolation
Multi-tenant architecture with full data isolation: each organization’s data resides in a separate PostgreSQL schema.
Tenant pool routing resolves the correct database connection per-request based on the authenticated user’s organization membership.
MQTT access control lists (ACLs) enforce per-device topic scoping. A device can only publish to and subscribe from its own org/device namespace: sentinel/{org_id}/devices/{device_id}/*.
Cross-tenant data leakage is structurally impossible — queries are executed against isolated schemas, not filtered rows in shared tables.
⚡
Infrastructure Hardening
All internal services (PostgreSQL, Redis, MQTT broker) are bound to 127.0.0.1 — inaccessible from the public internet.
Redis protected with authentication password and memory limits to prevent abuse.
PostgreSQL connections use SSL with certificate verification in production (rejectUnauthorized: true).