📝 Note
pro/av platform/architecture
reactfastifyqsystypescriptkubernetesmqttsocket-io
Architecture — av-platform
Liens : Decisions · Journal
Vue d’ensemble
Plateforme de contrôle AV pour salles — interface web temps réel, Q-SYS Core, intégration MQTT bâtiment.
Browser (React 19) ←→ Socket.IO ←→ Fastify 5 ←→ Q-SYS Core (QRWC/QRC)
↕
Redis (adapter K8s)
↕
MQTT Broker (HVAC, éclairage)
Composants principaux
apps/frontend
- Auth : MSAL +
useAuthhook +RoleGuardcomposant - State : Zustand —
qsysStore,roomStore,buildingStore - Socket :
socketClient.tssingleton, token MSAL danshandshake.auth.token - Thèmes : 8 thèmes CSS
[data-theme]sur<html>, persistance localStorage - WYSIWYG :
AdminRoomEditor— react-grid-layout + panneau de style - Contrôles :
Fader,MuteButton,SourceSelect,SnapshotButton - VU-mètres :
VUMeter— Canvas 2D, 30fps rAF, Float32Array (jamais React state)
apps/backend
- Auth plugin : JWT Entra ID (jwks-rsa, cache JWKS 1h)
- Redis adapter :
@socket.io/redis-adapter— scale horizontal pods QSysManager: QRWC + QRC fallback TCP, reconnexion backoff exponentielMQTTService: broker MQTT v5,topicMapbâtiment →BuildingUpdate- Routes :
GET /health,GET /ready,GET /metrics(Prometheus, sans auth)
packages/types (0 deps runtime)
Room,ControlConfig,Control,QSysStatus,AppRole,SocketEvents,BuildingUpdate- Extensions WYSIWYG :
ControlLayout,ControlStyle,Room.theme,Room.layoutMode
packages/qsys-client
QRWCClient(@q-sys/qrwc) +QRCClient(qrc-client-js, TCP)- Change Groups :
ui100ms ·meters50ms ·status1000ms - Keep-alive QRC : NoOp toutes les 30s
Flux de données
- Contrôle : Browser →
control:set→ RBAC check →QSysManager.setControl()→ Core - Update : Core → QRWC event →
io.to(room).emit('control:update')→ clients - Mètres : Core → Change Group
meters50ms →meters:update→useMeterCanvasrAF - Bâtiment : MQTT →
topicMap→building:update→buildingStore - Thème :
room.theme→RoomControl useEffect→document.documentElement.setAttribute('data-theme', ...)+ localStorage
Dépendances externes
| Service | Usage |
|---|---|
| Q-SYS Core | Contrôle audio (QRWC WebSocket + QRC TCP fallback) |
| Microsoft Entra ID | Auth JWT, JWKS, 4 rôles RBAC |
| Redis 7 | Socket.IO adapter K8s |
| MQTT Broker | Données bâtiment (HVAC, éclairage) |
| Prometheus / Grafana | Monitoring (cluster Millennium) |
Schémas
RBAC
av.admin → tout (config, WYSIWYG, snapshots, monitoring)
av.technician → toutes salles + snapshots + VU-mètres + statut
av.staff → salles assignées, contrôles de base
av.kiosk → une salle (claim av_room JWT), read-mostly
Monorepo
av-platform/
├── apps/frontend/ React 19 + Vite + TS strict
├── apps/backend/ Fastify 5 + Socket.IO + TS strict
├── packages/types/ Interfaces partagées (0 deps runtime)
├── packages/qsys-client/
├── k8s/ Manifests (namespace: av-dashboard)
└── docs/ PLAN.md, QSYS_SETUP.md
Infra K8s — cluster Millennium (Vaud), namespace av-dashboard
- Backend : 2 replicas min, HPA CPU 70%, max 5 pods
- Frontend : Nginx alpine, 1-2 replicas
- Ingress : annotations WebSocket obligatoires