Proposition : Migration dashboard-33800 vers projet GitLab avec CI/CD
Date : 15/02/2026
Contexte : Audit sécurité (36 findings) + demande utilisateur de passer en projet GitLab clean avec CI/CD full automatisé
Statut : VALIDÉE (principe) — choix architecture à confirmer
1. État actuel
Ce qu'est le dashboard aujourd'hui
Un ensemble de scripts bash (~150K lignes) qui :
- Collectent des données via SSH brut sur 8 VMs + 4 APIs HTTP
- Génèrent 30+ pages HTML statiques via heredocs bash
- Déploient via
git push o2switch main & (en background, sans CI/CD)
Problèmes majeurs
| Problème |
Impact |
| Credentials hardcodés dans les scripts (GitLab token, Redis passwords, JWT keys) |
Sécurité — exposés dans git history |
| 150K lignes de bash monolithique (generate.sh = 77K lignes) |
Maintenabilité impossible |
| Données statiques périmées dès la génération |
UX — snapshot, pas live |
| SSH brut pour collecter des données disponibles via API |
Fragilité + lenteur |
| Pas de CI/CD, déploiement = git push manuel en background |
Fiabilité — push peut échouer silencieusement |
| 7 systèmes de navigation, 2 CSS en doublon, design incohérent |
UX — chaque page est un monde |
| Pas de set -e, erreurs avalées partout |
Données partielles/corrompues sans alerte |
| git add -A pousse tout sans filtrage |
Sécurité — peut pousser des fichiers sensibles |
Structure des fichiers actuels
/stock_8to/33800-stack/monitoring/
├── generate.sh # Orchestrateur principal (77K lignes)
├── collect.sh # Collecte données
├── collect-gitlab.sh # Collecte GitLab CI/CD
├── config.json # Config centrale (hosts, services, deploy)
├── current.json # Cache données live (regénéré chaque cycle)
├── templates.sh # Templates HTML réutilisables
├── generate.d/ # 26 modules de génération (1 par page)
│ ├── _common.sh
│ ├── 01-index.sh → 26-claude.sh
├── collect.d/ # 10 modules de collecte
│ ├── _common.sh
│ ├── 01-pve.sh → 09-linkedin.sh
├── audit.d/ # 9 modules d'audit
├── assets/ # CSS, JS, SVG
│ ├── style.css (1210 lines)
│ ├── dashboard.css (688 lines, doublon)
│ ├── data-loader.js (142 lines)
│ └── nav.js (44 lines)
├── *.html # 30+ pages HTML générées
├── data/current.json # Symlink pour le JS frontend
├── logs/ # Logs quotidiens JSON
└── .git/ # Remotes: origin (GitLab) + o2switch
Sources de données actuelles
Collecte SSH (collect.d/)
| Module |
Host |
IP |
User |
Données collectées |
| 01-pve |
PVE |
192.168.1.10 |
gouroubleu |
ZFS pools, ARC cache, CPU/RAM/disk |
| 02-proxmox1 |
Proxmox 155 |
192.168.1.155 |
gouroubleu |
VMs, NFS, ZFS stock_1to, système |
| 03-prod-portainer |
Prod |
192.168.1.12 |
gouroubleu |
Docker containers, images, volumes, système |
| 04-dev-portainer |
Dev |
192.168.1.51 |
gouroubleu |
Docker containers, images, système |
| 05-gitlab |
GitLab |
192.168.1.196 |
gouroubleu |
Services GitLab, système |
| 06-nginx |
Nginx |
192.168.1.104 |
gouroubleu |
Service, SSL certs, logs, backups |
| 07-jellyfin |
Jellyfin |
192.168.1.199 |
gouroubleu |
Service, transcoding cache |
| 08-win11 |
Win11 |
192.168.1.30 |
gouro |
GPU nvidia-smi, CPU/RAM (PowerShell) |
| 09-linkedin |
Browser-connector |
192.168.1.12:5401 |
- |
LinkedIn messages, profil (HTTP) |
APIs HTTP appelées
| API |
Endpoint |
Données |
Auth |
| GitLab |
/api/v4/projects, /pipelines, /jobs |
CI/CD pipelines, déploiements |
Token hardcodé |
| AI Orchestrator |
/api/tools, /api/queue, /api/jobs |
GPU status, jobs, queue |
Aucune |
| Ollama |
/api/tags |
Modèles disponibles |
Aucune |
| Browser-connector |
/api/linkedin/* |
Messages LinkedIn |
Aucune |
| Notification |
/api/notify/push |
Envoyer notification |
Aucune |
Credentials dans le code (TOUS à externaliser)
| Credential |
Fichier |
Ligne |
GitLab token glpat-yaowLwWBJhXfzJEC8UBC |
collect-gitlab.sh |
15 |
| GitLab token dans git remote URL |
.git/config |
origin |
| Redis passwords |
collect.sh |
multiples |
| JWT Supabase anon keys |
collect.sh |
multiples |
2. Architecture cible
Principe : API backend + SPA frontend, CI/CD full automatisé
┌─────────────────────┐ ┌──────────────────────┐
│ O2switch │ │ prod-portainer │
│ │ HTTPS │ │
│ SPA Frontend │────────►│ Dashboard API │
│ (HTML/CSS/JS) │◄────────│ (Bun/Elysia) │
│ │ JSON │ │
│ - Affiche données │ │ - Collecte live │
│ - Auto-refresh 30s │ │ - Cache 30-60s │
│ - Zéro credential │ │ - Auth API key │
│ │ │ - Health check │
└─────────────────────┘ └──────────┬───────────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ APIs │ │ SSH via │ │ Direct │
│ existantes│ │connectors │ │ accès │
│ │ │ -api │ │ │
│ Portainer│ │ │ │ Redis │
│ GitLab │ │ PVE │ │ Postgres │
│ Ollama │ │ Proxmox155│ │ Loki │
│ AI-orch │ │ Win11 │ │ Prometheus│
│ Prometheus│ │ Nginx │ │ │
│ Loki │ │ Jellyfin │ │ │
└──────────┘ └──────────┘ └──────────┘
Pourquoi cette architecture
- Frontend sur O2switch : accessible de l'extérieur (IP protégé par .htaccess), même si l'infra locale est down → on voit le dernier état connu
- API backend sur prod-portainer : accès direct aux services internes, pas de SSH brut depuis O2switch, credentials côté serveur uniquement
- CI/CD GitLab → smart-deploy : comme tous les autres projets de la stack, full automatisé
Comment récupérer chaque donnée
| Donnée actuelle |
Source SSH actuelle |
Source API cible |
Existe déjà ? |
| Docker containers (prod/dev) |
SSH docker ps |
Portainer API via connectors-api |
OUI |
| Pipelines CI/CD |
GitLab API curl |
GitLab API via connectors-api |
OUI |
| GPU status |
SSH nvidia-smi |
ai-orchestrator /api/status |
OUI |
| AI jobs/queue |
SSH + API directe |
ai-orchestrator /api/jobs, /api/queue |
OUI |
| Ollama models |
API directe 11434 |
ai-orchestrator /api/tools (inclut models) |
OUI |
| Services health |
SSH curl localhost |
Health endpoints /health (après fix audit) |
À CRÉER (fix audit) |
| ZFS pools |
SSH zpool status |
SSH via connectors-api /api/ssh/execute |
OUI (via connectors-api) |
| Nginx sites/certs |
SSH nginx + openssl |
SSH via connectors-api |
OUI |
| System metrics (CPU/RAM/disk) |
SSH free/df/top |
Prometheus (node_exporter) |
OUI si node_exporter installé |
| Logs récents |
SSH journalctl |
Loki API |
OUI |
| LinkedIn |
Browser-connector API |
connectors-api /api/fetch |
OUI |
| NFS mounts |
SSH mount/df |
SSH via connectors-api |
OUI |
| Crons |
SSH crontab -l |
SSH via connectors-api |
OUI |
| SSL cert expiry |
SSH openssl |
SSH via connectors-api |
OUI |
Constat : Toutes les données sont déjà accessibles via des APIs existantes (Portainer, GitLab, ai-orchestrator, Prometheus, Loki) ou via connectors-api (SSH proxy). Aucune donnée ne nécessite du SSH brut depuis le dashboard.
Pages à conserver/migrer
| Page actuelle |
Garde ? |
Données |
Notes |
| index.html (dashboard principal) |
OUI |
Containers, VMs, GPU, services health |
Page principale |
| alerts.html |
OUI |
Health checks, ZFS errors, certs expiry |
Alertes temps réel |
| services.html |
OUI |
Registry smart-deploy, containers |
Remplace generate-services.sh |
| ai-jobs.html |
OUI |
Jobs AI, previews images/vidéos |
3371 lignes → composant SPA |
| ai-orchestrator.html |
OUI |
GPU dual, queue, tools status |
Via ai-orchestrator API |
| ai-tools.html |
OUI (statique) |
Guide outils IA |
Documentation, pas de données live |
| endpoints.html |
OUI (statique) |
Référence API |
Documentation |
| nginx.html |
OUI |
Sites, SSL certs, status |
Via SSH connectors-api |
| raidz.html |
OUI |
ZFS pools status |
Via SSH connectors-api |
| crons.html |
OUI |
Timeline tâches planifiées |
Via SSH connectors-api |
| gitlab-jobs.html |
OUI |
CI/CD pipelines live |
Via GitLab API |
| claude.html |
OUI |
Tasks, propositions, backlog |
Lire fichiers locaux via API |
| doc.html |
OUI (statique) |
Documentation infra |
Peut être généré au build |
| montages.html |
OUI |
NFS mounts, symlinks |
Via SSH connectors-api |
| shortlinks.html |
OUI (statique) |
Quick links |
Généré depuis config.json |
| models.html |
OUI |
Ollama models recommandés |
Via ai-orchestrator API |
| schema.html |
OUI (statique) |
Architecture D2 |
SVG généré au build |
| secrets.html |
SUPPRIMER |
Credentials masqués |
Pas sur un site web, même IP-protégé |
| needfinder.html |
À ÉVALUER |
NeedFinder projet |
8554 lignes — projet séparé ? |
| linkedin.html |
OUI |
LinkedIn messages |
Via connectors-api /api/fetch |
| o2switch.html |
OUI |
Monitoring backup |
Via SSH connectors-api |
| syncthing.html |
OUI (statique) |
Setup guide |
Documentation |
| yolo.html |
OUI (statique) |
YOLO guide |
Documentation |
3. Mapping des 36 findings d'audit
Findings résolus par la migration (plus besoin de patcher le vieux code)
| ID |
Finding |
Comment la migration résout |
| C-01 |
Credentials en clair dans HTML |
API backend = credentials côté serveur, jamais dans le frontend |
| C-02 |
7 systèmes de navigation |
SPA = 1 seul système de navigation (composant) |
| C-03 |
Variables CSS non définies |
Design system propre dans le nouveau CSS |
| C-04 |
IPs hardcodées dans scripts |
API backend utilise DNS Pi-hole *.internal.nowhere84.com |
| C-05 |
StrictHostKeyChecking=no |
Plus de SSH direct, tout passe par connectors-api |
| C-06 |
Pas de set -e |
Plus de bash, TypeScript avec gestion d'erreurs |
| C-08 |
Deux fichiers CSS doublon |
1 seul fichier CSS |
| C-09 |
25-services.sh design autonome |
Design system unifié |
| C-10 |
nav.js quasi-mort |
Supprimé, navigation SPA |
| C-11 |
data-loader.js sous-utilisé |
Supprimé, fetch API natif |
| C-12 |
gen_footer_full/gen_html_head code mort |
Supprimé, templates SPA |
| C-14 |
Variables non quotées dans heredocs |
Plus de heredocs bash |
| C-15 |
Redis passwords hardcodés |
Credentials dans env vars CI/CD |
| C-16 |
GitLab token hardcodé |
Credentials dans env vars CI/CD |
| C-17 |
git add -A pousse tout |
CI/CD = pipeline contrôlé, artefacts de build uniquement |
| C-18 |
services-registry.json permissions |
Plus de fichiers intermédiaires |
| U-01 |
GitLab token dans git remote URL |
CI/CD utilise variables GitLab, plus de token dans URL |
| U-02 |
JWT Supabase anon keys hardcodés |
Credentials dans env vars |
| U-04 |
sed -i avec regex sur contenu |
Plus de post-processing bash |
| U-06 |
SSH sans timeout dans 08-crons.sh |
Plus de SSH direct |
| U-07 |
Arithmetic comparison sans validation |
Plus de bash |
| U-08 |
Variable non quotée dans echo/tr |
Plus de bash |
| U-10 |
Pas de nettoyage /tmp/dashboard |
Plus de fichiers tmp |
| U-14 |
Race condition git push background |
CI/CD gère le déploiement |
| U-15 |
Pas de nettoyage /tmp/monitoring-buffer |
Plus de fichiers tmp |
| U-16 |
Notification JSON newline |
Faux problème (IMPRECIS) |
| U-17 |
Lockfile PID vulnérable |
Plus de scripts concurrents |
| U-18 |
Globbing non protégé |
Plus de bash |
Findings à intégrer comme exigences du nouveau projet
| ID |
Finding |
Exigence pour le nouveau dashboard |
| C-07 |
Échappement HTML incomplet |
Framework avec échappement automatique (Qwik/React/template literals) |
| C-13 |
Polling 15s sans visibilitychange |
Frontend SPA : document.visibilitychange → pause polling quand onglet caché |
| U-03 |
Injection jq (risque théorique) |
API backend : valider les inputs avant les requêtes |
| U-05 |
inject_json() sans échappement </script> |
Ne pas injecter de JSON dans des balises script, utiliser fetch API |
| U-09 |
XSS innerHTML sans échappement |
Utiliser textContent ou framework avec échappement auto |
| U-11 |
IP PVE inconsistante config.json |
config.json nettoyé, utiliser DNS Pi-hole |
| U-12 |
Port browser-connector faux (5401→5404) |
Plus de ports dans config, utiliser sous-domaines HTTPS |
| U-13 |
Port connectors-api faux (5400→5403) |
Idem |
4. Structure du nouveau projet
dashboard-33800/
├── backend/ # API Bun/Elysia
│ ├── src/
│ │ ├── index.ts # Point d'entrée Elysia
│ │ ├── routes/
│ │ │ ├── health.ts # GET /health (vérifie dépendances)
│ │ │ ├── infra.ts # GET /api/infra (VMs, ZFS, system)
│ │ │ ├── docker.ts # GET /api/docker (containers, images)
│ │ │ ├── gitlab.ts # GET /api/gitlab (pipelines, jobs)
│ │ │ ├── ai.ts # GET /api/ai (GPU, jobs, models, queue)
│ │ │ ├── services.ts # GET /api/services (health, registry)
│ │ │ ├── nginx.ts # GET /api/nginx (sites, certs)
│ │ │ ├── monitoring.ts # GET /api/monitoring (alerts, logs)
│ │ │ └── claude.ts # GET /api/claude (tasks, propositions)
│ │ ├── collectors/
│ │ │ ├── portainer.ts # Collecte via Portainer API
│ │ │ ├── gitlab.ts # Collecte via GitLab API
│ │ │ ├── ai-orchestrator.ts # Collecte via ai-orchestrator API
│ │ │ ├── prometheus.ts # Collecte via Prometheus API
│ │ │ ├── loki.ts # Collecte via Loki API
│ │ │ ├── ssh.ts # Collecte via connectors-api SSH
│ │ │ └── connectors.ts # Collecte via connectors-api /api/fetch
│ │ ├── cache.ts # Cache en mémoire avec TTL (30-60s)
│ │ ├── auth.ts # Auth API key
│ │ └── config.ts # Config depuis env vars
│ ├── package.json
│ ├── tsconfig.json
│ └── Dockerfile
│
├── frontend/ # SPA statique
│ ├── src/
│ │ ├── index.html # Shell HTML
│ │ ├── app.js # Routeur SPA + navigation
│ │ ├── pages/
│ │ │ ├── dashboard.js # Page principale
│ │ │ ├── services.js # Services registry
│ │ │ ├── ai-jobs.js # AI jobs + previews
│ │ │ ├── ai-orchestrator.js # GPU + queue
│ │ │ ├── gitlab.js # CI/CD pipelines
│ │ │ ├── infra.js # ZFS, NFS, VMs
│ │ │ ├── nginx.js # Sites + SSL
│ │ │ ├── alerts.js # Alertes temps réel
│ │ │ ├── claude.js # Tasks/propositions
│ │ │ └── [...].js # Autres pages
│ │ ├── components/
│ │ │ ├── nav.js # Navigation unique
│ │ │ ├── card.js # Composant carte
│ │ │ ├── table.js # Composant tableau
│ │ │ ├── status-badge.js # Badge statut
│ │ │ ├── chart.js # Graphiques simples
│ │ │ └── toast.js # Notifications
│ │ ├── api.js # Client API centralisé (fetch wrapper)
│ │ ├── style.css # Design system unique
│ │ └── utils.js # Helpers (formatDate, escapeHtml, etc.)
│ ├── static/
│ │ ├── architecture.svg # Diagramme D2
│ │ └── favicon.ico
│ └── package.json # Build (minify, bundle) si besoin
│
├── docs/ # Pages statiques (markdown → HTML au build)
│ ├── ai-tools.md
│ ├── endpoints.md
│ ├── syncthing.md
│ └── yolo.md
│
├── .gitlab-ci.yml # Pipeline CI/CD
├── conf.prod.gouroubleu.yml # Config smart-deploy
└── README.md
Choix technologiques
| Composant |
Technologie |
Raison |
| Backend |
Bun + Elysia |
Cohérent avec la stack (connectors-api, ulias-org) |
| Frontend |
Vanilla JS (ou Qwik SSG) |
Léger, pas de framework lourd pour un dashboard |
| CSS |
CSS custom properties (variables) |
Design system simple, dark theme |
| Build |
Bun bundler |
Déjà dans la stack |
| Deploy backend |
smart-deploy → Docker prod-portainer |
Comme les autres services |
| Deploy frontend |
smart-deploy → O2switch |
Via rsync ou git push automatisé |
Pourquoi pas un framework frontend lourd ?
Le dashboard est un outil interne de monitoring. Vanilla JS + fetch + template literals suffit :
- Pas de SEO nécessaire
- Pas d'interactivité complexe
- Pas de formulaires
- Juste afficher des données + auto-refresh
Si le besoin évolue, on peut migrer vers Qwik plus tard.
5. conf.prod.gouroubleu.yml
dashboard-api:
image: registry.33800.nowhere84.com/dashboard-api
port: 5520
nginx:
domain: dashboard-api.33800.nowhere84.com
ssl: true
private: true
websocket: false
env:
# Auth
API_KEY: "${DASHBOARD_API_KEY}"
# Sources
CONNECTORS_API_URL: "https://connectors.33800.nowhere84.com"
CONNECTORS_API_KEY: "${CONNECTORS_API_KEY}"
AI_ORCHESTRATOR_URL: "https://ai-orchestrator.33800.nowhere84.com"
AI_ORCHESTRATOR_API_KEY: "${AI_ORCHESTRATOR_API_KEY}"
GITLAB_URL: "https://gitlab.33800.nowhere84.com"
GITLAB_TOKEN: "${GITLAB_TOKEN}"
PORTAINER_URL: "https://prod-portainer.local:9443"
PORTAINER_API_KEY: "${PORTAINER_API_KEY}"
PROMETHEUS_URL: "http://localhost:9090"
LOKI_URL: "http://localhost:3100"
# Config
CACHE_TTL_SECONDS: "30"
ALLOWED_ORIGINS: "https://dashboard.nowhere84.com"
loki: true
6. Pipeline CI/CD (.gitlab-ci.yml)
stages:
- build
- deploy
# Backend: build Docker image + deploy via smart-deploy
build-backend:
stage: build
script:
- cd backend
- docker build -t $CI_REGISTRY_IMAGE/api:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE/api:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE/api:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE/api:latest
- docker push $CI_REGISTRY_IMAGE/api:latest
only:
- main
changes:
- backend/**
deploy-backend:
stage: deploy
script:
- smart-deploy dashboard-api
only:
- main
changes:
- backend/**
# Frontend: build + deploy to O2switch
build-frontend:
stage: build
script:
- cd frontend
- bun install
- bun run build # minify, bundle
artifacts:
paths:
- frontend/dist/
only:
- main
changes:
- frontend/**
- docs/**
deploy-frontend:
stage: deploy
script:
- rsync -avz --delete frontend/dist/ $O2SWITCH_USER@$O2SWITCH_HOST:~/repositories/dashboard/
only:
- main
changes:
- frontend/**
- docs/**
7. Endpoints API backend
| Méthode |
Endpoint |
Source de données |
Cache TTL |
| GET |
/health |
Toutes dépendances (ping) |
0s |
| GET |
/api/infra/vms |
SSH via connectors-api (PVE, Proxmox155) |
60s |
| GET |
/api/infra/zfs |
SSH via connectors-api (PVE) |
60s |
| GET |
/api/infra/nfs |
SSH via connectors-api (tous hosts) |
60s |
| GET |
/api/infra/system/:host |
SSH via connectors-api (CPU/RAM/disk) |
30s |
| GET |
/api/docker/containers |
Portainer API |
30s |
| GET |
/api/docker/images |
Portainer API |
60s |
| GET |
/api/gitlab/pipelines |
GitLab API |
30s |
| GET |
/api/gitlab/deploys |
GitLab API |
30s |
| GET |
/api/ai/status |
ai-orchestrator /api/status |
15s |
| GET |
/api/ai/jobs |
ai-orchestrator /api/jobs |
15s |
| GET |
/api/ai/queue |
ai-orchestrator /api/queue |
15s |
| GET |
/api/ai/models |
ai-orchestrator /api/tools |
120s |
| GET |
/api/services/health |
Health endpoints de chaque service |
30s |
| GET |
/api/services/registry |
services-registry.json ou Portainer |
60s |
| GET |
/api/nginx/sites |
SSH via connectors-api (nginx) |
60s |
| GET |
/api/nginx/certs |
SSH via connectors-api (openssl) |
300s |
| GET |
/api/monitoring/alerts |
Agrégation health checks + ZFS + certs |
30s |
| GET |
/api/monitoring/logs |
Loki API (derniers logs erreur) |
30s |
| GET |
/api/claude/tasks |
Lire fichiers ~/tasks/ |
60s |
| GET |
/api/claude/propositions |
Lire fichiers ~/propositions/ |
60s |
| GET |
/api/claude/backlog |
Lire fichiers ~/backlog/ |
60s |
| GET |
/api/crons |
SSH via connectors-api (crontab) |
120s |
| GET |
/api/metrics/prometheus |
Prometheus API (métriques clés) |
30s |
Authentification
- Frontend → Backend : header
X-API-Key: <DASHBOARD_API_KEY>
- Backend → connectors-api : header
X-API-Key: <CONNECTORS_API_KEY>
- Backend → ai-orchestrator : header
Authorization: Bearer <AI_ORCHESTRATOR_API_KEY> (après fix audit C-17)
- Backend → GitLab : header
PRIVATE-TOKEN: <GITLAB_TOKEN>
- Backend → Portainer : header
X-API-Key: <PORTAINER_API_KEY>
Cache
- Chaque endpoint a un cache en mémoire avec TTL configurable
- Le frontend fetch toutes les 30s (ou configurable)
- Le backend ne re-collecte que si le cache est expiré
- Résultat : les services sources ne sont appelés que toutes les TTL secondes, pas à chaque requête frontend
8. Frontend SPA — Design
Navigation unique
┌──────────────────────────────────────────────────────────────┐
│ 33800 Dashboard [Infra] [Docker] [AI] [CI/CD] [Alertes] │
├──────────────────────────────────────────────────────────────┤
│ │
│ Contenu de la page active │
│ │
│ - Auto-refresh toutes les 30s │
│ - Pause quand onglet caché (visibilitychange) │
│ - Toast notification si erreur │
│ - Bandeau "Dernière mise à jour : il y a Xs" │
│ │
└──────────────────────────────────────────────────────────────┘
Client API centralisé (api.js)
// Un seul wrapper fetch, utilisé par toutes les pages
// - Ajoute X-API-Key automatiquement
// - Gère les erreurs (toast)
// - Gère le cache côté client si besoin
// - Pause quand onglet caché
Sécurité frontend (exigences audit)
- Pas de
innerHTML pour du contenu dynamique → textContent ou échappement
- Pas de
javascript: URI dans les liens
- Pas d'injection JSON dans
<script> → fetch API
- CSP header strict via le backend
.htaccess IP restriction sur O2switch (comme actuellement)
9. Plan d'implémentation
Phase 1 : Setup projet (1 session)
- Créer le repo GitLab
dashboard-33800 (ou nettoyer l'existant)
- Initialiser la structure backend/ + frontend/
- Configurer
.gitlab-ci.yml
- Configurer
conf.prod.gouroubleu.yml
- Premier deploy : page blanche avec health check OK
Phase 2 : Backend API — collecteurs (2-3 sessions)
index.ts + auth middleware + CORS + health check
cache.ts — cache mémoire avec TTL
- Collecteurs un par un :
docker.ts (Portainer API) — containers, images
gitlab.ts (GitLab API) — pipelines, jobs
ai.ts (ai-orchestrator API) — GPU, jobs, queue, models
services.ts (health endpoints) — ping chaque service
ssh.ts (connectors-api SSH) — ZFS, NFS, crons, nginx, system
prometheus.ts — métriques système
loki.ts — derniers logs erreur
claude.ts — lire fichiers tasks/propositions/backlog
- Tester chaque endpoint
Phase 3 : Frontend SPA (2-3 sessions)
- Shell HTML + routeur + navigation + design system CSS
api.js — client API centralisé
- Pages une par une :
- Dashboard principal (containers, VMs, GPU, health)
- Services (registry, health status)
- AI (jobs, GPU, queue, models)
- CI/CD (pipelines, deploys)
- Infra (ZFS, NFS, system)
- Nginx (sites, certs)
- Alertes (agrégation)
- Claude (tasks, propositions)
- Pages statiques (docs, guides) — markdown → HTML au build
- Auto-refresh + visibilitychange + toast erreurs
Phase 4 : CI/CD + migration (1 session)
- Tester pipeline CI/CD complète (build → deploy backend + frontend)
- Vérifier que le dashboard live fonctionne sur O2switch
- Basculer le cron actuel vers le nouveau dashboard
- Garder l'ancien en backup quelques jours
- Supprimer l'ancien generate.sh quand le nouveau est stable
Phase 5 : Nettoyage (1 session)
- Supprimer les anciens scripts bash (generate.sh, collect.sh, etc.)
- Nettoyer les credentials de l'historique git si possible
- Régénérer les tokens exposés (GitLab, Redis, JWT)
- Mettre à jour CLAUDE.md + memory files
- Mettre à jour config.json si toujours utilisé par d'autres projets
10. Dépendances avec les autres correctifs d'audit
Le nouveau dashboard dépend de certains correctifs d'audit sur les autres projets :
| Dépendance |
Projet |
Finding |
Pourquoi |
| Health endpoints réels |
Tous |
connectors-api C-22, global |
Le dashboard API interroge /health de chaque service |
| Auth API key sur ai-orchestrator |
ai-orchestrator |
C-17 |
Le dashboard doit s'authentifier |
| Auth API key sur ulias-org |
ulias-org |
C-17 |
Idem |
| DNS Pi-hole internal |
Transversal |
Proposition validée |
Backend utilise les noms DNS |
| CORS *.nowhere84.com |
Tous |
connectors-api C-20, global |
Le frontend O2switch fetch l'API backend |
Ordre recommandé :
- D'abord les correctifs d'audit sur les services existants (auth, health, CORS, DNS)
- Ensuite la migration dashboard (qui utilise ces améliorations)
11. Résumé des décisions
| Décision |
Choix |
| Architecture |
API backend (Bun/Elysia) + SPA frontend |
| Backend host |
prod-portainer (Docker, smart-deploy) |
| Frontend host |
O2switch (.htaccess IP restriction) |
| CI/CD |
GitLab pipeline → smart-deploy (backend) + rsync (frontend) |
| Collecte données |
APIs existantes + connectors-api SSH, ZÉRO SSH direct |
| Credentials |
Env vars dans conf.prod.gouroubleu.yml + variables CI/CD |
| Framework frontend |
Vanilla JS (léger, suffisant pour du monitoring) |
| Framework backend |
Bun + Elysia (cohérent avec la stack) |
| Cache |
Mémoire avec TTL par endpoint (30-120s) |
| Auth |
API key simple (service interne) |
| 36 findings audit |
28 résolus par la migration, 8 intégrés comme exigences |
Informations pour reprise en session future
Fichiers de référence :
- Cette proposition :
~/propositions/15-02-2026-13-30-dashboard-projet-gitlab-complet.md
- Rapport audit vérifié :
~/propositions/15-02-2026-10-10-audit-rapport-final-verifie.md
- Revue des correctifs :
~/tasks/15-02-2026-10-30-revue-audit-correctifs.md
- Proposition DNS Pi-hole :
~/propositions/15-02-2026-12-00-migration-ip-vers-dns-pihole.md
- Ancien dashboard :
/stock_8to/33800-stack/monitoring/
Config réseau :
- config.json :
/stock_8to/33800-stack/monitoring/config.json
- Hosts/IPs : voir CLAUDE.md section machines principales
- DNS Pi-hole : voir
~/.claude/memory/pihole-split-dns.md
Stack technique :
- Bun + Elysia (comme connectors-api, ulias-org)
- smart-deploy pour déploiement (voir
~/.claude/memory/ci-cd.md)
- conf.prod.gouroubleu.yml = source de vérité (voir
~/.claude/memory/docker.md)