Application de sondage en temps réel conçue pour les démonstrations Nutanix Kubernetes Platform (NKP). Déployée avec GitOps via Flux CD.
- 🔄 Temps réel - Votes et résultats en direct via WebSocket (Socket.io)
- 📱 QR Code - Génération automatique pour partage facile
- 📊 Graphiques - Visualisation des résultats (barres et camembert)
- 🎨 Design Nutanix - Couleurs et branding officiels
- ☸️ Cloud Native - Kubernetes, GitOps, sécurité Zero Trust
- 🖥️ Mode présentateur - Vue plein écran pour projections
- 📄 Export CSV - Télécharger les résultats
- 📚 API Docs - Documentation Swagger/OpenAPI
- 📈 Métriques - Prometheus avec ServiceMonitor
| Environnement | URL |
|---|---|
| Production | https://tke-poll.ntnxlab.ch |
| Development | https://dev.tke-poll.ntnxlab.ch |
| Type | Color | Hex | Usage |
|---|---|---|---|
| Primary | 🟣 Iris Purple | #7855fa |
Buttons, accent |
| Primary | ⬜ White | #ffffff |
Background |
| Primary | ⬛ Charcoal | #131313 |
Text |
| Secondary | 🔵 Cyan | #1fdde9 |
Highlight |
| Secondary | 🟢 Lime | #92dd23 |
Success |
| Secondary | 🟠 Coral | #ff9178 |
Warning |
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└─────────────────────────┬───────────────────────────────────┘
│ HTTPS (443)
▼
┌─────────────────────────────────────────────────────────────┐
│ Traefik Ingress (kommander-traefik) │
│ + cert-manager (Let's Encrypt via kommander-acme-issuer) │
│ + External-DNS (automatic DNS records) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
│ / │ /api, /socket.io│
▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Frontend │ │ Backend │ │ Redis │
│ Next.js │──▶│ Express │──▶│ 7.4 │
│ :3000 │ │ :3001 │ │ :6379 │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└─────────────────┴─────────────────┘
Network Policies (Zero Trust)
├── backend/ # API Node.js + Express + Socket.io
│ ├── src/
│ │ ├── routes/ # Endpoints REST (/api/polls, /api/health)
│ │ ├── socket/ # WebSocket handlers
│ │ ├── models/ # Redis data layer
│ │ └── middleware/ # Rate limiting, error handling
│ └── Dockerfile
│
├── frontend/ # Next.js 15 + React 19 + TailwindCSS
│ ├── src/
│ │ ├── app/ # App Router pages
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom hooks (useSocket, usePolls)
│ │ └── lib/ # API client, utilities
│ └── Dockerfile
│
├── k8s/ # Kubernetes manifests
│ ├── base/ # Shared resources
│ │ ├── backend/ # Backend Deployment, Service, HPA
│ │ ├── frontend/ # Frontend Deployment, Service, HPA
│ │ ├── redis/ # Redis Deployment, Service, PVC
│ │ ├── ingress.yaml # Traefik Ingress
│ │ └── network-policies.yaml
│ ├── overlays/
│ │ ├── dev/ # dev.tke-poll.ntnxlab.ch
│ │ └── prod/ # tke-poll.ntnxlab.ch + ESO
│ └── flux-system/ # Flux CD configuration
│
├── .github/workflows/ # GitHub Actions CI/CD
│ └── build-images.yaml # Build & push to Harbor
│
├── docker-compose.yml # Local production (nginx proxy)
├── docker-compose.dev.yml # Local development (hot-reload)
└── nginx.conf # Reverse proxy for local prod
- Docker Desktop
- Node.js 22+ (optionnel, pour développement sans Docker)
# Développement avec hot-reload
docker compose -f docker-compose.dev.yml up
# Accéder à l'application
open http://localhost:3000# Build et run avec nginx proxy
docker compose up --build
# Accéder via nginx (port 80)
open http://localhost# Terminal 1: Redis
docker run -p 6379:6379 redis:7.4-alpine
# Terminal 2: Backend
cd backend && npm install && npm run dev
# Terminal 3: Frontend
cd frontend && npm install && npm run dev| Composant | Nom | Description |
|---|---|---|
| Ingress | kommander-traefik |
Traefik IngressClass |
| TLS | kommander-acme-issuer |
cert-manager ClusterIssuer |
| DNS | External-DNS | Automatise les enregistrements DNS |
| Secrets | External Secrets Operator | Synchronise les secrets depuis Vault/AWS |
# Dans Vault ou AWS Secrets Manager
vault kv put secret/realtime-poll/secrets \
redis-password="$(openssl rand -base64 32)" \
session-secret="$(openssl rand -base64 32)"flux bootstrap github \
--owner=tkelkermans \
--repository=nkp-webapp \
--branch=main \
--path=k8s/flux-system# Status Flux
flux get kustomizations
# Pods
kubectl get pods -n realtime-poll
# Ingress
kubectl get ingress -n realtime-poll
# Certificats TLS
kubectl get certificates -n realtime-poll
# External Secrets
kubectl get externalsecrets -n realtime-poll- ✅ Pod Security Standards: Mode
restricted - ✅ Network Policies: Zero Trust (deny all, allow specific)
- ✅ RBAC: ServiceAccounts dédiés sans automount token
- ✅ Resource Quotas: Limites CPU/mémoire par namespace
- ✅ Secrets: External Secrets Operator (pas de secrets en clair)
- ✅ Rate Limiting: Protection contre les abus
- ✅ Anti-double vote: Fingerprint (IP + User-Agent hash)
- ✅ Input Validation: Zod schemas
- ✅ CORS: Origines autorisées configurables
- ✅ Security Headers: X-Frame-Options, X-Content-Type-Options
Le workflow .github/workflows/build-images.yaml :
| Événement | Action |
|---|---|
Push sur main |
Build → Tag SHA → Update dev overlay → Flux déploie |
Tag v*.*.* |
Build → Tag version → Update prod overlay → Flux déploie |
# Développement (automatique sur push)
git push origin main
# → Images taguées avec SHA court (ex: abc1234)
# → k8s/overlays/dev mis à jour
# → Flux déploie sur dev.tke-poll.ntnxlab.ch
# Production (sur tag)
git tag v1.2.0
git push --tags
# → Images taguées avec version (ex: v1.2.0)
# → k8s/overlays/prod mis à jour
# → Flux déploie sur tke-poll.ntnxlab.chDans GitHub Settings → Environments → ntnxlab :
| Type | Nom | Description |
|---|---|---|
| Secret | HARBOR_USERNAME |
Robot account Harbor |
| Secret | HARBOR_PASSWORD |
Token Harbor |
| Variable | HARBOR_REGISTRY |
tke-nkpmgmt.ntnxlab.ch:5000 |
| Variable | HARBOR_PROJECT |
nkp-webapp |
Le backend expose des métriques Prometheus sur /metrics :
# Métriques disponibles
curl http://localhost:3001/metrics
# Métriques clés
http_requests_total # Total requêtes HTTP
http_request_duration_seconds # Latence des requêtes
poll_votes_total # Nombre total de votes
websocket_connections_active # Connexions WebSocket activesUn ServiceMonitor est inclus pour l'intégration avec le Prometheus de NKP.
Les logs sont au format JSON (pino) pour une meilleure intégration avec les outils d'observabilité.
# Logs Flux CD
flux logs --follow
# Logs applicatifs
kubectl logs -f -l app.kubernetes.io/name=realtime-poll -n realtime-poll
# Events Kubernetes
kubectl get events -n realtime-poll --sort-by='.lastTimestamp'
# Describe pods
kubectl describe pods -n realtime-poll# Backend unit tests (Jest)
cd backend && npm test
# Frontend unit tests (Vitest)
cd frontend && npm test
# Frontend tests en mode watch
cd frontend && npm run test:watch
# Type checking
cd frontend && npm run lint
cd backend && npm run buildLa documentation interactive est disponible sur /api/docs :
| Environnement | URL |
|---|---|
| Local | http://localhost:3001/api/docs |
| Dev | https://dev.tke-poll.ntnxlab.ch/api/docs |
| Prod | https://tke-poll.ntnxlab.ch/api/docs |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/health/ready |
Readiness probe (K8s) |
| GET | /api/health/live |
Liveness probe (K8s) |
| GET | /api/polls |
Liste des sondages actifs |
| GET | /api/polls/:id |
Détails d'un sondage |
| POST | /api/polls |
Créer un sondage |
| POST | /api/polls/:id/vote |
Voter |
| POST | /api/polls/:id/close |
Fermer un sondage |
| DELETE | /api/polls/:id |
Supprimer un sondage |
| GET | /api/polls/:id/export |
Exporter résultats (CSV/JSON) |
| GET | /metrics |
Métriques Prometheus |
| Event | Direction | Description |
|---|---|---|
join-poll |
Client → Server | Rejoindre un sondage |
leave-poll |
Client → Server | Quitter un sondage |
vote-update |
Server → Client | Mise à jour des votes |
poll-closed |
Server → Client | Sondage fermé |
Accédez à /poll/:id/present pour afficher les résultats en mode plein écran :
- Q : Afficher/masquer le QR code
- F11 : Mode plein écran
| Layer | Technologies |
|---|---|
| Frontend | Next.js 15, React 19, TailwindCSS 3.4, Chart.js 4, TanStack Query |
| Backend | Node.js 22, Express 4, Socket.io 4, ioredis, Zod |
| Database | Redis 7.4 (in-memory, AOF persistence) |
| Infrastructure | Kubernetes, Flux CD, Traefik, cert-manager |
| CI/CD | GitHub Actions, Harbor Registry |
Propulsé par Nutanix Kubernetes Platform 🟣