18 Commits

Author SHA1 Message Date
syoul
9fb80ef59f fix: sbom-generate - inclure node_modules pour SBOM complet
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Retirer l'exclusion des node_modules permet a Syft de scanner
les paquets reellement installes (transitifs inclus).
Seuls les artefacts de build sont exclus (build/, .next/, out/).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 20:42:49 +01:00
syoul
53ceb29bbe fix: sbom-generate - scanner le repertoire source au lieu de l'image Docker
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Les vars CI (CI_REPO_OWNER etc.) ne sont pas injectees dans les steps
avec volumes: sans environment: (bug Woodpecker next). Supprimer le
docker socket et scanner dir:. evite le probleme et donne un SBOM
complet des dependances npm declarees.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 19:20:47 +01:00
syoul
7862bb11b7 fix: sbom-generate - calculer le nom image depuis les vars CI
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Remplace la lecture de .env.deploy par un recalcul direct
depuis CI_REPO_OWNER/CI_REPO_NAME/CI_COMMIT_BRANCH (meme
logique que write-env), evitant la dependance sur le fichier.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 19:13:00 +01:00
syoul
42b3d28505 feat: integrer SBOM dans la pipeline CI
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- sbom-generate: Syft scanne l'image Docker buildee (radar-business)
- sbom-scan: Trivy CVE depuis le SBOM (cache /home/syoul/trivy-cache)
- sbom-publish: envoi vers Dependency-Track (dtrack.syoul.fr)
Nouveau secret requis: dependency_track_token

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 19:04:20 +01:00
syoul
658be24b7c fix: corriger les deux erreurs de build CI
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- scripts/build-radar.js: bash → sh (Alpine n'a pas bash)
- radar-app/package.json: ajouter postcss comme dépendance directe
- radar-app/package-lock.json: régénéré avec postcss ^8.5.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:51:49 +01:00
syoul
a2fbbe5d44 fix: restaurer cd .. après radar-app (shell partagé dans Woodpecker)
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Les commandes d'un step partagent le même shell dans Woodpecker.
cd radar-app persiste aux commandes suivantes — cd .. est nécessaire.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:43:50 +01:00
syoul
e1447aca28 fix: resynchroniser radar-app/package-lock.json + sous-shell Woodpecker
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- radar-app/package-lock.json : lock file désynchronisé (Next.js 15 -> 16), ajout au suivi git
- .woodpecker.yml : supprimer && cd .. inutile (chaque commande = sous-shell séparé dans Woodpecker next)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:41:04 +01:00
syoul
4755b392a3 fix: resynchroniser package-lock.json avec package.json
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
npm ci échouait en CI : lock file désynchronisé après renommage du package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:38:14 +01:00
syoul
445a540d54 ci: trigger pipeline Woodpecker
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:37:08 +01:00
syoul
1dd4b4d1d1 ci: trigger pipeline Woodpecker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:35:08 +01:00
syoul
7bb7484ec8 ci: corrections conformité prestashop
- Ajout step validate (docker compose config avec placeholder)
- Remplacement export \$(cat .env.deploy | xargs) → --env-file .env.deploy
- SERVICE_3000_TAGS : urlprefix-DOMAIN/ → urlprefix-DOMAIN/* (match tous les paths)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:33:40 +01:00
syoul
940834d993 refactor: COMPOSE_PROJECT_NAME dynamique depuis les vars CI
docker-compose.business.yml:
- Ajout name: ${COMPOSE_PROJECT_NAME:-ajr-techradardev-main}
- container_name et SERVICE_3000_NAME utilisent COMPOSE_PROJECT_NAME

.woodpecker.yml:
- write-env génère COMPOSE_PROJECT_NAME=owner-repo-branch (même convention que prestashop)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:31:05 +01:00
syoul
fa0aa808ac feat: intégration Fabio/Consul/Registrator + TLS acme.sh
docker-compose.business.yml:
- Suppression version: obsolete et ports: (Fabio gère le routing)
- Ajout labels SERVICE_3000_* pour Registrator/Consul/Fabio
- Ajout LETSENCRYPT_HOST pour sonic-acme-1
- Ajout réseau sonic (externe, partagé avec la stack)

.woodpecker.yml:
- Ajout write-env (RADAR_DOMAIN depuis secret, séparé car from_secret + volumes incompatibles)
- Ajout TLS acme.sh dans deploy (idempotent, exit 2 = skip)
- Healthcheck sur https://RADAR_DOMAIN (100s max)

Secret Woodpecker à créer : radar_domain

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:29:39 +01:00
syoul
002764ea9a ci: aligner pipeline sur le modèle de référence (fabio/consul/registrator)
- Suppression de deploy-rsync (hors stack)
- Renommage deploy-docker → deploy
- Ajout healthcheck (curl localhost:3006, max 100s)
- Remplacement notify Telegram/vars Drone → notify-failure avec vars CI
  ($CI_BUILD_NUMBER, $CI_COMMIT_SHA, $CI_COMMIT_BRANCH)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:26:52 +01:00
syoul
b4d7f7e10f docs: ajouter section "Où éditer le contenu" dans le README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:21:03 +01:00
syoul
029fbe5d26 docs: clarifier structure du projet dans le README
- Distinguer clairement radar-business/ (source) vs radar/ (temporaire)
- Indiquer data/ comme dossier de build versionné (suite déplacement docs/data/)
- Corriger branche principale (stand-alone → main)
- Simplifier section Documentation (docs/ non versionnée)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:18:41 +01:00
syoul
fe16d01be7 refactor: déplacer docs/data/ → data/ pour séparer données de build et docs
docs/ est entièrement ignoré par .gitignore, mais docs/data/team/*.md
est nécessaire au build (generate-team-visualization-data.js).
Déplacement vers data/ à la racine pour que ces fichiers soient
versionnés et disponibles lors du déploiement depuis le dépôt.

- Nouveau dossier data/ versionné (profils équipe, technologies)
- docs/ entièrement ignoré (documentation humaine uniquement)
- Mise à jour des 4 références dans les scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:14:56 +01:00
syoul
7c4204c689 ci: correction syntaxe Woodpecker (.woodpecker.yml)
- Suppression des headers Drone CI (kind/type/name)
- Déplacement du trigger when: au niveau global
- Volumes inline (host:container) au lieu des named volumes
- Suppression de la section volumes: Drone en bas de fichier
- Correction $$ → $ pour les variables dans les commandes
- Chaînage des cd avec && pour les commandes radar-app
- Image docker:27-cli cohérente avec le modèle de référence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 18:03:33 +01:00
31 changed files with 2219 additions and 793 deletions

2
.gitignore vendored
View File

@@ -31,4 +31,4 @@ public/strategie-inline.html
# Docs
docs/
docs-sbom/
docs-syoul/
docs-syoul/

View File

@@ -1,245 +1,158 @@
---
kind: pipeline
type: docker
name: build-and-deploy
# Ce pipeline Woodpecker CI automatise le build et le déploiement de l'application statique
# Il se déclenche automatiquement sur chaque push vers les branches main ou stand-alone
when:
- branch:
- main
- stand-alone
event: push
steps:
# ============================================
# ÉTAPE 1: BUILD DE L'APPLICATION STATIQUE
# ============================================
# Cette étape construit l'application Next.js et génère les fichiers statiques HTML/CSS/JS
# Etape 0 : Validation syntaxique du docker-compose
# Les vars CI (CI_REPO_OWNER, CI_COMMIT_BRANCH) sont injectees automatiquement par Woodpecker
- name: validate
image: docker:27-cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
RADAR_DOMAIN: validate.example.com
commands:
- |
export COMPOSE_PROJECT_NAME=$(printf '%s-%s-%s' "$CI_REPO_OWNER" "$CI_REPO_NAME" "$CI_COMMIT_BRANCH" | tr 'A-Z/' 'a-z-')
docker compose -f docker-compose.business.yml config --quiet
- echo "docker-compose.business.yml valide"
# Etape 1 : Build de l'application statique
- name: build
# Image Docker utilisée : Node.js 20 sur Alpine Linux (légère et rapide)
image: node:20-alpine
# Variables d'environnement nécessaires pour le build
environment:
NODE_ENV: production # Mode production (optimisations activées)
HUSKY: 0 # Désactive Husky (git hooks) pour éviter les erreurs
HUSKY_SKIP_INSTALL: 1 # Skip l'installation de Husky
# Commandes exécutées dans l'ordre
NODE_ENV: production
HUSKY: 0
HUSKY_SKIP_INSTALL: 1
commands:
# Installation des dépendances système nécessaires
# - git : pour cloner/récupérer des dépendances si nécessaire
# - python3 : requis pour les scripts de patch (patch_document.py, add_team_link.py)
- apk add --no-cache git python3
# Installation des dépendances Node.js de la racine du projet
# npm ci : Clean Install (supprime node_modules et réinstalle depuis package-lock.json)
# --legacy-peer-deps : Ignore les conflits de dépendances peer (compatibilité)
- npm ci --legacy-peer-deps
# Installation des dépendances de radar-app/ (le framework Next.js vendu)
# On se déplace dans le dossier radar-app pour installer ses dépendances
- cd radar-app
# Installation des dépendances de radar-app (y compris devDependencies)
# --include=dev : Inclut les dépendances de développement (tsx, eslint, etc.)
- npm ci --legacy-peer-deps --include=dev
# Build des icônes SVG en composants React TypeScript
# Ce script génère les composants Icons depuis les fichiers SVG dans src/icons/
- npm run build:icons
# Retour à la racine du projet
- cd ..
# Génération des données de visualisation équipe
# Ce script lit les profils dans docs/data/team/*.md et les technologies
# Il génère public/team-visualization-data.json utilisé par la page /team
- cd radar-app && npm ci --legacy-peer-deps --include=dev && npm run build:icons && cd ..
- node scripts/generate-team-visualization-data.js
# Build de l'application complète
# Ce script (build-radar.js) :
# 1. Copie config-business.json vers radar-app/data/config.json
# 2. Copie radar-business/2025-01-15/ vers radar-app/data/radar/2025-01-15/
# 3. Copie public/* vers radar-app/public/
# 4. Applique les patches (team page, _document, Navigation)
# 5. Lance npm run build:data puis npm run build dans radar-app/
# 6. Copie radar-app/out/ vers build/ à la racine
- npm run build
# Vérification que le build a réussi
# Affiche les 10 premiers fichiers du dossier build/ pour vérifier la génération
- ls -la build/ | head -10
# Volumes temporaires pour accélérer les builds suivants
# Ces volumes persistent les node_modules entre les étapes pour éviter de réinstaller
volumes:
- name: node_modules_root
path: /app/node_modules
- name: node_modules_radar_app
path: /app/radar-app/node_modules
# ============================================
# ÉTAPE 2: DÉPLOIEMENT VIA RSYNC (OPTIONNEL)
# ============================================
# Cette étape synchronise les fichiers statiques vers un serveur web distant
# Utile si vous avez un serveur Nginx/Apache qui sert des fichiers statiques
- name: deploy-rsync
# Image Alpine (légère) avec rsync et SSH
image: alpine:latest
# Variables d'environnement récupérées depuis les secrets Woodpecker
# Etape 2a : Ecriture du .env depuis les secrets
# NOTE: from_secret et volumes: incompatibles dans le meme step (bug Woodpecker next)
- name: write-env
image: alpine:3.20
environment:
DEPLOY_HOST:
from_secret: deploy_host # Exemple: techradar.example.com
DEPLOY_USER:
from_secret: deploy_user # Exemple: deploy
DEPLOY_PATH:
from_secret: deploy_path # Exemple: /var/www/techradar
DEPLOY_KEY:
from_secret: deploy_key # Clé privée SSH complète
RADAR_DOMAIN:
from_secret: radar_domain
commands:
# Installation des outils nécessaires
- apk add --no-cache openssh-client rsync
# Création du dossier .ssh pour les clés SSH
- mkdir -p ~/.ssh
# Écriture de la clé privée SSH dans le fichier id_rsa
# $$ est échappé pour éviter l'interpolation par le shell
- echo "$$DEPLOY_KEY" > ~/.ssh/id_rsa
# Protection de la clé privée (lecture/écriture uniquement pour le propriétaire)
- chmod 600 ~/.ssh/id_rsa
# Ajout de la clé publique du serveur dans known_hosts
# Évite la vérification manuelle lors de la première connexion
- ssh-keyscan -H $$DEPLOY_HOST >> ~/.ssh/known_hosts || true
# Synchronisation des fichiers
# rsync -avz : Archive mode, Verbose, Compression
# --delete : Supprime les fichiers sur le serveur qui n'existent plus localement
# build/ : Source (dossier build généré à l'étape précédente)
# $$DEPLOY_USER@$$DEPLOY_HOST:$$DEPLOY_PATH/ : Destination (serveur distant)
- rsync -avz --delete build/ $$DEPLOY_USER@$$DEPLOY_HOST:$$DEPLOY_PATH/
# Message de confirmation
- echo "✅ Déploiement terminé sur $$DEPLOY_HOST:$$DEPLOY_PATH"
# Conditions de déclenchement
# Cette étape ne s'exécute que si :
when:
branch:
- main # Sur la branche main
- stand-alone # Ou sur la branche stand-alone
event:
- push # Et uniquement sur un événement push (pas sur les PR)
- env | grep -E "^(RADAR_DOMAIN)=" > .env.deploy
# COMPOSE_PROJECT_NAME : convention user-project-branch, genere depuis les vars CI
- OWNER=$(echo "$CI_REPO_OWNER" | tr 'A-Z' 'a-z') && REPO=$(echo "$CI_REPO_NAME" | tr 'A-Z' 'a-z') && BRANCH=$(echo "$CI_COMMIT_BRANCH" | tr 'A-Z/' 'a-z-') && echo "COMPOSE_PROJECT_NAME=$OWNER-$REPO-$BRANCH" >> .env.deploy
- echo "Fichier .env.deploy cree ($(wc -c < .env.deploy) octets)"
# ============================================
# ÉTAPE 3: DÉPLOIEMENT DOCKER (RECOMMANDÉ)
# ============================================
# Cette étape build et déploie l'application via Docker
# Plus simple et reproductible que rsync
- name: deploy-docker
# Image Docker officielle avec docker-compose
image: docker:latest
# Configuration Docker
environment:
DOCKER_HOST: unix:///var/run/docker.sock # Socket Docker du serveur Woodpecker
commands:
# Installation de docker-compose
- apk add --no-cache docker-compose
# Build de l'image Docker sans cache
# --no-cache : Force un rebuild complet (garantit que tout est à jour)
# docker-compose.business.yml : Fichier de configuration Docker Compose
- docker compose -f docker-compose.business.yml build --no-cache
# Démarrage du conteneur en mode détaché
# -d : Détaché (en arrière-plan)
# up : Crée et démarre les conteneurs
- docker compose -f docker-compose.business.yml up -d
# Vérification que le conteneur tourne
# Affiche les conteneurs contenant "laplank-radar" ou un message si non trouvé
- docker ps | grep laplank-radar || echo "Conteneur non trouvé"
# Volume pour accéder au socket Docker du serveur
# Nécessaire pour que le conteneur puisse utiliser Docker
# Etape 2b : Deploiement sur sonic via Docker socket
# NOTE: from_secret et volumes: incompatibles — pas de secrets ici
- name: deploy
image: docker:27-cli
volumes:
- name: dockersock
path: /var/run/docker.sock
# Conditions de déclenchement (identique à deploy-rsync)
when:
branch:
- main
- stand-alone
event:
- push
- /var/run/docker.sock:/var/run/docker.sock
commands:
- docker compose --env-file .env.deploy -f docker-compose.business.yml build --no-cache
- docker compose --env-file .env.deploy -f docker-compose.business.yml up -d --remove-orphans
- docker compose --env-file .env.deploy -f docker-compose.business.yml ps
- |
DOMAIN=$(grep '^RADAR_DOMAIN=' .env.deploy | cut -d= -f2)
# ============================================
# ÉTAPE 4: NOTIFICATION TELEGRAM
# ============================================
# Cette étape envoie une notification Telegram à la fin du pipeline
# Utile pour être informé immédiatement du résultat du build
- name: notify
# Plugin Drone/Woodpecker pour Telegram
# Compatible avec Woodpecker (fork de Drone)
image: appleboy/drone-telegram
# Configuration du plugin Telegram
settings:
token:
from_secret: telegram_token # Token du bot Telegram
to:
from_secret: telegram_chat_id_ajr # ID du chat Telegram (destinataire)
format: markdown # Format du message (Markdown supporté)
# Message personnalisé avec template Woodpecker
# {{#success build.status}} : Condition si le build a réussi
# {{repo.name}} : Nom du dépôt Git
# {{commit.branch}} : Branche du commit
# {{commit.message}} : Message du commit
# {{commit.author}} : Auteur du commit
# {{build.link}} : Lien vers le build dans Woodpecker
message: >
{{#success build.status}}
✅ Build réussi pour `{{repo.name}}` sur la branche `{{commit.branch}}`
📝 Commit: `{{commit.message}}`
👤 Auteur: {{commit.author}}
🔗 {{ build.link }}
{{else}}
❌ Build échoué pour `{{repo.name}}` sur la branche `{{commit.branch}}`
📝 Commit: `{{commit.message}}`
👤 Auteur: {{commit.author}}
🔗 {{ build.link }}
{{/success}}
# Conditions de déclenchement
# S'exécute toujours, que le build réussisse ou échoue
when:
status:
- success # Si le build réussit
- failure # Si le build échoue
# --- Certificat TLS (acme.sh via sonic-acme-1) ---
# acme.sh est idempotent : skip si cert valide, renouvelle si proche expiration
# exit 0 = emis/renouvele, exit 2 = skip (domaine inchange), autres = erreur
ACME_EXIT=0
docker exec sonic-acme-1 /app/acme.sh \
--home /etc/acme.sh \
--issue -d "$DOMAIN" \
--webroot /usr/share/nginx/html \
--server letsencrypt \
--accountemail support+acme@asycn.io || ACME_EXIT=$?
if [ "$ACME_EXIT" -ne 0 ] && [ "$ACME_EXIT" -ne 2 ]; then
echo "ERREUR: acme.sh a echoue (exit $ACME_EXIT)"
exit 1
fi
docker exec sonic-acme-1 cp /etc/acme.sh/$DOMAIN/fullchain.cer /host/certs/$DOMAIN-cert.pem
docker exec sonic-acme-1 cp /etc/acme.sh/$DOMAIN/$DOMAIN.key /host/certs/$DOMAIN-key.pem
echo "Cert TLS: /host/certs/$DOMAIN-cert.pem OK (acme exit $ACME_EXIT)"
# ============================================
# VOLUMES TEMPORAIRES
# ============================================
# Ces volumes sont créés temporairement pour chaque pipeline
# Ils permettent de partager des données entre les étapes
volumes:
# Volume pour les node_modules de la racine
# Persiste entre les étapes pour éviter de réinstaller
- name: node_modules_root
temp: {} # Volume temporaire (supprimé à la fin du pipeline)
# Volume pour les node_modules de radar-app
# Persiste entre les étapes pour éviter de réinstaller
- name: node_modules_radar_app
temp: {}
# Volume pour accéder au socket Docker du serveur
# Nécessaire pour que les conteneurs puissent utiliser Docker
- name: dockersock
host:
path: /var/run/docker.sock # Chemin du socket Docker sur le serveur
# Etape 3a : Generation SBOM (Syft) — inventaire des dependances npm du workspace
# Scan du repertoire source (pas de docker socket = pas de bug volumes/CI-vars)
- name: sbom-generate
image: alpine:3.20
commands:
- apk add --no-cache curl
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin latest
- mkdir -p .reports
- syft dir:. --exclude './build' --exclude './radar-app/.next' --exclude './radar-app/out' -o cyclonedx-json --file .reports/sbom-radar.cyclonedx.json
- echo "SBOM genere $(wc -c < .reports/sbom-radar.cyclonedx.json) octets"
# Etape 3b : Scan CVE (Trivy) depuis le SBOM Syft
# Cache /home/syoul/trivy-cache evite ~200Mo de telechargement des DB CVE a chaque build
# Prerequis sur sonic : mkdir -p /home/syoul/trivy-cache
- name: sbom-scan
image: aquasec/trivy:latest
volumes:
- /home/syoul/trivy-cache:/root/.cache/trivy
commands:
- trivy sbom --format json --output .reports/trivy-radar.json .reports/sbom-radar.cyclonedx.json
- echo "Scan CVE termine"
# Etape 3c : Publication SBOM vers Dependency-Track (dtrack.syoul.fr)
# NOTE: from_secret et volumes: incompatibles — pas de volumes ici
- name: sbom-publish
image: alpine/curl:latest
environment:
DTRACK_TOKEN:
from_secret: dependency_track_token
commands:
- |
VERSION=$(date +%Y-%m-%d)-$(echo "$CI_COMMIT_SHA" | cut -c1-8)
HTTP=$(curl -s -o /tmp/dtrack-response.txt -w "%{http_code}" -X POST "https://dtrack.syoul.fr/api/v1/bom" \
-H "X-Api-Key: $DTRACK_TOKEN" \
-F "autoCreate=true" \
-F "projectName=techradardev-app" \
-F "projectVersion=$VERSION" \
-F "bom=@.reports/sbom-radar.cyclonedx.json")
echo "HTTP $HTTP : $(cat /tmp/dtrack-response.txt)"
[ "$HTTP" -ge 200 ] && [ "$HTTP" -lt 300 ] || exit 1
# Etape 4 : Healthcheck post-deploiement
- name: healthcheck
image: alpine:3.20
commands:
- apk add --no-cache --quiet curl
- |
DOMAIN=$(grep '^RADAR_DOMAIN=' .env.deploy | cut -d= -f2)
if [ -z "$DOMAIN" ]; then
echo "ERREUR: RADAR_DOMAIN non defini dans .env.deploy"
exit 1
fi
TARGET="https://$DOMAIN"
echo "Healthcheck sur $TARGET (max 100s)..."
MAX=20
i=0
until [ $i -ge $MAX ]; do
CODE=$(curl -sSo /dev/null -w "%{http_code}" "$TARGET" 2>/dev/null)
echo "Tentative $((i+1))/$MAX - HTTP $CODE"
if [ "$CODE" = "200" ] || [ "$CODE" = "301" ] || [ "$CODE" = "302" ]; then
echo "Radar repond sur $TARGET"
exit 0
fi
i=$((i+1))
sleep 5
done
echo "ERREUR: Radar ne repond pas apres 100 secondes"
exit 1
# Notification en cas d'echec
- name: notify-failure
image: alpine:3.20
commands:
- 'echo "ECHEC pipeline #$CI_BUILD_NUMBER sur commit $CI_COMMIT_SHA"'
- 'echo "Branche: $CI_COMMIT_BRANCH"'
when:
- status: failure

View File

@@ -124,27 +124,27 @@ Accès à trois pages de stratégie depuis le header :
```
TechradarDev/
├── radar-app/ # Framework Next.js vendu (stand-alone)
│ ├── src/ # Code source Next.js
│ ├── data/ # Données du radar
│ └── package.json # Next.js 16.1.6, React 19
├── radar-business/ # Contenu du radar business
── 2025-01-15/ # Release actuelle (38 technologies)
│ └── config-business.json # Configuration du radar
├── docs/
── data/
└── team/ # Profils des 12 membres
│ └── app/ # Documentation technique
├── radar-business/ # ✏️ SOURCE DE VÉRITÉ — éditer ici
│ ├── 2025-01-15/ # Fichiers .md des technologies (38 blips)
│ ├── config-business.json # Configuration du radar (quadrants, rings)
│ └── FORMAT-BLIP.md # Format des métadonnées
├── data/ # ✏️ Données de build versionnées
── team/ # Profils des 12 membres (*.md)
├── radar-app/ # ⚙️ Framework Next.js (ne pas éditer)
│ ├── src/ # Code source Next.js
── data/ # Copie générée au build (ne pas éditer)
├── radar/ # ⚠️ Dossier temporaire (généré par serve-business.sh)
│ └── ... # Ne jamais éditer ici — écrasé à chaque lancement
├── scripts/
│ ├── build-radar.js # Script de build stand-alone
│ ├── serve-radar.js # Script de serve
│ ├── generate-team-visualization-data.js # Génération données équipe
│ ├── generate-team-visualization-data.js
│ └── ...
├── public/ # Fichiers statiques
│ ├── team-block-script.js # Script page équipe
│ └── team-visualization-data.json # Données visualisations
├── Dockerfile.business # Dockerfile pour déploiement
└── docker-compose.business.yml # Configuration Docker Compose
│ ├── team-block-script.js
│ └── team-visualization-data.json # Généré par generate-team-visualization-data.js
├── Dockerfile.business
└── docker-compose.business.yml
```
## 🛠️ Scripts disponibles
@@ -158,6 +158,15 @@ TechradarDev/
| `npm run extract-tech` | Extraction des technologies depuis la doc |
| `npm run analyze-business` | Analyse des métriques business |
## ✏️ Où éditer le contenu
| Quoi | Dossier |
|---|---|
| Ajouter / modifier une technologie | `radar-business/2025-01-15/` |
| Ajouter / modifier un membre d'équipe | `data/team/` |
> ⚠️ Ne jamais éditer dans `radar/` (temporaire, écrasé au lancement) ni dans `radar-app/data/` (copie générée au build).
## 📝 Content Guidelines
### Tags disponibles
@@ -191,20 +200,14 @@ Voir `radar-business/FORMAT-BLIP.md` pour le format complet des métadonnées bu
## 📚 Documentation
La documentation complète est disponible dans le dossier `docs/` :
La documentation technique est disponible dans `docs/app/` (non versionnée, locale uniquement) :
- [Architecture](./docs/app/architecture.md) - Architecture technique du projet
- [Configuration](./docs/app/configuration.md) - Configuration du radar
- [Développement](./docs/app/developpement.md) - Guide de développement
- [Déploiement](./docs/app/deploiement.md) - Guide de déploiement
- [Contribution](./docs/app/contribution.md) - Guide de contribution
- [Guide Radar Business](./docs/app/guide-radar-business.md) - Guide spécifique au radar business
- [Guide Page Équipe](./docs/app/guide-page-equipe.md) - Documentation de la page équipe
- [Migration Next.js 16](./docs/app/migration-nextjs-16.md) - Notes de migration
- Architecture, Configuration, Développement, Déploiement
- Guide Radar Business, Guide Page Équipe, Migration Next.js 16
## 🔄 État du projet
- **Branche actuelle** : `stand-alone`
- **Branche principale** : `main`
- **Version** : 4.3.0
- **Statut** : Projet stand-alone, indépendant du package externe `aoe_technology_radar`
- **Framework** : Code vendu dans `radar-app/` (basé sur aoe_technology_radar)

View File

@@ -1,26 +1,34 @@
version: '3.8'
# Convention de nommage : user-project-branch (ex: ajr-techradardev-main)
# Permet plusieurs instances en parallele (prod/test) sans collision
name: ${COMPOSE_PROJECT_NAME:-ajr-techradardev-main}
services:
radar-business:
container_name: laplank-radar-technolologique
container_name: ${COMPOSE_PROJECT_NAME:-ajr-techradardev-main}-app
build:
context: .
dockerfile: Dockerfile.business
pull: true # Force le pull de l'image de base pour éviter le cache
pull: true
args:
BUILD_DATE: "${BUILD_DATE:-$(date +%s)}"
BUILD_VERSION: "${BUILD_VERSION:-dev}"
CACHE_BUST: "${CACHE_BUST:-$(date +%s%N)}" # Nanosecondes pour garantir l'unicité et forcer l'invalidation
# Note: no_cache n'est pas supporté dans docker-compose
# Pour forcer le rebuild sans cache dans Portainer, utilisez l'option "Rebuild" avec "No cache" dans l'interface
# Si vous utilisez une image pré-bâtie, décommentez image et commentez build
# image: votre-registre/laplank-radar-business:latest
CACHE_BUST: "${CACHE_BUST:-$(date +%s%N)}"
restart: unless-stopped
ports:
- "3006:3000" # Mappe le port 3006 de l'hôte vers le port 3000 du conteneur
environment:
- NODE_ENV=production
# Optionnel : Persistance des logs si nécessaire
# volumes:
# - ./logs:/app/logs
labels:
# Registrator lit l'IP du conteneur depuis le reseau "sonic" (-useIpFromNetwork sonic)
# et enregistre le service dans Consul avec le tag urlprefix- -> Fabio route vers ce service
- SERVICE_3000_NAME=${COMPOSE_PROJECT_NAME:-ajr-techradardev-main}-app-3000
- SERVICE_3000_TAGS=urlprefix-${RADAR_DOMAIN}/*
- SERVICE_3000_CHECK_TCP=true
# sonic-acme-1 (acme-companion) emet le cert TLS et le copie dans /host/certs/
# Fabio le detecte automatiquement par SNI pour HTTPS
- LETSENCRYPT_HOST=${RADAR_DOMAIN}
networks:
- sonic
networks:
sonic:
# Reseau externe existant sur le serveur (partage avec Registrator/Consul/Fabio)
external: true

1129
package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,7 @@
"marked": "^15.0.7",
"marked-highlight": "^2.2.1",
"next": "16.1.6",
"postcss": "^8.5.3",
"postcss-nested": "^7.0.2",
"postcss-preset-env": "^10.1.5",
"prettier": "^3.5.3",

View File

@@ -358,7 +358,7 @@ ${metrics.emergingTechnologies.filter(t => t.differentiation === 'high').length
// Main
function main() {
const radarDir = path.join(__dirname, '../radar-business/2025-01-15');
const outputFile = path.join(__dirname, '../docs/data/analyse-strategique.md');
const outputFile = path.join(__dirname, '../data/analyse-strategique.md');
if (!fs.existsSync(radarDir)) {
console.error(`Répertoire non trouvé: ${radarDir}`);

View File

@@ -164,7 +164,7 @@ try {
// Modifier Navigation.tsx
const patchNavScript = path.join(CWD, 'docker', 'add_team_link.sh');
if (fs.existsSync(patchNavScript)) {
execSync(`bash ${patchNavScript}`, {
execSync(`sh ${patchNavScript}`, {
cwd: CWD,
stdio: 'inherit'
});

View File

@@ -10,7 +10,7 @@ const path = require('path');
// Charger les compétences de l'équipe depuis les fichiers individuels
function loadTeamSkills() {
const teamDir = path.join(__dirname, '../docs/data/team');
const teamDir = path.join(__dirname, '../data/team');
const teamSkills = {};
if (!fs.existsSync(teamDir)) {
@@ -291,7 +291,7 @@ function parseTechnologiesFile(filePath) {
// Main
function main() {
const techFile = path.join(__dirname, '../docs/data/technologies-duniter.md');
const techFile = path.join(__dirname, '../data/technologies-duniter.md');
const outputDir = path.join(__dirname, '../radar-business/2025-01-15');
if (!fs.existsSync(outputDir)) {

View File

@@ -145,7 +145,7 @@ function loadTechnologies() {
// Charger les membres de l'équipe (avec profils complets)
function loadTeamMembers() {
const teamDir = path.join(__dirname, '../docs/data/team');
const teamDir = path.join(__dirname, '../data/team');
const members = [];
if (!fs.existsSync(teamDir)) {