# OPS_COCKPIT — Exploitation “cockpit” (DS220+ / DSM 7.3)

Dernière mise à jour : 2026-01-29

Objectif : déployer en **blue/green** (2 slots), basculer via **DSM Reverse Proxy**, rollback en ~10 secondes.

---

## 1) Repères (à ne pas confondre)

- Dossier NAS : `/volume2/docker/archicratie-web/current`
- Domaine site : `https://archicratie.trans-hands.synology.me`
- Gitea public : `https://gitea.archicratie.trans-hands.synology.me`
- Slot BLUE : conteneur `archicratie-web-blue` → `127.0.0.1:8081 -> 80`
- Slot GREEN : conteneur `archicratie-web-green` → `127.0.0.1:8082 -> 80`
- DSM Reverse Proxy pointe **soit** vers 8081 **soit** vers 8082 (c’est *ça* la bascule)

💡 Les couleurs n’ont pas de “sens métier”.  
**Le slot pointé par DSM = PRODUCTION.** L’autre = pré-prod / candidat.

---

## 2) Commandes “état des lieux” (30 secondes)

en bash
cd /volume2/docker/archicratie-web/current

docker compose ps
docker inspect -f '{{.State.Health.Status}}' archicratie-web-blue
docker inspect -f '{{.State.Health.Status}}' archicratie-web-green

# Test local direct (depuis le NAS)
curl -I http://127.0.0.1:8081/ | head
curl -I http://127.0.0.1:8082/ | head

# Pour voir quelle version est SERVIE par DSM :
curl -kI https://archicratie.trans-hands.synology.me/ | head

## 3) Déploiement standard (build sur slot inactif)

Hypothèse : DSM pointe actuellement sur 8081 (BLUE) → on déploie sur GREEN (8082).

### 3.1 Pré-check (obligatoire)
cd /volume2/docker/archicratie-web/current
ls -la docker-compose.yml Dockerfile nginx.conf .env
cat .env

### 3.2 Build GREEN (image + dist + pagefind)
cd /volume2/docker/archicratie-web/current

export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1

docker compose build --no-cache web_green

### 3.3 Démarrer GREEN
docker compose up -d --force-recreate web_green
docker compose ps

### 3.4 Smoke test (GREEN)
./scripts/smoke.sh 8082

### 3.5 Health + logs (GREEN)
docker inspect -f '{{.State.Health.Status}}' archicratie-web-green
docker compose logs -f --tail=80 web_green

## 4) Basculer PROD (DSM) — 10 secondes

# Dans DSM 7.3 :

Panneau de configuration → Portail des applications → Proxy inversé

# Ouvre la règle du host :

Source : https / archicratie.trans-hands.synology.me / port 443

# Destination :

Protocole : http

Hôte : 127.0.0.1

Port : 8082 (pour basculer vers GREEN)

Enregistre.

# Validation rapide :

Dans ton navigateur : recharge le site (Ctrl+F5)

# Ou en shell :
curl -kI https://archicratie.trans-hands.synology.me/ | head

## 5) Rollback (si souci) — 10 secondes

Dans DSM → même écran → repasse Destination Port à 8081.

Optionnel (si GREEN est “pollué” / à arrêter) :
docker compose stop web_green
docker compose logs --tail=200 web_green

## 6) Dépannage “scénarios typiques”
### A) DSM renvoie HTTP 504 (timeout)

# Symptôme : curl -kI https://archicratie... → 504, et DSM affiche “noindex”.

# Causes probables

Le conteneur n’écoute pas / est down

Le port DSM ne correspond pas au bon slot

Bind local absent (ports mal écrits)

Santé KO (mais DSM bascule quand même et tombe sur un truc mort)

# Checklist
docker compose ps
curl -I http://127.0.0.1:8081/ | head
curl -I http://127.0.0.1:8082/ | head
docker compose logs --tail=200 web_blue
docker compose logs --tail=200 web_green

Dans DSM : vérifie Destination = http://127.0.0.1:808X

⚠️ Important : ne pas ouvrir 8081/8082 au WAN.
Le reverse proxy DSM accède en loopback. Les ports restent en local (127.0.0.1:...).

### B) Gitea : 404 sur la redirection “Proposer”

Ca arrive si OWNER/REPO n’existent pas, ou si la casse est mauvaise.

# 1) Vérifier les variables injectées
cat .env

# 2) Vérifier que le repo existe vraiment
BASE="https://gitea.archicratie.trans-hands.synology.me"
OWNER="Archicratia"
REPO="archicratie-edition"

curl -kI "$BASE/$OWNER/$REPO/" | head -n 12

# 3) Vérifier via API
curl -ks "$BASE/api/v1/users/$OWNER" | head -c 250; echo
curl -ks "$BASE/api/v1/users/$OWNER/repos?limit=100" | grep -o '"full_name":"[^"]*"' | head

# 4) Si c’est bon côté Gitea mais Proposer continue à viser l’ancien repo
→ tu as juste une image web construite avec les anciennes valeurs. Rebuild le slot.

docker compose build --no-cache web_green
docker compose up -d --force-recreate web_green
./scripts/smoke.sh 8082

# 5) Contrôle dans le HTML servi
docker exec -it archicratie-web-green sh -lc \
'grep -Rin "const GITEA_BASE" /usr/share/nginx/html | head -n 20'

### C) “Proposer” échoue (pas de ticket / pas de redirection)

# Cas typiques :

JS inline bloqué / non injecté

la page a été rebuild sans les variables publiques

erreur CORS / cookies / mauvais domaine (http vs https)

# Check rapide

Ouvre la console navigateur → onglet Network

Vérifie que la redirection pointe bien vers :
https://gitea.archicratie.../Archicratia/archicratie-edition/...

# Check côté build
docker exec -it archicratie-web-green sh -lc \
'grep -Rin "PUBLIC_GITEA" /usr/share/nginx/html | head -n 50'

### D) Pagefind ne marche plus (recherche vide / pagefind.js absent)

# Check HTTP
curl -I http://127.0.0.1:8082/pagefind/pagefind.js | head

# Check fichier dans le conteneur
docker exec -it archicratie-web-green sh -lc 'ls -la /usr/share/nginx/html/pagefind | head'

# Causes

build lancé via astro build au lieu de npm run build (donc postbuild non exécuté)

pagefind a échoué pendant postbuild

dist non généré / non copié dans nginx

# Remède
docker compose build --no-cache web_green
docker compose up -d --force-recreate web_green
./scripts/smoke.sh 8082

## 7) Logs “propres”
docker compose logs --tail=200 web_blue
docker compose logs --tail=200 web_green

# Si tu veux suivre en live :
docker compose logs -f web_green


## Historique synthétique (2026-03-03) — Stabilisation CI/CD “zéro surprise”

### Problème initial observé
- Déploiement parfois lancé en “hotpatch” alors qu’un rebuild était nécessaire.
- Sur merge commits, la détection de fichiers modifiés pouvait être ambiguë.
- Résultat : besoin de `force=1` manuel pour éviter des incohérences.

### Correctif appliqué
- Gate CI rendu **merge-proof** :
  - lecture de `BEFORE` et `AFTER` depuis `event.json`
  - calcul des fichiers modifiés via `git diff --name-only BEFORE AFTER`

- Politique de décision stabilisée :
  - FULL auto dès qu’un changement impacte build/runtime (content/pages/scripts/anchors/etc.)
  - HOTPATCH auto uniquement pour annotations/media

### Preuves
- Test A (touch src/content) :
  - Gate flags: HAS_FULL=1 HAS_HOTPATCH=0 → MODE=full
- Test B (touch src/annotations) :
  - Gate flags: HAS_FULL=0 HAS_HOTPATCH=1 → MODE=hotpatch

### Audit post-déploiement (preuves côté NAS)
- 8081 + 8082 répondent HTTP 200
- `/para-index.json` + `/annotations-index.json` OK
- Aliases injectés visibles dans HTML via `.para-alias` quand alias présent

