# Le livre de Claude

Pages de scripts et d'études de Claude Code sur le PC Elio+Jux

# 0_Claude et le Jux_VPS

# A_liens entre Claude et le KDRIVE

---

## kDrive API REST — Infomaniak

<table id="bkmrk-param%C3%A8tre-valeur-dri"><thead><tr><th>Paramètre</th><th>Valeur</th></tr></thead><tbody><tr><td>Drive ID</td><td>`591617`</td></tr><tr><td>Token Bearer</td><td>`cnAZannhRpecgAfsQM7QiO4Vqh37g6Ht_hm4f0E6eDihMRaP2ZckKCmW959T5ST2Nv3qhGlqs0ltpNAb`</td></tr><tr><td>Base URL</td><td>`https://api.infomaniak.com/3/drive/591617`</td></tr></tbody></table>

## Endpoints fonctionnels

<table id="bkmrk-m%C3%A9thode-endpoint-usa"><thead><tr><th>Méthode</th><th>Endpoint</th><th>Usage</th></tr></thead><tbody><tr><td>`GET`</td><td>`/files/{dir_id}/files`</td><td>Lister le contenu d'un dossier</td></tr><tr><td>`GET`</td><td>`/files/{file_id}`</td><td>Métadonnées d'un fichier</td></tr><tr><td>`POST`</td><td>`/upload?directory_id={id}&file_name={name}&conflict=replace&total_size={bytes}`</td><td>Uploader un fichier. `conflict=replace` écrase le fichier existant de même nom. `conflict=version` crée une nouvelle version.</td></tr></tbody></table>

---

## Recovery automatique FUSE — monitor-rclone.sh (2026-06-24)

Le script /home/debian/monitor-rclone.sh (cron \*/5 \* \* \* \*) surveille les 5 mounts rclone et effectue une recovery complète si l'un d'eux est mort.

Fonctionnement

Pour chaque mount (/music, /komga, /livres, /audiobookshelf/audiobooks, /photo) :

timeout 10 ls — si inaccessible : sudo systemctl restart (kdrive-music, kdrive-komga, kdrive-livres, rclone-audiobooks, rclone-photo) Attente 5s + vérification que le mount répond Restart des containers Docker associés : /music → navidrome-navidrome-1 /komga → komga /livres → Kavita /audiobookshelf/audiobooks → audiobookshelf /photo → Immich-SERVER Immich-MICROSERVICES

Le script est silencieux quand tout va bien — il ne logue que les pannes et recoveries. Log : /home/debian/logs/rclone-monitor.log

Avant cette refactorisation, le script lançait un rclone mount direct (en parallèle des services systemd) et ne redémarrait pas les containers — le FUSE était remonté mais Navidrome gardait l'ancienne référence corrompue.

## Suppression de fichiers — non fonctionnelle (testé 2026-06-09)

Tous les endpoints suivants retournent `{"result":"error","error":{"code":"method_not_found"}}` :

- `DELETE /files/{file_id}`
- `POST /files/trash` avec body `{"file_ids":[id]}`
- `POST /files/trash` avec body `{"ids":[id]}`
- `POST /files/{file_id}/trash`
- `PUT /files/{file_id}` avec `{"deleted":true}`
- `DELETE /files` avec body `{"ids":[id]}`

La doc officielle (`developer.infomaniak.com`) n'est pas accessible publiquement. L'endpoint de suppression reste inconnu.

## Stratégie de rétention — rotation par jour de la semaine

Puisque la suppression via API ne fonctionne pas, le script de backup utilise une rotation par jour de la semaine (`date +%u` → 1=lundi … 7=dimanche) avec `conflict=replace`. Résultat : exactement **7 fichiers max** par service, les anciens sont écrasés automatiquement chaque semaine.

Script : `/opt/backups/vps_backup.sh` — cron : `0 2 * * *`

## Dossiers kDrive (TOOJUX/jux\_vps)

<table id="bkmrk-service-dossier-id-e"><thead><tr><th>Service</th><th>Dossier ID</th><th>Exemple de fichier</th></tr></thead><tbody><tr><td>BookStack</td><td>`1427916`</td><td>`bookstack_db_day1.7z`</td></tr><tr><td>Immich</td><td>`1427919`</td><td>`immich_db_day1.7z`</td></tr><tr><td>Joplin</td><td>`1427920`</td><td>`joplin_db_day1.7z` (~630 Mo)</td></tr><tr><td>Mealie</td><td>`1427921`</td><td>`mealie_db_day1.7z`</td></tr><tr><td>Readeck</td><td>`1427922`</td><td>`readeck_db_day1.7z`</td></tr></tbody></table>

# B_les procédures de Claude

1/ [la sauvegarde quotidienne de la base de données Joplin sur Kdrive (sans images) ](https://bookstack.juxjux.ovh/link/166#bkmrk-sauvegarde-bdd)

5/ 260611 - [Komga-PDF](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/260611-procedure-komga-pdf-par-claude-sur-stirlingpdf "260611_procédure Komga-PDF par Claude sur StirlingPDF")

6/ 260614 - [Joplin-Compression](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/260614-procedure-joplin-compression "260614 - procedure Joplin-compression")

# C_ installation de Claude Code dans le VPS juxjux

# Installation de Claude Code dans le VPS juxjux

## Objectif

Pouvoir intervenir sur les containers du VPS (redémarrage, diagnostic, logs, fix rapide) depuis un mobile Android en mobilité, via SSH + tmux + Claude Code CLI directement installé sur le VPS.

## Prérequis constatés (2026-07-21)

- **Node.js** : v20.20.2 déjà présent sur le VPS (Debian) — aucune installation nécessaire
- **npm** : v10.8.2
- **tmux** : absent, installé via `sudo apt-get install -y tmux` (v3.3a-3)

## Installation de Claude Code CLI

Installation en **local user** (pas de `sudo npm install -g`) pour éviter de faire tourner le CLI en root et éviter les conflits de permissions npm globales :

```bash
mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
npm install -g @anthropic-ai/claude-code
```

Ajout du PATH dans `~/.bashrc` :

```bash
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
```

Version installée : **2.1.197**

## Authentification

Choix retenu : **login OAuth avec le compte claude.ai (Julien, plan Claude Pro)** — pas de clé API Anthropic séparée, donc pas de facturation à l'usage additionnelle.

Procédure suivie (le VPS est headless, pas de navigateur local) :

1. Lancer `claude` dans une session **tmux** dédiée (`tmux new-session -d -s claude`) pour que la session survive à une déconnexion SSH
2. Choisir "Claude account with subscription" au login
3. Le CLI affiche une URL `https://claude.com/cai/oauth/authorize?...` — impossible à ouvrir depuis le VPS, donc récupérée via `tmux capture-pane` et ouverte manuellement sur un navigateur (PC ou mobile)
4. Après connexion sur claude.ai, un code `xxxx#yyyy` est retourné — collé dans le prompt `Paste code here if prompted >` via `tmux send-keys`
5. Confirmation : `Logged in as julien.bertrand@live.fr`

Les credentials sont persistés dans `~/.claude/.credentials.json` (permissions `600`, `debian:debian`) — la connexion reste valide pour les sessions futures, pas besoin de se ré-authentifier à chaque lancement.

## Usage depuis Android (Termux)

1. Installer **Termux** depuis F-Droid (pas le Play Store, version obsolète)
2. Se connecter en SSH au VPS :
   ```bash
   ssh debian@51.77.141.54
   ```
3. Rattacher ou créer la session tmux :
   ```bash
   tmux attach -t claude   # si la session existe déjà
   tmux new -s claude      # sinon
   ```
4. Lancer `claude` (ou il tourne déjà si la session persiste)
5. Détacher sans tuer la session : `Ctrl+b` puis `d` — permet de couper la connexion mobile sans interrompre Claude Code

## Sécurité

- Le VPS a déjà subi un incident de sécurité (CVE rclone RC, 2026-06-09 — voir page correspondante) : rester vigilant sur toute nouvelle surface d'exposition
- Claude Code tourne en utilisateur `debian` (non-root), scope de travail `/home/debian` accepté comme dossier de confiance
- Authentification liée au compte personnel Julien (Claude Pro) — pas de clé API partagée à protéger séparément
- Accès à la session Claude Code = accès SSH au VPS (mot de passe `debian`) — aucune surface réseau supplémentaire ouverte (pas de port exposé, tout passe par SSH existant)

## Répertoire de lancement recommandé

Le VPS a déjà en local le CLAUDE.md partagé, synchronisé via Syncthing :

```
~/Documents/Jux_univers/Claude-pcelio+jux/CLAUDE.md
```

C'est le même fichier que celui utilisé sur le PC Windows (`D:\Syncthing\Jux_univers\Claude-pcelio+jux\CLAUDE.md`) et sur Ubuntu. Il fait partie du dossier Syncthing `afltj-njyuy` ("Tablette VPS Syncthing"), local path `~/Documents`.

**Lancer `claude` depuis ce dossier plutôt que `/home/debian`** : le CLI charge automatiquement ce CLAUDE.md et récupère tout le contexte partagé (MCPs, infra, conventions) sans rien reconfigurer.

```bash
cd ~/Documents/Jux_univers/Claude-pcelio+jux/
claude
```

## Piège constaté — Syncthing VPS silencieusement déconnecté (2026-07-21)

En vérifiant le CLAUDE.md sur le VPS, le fichier était resté figé au **24 juin** alors que la version de référence (PC Windows) avait été mise à jour bien plus récemment (ex. section Inkscape du 21/07).

Diagnostic via le MCP Syncthing :
- `get_folder_status` sur le dossier `afltj-njyuy` renvoyait `state: idle`, `needBytes: 0`, `errors: 0` — en apparence tout va bien
- Mais `get_connections` / `get_devices` montrait `numConnections: 0` sur **tous** les appareils — le VPS n'avait **aucune connexion active** vers ses pairs, y compris PC-Elio+Jux

Autrement dit : Syncthing sur le VPS ne remonte aucune erreur quand il est déconnecté de tout le monde — il affiche juste l'état "idle" du dernier sync connu, ce qui peut faire croire à tort que tout est synchronisé.

**Résolution** : dès que Syncthing a été relancé côté PC Windows, la connexion TCP vers le VPS (device `I4M5WXU`) s'est rétablie en quelques secondes, et le CLAUDE.md s'est mis à jour immédiatement (nouveau hash, date du jour).

**Point de vigilance pour la suite** : si le CLAUDE.md sur le VPS semble périmé, ne pas se fier à `get_folder_status` seul (peut afficher "idle" à tort) — vérifier `get_connections` pour confirmer que le VPS a bien une connexion active vers au moins un appareil source avant de creuser plus loin.

## Points d'attention pour la suite

- Penser à `/init` pour générer un CLAUDE.md propre au contexte VPS si l'usage se confirme
- Vérifier que la session tmux ne meurt pas silencieusement (pas de `Restart=always` type systemd ici, contrairement aux services rclone)

# 00_Recapitulatif

## 260802 - Allegement JVM Komga + StirlingPDF (applique le 2026-08-02 a 22h)

Application des optimisations memoire validees le 2026-08-01, apres verification du backup quotidien (BILAN 5/5 OK). Les deux stacks ont ete redeployees depuis `/home/debian/{komga,stirling}-compose-new.yml`, les composes precedents sauvegardes en `.bak-260802`.

<table id="bkmrk-serviceavantapresres"><tbody><tr><th style="width:150px;">Service</th><th>Avant</th><th>Apres</th><th>Resultat</th></tr><tr><td>**Komga** (stack 7)</td> <td>`-Xmx4g -Xms2g -XX:MaxRAMPercentage=70.0`  
limits 4500M / reservations 3000M  
707 Mio residents</td> <td>`-Xmx1g`  
limits 1500M / reservations 256M</td> <td>**415 Mio** (-292 Mio, -41 %)</td></tr><tr><td>**StirlingPDF** (stack 89)</td> <td>JVM sans limite  
722 Mio residents</td> <td>`-Xmx512m`  
limits 2g</td> <td>**785 Mio** — pas de reduction, mais consommation desormais bornee</td></tr></tbody></table>

**Bilan hote :** swap **3,7 Go -&gt; 2,2 Go** (-1,5 Go), memoire disponible 4,4 -&gt; 4,6 Gi. L'essentiel du gain vient de Komga : c'est le `-Xms2g` qui pre-allouait 2 Go de heap au demarrage.

**Pourquoi StirlingPDF ne baisse pas :** le process `java` conserve 799 Mio de RSS malgre `-Xmx512m` (512 Mio de heap + non-heap : metaspace, code cache, piles de threads), auxquels s'ajoutent LibreOffice (`soffice.bin`, ~98 Mio), `unoserver` et `Xvfb` que Stirling lance pour les conversions. Le benefice obtenu n'est pas une baisse mais un plafond : la consommation ne peut plus deborder.

**Limite portee de 1 Go a 2 Go avant application.** Le plan initial prevoyait 1 Go. Or l'OCR fait tourner ocrmypdf et tesseract comme processus Python *hors JVM* : `-Xmx` ne les borne pas, seul le plafond cgroup du container s'applique. Pic mesure a **894-969 Mio pour une seule page A4 300 dpi** — un plafond de 1 Go aurait provoque un OOM kill des le premier OCR. La version 1 Go est conservee en `/home/debian/stirling-compose-new.yml.orig1g` mais ne doit pas etre utilisee.

**Verifications apres deploiement :** Komga repond 200 et son API `/api/v1/libraries` renvoie bien les bibliotheques ; StirlingPDF valide ses deux fonctions critiques, `compress-pdf` (utilise par les workflows komga-pdf et nas\_geo\_compress) et l'**OCR** (page A4 300 dpi, pic 969 Mio, aucun OOM kill, aucun redemarrage).

**Piege de deploiement :** les projets compose s'appellent `7` et `89` (les IDs de stack Portainer), pas `komga` / `stirlingpdf`. La commande correcte est `sudo docker compose -p 7 -f /var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml up -d`.

**Rollback :** restaurer le `.bak-260802` de la stack concernee et redeployer de la meme facon.

---

## Vue d ensemble - VPS Jux + Claude Code

34 containers en production sur le VPS. 25 pages de documentation, une par service. 13 services disposent d un MCP actif dans Claude Code. Mis a jour le 2026-05-30.

<table id="bkmrk-pageurlmcp-claude-co"><thead><tr><th>Page</th><th>URL</th><th>MCP Claude Code</th><th>Statut integration</th></tr></thead><tbody><tr><td>[01\_Portainer](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/152)</td><td>[https://portainer.juxjux.ovh](https://portainer.juxjux.ovh)</td><td>`mcp__portainer__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[02\_Bookstack](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/153)</td><td>[https://bookstack.juxjux.ovh](https://bookstack.juxjux.ovh)</td><td>`bookstack-mcp-server (npm)`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[03\_Homarr](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/154)</td><td>[https://homarr.juxjux.ovh](https://homarr.juxjux.ovh)</td><td>`mcp__homarr__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[04\_Audiobookshelf](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/155)</td><td>[https://audiobookshelf.juxjux.ovh](https://audiobookshelf.juxjux.ovh)</td><td>`mcp__audiobookshelf__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[05\_BentoPDF](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/156)</td><td>-</td><td>-</td><td><span style="color:#ffa500;">API directe</span></td></tr><tr><td>[06\_Cadvisor](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/157)</td><td>-</td><td>-</td><td><span style="color:#808080;">via Prometheus</span></td></tr><tr><td>[07\_Calibre-web](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/158)</td><td>-</td><td>-</td><td><span style="color:#ffa500;">OPDS</span></td></tr><tr><td>[08\_Dozzle](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/159)</td><td>-</td><td>-</td><td><span style="color:#808080;">via Portainer MCP</span></td></tr><tr><td>[09\_FileBrowser](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/160)</td><td>[https://files.juxjux.ovh](https://files.juxjux.ovh)</td><td>`mcp__filebrowser__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[10\_FreshRSS](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/161)</td><td>[https://freshrss.juxjux.ovh](https://freshrss.juxjux.ovh)</td><td>`mcp__freshrss__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[11\_Gitea](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/162)</td><td>-</td><td>-</td><td><span style="color:#ffa500;">API REST directe</span></td></tr><tr><td>[12\_Grafana](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/163)</td><td>[https://grafana.juxjux.ovh](https://grafana.juxjux.ovh)</td><td>-</td><td><span style="color:#ffa500;">API REST directe</span></td></tr><tr><td>[13\_Immich](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/164)</td><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td><td>`mcp__immich__*`</td><td><span style="color:#008000;">MCP actif (5 containers)</span></td></tr><tr><td>[14\_Jellyfin](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/165)</td><td>[https://jellyfin.juxjux.ovh](https://jellyfin.juxjux.ovh)</td><td>`mcp__jellyfin__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[15\_Joplin](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/166)</td><td>-</td><td>-</td><td><span style="color:#808080;">sync server uniquement</span></td></tr><tr><td>[16\_Kavita](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/167)</td><td>[https://kavita.juxjux.ovh](https://kavita.juxjux.ovh)</td><td>`mcp__kavita__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[17\_Komga](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/168)</td><td>[https://komga.juxjux.ovh](https://komga.juxjux.ovh)</td><td>`mcp__komga__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[18\_Mealie](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/169)</td><td>[https://mealie.juxjux.ovh](https://mealie.juxjux.ovh)</td><td>`mcp__mealie__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[19\_Navidrome](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/170)</td><td>[https://navidrome.juxjux.ovh](https://navidrome.juxjux.ovh)</td><td>`mcp__navidrome__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[20\_NodeExporter](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/171)</td><td>-</td><td>-</td><td><span style="color:#808080;">via Prometheus</span></td></tr><tr><td>[21\_Prometheus](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/172)</td><td>-</td><td>-</td><td><span style="color:#ffa500;">API REST / PromQL</span></td></tr><tr><td>[22\_Readeck](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/173)</td><td>[https://readeck.juxjux.ovh](https://readeck.juxjux.ovh)</td><td>`mcp__readeck__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[23\_Syncthing](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/174)</td><td>[https://syncthing.juxjux.ovh](https://syncthing.juxjux.ovh)</td><td>`mcp__syncthing__*`</td><td><span style="color:#008000;">MCP actif</span></td></tr><tr><td>[24\_Yourls](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/175)</td><td>-</td><td>-</td><td><span style="color:#ffa500;">API REST directe</span></td></tr><tr><td>[25\_StirlingPDF](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/208)</td><td>[https://spdf.juxjux.ovh](https://spdf.juxjux.ovh)</td><td>-</td><td><span style="color:#ffa500;">API directe</span></td></tr><tr><td>[A\_liens entre Claude et le KDRIVE](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/176)</td><td>[kdrive.infomaniak.com](https://kdrive.infomaniak.com)</td><td>`@infomaniak/mcp-server-kdrive` + API REST</td><td><span style="color:#008000;">MCP actif (kdrive\_search) + API directe</span></td></tr></tbody></table>

## Scripts de maintenance

<table id="bkmrk-fill_bookstack_pages"><tbody><tr><th>fill\_bookstack\_pages.py</th><td>Remplit les pages avec les infos containers (image, ports, volumes)</td><td>`C:\Users\eliob\.claude\fill_bookstack_pages.py`</td></tr><tr><th>fill\_bookstack\_mcp.py</th><td>Ajoute la section integration Claude Code / MCP a chaque page</td><td>`C:\Users\eliob\.claude\fill_bookstack_mcp.py`</td></tr></tbody></table>

## Configuration MCP

Scripts dans `C:\Users\eliob\.claude\`, enregistres dans `C:\Users\eliob\.mcp.json`. Projet Claude Code principal : `C:\Users\eliob`. Endpoint Portainer Docker local : ID **3**.

## 260611-REX VPS par Claude

Releve du 2026-06-11 via Prometheus (PromQL sur localhost:9090) + Portainer MCP.

### Etat global

<table id="bkmrk-ram8.4-%2F-11.41-gb-%287"><tbody><tr><th>RAM</th><td>8.4 / 11.41 GB (73.6%)</td></tr><tr><th>Swap</th><td><span style="color:#cc0000;">3.99 / 4.0 GB (quasi plein)</span></td></tr><tr><th>CPU</th><td>5.2%</td></tr></tbody></table>

### Top consommateurs RAM (RSS)

<table id="bkmrk-containerram-rss-kom"><thead><tr><th>Container</th><th>RAM RSS</th></tr></thead><tbody><tr><td>komga</td><td>1059 MB</td></tr><tr><td>Immich-SERVER</td><td>1011 MB</td></tr><tr><td>Immich-MICROSERVICES</td><td>520 MB</td></tr><tr><td>stirling-pdf</td><td>442 MB</td></tr><tr><td>homarr2026</td><td>355 MB</td></tr><tr><td>jellyfin</td><td>272 MB</td></tr><tr><td>prometheus</td><td>259 MB</td></tr><tr><td>jdownloader</td><td>220 MB</td></tr><tr><td>Kavita</td><td>196 MB</td></tr><tr><td>joplin</td><td>179 MB</td></tr><tr><td>calibre-web-eyrolles</td><td>132 MB</td></tr><tr><td>mealie</td><td>129 MB</td></tr><tr><td>grafana</td><td>125 MB</td></tr><tr><td>cadvisor</td><td>91 MB</td></tr><tr><td>navidrome</td><td>86 MB</td></tr></tbody></table>

Swap sature : komga + Immich representent ~2.5 GB a eux deux. StirlingPDF (442 MB) reste charge entre les appels.

## 260801-REX VPS par Claude

Releve du 2026-08-01 via docker stats + /proc en SSH (PC eliob).

### Etat global

<table id="bkmrk-ram-8.2-%2F-11.41-gb-%28"><tbody><tr><th>RAM</th><td>8.2 / 11.41 GB (71.7%)</td></tr><tr><th>Swap</th><td><span style="color:#cc0000;">4.0 / 4.0 GB (sature a 100%)</span></td></tr><tr><th>CPU</th><td>28% (compression 7z du backup en cours)</td></tr></tbody></table>

### Top consommateurs RAM (RSS)

<table id="bkmrk-container-ram-rss-im"><thead><tr><th>Container</th><th>RAM RSS</th></tr></thead><tbody><tr><td>Immich-SERVER</td><td>1147 MB</td></tr><tr><td>komga</td><td>791 MB</td></tr><tr><td>Immich-MICROSERVICES</td><td>618 MB</td></tr><tr><td>stirling-pdf</td><td>566 MB</td></tr><tr><td>jellyfin</td><td>380 MB</td></tr><tr><td>homarr2026</td><td>313 MB</td></tr><tr><td>Immich-DB</td><td>310 MB</td></tr><tr><td>prometheus</td><td>282 MB</td></tr><tr><td>joplin</td><td>241 MB</td></tr><tr><td>Kavita</td><td>240 MB</td></tr><tr><td>cadvisor</td><td>195 MB</td></tr><tr><td>grafana</td><td>164 MB</td></tr><tr><td>joplin-db</td><td>158 MB</td></tr><tr><td>yourls-db</td><td>157 MB</td></tr><tr><td>audiobookshelf</td><td>140 MB</td></tr></tbody></table>

Swap sature : komga (760 MB) + StirlingPDF (406 MB) en tete des processus swappes, Immich ~330 MB. Des limites memoire ont ete posees depuis juin sur les gros containers (komga 4.4G, Immich 2G, Kavita 4G, joplin 2G). Decouvertes du jour : GNOME/gdm3 tourne a vide sur tty1 depuis le 8 juillet (98 paquets installes, ~150 MB RAM, aucun acces distant configure) ; sauvegardes Immich vides depuis l'origine (pg\_dump sans -d immich, archives de 4 Ko) — corrigees le 2026-08-01, dump reel 307 MB.

### Actions realisees le 2026-08-01 (soir)

<table id="bkmrk-action-detail-gain-f"><thead><tr><th>Action</th><th>Detail</th><th>Gain</th></tr></thead><tbody><tr><td>Fix backup Immich</td><td>`-d immich` ajoute dans `/opt/backups/vps_backup.sh` + run manuel complet 5/5 OK (archive 87 MB sur kDrive, premiere sauvegarde Immich valide)</td><td>donnees enfin sauvegardees</td></tr><tr><td>Fusion Immich</td><td>5 containers → 3 : SERVER unique (API + workers, `NODE_OPTIONS=--max-old-space-size=768`), MICROSERVICES et LEARNING supprimes (recherche semantique et visages non utilises). Ancien compose : `compose/29/docker-compose.yml.bak-260801`</td><td>~900 MB RAM</td></tr><tr><td>Arret cAdvisor</td><td>`docker update --restart=no cadvisor` + stop. Plus de metriques par container dans Prometheus/Grafana (node-exporter conserve le host)</td><td>~200 MB RAM + 4-8% CPU</td></tr><tr><td>GDM/GNOME desactive puis purge</td><td>gdm3 + gnome-shell + Xorg tournaient a vide sur tty1 depuis le 2026-07-08. `systemctl disable --now gdm` puis purge apt de 263 paquets (bureau complet + LibreOffice, jeux...). Verifie avant : ens3 gere par systemd-networkd, NetworkManager non critique. Verifie apres : 30 containers up, nginx/docker/ssh/wg actifs, sites en 200</td><td>~150 MB RAM + 3,5 GB disque</td></tr></tbody></table>

**Resultat global du 2026-08-01** : swap 4,0/4,0 GB (sature depuis juin) → 2,6/4,0 GB ; disque 62% → 59% ; ~1,3 GB de RAM liberes. Immich verifie fonctionnel par Julien.

### Plan du 2026-08-02 a 19h (tache planifiee Claude Code)

Apres verification du backup nocturne (BILAN 5/5 OK), appliquer les deux fixes JVM prepares et valides (fichiers en attente dans `/home/debian/`) :

<table id="bkmrk-service-avant-apres-"><thead><tr><th>Service</th><th>Avant</th><th>Apres</th><th>Gain attendu</th></tr></thead><tbody><tr><td>Komga (stack 7)</td><td>`-Xmx4g -Xms2g` (2 GB pre-alloues, ~760 MB en swap), limites 4500M/3000M</td><td>`-Xmx1g` sans Xms, limites 1500M/256M</td><td>~400-500 MB RAM + ~700 MB swap</td></tr><tr><td>StirlingPDF (stack 89)</td><td>JVM sans plafond (566-643 MB residents + ~406 MB swap)</td><td>`JAVA_TOOL_OPTIONS=-Xmx512m`, limite 1g</td><td>~300-400 MB RAM</td></tr></tbody></table>

Verifications prevues : komga.juxjux.ovh en 200, test compress-pdf sur spdf.juxjux.ovh (fonction critique des workflows komga-pdf et geo\_loud), docker stats, free -h (swap attendu sous ~2 GB). Rollback : restaurer les `.bak-260802`. Nota : BentoPDF n'existe plus sur le VPS (container supprime) — il ne peut de toute facon pas remplacer StirlingPDF (pas d'API serveur, traitement 100% navigateur).

# 01_Portainer

## portainer

*Docker container management made simple, with the world’s most popular GUI-based container management platform.*

<table id="bkmrk-imageportainer%2Fporta"><tbody><tr><th>Image</th><td>`portainer/portainer-ce:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Reseau</th><td>bridge</td></tr><tr><th>URL</th><td>[https://portainer.juxjux.ovh](https://portainer.juxjux.ovh)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip94439"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>9443</td><td>9443/tcp</td><td>0.0.0.0</td></tr><tr><td>9443</td><td>9443/tcp</td><td>::</td></tr><tr><td>8000</td><td>8000/tcp</td><td>0.0.0.0</td></tr><tr><td>8000</td><td>8000/tcp</td><td>::</td></tr><tr><td>9000</td><td>9000/tcp</td><td>0.0.0.0</td></tr><tr><td>9000</td><td>9000/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/lib/docker/volumes/portainer_data/_data`</td><td>`/data`</td><td>volume</td><td>rw</td></tr><tr><td>`/var/run/docker.sock`</td><td>`/var/run/docker.sock`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__portainer__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_portainer.py | Projet Claude Code : C:\\Users\\eliob | Auth : JWT via POST /api/auth, endpoint Docker local ID 3</td></tr></tbody></table>

### Outils disponibles

- `list_endpoints`
- `list_stacks`
- `get_stack`
- `get_stack_file`
- `redeploy_stack`
- `list_containers`
- `get_container`
- `get_container_logs`
- `restart_container`
- `start_container`
- `stop_container`
- `list_images`

### Ce que nous pouvons faire ensemble

- Lister et inspecter tous les containers et leurs états
- Consulter les logs d'un container en temps réel
- Redémarrer, démarrer ou arrêter un container à la demande
- Lire le fichier docker-compose.yml d'une stack
- Redéployer une stack après modification
- Lister toutes les images Docker disponibles sur le VPS

# 02_Bookstack

## bookstack

*\[Bookstack\](https://github.com/BookStackApp/BookStack) is a free and open source Wiki designed for creating beautiful documentation. Featuring a simple, but powerful WYSIWYG editor it allows for teams to create detailed and useful documentation with ease. Powered by SQL and including a Markdown editor for those who prefer it, BookStack is geared towards making documentation more of a pleasure than a chore. For more information on BookStack visit their website and check it out: https://www.bookstackapp.com*

<table id="bkmrk-imagelscr.io%2Flinuxse"><tbody><tr><th>Image</th><td>`lscr.io/linuxserver/bookstack:latest`</td></tr><tr><th>Version</th><td>v26.03.3-ls256</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>bookstack</td></tr><tr><th>Reseau</th><td>bookstack\_default</td></tr><tr><th>URL</th><td>[https://bookstack.juxjux.ovh](https://bookstack.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/linuxserver/docker-bookstack](https://github.com/linuxserver/docker-bookstack)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip68758"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>6875</td><td>80/tcp</td><td>0.0.0.0</td></tr><tr><td>6875</td><td>80/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/bookstack/app`</td><td>`/config`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## bookstack\_db

*\[Mariadb\](https://mariadb.org/) is one of the most popular database servers. Made by the original developers of MySQL.*

<table id="bkmrk-imagelscr.io%2Flinuxse-1"><tbody><tr><th>Image</th><td>`lscr.io/linuxserver/mariadb:latest`</td></tr><tr><th>Version</th><td>11.4.9-r0-ls212</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>bookstack</td></tr><tr><th>Reseau</th><td>bookstack\_default</td></tr><tr><th>URL</th><td>[https://bookstack.juxjux.ovh](https://bookstack.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/linuxserver/docker-mariadb](https://github.com/linuxserver/docker-mariadb)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-1"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/bookstack/db`</td><td>`/config`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`bookstack MCP (npm bookstack-mcp-server)`</td></tr><tr><th>Configuration</th><td>npm via npx -y bookstack-mcp-server | Projet Claude Code : C:\\Users\\eliob | Auth : Token ID + Secret en variables d'environnement (.claude.json)</td></tr></tbody></table>

### Outils disponibles

- `list_books`
- `get_book`
- `list_chapters`
- `get_chapter`
- `list_pages`
- `get_page`
- `create_page`
- `update_page`
- `search`
- `get_shelves`

### Ce que nous pouvons faire ensemble

- Lire et écrire des pages de documentation directement depuis Claude Code
- Créer et organiser des livres, chapitres et pages
- Rechercher du contenu dans toute la base de connaissance
- Auto-documenter des projets ou des sessions de travail
- Mettre à jour cette page et les autres pages containers automatiquement

---

## Sauvegarde de la base de données

Sauvegarde automatique quotidienne de la base MariaDB `bookstackapp` vers kDrive Infomaniak. Mise en place le 2026-06-01.

### Paramètres

<table id="bkmrk-script%2Fopt%2Fbackups%2Fb"><tbody><tr><th>Script</th><td>`/opt/backups/bookstack_backup.sh`</td></tr><tr><th>Cron</th><td>Tous les jours à 2h du matin (`0 2 * * *`)</td></tr><tr><th>Base sauvegardée</th><td>`bookstackapp` — container `bookstack_db` (MariaDB)</td></tr><tr><th>Taille base (disque)</th><td>~203 Mo</td></tr><tr><th>Format archive</th><td>.7z (compression niveau 5) — ~564 Ko</td></tr><tr><th>Destination</th><td>kDrive Infomaniak — `TOOJUX/jux_vps/bookstack` (dossier ID 1427916)</td></tr><tr><th>Rétention</th><td>7 jours glissants (purge automatique des anciens fichiers)</td></tr><tr><th>Log</th><td>`/opt/backups/backup.log`</td></tr><tr><th>Nommage fichier</th><td>`bookstack_db_YYYY-MM-DD.7z`</td></tr></tbody></table>

### Fonctionnement du script

1. Exécute `mysqldump` depuis le container `bookstack_db` vers `/tmp/`
2. Compresse en `.7z` avec `7z` (déjà installé sur le VPS)
3. Upload sur kDrive via l'API REST Infomaniak (`POST /3/drive/{id}/upload`) avec le paramètre `total_size`
4. Supprime le fichier temporaire local
5. Purge les fichiers kDrive nommés `bookstack_db_*` de plus de 7 jours

### Consulter les logs

```
ssh debian@51.77.141.54 "tail -50 /opt/backups/backup.log"
```

### Relancer manuellement

```
ssh debian@51.77.141.54 "bash /opt/backups/bookstack_backup.sh"
```

# 03_Homarr

## homarr2026

*A modern and easy to use dashboard. 30+ integrations. 10K+ icons built in. Authentication out of the box. No YAML, drag and drop configuration.*

<table id="bkmrk-imageghcr.io%2Fhomarr-"><tbody><tr><th>Image</th><td>`ghcr.io/homarr-labs/homarr:latest`</td></tr><tr><th>Version</th><td>main</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>homarr</td></tr><tr><th>Reseau</th><td>homarr\_homarr\_network</td></tr><tr><th>URL</th><td>[https://homarr.juxjux.ovh](https://homarr.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/homarr-labs/homarr](https://github.com/homarr-labs/homarr)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip75753"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>7575</td><td>3000/tcp</td><td>0.0.0.0</td></tr><tr><td>7575</td><td>3000/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/etc/localtime`</td><td>`/etc/localtime`</td><td>bind</td><td>ro</td></tr><tr><td>`/var/run/docker.sock`</td><td>`/var/run/docker.sock`</td><td>bind</td><td>ro</td></tr><tr><td>`/home/debian/docker/homarr2026/icons`</td><td>`/app/public/icons`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/homarr2026/appdata`</td><td>`/appdata`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__homarr__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_homarr.py | Projet Claude Code : C:\\Users\\eliob | Auth : cookie NextAuth session (authjs.session-token)</td></tr></tbody></table>

### Outils disponibles

- `get_all_boards`
- `get_board_items`
- `get_home_board`
- `get_integrations`
- `trpc_call`

### Ce que nous pouvons faire ensemble

- Lire la configuration du tableau de bord principal
- Lister les services et widgets configurés
- Consulter les intégrations actives (Jellyfin, Sonarr, etc.)
- Appeler des procédures tRPC personnalisées

---

## Mise a jour disponible (verifie le 2026-07-19)

<table id="bkmrk-versions"><tbody><tr><th>Version installee</th><td>0.53</td></tr><tr><th>Derniere version</th><td>1.71.0 (2026-07-17)</td></tr><tr><th>Ecart</th><td>Traverse la refonte majeure 1.0 (reecriture complete, ete 2024) + ~70 releases mineures jusqu'a juillet 2026</td></tr></tbody></table>

### Attention : migration majeure, pas un simple bump

Le projet a ete entierement reecrit en version 1.0 et le depot a change de proprietaire : `ghcr.io/ajnart/homarr` -&gt; `ghcr.io/homarr-labs/homarr`. Le stack VPS (homarr2026) utilise deja l'image `homarr-labs` avec le tag `latest` et un volume `/appdata`, donc une partie de la migration structurelle semble deja faite -- a verifier avant de bumper vers un tag fige.

### Principaux breaking changes (0.x -&gt; 1.0)

- Variables d'env renommees : `DATABASE_URL` -&gt; `DB_URL` (conditionnelle), `DOCKER_HOST` -&gt; `DOCKER_HOSTNAMES` + `DOCKER_PORTS`, `AUTH_PROVIDER` -&gt; `AUTH_PROVIDERS`
- Nouvelle variable requise : `SECRET_ENCRYPTION_KEY`
- Variables supprimees : `DISABLE_ANALYTICS`, `AUTH_OIDC_TIMEOUT`, `AUTH_LDAP_ADMIN_GROUP`, `AUTH_LDAP_OWNER_GROUP`, `AUTH_OIDC_ADMIN_GROUP`, `AUTH_OIDC_OWNER_GROUP` (gestion des groupes/permissions passee dans l'UI)
- `/data` restructure et deplace vers `/appdata` (non retrocompatible)
- `/app/data/configs` (JSON) et `/app/public/icons` abandonnes -- gestion des icones et des configs via l'UI
- Support ARM v7 supprime
- Tous les widgets reecrits ; systeme d'integrations passe en asynchrone (fetch en arriere-plan + WebSockets/bus de messages)
- Test de connexion desormais obligatoire avant d'activer une integration

### Nouveautes notables depuis la 1.0 (jusqu'a 1.71.0)

- **v1.65.0** -- support MCP (integration IA), nouvelles integrations Beszel, Technitium DNS, Uptime Kuma, Audiobookshelf, Paperless-ngx, Navidrome ; widgets personnalises ; sauvegarde/restauration SQLite avec apercu WASM ; cache Redis global
- **v1.66.1** -- support des groupes locaux OIDC
- **v1.68.0** -- ameliorations de l'interface Beszel (stats en direct)
- **v1.69.0** -- menu contextuel (clic droit) sur les widgets avec actions auto-generees, evenements calendrier au survol avec epinglage au clic, stockage de secrets par widget
- **v1.70.0** -- integrations Traefik (widget dedie), Bazarr, PatchMon, et monitoring systeme Synology ; widgets media manquants/en file d'attente pour Radarr et Sonarr
- **v1.71.0** -- support direction de texte pour le widget notes, bouton de rafraichissement compact sur le widget Docker, tri ameliore des torrents qBittorrent

### Etapes de migration recommandees

1. Sauvegarder `/home/debian/docker/homarr2026/appdata` avant toute action
2. Exporter la config du dashboard depuis l'UI (fonction export/backup SQLite)
3. Verifier les variables d'environnement du compose homarr2026 contre la liste des breaking changes ci-dessus (notamment `SECRET_ENCRYPTION_KEY`, `DOCKER_HOSTNAMES`/`DOCKER_PORTS`)
4. Redeployer le stack, puis retester chaque integration (Jellyfin, Sonarr, etc.) -- test de connexion obligatoire en 1.x
5. Reimporter la sauvegarde SQLite si necessaire

*Sources : [github.com/homarr-labs/homarr/releases](https://github.com/homarr-labs/homarr/releases), [homarr.dev/blog - Homarr 1.0](https://homarr.dev/blog/2024/09/23/version-1.0/)*

# 04_Audiobookshelf

## audiobookshelf

*Self-hosted audiobook and podcast server*

<table id="bkmrk-imageghcr"><tbody><tr><th>Image</th><td>`ghcr.io/advplyr/audiobookshelf:latest`</td></tr><tr><th>Version</th><td>2.35.0</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>audiobookshelf</td></tr><tr><th>Reseau</th><td>audiobookshelf\_audiobookshelf\_network</td></tr><tr><th>URL</th><td>[https://audiobookshelf.juxjux.ovh](https://audiobookshelf.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/advplyr/audiobookshelf](https://github.com/advplyr/audiobookshelf)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip13378"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>13378</td><td>80/tcp</td><td>127.0.0.1</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-hote-destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/audiobookshelf/config`</td><td>`/config`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/audiobookshelf/metadata`</td><td>`/metadata`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/audiobookshelf/podcasts`</td><td>`/podcasts`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/audiobookshelf/audiobooks`</td><td>`/audiobooks`</td><td>bind</td><td>rw, :shared</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__audiobookshelf__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_audiobookshelf.py | Auth : JWT Bearer via POST /login</td></tr></tbody></table>

### Outils disponibles

- `get_libraries`
- `get_library`
- `get_library_items`
- `get_library_personalized`
- `get_item`
- `get_item_progress`
- `get_podcast_episodes`
- `download_podcast_episodes`
- `get_listening_sessions`
- `get_listening_stats`
- `get_me`
- `search_library`

### Ce que nous pouvons faire ensemble

- Parcourir la bibliothèque d'audiobooks et de podcasts
- Suivre la progression d'écoute d'un livre ou épisode
- Rechercher un titre, auteur ou podcast
- Consulter les statistiques d'écoute (temps total, sessions)
- Télécharger des épisodes de podcast

---

## Scan quotidien automatique — 2026-06-24

Un cron tourne chaque nuit à 04h00 UTC pour scanner toutes les bibliothèques Audiobookshelf et détecter les nouveaux contenus ou les renommages de dossiers.

### Script

`/home/debian/abs_scan.sh` — log : `/var/log/abs_scan.log`

```
0 4 * * * bash /home/debian/abs_scan.sh
```

### Fonctionnement

1. Authentification via `POST /login` pour obtenir un token JWT frais
2. Récupération de toutes les bibliothèques via `GET /api/libraries`
3. Déclenchement d'un scan pour chaque bibliothèque via `POST /api/libraries/{id}/scan`

Bibliothèques scannées : 36 (audiobooks + podcasts). Durée estimée : quelques minutes.

Exemple de log :

```
2026-06-24 04:00 SCAN OK 36/36 libs
```

---

## REX — 2026-06-24 : audiobook illisible après renommage de dossier

### Contexte

Audiobookshelf ne pouvait plus lire *Les routes de la soie* (Peter Frankopan). Erreur dans les logs :

```
Error: ENOENT: no such file or directory, stat '/audiobooks/Histoire/2 - Moyen Age/Peter Frankopan - Les routes de la soie/27_CH_08_LA_ROUTE_DU_CIEL.mp3'
```

### Cause

Le dossier avait été renommé sur kDrive/NAS de `Peter Frankopan - Les routes de la soie` en `Peter Frankopan-les routes de la soie` (tiret sans espaces, minuscule). Audiobookshelf conservait l'ancien chemin dans sa base.

### Solution

Le scan quotidien `abs_scan.sh` détecte ce type de désynchronisation et met à jour les chemins. Pour forcer immédiatement : lancer un scan manuel depuis l'interface Audiobookshelf ou exécuter `bash /home/debian/abs_scan.sh`.

# 05_BentoPDF

## bentopdf

*Unprivileged NGINX Dockerfiles*

<table id="bkmrk-imagebentopdfteam%2Fbe"><tbody><tr><th>Image</th><td>`bentopdfteam/bentopdf-simple:latest`</td></tr><tr><th>Version</th><td>1.28.0-alpine-slim</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>bentopdf</td></tr><tr><th>Reseau</th><td>bentopdf\_default</td></tr><tr><th>URL</th><td>[https://bento.juxjux.ovh](https://bento.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/alam00000/bentopdf](https://github.com/alam00000/bentopdf)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip80898"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8089</td><td>8080/tcp</td><td>0.0.0.0</td></tr><tr><td>8089</td><td>8080/tcp</td><td>::</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>API REST interne, pas de MCP configuré. Accessible via PowerShell/Python httpx.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Manipulation de PDF via l'API REST (fusion, découpage, conversion)
- Automatisation de traitements PDF dans des scripts Claude Code

# 06_Cadvisor

## cadvisor

<table id="bkmrk-imagegcr.io%2Fcadvisor"><tbody><tr><th>Image</th><td>`gcr.io/cadvisor/cadvisor:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>gemini\_grafana</td></tr><tr><th>Reseau</th><td>gemini\_grafana\_monitor\_net</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/run`</td><td>`/var/run`</td><td>bind</td><td>rw</td></tr><tr><td>`/`</td><td>`/root`</td><td>bind</td><td>ro</td></tr><tr><td>`/sys`</td><td>`/sys`</td><td>bind</td><td>ro</td></tr><tr><td>`/var/lib/docker`</td><td>`/var/lib/docker`</td><td>bind</td><td>ro</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>Endpoint Prometheus /metrics exposé à Prometheus (port 8080). Pas de MCP. Données lisibles via Prometheus MCP ou requêtes PromQL directes.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Métriques CPU/RAM/réseau/disque par container (via Prometheus)
- Surveillance des performances en temps réel de chaque service
- Détection de containers consommant trop de ressources

# 07_Calibre-web

## calibre-web-eyrolles

*\[Calibre-web\](https://github.com/janeczku/calibre-web) is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. It is also possible to integrate google drive and edit metadata and your calibre library through the app itself. This software is a fork of library and licensed under the GPL v3 License.*

<table id="bkmrk-imagelscr.io%2Flinuxse"><tbody><tr><th>Image</th><td>`lscr.io/linuxserver/calibre-web:latest`</td></tr><tr><th>Version</th><td>0.6.26-ls383</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>calibreweb\_automated</td></tr><tr><th>Reseau</th><td>calibre\_network</td></tr><tr><th>Source</th><td>[https://github.com/linuxserver/docker-calibre-web](https://github.com/linuxserver/docker-calibre-web)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip82148"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8214</td><td>8083/tcp</td><td>0.0.0.0</td></tr><tr><td>8214</td><td>8083/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/livres/Eyrolles`</td><td>`/books`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/calibre-web-automated/config`</td><td>`/config`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>Interface OPDS disponible pour parcourir la bibliothèque. API REST limitée. Pas de MCP configuré.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Parcourir la bibliothèque Eyrolles via le catalogue OPDS
- Potentielle automatisation d'ajout/export de livres via l'API

# 08_Dozzle

## dozzle

*Realtime log viewer for containers. Supports Docker, Swarm and K8s.*

<table id="bkmrk-imageamir20%2Fdozzle%3Al"><tbody><tr><th>Image</th><td>`amir20/dozzle:latest`</td></tr><tr><th>Version</th><td>v8.14.9</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>dozzle</td></tr><tr><th>Reseau</th><td>nginx\_npm-network</td></tr><tr><th>URL</th><td>[https://dozzle.juxjux.ovh](https://dozzle.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/amir20/dozzle](https://github.com/amir20/dozzle)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip90918"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>9091</td><td>8080/tcp</td><td>0.0.0.0</td></tr><tr><td>9091</td><td>8080/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/run/docker.sock`</td><td>`/var/run/docker.sock`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>Interface de visualisation de logs uniquement. Pas d'API publique exploitable. Les logs sont mieux accessibles via mcp\_\_portainer\_\_get\_container\_logs.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Logs containers accessibles en alternative via le MCP Portainer

# 09_FileBrowser

## File-Browser

<table id="bkmrk-imagefilebrowser%2Ffil"><tbody><tr><th>Image</th><td>`filebrowser/filebrowser:latest`</td></tr><tr><th>Version</th><td>2.63.3</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>filebrowser</td></tr><tr><th>Reseau</th><td>filebrowser\_default</td></tr><tr><th>URL</th><td>[https://files.juxjux.ovh](https://files.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/filebrowser/filebrowser](https://github.com/filebrowser/filebrowser)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip81478"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8147</td><td>80/tcp</td><td>0.0.0.0</td></tr><tr><td>8147</td><td>80/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/filebrowser/database`</td><td>`/database`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian`</td><td>`/srv`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/filebrowser/config`</td><td>`/config`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__filebrowser__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_filebrowser.py | Auth : JWT via POST /api/login (admin)</td></tr></tbody></table>

### Outils disponibles

- `list_files`
- `read_text_file`
- `upload_text_file`
- `get_file_info`
- `search_files`
- `copy_file`
- `move_or_rename`
- `create_directory`
- `delete_path`

### Ce que nous pouvons faire ensemble

- Naviguer dans l'arborescence de fichiers du VPS
- Lire et écrire des fichiers texte (configs, scripts, logs)
- Rechercher des fichiers par nom ou contenu
- Copier, déplacer, renommer des fichiers et dossiers
- Déposer des fichiers de config ou des scripts directement sur le VPS

# 10_FreshRSS

## freshrss

*A free, self-hostable news aggregator…*

<table id="bkmrk-imagefreshrss%2Ffreshr"><tbody><tr><th>Image</th><td>`freshrss/freshrss:latest`</td></tr><tr><th>Version</th><td>1.28.1</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 26 minutes</span></td></tr><tr><th>Compose project</th><td>freshrss</td></tr><tr><th>Reseau</th><td>freshrss\_default</td></tr><tr><th>URL</th><td>[https://freshrss.juxjux.ovh](https://freshrss.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/FreshRSS/FreshRSS](https://github.com/FreshRSS/FreshRSS)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip80818"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8081</td><td>80/tcp</td><td>0.0.0.0</td></tr><tr><td>8081</td><td>80/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/freshrss/data`</td><td>`/var/www/FreshRSS/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__freshrss__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_freshrss.py | Auth : GReader API avec mot de passe API dédié (≠ mot de passe web)</td></tr></tbody></table>

### Outils disponibles

- `get_feeds`
- `get_categories`
- `get_articles`
- `get_unread_count`
- `get_starred_articles`
- `mark_as_read`
- `mark_feed_as_read`
- `star_article`
- `search_articles`
- `add_feed`
- `delete_feed`

### Ce que nous pouvons faire ensemble

- Lire les derniers articles de tous les flux RSS
- Rechercher des articles par mots-clés dans toute la veille
- Marquer des articles comme lus ou les étoiler
- Ajouter ou supprimer des flux
- Faire une synthèse de veille thématique à partir des non-lus

# 11_Gitea

## gitea

*Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package registry and CI/CD*

<table id="bkmrk-imagegitea%2Fgitea%3Alat"><tbody><tr><th>Image</th><td>`gitea/gitea:latest`</td></tr><tr><th>Version</th><td>1.25.4</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>gitea</td></tr><tr><th>Reseau</th><td>gitea\_default</td></tr><tr><th>URL</th><td>[https://gitea.juxjux.ovh](https://gitea.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/go-gitea/gitea](https://github.com/go-gitea/gitea)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip22222"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>2222</td><td>2222/tcp</td><td>0.0.0.0</td></tr><tr><td>2222</td><td>2222/tcp</td><td>::</td></tr><tr><td>3005</td><td>3000/tcp</td><td>0.0.0.0</td></tr><tr><td>3005</td><td>3000/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/lib/gitea_data`</td><td>`/data`</td><td>bind</td><td>rw</td></tr><tr><td>`/etc/localtime`</td><td>`/etc/localtime`</td><td>bind</td><td>ro</td></tr><tr><td>`/etc/timezone`</td><td>`/etc/timezone`</td><td>bind</td><td>ro</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>API REST Gitea complète disponible sur /api/v1. Auth : token Bearer ou Basic Auth. Pas de MCP configuré — appels directs via PowerShell/Python.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Lister repositories, branches, commits via l'API REST
- Lire/écrire des fichiers dans les repos (contenu base64)
- Gérer issues, pull requests, tags et releases
- Automatiser des workflows de versionning depuis Claude Code

# 12_Grafana

## grafana

| | |
|---|---|
| **Image** | `grafana/grafana:latest` |
| **Etat** | Up 5 days (healthy) |
| **Compose project** | gemini_grafana (stack ID 63) |
| **Réseau** | gemini_grafana_monitor_net |
| **URL** | https://grafana.juxjux.ovh |
| **Source** | https://github.com/grafana/grafana |

### Ports

| Hote | Container | IP |
|---|---|---|
| 3000 | 3000/tcp | 0.0.0.0 |
| 3000 | 3000/tcp | :: |

### Volumes

| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
| `/opt/monitoring/grafana_data` | `/var/lib/grafana` | bind | rw |

---

## Intégration Claude Code — API directe

| | |
|---|---|
| **Statut MCP** | Pas de MCP — API directe possible |
| **Note technique** | API REST Grafana sur /api. Auth : clé API ou Basic Admin. Pas de MCP configuré — appels directs possibles. |

### Ce que nous pouvons faire ensemble

- Lister les dashboards et leur état
- Interroger des datasources Prometheus via l'API (PromQL)
- Créer ou modifier des annotations sur les graphiques
- Exporter des dashboards en JSON pour sauvegarde/versioning

---

## Compte rendu — 2026-06-11

Vérification via Portainer MCP (endpoint 3) + Prometheus PromQL (localhost:9090).

### Métriques VPS globales

| Métrique | Valeur | |
|---|---|---|
| **RAM** | 8.4 / 11.41 GB | 73.6% |
| **Swap** | 3.99 / 4.0 GB | quasi plein |
| **CPU** | 5.2% | — |

### Stack gemini_grafana — 4 containers, tous running (5 jours)

| Container | Image | Etat | Healthcheck | Port exposé |
|---|---|---|---|---|
| grafana | grafana/grafana:latest | running | healthy | 3000 |
| prometheus | prom/prometheus:latest | running | — | 9090 |
| node-exporter | prom/node-exporter:latest | running | — | 9100 |
| cadvisor | gcr.io/cadvisor/cadvisor:latest | running | healthy | 8080 (interne) |

### Notes

- Stack ID Portainer : 63 — compose sur `/data/compose/63/docker-compose.yml`
- Config Prometheus : `/opt/monitoring/prometheus.yml` | Data : `/opt/monitoring/prometheus_data`
- `--web.enable-lifecycle` actif sur Prometheus (reload API disponible sur `:9090/-/reload`)
- cadvisor port 8080 non exposé publiquement (aucun mapping IP externe)
- **grafana.juxjux.ovh** : DNS non résolu depuis l'extérieur — pas de vhost nginx configuré, accès direct via port 3000
- Ports 3000, 9090, 9100 exposés sur `0.0.0.0` — à vérifier dans ufw

# 13_Immich

## Immich-SERVER

*High performance self-hosted photo and video management solution.*

<table id="bkmrk-imageghcr.io%2Fimmich-"><tbody><tr><th>Image</th><td>`ghcr.io/immich-app/immich-server:release`</td></tr><tr><th>Version</th><td>v2.7.5</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>immich</td></tr><tr><th>Reseau</th><td>immich\_immich-network</td></tr><tr><th>URL</th><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/immich-app/immich](https://github.com/immich-app/immich)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip-8212"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8212</td><td>2283/tcp</td><td>0.0.0.0</td></tr><tr><td>8212</td><td>2283/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/immich/upload`</td><td>`/data`</td><td>bind</td><td>rw</td></tr><tr><td>`/etc/localtime`</td><td>`/etc/localtime`</td><td>bind</td><td>ro</td></tr><tr><td>`/home/debian/docker/immich/upload/encoded-video`</td><td>`/mnt/media/encoded-video`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/photo`</td><td>`/mnt/media/photo`</td><td>bind</td><td>ro,shared</td></tr></tbody></table>

---

## Immich-MICROSERVICES

*High performance self-hosted photo and video management solution.*

<table id="bkmrk-imageghcr.io%2Fimmich--1"><tbody><tr><th>Image</th><td>`ghcr.io/immich-app/immich-server:release`</td></tr><tr><th>Version</th><td>v2.7.5</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>immich</td></tr><tr><th>Reseau</th><td>immich\_immich-network</td></tr><tr><th>URL</th><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/immich-app/immich](https://github.com/immich-app/immich)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-1"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/immich/upload`</td><td>`/data`</td><td>bind</td><td>rw</td></tr><tr><td>`/etc/localtime`</td><td>`/etc/localtime`</td><td>bind</td><td>ro</td></tr><tr><td>`/home/debian/docker/immich/upload/encoded-video`</td><td>`/mnt/media/encoded-video`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/photo`</td><td>`/mnt/media/photo`</td><td>bind</td><td>ro,shared</td></tr></tbody></table>

---

## Immich-LEARNING

*High performance self-hosted photo and video management solution.*

<table id="bkmrk-imageghcr.io%2Fimmich--2"><tbody><tr><th>Image</th><td>`ghcr.io/immich-app/immich-machine-learning:release`</td></tr><tr><th>Version</th><td>v2.7.5</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>immich</td></tr><tr><th>Reseau</th><td>immich\_immich-network</td></tr><tr><th>URL</th><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/immich-app/immich](https://github.com/immich-app/immich)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-2"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/immich/cache`</td><td>`/cache`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Immich-REDIS

<table id="bkmrk-imageredis%3A6.2-alpin"><tbody><tr><th>Image</th><td>`redis:6.2-alpine`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>immich</td></tr><tr><th>Reseau</th><td>immich\_immich-network</td></tr><tr><th>URL</th><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-3"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td> </td><td>`/data`</td><td>volume</td><td>rw</td></tr></tbody></table>

---

## Immich-DB

*Base images for Immich containers*

<table id="bkmrk-imageghcr.io%2Fimmich--3"><tbody><tr><th>Image</th><td>`ghcr.io/immich-app/postgres:16-vectorchord0.3.0-pgvectors0.2.0`</td></tr><tr><th>Version</th><td>16-vectorchord0.3.0-pgvector0.8.1-pgvectors0.2.0</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>immich</td></tr><tr><th>Reseau</th><td>immich\_immich-network</td></tr><tr><th>URL</th><td>[https://immich.juxjux.ovh](https://immich.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/immich-app/base-images](https://github.com/immich-app/base-images)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-4"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/immich/db`</td><td>`/var/lib/postgresql/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actif-"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__immich__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_immich.py | Auth : JWT via POST /api/auth/login</td></tr></tbody></table>

### Outils disponibles

- `get_assets`
- `get_asset`
- `search_assets`
- `update_asset`
- `get_albums`
- `get_album`
- `create_album`
- `get_people`
- `get_person_assets`
- `get_memories`
- `get_statistics`
- `get_my_user`
- `get_server_info`

### Ce que nous pouvons faire ensemble

- Rechercher des photos par date, lieu, contenu ou personne reconnue
- Parcourir les albums et les souvenirs générés automatiquement
- Consulter les statistiques de la photothèque (nb photos, vidéos, taille)
- Créer un album et y regrouper des assets
- Mettre à jour les métadonnées d'un asset (description, date, lieu)

---

## Sauvegarde de la base de données

Sauvegarde automatique quotidienne de la base PostgreSQL `Immich-DB` vers kDrive Infomaniak. Mise en place le 2026-06-01.

### Paramètres

<table id="bkmrk-script%2Fopt%2Fbackups%2Fv"><tbody><tr><th>Script</th><td>`/opt/backups/vps_backup.sh`</td></tr><tr><th>Cron</th><td>Tous les jours à 2h du matin (`0 2 * * *`)</td></tr><tr><th>Container DB</th><td>`Immich-DB` (PostgreSQL 16)</td></tr><tr><th>Commande</th><td>`pg_dump -U postgres`</td></tr><tr><th>Taille base (disque)</th><td>~7.5 Mo (métadonnées uniquement — photos sur volume séparé)</td></tr><tr><th>Format archive</th><td>.7z (compression niveau 5)</td></tr><tr><th>Destination</th><td>kDrive Infomaniak — `TOOJUX/jux_vps/immich` (dossier ID 1427919)</td></tr><tr><th>Rétention</th><td>7 jours glissants</td></tr><tr><th>Nommage fichier</th><td>`immich_db_YYYY-MM-DD.7z`</td></tr></tbody></table>

### Note importante

Cette sauvegarde couvre uniquement les métadonnées (albums, faces, tags, utilisateurs). Les fichiers photos/vidéos sont stockés dans `/home/debian/docker/immich/upload` et `/home/debian/photo` — ils ne sont pas inclus dans ce backup.

---

## REX — 2026-06-21 — FUSE cassé après restart rclone-photo

### Symptôme

Immich connecté mais aucune photo visible. Logs Immich-SERVER :

```
WARN [Microservices:LibraryService] Skipping invalid import path: /mnt/media/photo. Reason: Error: ENOTCONN: socket is not connected, stat '/mnt/media/photo'
```

### Cause

Le service `rclone-photo.service` a redémarré le 2026-06-18 (suite à l'incident sécurité du 2026-06-09 — fix `--rc-addr 127.0.0.1`). Les containers `Immich-SERVER` et `Immich-MICROSERVICES`, démarrés avant ce restart, conservent un file descriptor FUSE invalide. La propagation `:shared` aide pour les *nouveaux* montages mais ne restaure pas un fd FUSE mort.

### Fix immédiat

```
docker restart Immich-SERVER Immich-MICROSERVICES
# puis déclencher un scan de bibliothèque :
curl -s -X POST "https://immich.juxjux.ovh/api/libraries/89bfcdc1-1604-47a1-90a3-975d2f6c4639/scan" \
  -H "Authorization: Bearer TOKEN"
# TOKEN obtenu via POST /api/auth/login (bertrand.dadone@gmail.com / 27101809)
```

### Fix structurel — ExecStartPost dans rclone-photo.service (2026-06-21)

Ajout d'un `ExecStartPost` dans `/etc/systemd/system/rclone-photo.service` : à chaque redémarrage de rclone-photo, les containers Immich sont automatiquement relancés si et seulement s'ils tournent déjà (pas de blocage au boot).

```
ExecStartPost=/bin/bash -c 'sleep 3; docker ps --filter name=Immich-SERVER --filter status=running -q | grep -q . && docker restart Immich-SERVER Immich-MICROSERVICES || true'
```

Rechargement : `sudo systemctl daemon-reload` (pas de restart du service nécessaire — prendra effet au prochain redémarrage de rclone-photo).

### Library ID Immich

`89bfcdc1-1604-47a1-90a3-975d2f6c4639`

---

### Inventaire par Claude le 251001

# 14_Jellyfin

## jellyfin

*The Free Software Media System*

<table id="bkmrk-imagejellyfin%2Fjellyf"><tbody><tr><th>Image</th><td>`jellyfin/jellyfin:latest`</td></tr><tr><th>Version</th><td>10.10.7</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>jellyfin</td></tr><tr><th>Reseau</th><td>host</td></tr><tr><th>URL</th><td>[https://jellyfin.juxjux.ovh](https://jellyfin.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/jellyfin/jellyfin-packaging](https://github.com/jellyfin/jellyfin-packaging)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/mnt/nas_videos/movies`</td><td>`/data/movies`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/palettes`</td><td>`/data/palettes`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/jellyfin/config`</td><td>`/config`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/cinema_europe`</td><td>`/data/cinema_europe`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/cinema_UK`</td><td>`/data/cinema_uk`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/spectacles`</td><td>`/data/spectacles`</td><td>bind</td><td>rw</td></tr><tr><td>``</td><td>`/cache`</td><td>volume</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/animes`</td><td>`/data/animes`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/cinema_asie`</td><td>`/data/cinema_asie`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/cinema_realisateurs`</td><td>`/data/cinema_realisateurs`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/fantastique_et_SF`</td><td>`/data/fantastique_et_SF`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/historiques`</td><td>`/data/historiques`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/series`</td><td>`/data/series`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/cinema_italie`</td><td>`/data/cinema_italie`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/culture_cuisine`</td><td>`/data/culture_cuisine`</td><td>bind</td><td>rw</td></tr><tr><td>`/mnt/nas_videos/documentaires`</td><td>`/data/documentaires`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__jellyfin__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_jellyfin.py | Auth : JWT MediaBrowser Token via POST /Users/AuthenticateByName</td></tr></tbody></table>

### Outils disponibles

- `get_libraries`
- `get_items`
- `get_item`
- `get_recently_added`
- `get_resume_items`
- `get_sessions`
- `get_users`
- `get_server_info`
- `scan_library`
- `search_items`

### Ce que nous pouvons faire ensemble

- Parcourir films, séries et musiques de la médiathèque
- Voir les ajouts récents et les éléments en cours de lecture
- Surveiller les sessions actives (qui lit quoi en ce moment)
- Déclencher un scan de bibliothèque après ajout de contenu
- Rechercher un titre dans toute la médiathèque

# 15_Joplin

## joplin\_to\_obsidian

<table id="bkmrk-imagejoplin_to_obsid"><tbody><tr><th>Image</th><td>`joplin_to_obsidian-joplin_to_obsidian`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>joplin\_to\_obsidian</td></tr><tr><th>Reseau</th><td>joplin\_joplin\_network</td></tr><tr><th>URL</th><td>[https://joplin.juxjux.ovh](https://joplin.juxjux.ovh)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/Documents/Joplin_Obsidian`</td><td>`/home/debian/Documents/Joplin_Obsidian`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## joplin-nginx

<table id="bkmrk-imagenginx%3Aalpineeta"><tbody><tr><th>Image</th><td>`nginx:alpine`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>joplin</td></tr><tr><th>Reseau</th><td>joplin\_joplin\_network</td></tr><tr><th>URL</th><td>[https://joplin.juxjux.ovh](https://joplin.juxjux.ovh)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip22301"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>22301</td><td>80/tcp</td><td>0.0.0.0</td></tr><tr><td>22301</td><td>80/tcp</td><td>::</td></tr></tbody></table>

---

## joplin

*Docker image for Joplin Server*

<table id="bkmrk-imagejoplin%2Fserver%3Al"><tbody><tr><th>Image</th><td>`joplin/server:latest`</td></tr><tr><th>Version</th><td>3.4.3</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>joplin</td></tr><tr><th>Reseau</th><td>joplin\_joplin\_network</td></tr><tr><th>URL</th><td>[https://joplin.juxjux.ovh](https://joplin.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/laurent22/joplin.git](https://github.com/laurent22/joplin.git)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip22300"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>22300</td><td>22300/tcp</td><td>0.0.0.0</td></tr><tr><td>22300</td><td>22300/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-1"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/joplin-data`</td><td>`/home/joplin/.config/joplin`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## joplin-db

<table id="bkmrk-imagepostgres%3A15-alp"><tbody><tr><th>Image</th><td>`postgres:15-alpine`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>joplin</td></tr><tr><th>Reseau</th><td>joplin\_joplin\_network</td></tr><tr><th>URL</th><td>[https://joplin.juxjux.ovh](https://joplin.juxjux.ovh)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-2"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/joplin-db-data`</td><td>`/var/lib/postgresql/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:#FFA500;">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>Le container Joplin est un serveur de synchronisation (sync server), pas un serveur de notes interrogeable. Pas d'API de lecture du contenu. Le container joplin\_to\_obsidian est un script de migration ponctuelle vers Obsidian.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Synchronisation des notes entre appareils (via le client Joplin)
- Migration Joplin → Obsidian via le script joplin\_to\_obsidian (ponctuel)

---

## Sauvegarde de la base de données

Sauvegarde automatique quotidienne de la base PostgreSQL `joplin-db` vers kDrive Infomaniak. Mise en place le 2026-06-01.

### Paramètres

<table id="bkmrk-script%2Fopt%2Fbackups%2Fv"><tbody><tr><th>Script</th><td>`/opt/backups/vps_backup.sh`</td></tr><tr><th>Cron</th><td>Tous les jours à 2h du matin (`0 2 * * *`)</td></tr><tr><th>Container DB</th><td>`joplin-db` (PostgreSQL 15)</td></tr><tr><th>Commande</th><td>`pg_dump -U joplin -d joplin`</td></tr><tr><th>Taille base (disque)</th><td>~1.4 Go (notes + pièces jointes stockées en BLOB)</td></tr><tr><th>Format archive</th><td>.7z (compression niveau 5)</td></tr><tr><th>Destination</th><td>kDrive Infomaniak — `TOOJUX/jux_vps/joplin` (dossier ID 1427920)</td></tr><tr><th>Rétention</th><td>7 jours glissants</td></tr><tr><th>Nommage fichier</th><td>`joplin_db_YYYY-MM-DD.7z`</td></tr></tbody></table>

### Note

La base est volumineuse (~1.4 Go) car Joplin stocke toutes les pièces jointes en BLOB dans PostgreSQL. L'archive compressée pèse ~500 Mo à 1 Go. Quota kDrive consommé : ~3.5 à 7 Go pour 7 jours.

---

## Observatoire Joplin-Compression

*Mis ? jour le 14/06/2026 12:50 ? dernier run compression : 2026-06-14T10:47*

### Bilan global

<table id="bkmrk-ressources-totales-%28"><tbody><tr><th>Ressources totales (actuelles)</th><td>736 fichiers</td></tr><tr><th>Poids total actuel</th><td>**119.7 Mo**</td></tr><tr><th>Ressources compress?es</th><td>424</td></tr><tr><th>Poids avant compression</th><td>451.5 Mo</td></tr><tr><th>?conomie r?alis?e</th><td><span style="color:#008000;">**356.3 Mo (-78.9%)**</span></td></tr><tr><th>Ignor?es (gain insuffisant)</th><td>212</td></tr><tr><th>Erreurs</th><td>0</td></tr></tbody></table>

### Top 15 ressources les plus lourdes (?tat actuel)

<table id="bkmrk-%23idformattaille-actu"><thead><tr><th>\#</th><th>ID</th><th>Format</th><th>Taille actuelle</th><th>Gain compression</th></tr></thead><tbody><tr><td>1</td><td>`vVO2ePdMvtty3sXZy5nY6M`</td><td>?</td><td>3146 KB</td><td></td></tr><tr><td>2</td><td>`0xh87pWrRt82z0DbO9n3yQ`</td><td>ZIP</td><td>2250 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>3</td><td>`VasIoF2e9EGuNQt38aOFMx`</td><td>JPEG</td><td>1633 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>4</td><td>`TzWK21r4n0yvbEtJh02DGB`</td><td>JPEG</td><td>1529 KB</td><td><span style="color:#008000;">-63%</span></td></tr><tr><td>5</td><td>`M0C32hKC2hMqPAxpRGiVgp`</td><td>JPEG</td><td>937 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>6</td><td>`Hn6z6lvvbJzRsX0KGM8FNW`</td><td>JPEG</td><td>928 KB</td><td><span style="color:#008000;">-53%</span></td></tr><tr><td>7</td><td>`7EyAL9NNysJzWke6NT4ttJ`</td><td>JPEG</td><td>803 KB</td><td><span style="color:#008000;">-76%</span></td></tr><tr><td>8</td><td>`bz9Twmb2F5lj0mPIQi48IB`</td><td>JPEG</td><td>798 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>9</td><td>`UbAqQY3cEbH62vioIHU6Pj`</td><td>JPEG</td><td>776 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>10</td><td>`SrJi1UyeNGf8OhaRsaOCGq`</td><td>JPEG</td><td>745 KB</td><td><span style="color:#008000;">-79%</span></td></tr><tr><td>11</td><td>`87mV49tXupZcpt2wplcGjU`</td><td>JPEG</td><td>685 KB</td><td><span style="color:#008000;">-59%</span></td></tr><tr><td>12</td><td>`JsJFO6dIzqMKLA7clqW8nG`</td><td>JPEG</td><td>683 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>13</td><td>`VSyNmO0uN1fNNeqN6XZucO`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-19%</span></td></tr><tr><td>14</td><td>`hExoJEEWT2tHz1demE5Nhm`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-84%</span></td></tr><tr><td>15</td><td>`slTzAxAQ4xi0pMvzsLIDez`</td><td>?</td><td>670 KB</td><td></td></tr></tbody></table>

---

## Observatoire Joplin-Compression

*Mis ? jour le 15/06/2026 03:00 ? dernier run compression : 2026-06-15T03:00*

### Bilan global

<table id="bkmrk-ressources-totales-%28-1"><tbody><tr><th>Ressources totales (actuelles)</th><td>736 fichiers</td></tr><tr><th>Poids total actuel</th><td>**119.9 Mo**</td></tr><tr><th>Ressources compress?es</th><td>425</td></tr><tr><th>Poids avant compression</th><td>452.0 Mo</td></tr><tr><th>?conomie r?alis?e</th><td><span style="color:#008000;">**356.4 Mo (-78.8%)**</span></td></tr><tr><th>Ignor?es (gain insuffisant)</th><td>212</td></tr><tr><th>Erreurs</th><td>0</td></tr></tbody></table>

### Top 15 ressources les plus lourdes (?tat actuel)

<table id="bkmrk-%23idformattaille-actu-1"><thead><tr><th>\#</th><th>ID</th><th>Format</th><th>Taille actuelle</th><th>Gain compression</th></tr></thead><tbody><tr><td>1</td><td>`vVO2ePdMvtty3sXZy5nY6M`</td><td>?</td><td>3146 KB</td><td></td></tr><tr><td>2</td><td>`0xh87pWrRt82z0DbO9n3yQ`</td><td>ZIP</td><td>2250 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>3</td><td>`VasIoF2e9EGuNQt38aOFMx`</td><td>JPEG</td><td>1633 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>4</td><td>`TzWK21r4n0yvbEtJh02DGB`</td><td>JPEG</td><td>1529 KB</td><td><span style="color:#008000;">-63%</span></td></tr><tr><td>5</td><td>`M0C32hKC2hMqPAxpRGiVgp`</td><td>JPEG</td><td>937 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>6</td><td>`Hn6z6lvvbJzRsX0KGM8FNW`</td><td>JPEG</td><td>928 KB</td><td><span style="color:#008000;">-53%</span></td></tr><tr><td>7</td><td>`7EyAL9NNysJzWke6NT4ttJ`</td><td>JPEG</td><td>803 KB</td><td><span style="color:#008000;">-76%</span></td></tr><tr><td>8</td><td>`bz9Twmb2F5lj0mPIQi48IB`</td><td>JPEG</td><td>798 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>9</td><td>`UbAqQY3cEbH62vioIHU6Pj`</td><td>JPEG</td><td>776 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>10</td><td>`SrJi1UyeNGf8OhaRsaOCGq`</td><td>JPEG</td><td>745 KB</td><td><span style="color:#008000;">-79%</span></td></tr><tr><td>11</td><td>`87mV49tXupZcpt2wplcGjU`</td><td>JPEG</td><td>685 KB</td><td><span style="color:#008000;">-59%</span></td></tr><tr><td>12</td><td>`JsJFO6dIzqMKLA7clqW8nG`</td><td>JPEG</td><td>683 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>13</td><td>`VSyNmO0uN1fNNeqN6XZucO`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-19%</span></td></tr><tr><td>14</td><td>`hExoJEEWT2tHz1demE5Nhm`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-84%</span></td></tr><tr><td>15</td><td>`slTzAxAQ4xi0pMvzsLIDez`</td><td>?</td><td>670 KB</td><td></td></tr></tbody></table>

---

## Observatoire Joplin-Compression

*Mis ? jour le 16/06/2026 03:00 ? dernier run compression : 2026-06-16T03:00*

### Bilan global

<table id="bkmrk-ressources-totales-%28-2"><tbody><tr><th>Ressources totales (actuelles)</th><td>736 fichiers</td></tr><tr><th>Poids total actuel</th><td>**119.9 Mo**</td></tr><tr><th>Ressources compress?es</th><td>425</td></tr><tr><th>Poids avant compression</th><td>452.0 Mo</td></tr><tr><th>?conomie r?alis?e</th><td><span style="color:#008000;">**356.4 Mo (-78.8%)**</span></td></tr><tr><th>Ignor?es (gain insuffisant)</th><td>212</td></tr><tr><th>Erreurs</th><td>0</td></tr></tbody></table>

### Top 15 ressources les plus lourdes (?tat actuel)

<table id="bkmrk-%23idformattaille-actu-2"><thead><tr><th>\#</th><th>ID</th><th>Format</th><th>Taille actuelle</th><th>Gain compression</th></tr></thead><tbody><tr><td>1</td><td>`vVO2ePdMvtty3sXZy5nY6M`</td><td>?</td><td>3146 KB</td><td></td></tr><tr><td>2</td><td>`0xh87pWrRt82z0DbO9n3yQ`</td><td>ZIP</td><td>2250 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>3</td><td>`VasIoF2e9EGuNQt38aOFMx`</td><td>JPEG</td><td>1633 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>4</td><td>`TzWK21r4n0yvbEtJh02DGB`</td><td>JPEG</td><td>1529 KB</td><td><span style="color:#008000;">-63%</span></td></tr><tr><td>5</td><td>`M0C32hKC2hMqPAxpRGiVgp`</td><td>JPEG</td><td>937 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>6</td><td>`Hn6z6lvvbJzRsX0KGM8FNW`</td><td>JPEG</td><td>928 KB</td><td><span style="color:#008000;">-53%</span></td></tr><tr><td>7</td><td>`7EyAL9NNysJzWke6NT4ttJ`</td><td>JPEG</td><td>803 KB</td><td><span style="color:#008000;">-76%</span></td></tr><tr><td>8</td><td>`bz9Twmb2F5lj0mPIQi48IB`</td><td>JPEG</td><td>798 KB</td><td><span style="color:#008000;">-81%</span></td></tr><tr><td>9</td><td>`UbAqQY3cEbH62vioIHU6Pj`</td><td>JPEG</td><td>776 KB</td><td><span style="color:#008000;">-87%</span></td></tr><tr><td>10</td><td>`SrJi1UyeNGf8OhaRsaOCGq`</td><td>JPEG</td><td>745 KB</td><td><span style="color:#008000;">-79%</span></td></tr><tr><td>11</td><td>`87mV49tXupZcpt2wplcGjU`</td><td>JPEG</td><td>685 KB</td><td><span style="color:#008000;">-59%</span></td></tr><tr><td>12</td><td>`JsJFO6dIzqMKLA7clqW8nG`</td><td>JPEG</td><td>683 KB</td><td><span style="color:#008000;">-66%</span></td></tr><tr><td>13</td><td>`VSyNmO0uN1fNNeqN6XZucO`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-19%</span></td></tr><tr><td>14</td><td>`hExoJEEWT2tHz1demE5Nhm`</td><td>JPEG</td><td>674 KB</td><td><span style="color:#008000;">-84%</span></td></tr><tr><td>15</td><td>`slTzAxAQ4xi0pMvzsLIDez`</td><td>?</td><td>670 KB</td><td></td></tr></tbody></table>

# 16_Kavita

## Kavita

*Kavita is a fast, feature rich, cross platform reading server. Built with the goal of being a full solution for all your reading needs. Setup your own server and share your reading collection with your friends and family.*

| | |
|---|---|
| **Image** | `jvmilazz0/kavita:latest` |
| **Version** | latest |
| **Etat** | Up (healthy) |
| **Compose project** | kavita |
| **Réseau** | kavita_default |
| **URL** | https://kavita.juxjux.ovh |
| **Source** | https://github.com/Kareadita/Kavita |

### Ports

| Hote | Container | IP |
|---|---|---|
| 5471 | 5000/tcp | 0.0.0.0 |

### Volumes

| Source (hote) | Destination | Type | Mode |
|---|---|---|---|
| `/home/debian/docker/kavita/config` | `/kavita/config` | bind | rw |
| `/home/debian/livres` | `/manga` | bind | rw |

---

## Integration Claude Code — MCP

| | |
|---|---|
| **Statut MCP** | MCP actif |
| **Outils (prefix)** | `mcp__kavita__` |
| **Configuration** | Script Python : `C:\Users\eliob\.claude\mcp_kavita.py` \| Auth : JWT via POST /api/Account/login |

### Outils opérationnels (confirmés 2026-06-25)

- `get_libraries` — liste les 53 bibliothèques
- `get_series` — liste les séries (filtre library_id non fonctionnel : retourne toutes les bibliothèques)
- `get_series_detail`
- `get_series_metadata` — retourne genres, auteurs, éditeur, résumé, année
- `get_series_volumes`
- `get_recently_added`
- `get_on_deck` — séries en cours de lecture
- `get_server_stats`
- `search` — recherche full-text sur noms de séries, genres, fichiers, chapitres
- `get_collections` — corrigé 2026-06-25
- `get_reading_lists` — corrigé 2026-06-25
- `get_want_to_read` — corrigé 2026-06-25
- `add_to_want_to_read`
- `remove_from_want_to_read`
- `get_user_stats` — corrigé 2026-06-25
- `get_reading_list`

### Ce que nous pouvons faire ensemble

- Parcourir la bibliothèque par série, volume ou bibliothèque thématique
- Rechercher un titre, auteur ou genre
- Consulter les séries récemment ajoutées ou en cours de lecture
- Gérer la liste "À lire" (ajout/suppression)
- Consulter les collections et listes de lecture
- Appeler l'API directement via PowerShell pour filtrer par genre (`/api/Series/all-v2`)

---

## REX — 2026-06-25

### Statistiques bibliothèque

| Stat | Valeur |
|---|---|
| Bibliothèques | 53 (toutes de type Book/epub+PDF) |
| Séries | 2 976 |
| Fichiers | 5 519 |
| Volumes | 1 173 |
| Taille totale | ~79 Go |
| Auteurs/contributeurs indexés | 3 475 |
| Genres indexés | 6 990 |
| Tags | 0 |

### Étiquettes Calibre → genres Kavita

Les étiquettes appliquées via Calibre sont **visibles dans Kavita sous le champ `genres`**, pas `tags` (qui reste toujours vide, `totalTags: 0`).

Mécanisme : Calibre écrit ses étiquettes dans `<dc:subject>` du fichier epub lors du writeback → Kavita lit ce champ et le mappe en genres.

**Exemple confirmé** — "Il faut s'adapter" (Barbara Stiegler, lib. Actualités, ID série 4210) :
- genres : `Actualités`, `Philosophie`, `Politique`, `2020-2025`

**Conditions pour que ça fonctionne :**
- Le fichier epub doit avoir été re-sauvegardé depuis Calibre après ajout des étiquettes (Préférences > Sauvegarde des métadonnées → writeback activé)
- La bibliothèque Kavita doit avoir `enableMetadata: true` (c'est le cas pour Actualités)
- Les PDFs ne portent généralement pas les métadonnées Calibre → genres vides

La bibliothèque **Actualités** (ID 63) est entièrement étiquetée et correctement indexée.

### Lecture du contenu

Le MCP **ne permet pas de lire le contenu** des livres — uniquement les métadonnées. Kavita expose des endpoints de lecture (`/api/Reader/image`, `/api/Reader/epub-file`) mais non implémentés dans le MCP. Pour les epub, la lecture via appel API direct + parsing HTML serait techniquement faisable au cas par cas.

### Corrections endpoints MCP (2026-06-25)

4 outils retournaient 404 suite à des changements d'API dans la version Kavita en production. Corrections appliquées dans `mcp_kavita.py` :

| Outil | Ancien endpoint (404) | Nouveau endpoint (200) |
|---|---|---|
| `get_collections` | `GET /api/Collection/list` | `GET /api/Collection` |
| `get_reading_lists` | `GET /api/ReadingList/lists?includePromoted=true` | `POST /api/ReadingList/lists` body `{}` |
| `get_want_to_read` | `POST /api/Want-To-Read/get-list` | `POST /api/Want-To-Read` |
| `get_user_stats` | `GET /api/Stats/user/0/read` | `GET /api/Stats/user-stats?userId={id}` |

Note : le `userId` est désormais extrait dynamiquement du payload de login (`data["id"]`) et stocké dans `_user_id`.

### Limitations MCP identifiées

- Le paramètre `library_id` de `get_series` ne filtre pas : retourne toutes les bibliothèques triées alphabétiquement
- Pour filtrer par genre, utiliser l'API directe : `POST /api/Series/all-v2` avec filtre JSON (hors MCP, via PowerShell)

### Problème pipeline Calibre → Kavita — À résoudre

**Constat (2026-06-25)** : les fichiers enrichis par Calibre (avec étiquettes + métadonnées ISBN) ne remplacent pas les fichiers originaux dans le dossier Kavita. Kavita lit depuis le dossier source original (`/manga` = kDrive `Sync_NAS-Maison/Foxy`) qui contient les fichiers **sans métadonnées**.

Calibre, en mode par défaut, **copie** les fichiers dans sa propre arborescence et les enrichit là — les originaux restent intacts. Résultat : 98% des fichiers ont des métadonnées correctes dans Calibre, mais Kavita voit des genres vides.

**Questions ouvertes à clarifier :**
- Où est la bibliothèque Calibre (Windows, NAS Maison, autre) ?
- Le dossier source Kavita et le dossier d'import Calibre sont-ils le même, ou séparés ?
- Calibre est-il en mode copie (défaut) ou lien vers fichier original ?

**Piste de solution** : exporter les fichiers enrichis depuis la bibliothèque Calibre vers le dossier source Kavita (via "Enregistrer sur le disque" dans Calibre), en remplacement des originaux. Peut s'automatiser. À instruire.

# 17_Komga

## komga

<table id="bkmrk-imagegotson%2Fkomgaver"><tbody><tr><th>Image</th><td>`gotson/komga`</td></tr><tr><th>Version</th><td>24.10</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>komga</td></tr><tr><th>Reseau</th><td>komga\_default</td></tr><tr><th>URL</th><td>[https://komga.juxjux.ovh](https://komga.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/gotson/komga](https://github.com/gotson/komga)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip25600"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>25600</td><td>25600/tcp</td><td>0.0.0.0</td></tr><tr><td>25600</td><td>25600/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/komga/config`</td><td>`/config`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/komga`</td><td>`/data`</td><td>bind</td><td>rw</td></tr><tr><td>`/etc/timezone`</td><td>`/etc/timezone`</td><td>bind</td><td>ro</td></tr><tr><td>``</td><td>`/tmp`</td><td>volume</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__komga__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_komga.py | Auth : Basic Auth (Base64 login:password)</td></tr></tbody></table>

### Outils disponibles

- `get_libraries`
- `get_series`
- `get_series_detail`
- `get_series_books`
- `get_book`
- `get_book_metadata`
- `get_books`
- `get_latest_books`
- `get_new_series`
- `get_updated_series`
- `get_on_deck`
- `get_read_lists`
- `get_read_list`
- `get_collections`
- `get_collection`
- `search`
- `mark_series_read`
- `update_book_progress`
- `get_recently_added`

### Ce que nous pouvons faire ensemble

- Parcourir la bibliothèque comics/manga par série et tome
- Voir les dernières acquisitions et séries mises à jour
- Marquer une série comme lue ou mettre à jour la progression
- Gérer les listes de lecture et collections
- Rechercher dans toute la bibliothèque

# 18_Mealie

## mealie

*Mealie is a self hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the url and mealie will automatically import the relevant data or add a family recipe with the UI editor*

<table id="bkmrk-imageghcr.io%2Fmealie-"><tbody><tr><th>Image</th><td>`ghcr.io/mealie-recipes/mealie:latest`</td></tr><tr><th>Version</th><td>v3.16.0</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>mealie2</td></tr><tr><th>Reseau</th><td>mealie2\_default</td></tr><tr><th>URL</th><td>[https://mealie.juxjux.ovh](https://mealie.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/mealie-recipes/mealie](https://github.com/mealie-recipes/mealie)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip99259"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>9925</td><td>9000/tcp</td><td>0.0.0.0</td></tr><tr><td>9925</td><td>9000/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/docker/mealie/backups`</td><td>`/app/backups`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/mealie/config`</td><td>`/app/config`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/mealie/data`</td><td>`/app/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__mealie__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_mealie.py | Auth : OAuth2 Bearer Token via POST /api/auth/token</td></tr></tbody></table>

### Outils disponibles

- `get_recipes`
- `get_recipe`
- `create_recipe`
- `create_recipe_from_url`
- `delete_recipe`
- `get_categories`
- `get_tags`
- `get_cookbooks`
- `get_cookbook`
- `get_meal_plan`
- `add_meal_plan_entry`
- `get_shopping_lists`
- `get_shopping_list`
- `add_shopping_item`

### Ce que nous pouvons faire ensemble

- Parcourir et rechercher des recettes par catégorie ou tag
- Importer automatiquement une recette depuis une URL
- Planifier les repas de la semaine
- Gérer les listes de courses (ajout d'ingrédients)
- Créer une recette depuis une description ou un texte fourni

---

## Sauvegarde de la base de données

Sauvegarde automatique quotidienne de la base SQLite de Mealie vers kDrive Infomaniak. Mise en place le 2026-06-01.

### Paramètres

<table id="bkmrk-script%2Fopt%2Fbackups%2Fv"><tbody><tr><th>Script</th><td>`/opt/backups/vps_backup.sh`</td></tr><tr><th>Cron</th><td>Tous les jours à 2h du matin (`0 2 * * *`)</td></tr><tr><th>Type base</th><td>SQLite — `/app/data/mealie.db` (dans le container)</td></tr><tr><th>Méthode</th><td>`docker cp mealie:/app/data/mealie.db`</td></tr><tr><th>Taille base</th><td>~2.9 Mo</td></tr><tr><th>Format archive</th><td>.7z (compression niveau 5)</td></tr><tr><th>Destination</th><td>kDrive Infomaniak — `TOOJUX/jux_vps/mealie` (dossier ID 1427921)</td></tr><tr><th>Rétention</th><td>7 jours glissants</td></tr><tr><th>Nommage fichier</th><td>`mealie_db_YYYY-MM-DD.7z`</td></tr></tbody></table>

# 19_Navidrome

## navidrome-navidrome-1

*🎧 Your Personal Streaming Service*

<table id="bkmrk-imagedeluan%2Fnavidrom"><tbody><tr><th>Image</th><td>`deluan/navidrome:latest`</td></tr><tr><th>Version</th><td>0.61.2</td></tr><tr><th>Etat</th><td><span style="color: #008000;">Up</span></td></tr><tr><th>Compose project</th><td>navidrome</td></tr><tr><th>Reseau</th><td>navidrome\_default</td></tr><tr><th>URL</th><td>[https://navidrome.juxjux.ovh](https://navidrome.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/navidrome/navidrome](https://github.com/navidrome/navidrome)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip45334"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>4533</td><td>4533/tcp</td><td>0.0.0.0</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/music`</td><td>`/music`</td><td>bind</td><td>rw, :shared</td></tr><tr><td>`/home/debian/docker/navidrome/data`</td><td>`/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color: #008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__navidrome__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_navidrome.py | Auth : Subsonic API avec hachage MD5 (user + token + sel)</td></tr></tbody></table>

### Outils disponibles

- `ping`
- `get_artists`
- `get_artist`
- `get_albums`
- `get_album`
- `get_song`
- `get_genres`
- `get_random_songs`
- `get_playlists`
- `get_playlist`
- `create_playlist`
- `get_starred`
- `star`
- `unstar`
- `search`
- `get_now_playing`

### Ce que nous pouvons faire ensemble

- Parcourir artistes, albums et pistes de la médiathèque musicale
- Rechercher un titre, artiste ou album
- Voir ce qui est en cours de lecture (now playing)
- Gérer les playlists (création, lecture)
- Étoiler/désigner des favoris
- Générer une sélection aléatoire par genre

---

## Scans automatiques

Trois mécanismes automatiques assurent la fraîcheur de la bibliothèque :

<table id="bkmrk-cronscripttyper%C3%B4le-%2A"><thead><tr><th>Cron</th><th>Script</th><th>Type</th><th>Rôle</th></tr></thead><tbody><tr><td>`*/5 * * * *`</td><td>`/home/debian/monitor-rclone.sh`</td><td>Watchdog</td><td>Détecte FUSE mort → restart service + restart container (recovery auto)</td></tr><tr><td>`30 4 * * *`</td><td>`/home/debian/navidrome_scan.sh`</td><td>Quick scan</td><td>vfs/refresh + scan quotidien (MAJ des titres existants)</td></tr><tr><td>`0 3 * * 1`</td><td>`/home/debian/navidrome_fullscan.sh`</td><td>Full scan</td><td>vfs/refresh + restart container → full scan hebdomadaire (détecte nouveaux albums/artistes)</td></tr></tbody></table>

Log commun : `/var/log/navidrome_scan.log`

### Quick scan vs Full scan

Le **quick scan** (`startScan` via API Subsonic) ne traverse que les dossiers déjà connus de Navidrome — il ne détecte pas les nouveaux artistes ou albums ajoutés sur kDrive. Seul un **full scan** indexe les nouveaux dossiers.

Le full scan est déclenché automatiquement au démarrage du container. C'est pourquoi `navidrome_fullscan.sh` fait un restart container plutôt qu'un simple appel API.

### Auth RC sur kdrive-music.service

Depuis rclone 1.74.3, `vfs/refresh` exige une authentification RC. Le service `kdrive-music.service` a été mis à jour le 2026-06-24 avec `--rc-user=rcadmin --rc-pass=RcMusic2026!`.

Commande de refresh manuel :

```
rclone rc --rc-addr 127.0.0.1:5576 --rc-user=rcadmin --rc-pass=RcMusic2026! vfs/refresh recursive=true
```

---

## REX — 2026-06-24 : FUSE mort récurrent

### Contexte

Le FUSE `/music` est mort en cours de journée. Symptôme Navidrome : `stat /music: transport endpoint is not connected` lors du scan.

### Cause

Le service `kdrive-music.service` peut rester `active (running)` avec un FUSE mort — le process rclone est vivant mais la connexion noyau FUSE est cassée. Systemd ne détecte pas ce cas et ne redémarre pas le service.

### Solution mise en place

Refactorisation de `monitor-rclone.sh` pour utiliser `systemctl restart` (au lieu d'un `rclone mount` direct) et redémarrer les containers Docker après remontage. Le watchdog tourne toutes les 5 minutes — la panne est détectée et corrigée automatiquement sans intervention.

### Procédure manuelle si besoin

```
sudo systemctl restart kdrive-music.service
ls /home/debian/music | head -5
sudo docker restart navidrome-navidrome-1
```

Puis force-fermer Symfonium et relancer — le token de session Navidrome est invalidé après le restart du container.

---

## REX — 2026-06-24 : nouveaux albums non détectés

### Contexte

Les Négresses Vertes (et d'autres albums récemment ajoutés sur kDrive) n'apparaissaient pas dans Navidrome malgré le cron quotidien.

### Cause

Double problème :

1. **Cache VFS 72h** : `--dir-cache-time 72h` sur `kdrive-music.service` — les nouveaux dossiers kDrive ne sont pas visibles dans le mount avant expiration ou `vfs/refresh`.
2. **Quick scan insuffisant** : le scan quotidien (`startScan` API) est un quick scan qui ne traverse que les dossiers déjà connus. Il ne détecte pas de nouveaux artistes.

### Solution immédiate

```
rclone rc --rc-addr 127.0.0.1:5576 --rc-user=rcadmin --rc-pass=RcMusic2026! vfs/refresh recursive=true
sudo docker restart navidrome-navidrome-1
```

Le restart container déclenche un full scan au démarrage (~20 min pour 16 000 titres). Vérifier avec `getScanStatus` (`"scanning":false` = terminé).

### Solution pérenne

Full scan hebdomadaire chaque lundi à 3h UTC (`navidrome_fullscan.sh`) — garantit que tout nouvel album ajouté dans la semaine est indexé au plus tard le lundi matin.

---

## REX — 2026-06-13 : FUSE corrompu / Symfonium inaccessible

### Contexte

Après l'incident sécurité rclone du 2026-06-09 (CVE-2026-41179), le service `kdrive-music.service` a été relancé. Il est resté actif 4 jours sans crash apparent, mais le mount FUSE `/home/debian/music` était silencieusement corrompu.

### Symptômes

- Symfonium (Subsonic) : erreur "trop d'erreurs, arrêt de lecture" sur tous les appareils portables
- Logs Navidrome : `transport endpoint is not connected` sur tous les fichiers audio
- `systemctl status kdrive-music.service` : **active (running)** depuis 3 jours — aucune indication du problème

### Cause

Le process rclone était vivant mais la connexion noyau FUSE était morte. Pas de crash = pas de restart automatique par systemd.

### Procédure de résolution

1. Redémarrer le service rclone : `sudo systemctl restart kdrive-music.service`
2. Vérifier que le mount répond : `ls /home/debian/music | head -5`
3. Redémarrer le container Navidrome — nécessaire même avec `:shared`, car le container garde l'ancienne référence FUSE corrompue
4. Sur les appareils : force-fermer Symfonium et relancer

### Notes

- La propagation `:shared` ne suffit pas à propager un nouveau mount FUSE à un container déjà démarré — le container doit être redémarré.
- **Attention spool /tmp** : un restart du service rclone peut créer un fichier `/tmp/rclone-spool*` de plusieurs Go si des fichiers cachés sont marqués "dirty". Préférer `vfs/refresh` (avec auth RC) au restart quand le FUSE n'est pas corrompu.

# 20_NodeExporter

## node-exporter

<table id="bkmrk-imageprom%2Fnode-expor"><tbody><tr><th>Image</th><td>`prom/node-exporter:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>gemini\_grafana</td></tr><tr><th>Reseau</th><td>gemini\_grafana\_monitor\_net</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip91009"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>9100</td><td>9100/tcp</td><td>0.0.0.0</td></tr><tr><td>9100</td><td>9100/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/proc`</td><td>`/host/proc`</td><td>bind</td><td>ro</td></tr><tr><td>`/sys`</td><td>`/host/sys`</td><td>bind</td><td>ro</td></tr><tr><td>`/`</td><td>`/rootfs`</td><td>bind</td><td>ro</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>Exporte des métriques système (CPU, RAM, disque, réseau) au format Prometheus sur /metrics. Pas de MCP. Données consommées par Prometheus puis visualisées dans Grafana.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Métriques système VPS (CPU load, RAM libre, espace disque, I/O)
- Accessible via requêtes PromQL sur Prometheus ou via l'API Grafana

# 21_Prometheus

## prometheus

<table id="bkmrk-imageprom%2Fprometheus"><tbody><tr><th>Image</th><td>`prom/prometheus:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>gemini\_grafana</td></tr><tr><th>Reseau</th><td>gemini\_grafana\_monitor\_net</td></tr><tr><th>Source</th><td>[https://github.com/prometheus/prometheus](https://github.com/prometheus/prometheus)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip90909"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>9090</td><td>9090/tcp</td><td>0.0.0.0</td></tr><tr><td>9090</td><td>9090/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/opt/monitoring/prometheus.yml`</td><td>`/etc/prometheus/prometheus.yml`</td><td>bind</td><td>ro</td></tr><tr><td>`/opt/monitoring/prometheus_data`</td><td>`/prometheus`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>API REST Prometheus sur /api/v1. Requêtes PromQL via /api/v1/query et /api/v1/query\_range. Pas de MCP configuré — appels directs via PowerShell/Python.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Requêtes PromQL pour métriques CPU, RAM, réseau, containers
- Interroger l'historique d'un container ou du système sur une période
- Détecter des anomalies ou pics de consommation
- Lister les targets et leurs états (up/down)

# 22_Readeck

## readeck

<table id="bkmrk-imagecodeberg.org%2Fre"><tbody><tr><th>Image</th><td>`codeberg.org/readeck/readeck:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>readeck</td></tr><tr><th>Reseau</th><td>readeck\_default</td></tr><tr><th>URL</th><td>[https://readeck.juxjux.ovh](https://readeck.juxjux.ovh)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip45678"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>4567</td><td>8000/tcp</td><td>0.0.0.0</td></tr><tr><td>4567</td><td>8000/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/home/debian/readeck/exports`</td><td>`/exports`</td><td>bind</td><td>rw</td></tr><tr><td>``</td><td>`/readeck`</td><td>volume</td><td>rw</td></tr><tr><td>`/home/debian/readeck/data`</td><td>`/readeck/data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:#008000;">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__readeck__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_readeck.py | Auth : token API Bearer (MFA actif sur le compte web)</td></tr></tbody></table>

### Outils disponibles

- `get_bookmarks`
- `get_bookmark`
- `create_bookmark`
- `update_bookmark`
- `delete_bookmark`
- `get_labels`
- `get_profile`

### Ce que nous pouvons faire ensemble

- Sauvegarder un article ou une page web depuis Claude Code
- Parcourir et rechercher les articles enregistrés
- Organiser les bookmarks avec des labels
- Mettre à jour le statut (lu/archivé) d'un article
- Supprimer des bookmarks obsolètes

---

## Sauvegarde de la base de données

Sauvegarde automatique quotidienne de la base SQLite de Readeck vers kDrive Infomaniak. Mise en place le 2026-06-01.

### Paramètres

<table id="bkmrk-script%2Fopt%2Fbackups%2Fv"><tbody><tr><th>Script</th><td>`/opt/backups/vps_backup.sh`</td></tr><tr><th>Cron</th><td>Tous les jours à 2h du matin (`0 2 * * *`)</td></tr><tr><th>Type base</th><td>SQLite — `/readeck/data/db.sqlite3` (dans le container)</td></tr><tr><th>Méthode</th><td>`docker cp readeck:/readeck/data/db.sqlite3`</td></tr><tr><th>Taille base</th><td>~8.5 Mo</td></tr><tr><th>Format archive</th><td>.7z (compression niveau 5)</td></tr><tr><th>Destination</th><td>kDrive Infomaniak — `TOOJUX/jux_vps/readeck` (dossier ID 1427922)</td></tr><tr><th>Rétention</th><td>7 jours glissants</td></tr><tr><th>Nommage fichier</th><td>`readeck_db_YYYY-MM-DD.7z`</td></tr></tbody></table>

### Note

Le volume `/readeck` (non bindé) contient les fichiers des articles (images, HTML). La base SQLite ne couvre que les métadonnées et le texte extrait — les contenus médias ne sont pas inclus dans ce backup.

# 23_Syncthing

## syncthing

<table id="bkmrk-imagesyncthing%2Fsynct"><tbody><tr><th>Image</th><td>`syncthing/syncthing:latest`</td></tr><tr><th>Version</th><td>v2.0.14</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>syncthing</td></tr><tr><th>Reseau</th><td>syncthing\_syncthing\_net</td></tr><tr><th>URL</th><td>[https://syncthing.juxjux.ovh](https://syncthing.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/syncthing/syncthing](https://github.com/syncthing/syncthing)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip21027"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>21027</td><td>21027/udp</td><td>0.0.0.0</td></tr><tr><td>21027</td><td>21027/udp</td><td>::</td></tr><tr><td>22000</td><td>22000/tcp</td><td>0.0.0.0</td></tr><tr><td>22000</td><td>22000/tcp</td><td>::</td></tr><tr><td>22000</td><td>22000/udp</td><td>0.0.0.0</td></tr><tr><td>22000</td><td>22000/udp</td><td>::</td></tr><tr><td>8384</td><td>8384/tcp</td><td>0.0.0.0</td></tr><tr><td>8384</td><td>8384/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>``</td><td>`/var/syncthing`</td><td>volume</td><td>rw</td></tr><tr><td>`/home/debian/Documents`</td><td>`/var/syncthing/Documents`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/Public`</td><td>`/var/syncthing/Public`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/syncthing/config`</td><td>`/var/syncthing/config`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/syncthing/data1`</td><td>`/var/syncthing/data1`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/syncthing/data2`</td><td>`/var/syncthing/data2`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/joplin-data`</td><td>`/var/syncthing/joplin-data`</td><td>bind</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — MCP

<table id="bkmrk-statut-mcpmcp-actifo"><tbody><tr><th>Statut MCP</th><td><span style="color:green">MCP actif</span></td></tr><tr><th>Outils (prefix)</th><td>`mcp__syncthing__`</td></tr><tr><th>Configuration</th><td>Script Python : C:\\Users\\eliob\\.claude\\mcp\_syncthing.py | Auth : clé API dans header X-API-Key</td></tr></tbody></table>

### Outils disponibles

- `ping`
- `get_status`
- `get_version`
- `get_devices`
- `get_device_stats`
- `get_folders`
- `get_folder_status`
- `get_folder_stats`
- `get_folder_errors`
- `get_connections`
- `get_completion`
- `pause_device`
- `resume_device`
- `scan_folder`

### Ce que nous pouvons faire ensemble

- Vérifier l'état de synchronisation de chaque dossier
- Voir la progression de sync entre appareils (PC ↔ VPS)
- Détecter des erreurs de synchronisation
- Déclencher un scan d'un dossier manuellement
- Mettre en pause ou reprendre la sync avec un appareil
- Consulter les statistiques de transfert par device

# 24_Yourls

## yourls

<table id="bkmrk-imageyourls%3Alatestet"><tbody><tr><th>Image</th><td>`yourls:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours</span></td></tr><tr><th>Compose project</th><td>yourls</td></tr><tr><th>Reseau</th><td>yourls\_default</td></tr><tr><th>URL</th><td>[https://yourls.juxjux.ovh](https://yourls.juxjux.ovh)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip80858"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8085</td><td>80/tcp</td><td>0.0.0.0</td></tr><tr><td>8085</td><td>80/tcp</td><td>::</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/lib/docker/volumes/yourls_yourls_plugins/_data`</td><td>`/var/www/html/user/plugins`</td><td>volume</td><td>rw</td></tr><tr><td>`/home/debian/docker/yourls/ports.conf`</td><td>`/etc/apache2/ports.conf`</td><td>bind</td><td>rw</td></tr><tr><td>`/home/debian/docker/yourls/000-default.conf`</td><td>`/etc/apache2/sites-available/000-default.conf`</td><td>bind</td><td>rw</td></tr><tr><td>`/var/lib/docker/volumes/yourls_yourls_html/_data`</td><td>`/var/www/html`</td><td>volume</td><td>rw</td></tr><tr><td>`/var/lib/docker/volumes/yourls_yourls_user/_data`</td><td>`/var/www/html/user`</td><td>volume</td><td>rw</td></tr></tbody></table>

---

## yourls-db

<table id="bkmrk-imagemysql%3A8.0etatup"><tbody><tr><th>Image</th><td>`mysql:8.0`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up 9 hours (healthy)</span></td></tr><tr><th>Compose project</th><td>yourls</td></tr><tr><th>Reseau</th><td>yourls\_default</td></tr><tr><th>URL</th><td>[https://yourls.juxjux.ovh](https://yourls.juxjux.ovh)</td></tr></tbody></table>

### Volumes

<table id="bkmrk-source-%28hote%29destina-1"><thead><tr><th>Source (hote)</th><th>Destination</th><th>Type</th><th>Mode</th></tr></thead><tbody><tr><td>`/var/lib/docker/volumes/yourls_yourls_mysql_data/_data`</td><td>`/var/lib/mysql`</td><td>volume</td><td>rw</td></tr></tbody></table>

---

## Integration Claude Code — API directe

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:orange">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>API REST Yourls sur /yourls-api.php. Auth : signature HMAC ou token. Pas de MCP configuré — appels directs possibles.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Créer des URLs courtes personnalisées depuis Claude Code
- Lister et gérer les liens raccourcis existants
- Consulter les statistiques de clics sur un lien

# 25_StirlingPDF

## stirling-pdf

*Suite complète de manipulation de PDF — open source, auto-hébergée*

<table id="bkmrk-imagestirlingtools%2Fs"><tbody><tr><th>Image</th><td>`stirlingtools/stirling-pdf:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (healthy)</span></td></tr><tr><th>Compose project</th><td>stirlingpdf</td></tr><tr><th>Reseau</th><td>stirlingpdf\_default</td></tr><tr><th>URL</th><td>[https://spdf.juxjux.ovh](https://spdf.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/Stirling-Tools/Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip80908"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>8090</td><td>8080/tcp</td><td>0.0.0.0</td></tr></tbody></table>

### Variables

<table id="bkmrk-variablevaleurdocker"><thead><tr><th>Variable</th><th>Valeur</th></tr></thead><tbody><tr><td>DOCKER\_ENABLE\_SECURITY</td><td>false</td></tr><tr><td>LANGS</td><td>fr\_FR</td></tr></tbody></table>

### Volumes

<table id="bkmrk-hotecontainer%2Fopt%2Fst"><thead><tr><th>Hote</th><th>Container</th></tr></thead><tbody><tr><td>/opt/stirling-pdf/configs</td><td>/configs</td></tr><tr><td>/opt/stirling-pdf/logs</td><td>/logs</td></tr></tbody></table>

---

## Notes

- Remplacera BentoPDF (bento.juxjux.ovh / port 8089) quand la transition sera faite
- A terme : récupérer le domaine pdf.juxjux.ovh et désactiver la stack bentopdf
- Sécurité désactivée (DOCKER\_ENABLE\_SECURITY=false)

---

## Integration Claude Code

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:#FFA500;">Pas de MCP — API directe possible</span></td></tr><tr><th>Note technique</th><td>API REST sur /api — scriptable via PowerShell/Python httpx.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Fusion, découpage, compression, conversion PDF via API REST
- OCR, extraction de texte, filigrane, rotation
- Automatisation dans des scripts Claude Code

# 26_JDownloader

## jdownloader

*Gestionnaire de téléchargements avancé — interface web noVNC, supporte hôtes premium et lien direct*

<table id="bkmrk-imagejlesage-jdownlo"><tbody><tr><th>Image</th><td>`jlesage/jdownloader-2:latest`</td></tr><tr><th>Etat</th><td><span style="color:#008000;">Up (running)</span></td></tr><tr><th>Compose project</th><td>jdownloader</td></tr><tr><th>Reseau</th><td>jdownloader\_default</td></tr><tr><th>URL</th><td>[https://jdownloader.juxjux.ovh](https://jdownloader.juxjux.ovh)</td></tr><tr><th>Source</th><td>[https://github.com/jlesage/docker-jdownloader-2](https://github.com/jlesage/docker-jdownloader-2)</td></tr></tbody></table>

### Ports

<table id="bkmrk-hotecontainerip58005"><thead><tr><th>Hote</th><th>Container</th><th>IP</th></tr></thead><tbody><tr><td>5800</td><td>5800/tcp</td><td>127.0.0.1</td></tr></tbody></table>

### Variables

<table id="bkmrk-variablevaleuruser-i"><thead><tr><th>Variable</th><th>Valeur</th></tr></thead><tbody><tr><td>USER\_ID</td><td>1000</td></tr><tr><td>GROUP\_ID</td><td>1000</td></tr><tr><td>TZ</td><td>Europe/Paris</td></tr></tbody></table>

### Volumes

<table id="bkmrk-hotecontaineropt-jd"><thead><tr><th>Hote</th><th>Container</th></tr></thead><tbody><tr><td>/opt/jdownloader/config</td><td>/config</td></tr><tr><td>/home/debian/downloads</td><td>/output</td></tr></tbody></table>

---

## Notes

- Interface noVNC accessible via navigateur — pas besoin de client VNC
- Port 5800 lié à `127.0.0.1` uniquement — non exposé directement à l'internet
- Au 1er lancement, JDownloader télécharge ses composants (~1 min) avant d'afficher l'UI
- Cert SSL Let's Encrypt valide jusqu'au 2026-08-31 (renouvellement automatique certbot)
- Installé le 2026-06-02 via stack Portainer (ID 90)

---

## Integration Claude Code

<table id="bkmrk-statut-mcppas-de-mcp"><tbody><tr><th>Statut MCP</th><td><span style="color:#FFA500;">Pas de MCP — interface web uniquement (noVNC)</span></td></tr><tr><th>Note technique</th><td>Pas d'API REST publique documentée. Pilotage uniquement via l'interface graphique.</td></tr></tbody></table>

### Ce que nous pouvons faire ensemble

- Vérifier l'état du container via l'API Portainer
- Redémarrer le container si l'interface ne répond plus
- Lister les fichiers téléchargés dans `/home/debian/downloads` via SSH

# 27 - Rustdesk

# RustDesk — Serveur auto-hébergé (hbbs/hbbr)

## Qu'est-ce que c'est

RustDesk est un logiciel de bureau à distance open-source (alternative à TeamViewer/AnyDesk). Il repose sur deux briques serveur :

- **hbbs** (ID/rendezvous server) — enregistre les IDs des clients, gère le heartbeat, tente d'établir une connexion P2P directe.
- **hbbr** (relay server) — relaie le flux quand le P2P direct échoue (NAT symétrique, pare-feu strict, etc.).

Auto-héberger ces deux services évite de dépendre des serveurs publics RustDesk (rendezvous/relais tiers) : tout le trafic de contrôle passe par une infrastructure qu'on maîtrise.

## Poids du service Docker

| Élément | Valeur |
|---|---|
| Image `rustdesk/rustdesk-server:latest` (amd64) | **5,61 Mo** compressée |
| Image (arm64) | 5,2 Mo |
| Image (armv7) | 5,04 Mo |
| Nombre de containers | 2 (hbbs + hbbr) |
| RAM au repos | quelques dizaines de Mo par container (binaires Rust natifs, pas de VM/interpréteur) |
| CPU au repos | négligeable |
| CPU/RAM en charge | dépend du nombre de sessions actives relayées par hbbr (le flux vidéo transite par lui si pas de P2P direct) — reste très léger pour un usage perso/familial (quelques sessions simultanées max) |

Pour comparaison, c'est très inférieur au poids des autres containers déjà en place sur le VPS Jux (BookStack/MariaDB, Immich, etc.).

## Ports requis (conditions réseau)

| Port | Protocole | Service | Rôle |
|---|---|---|---|
| 21115 | TCP | hbbs | Test de type NAT |
| 21116 | TCP **+** UDP | hbbs | UDP = enregistrement ID + heartbeat / TCP = hole punching + connexion |
| 21117 | TCP | hbbr | Service de relais |
| 21118 | TCP | hbbs | Client web (optionnel) |
| 21119 | TCP | hbbr | Client web (optionnel) |
| 21114 | TCP | hbbs | Console web — **Pro uniquement**, pas utile en OSS |

Si le client web n'est pas utilisé, 21118/21119 peuvent rester fermés (recommandé : ces deux ports font confiance aux en-têtes `X-Real-IP`/`X-Forwarded-For` sans les valider, donc à n'exposer que derrière un reverse proxy qui les fixe lui-même, jamais en direct).

## docker-compose.yml (référence officielle RustDesk)

```yaml
services:
  hbbs:
    container_name: hbbs
    image: rustdesk/rustdesk-server:latest
    command: hbbs
    volumes:
      - ./data:/root
    network_mode: "host"
    depends_on:
      - hbbr
    restart: unless-stopped

  hbbr:
    container_name: hbbr
    image: rustdesk/rustdesk-server:latest
    command: hbbr
    volumes:
      - ./data:/root
    network_mode: "host"
    restart: unless-stopped
```

- `network_mode: host` est la méthode recommandée sous Linux : hbbs/hbbr voient l'IP réelle du client au lieu de l'IP interne du container. Fonctionne uniquement sur Linux (donc OK sur le VPS Debian, pas sur un NAS DSM qui a ses propres contraintes réseau — voir plus bas).
- Alternative sans host networking (mapping de ports classique, pour Portainer/stack isolée) :

```yaml
services:
  hbbs:
    container_name: hbbs
    image: rustdesk/rustdesk-server:latest
    command: hbbs -r rustdesk.exemple.com:21117
    ports:
      - "21115:21115"
      - "21116:21116"
      - "21116:21116/udp"
      - "21118:21118"
    volumes:
      - ./data:/root
    depends_on:
      - hbbr
    restart: unless-stopped

  hbbr:
    container_name: hbbr
    image: rustdesk/rustdesk-server:latest
    command: hbbr
    ports:
      - "21117:21117"
      - "21119:21119"
    volumes:
      - ./data:/root
    restart: unless-stopped
```

Variable d'environnement utile : `ALWAYS_USE_RELAY=Y` sur hbbs pour forcer systématiquement le passage par le relais (utile si on veut masquer les IP réelles des clients, au prix d'un peu plus de charge sur hbbr).

## Clé de chiffrement et configuration client

- Au premier démarrage, hbbs génère une paire de clés dans le volume `./data` : le fichier **`id_ed25519.pub`** contient la clé publique à distribuer aux clients.
- Configuration côté client RustDesk (menu **⋮ → Réseau**, déverrouiller) :
  - **ID Server** : IP ou domaine du VPS (ex. `vps.juxjux.ovh` ou l'IP directe)
  - **Relay Server** : peut rester vide (déduit automatiquement, sinon `IP:21117`)
  - **Key** : contenu de `id_ed25519.pub`
- Export/import de config possible entre clients (bouton "Export Server Config"), pratique pour déployer sur plusieurs machines (PC Windows, Ubuntu, etc.) sans ressaisir.

## VPS Jux vs NAS Synology sasnexte — analyse

RustDesk propose officiellement un **guide d'installation Synology** (DSM 6 et DSM 7.2/Container Manager), donc l'hébergement NAS est une voie supportée en soi — la question n'est pas la faisabilité technique mais la **joignabilité réseau**.

| Critère | VPS Jux (51.77.141.54) | NAS sasnexte (82.66.244.248) |
|---|---|---|
| IP publique fixe | Oui | Non confirmée — SSH déjà signalé comme parfois inaccessible depuis l'extérieur (fail2ban/whitelist) |
| `network_mode: host` (recommandé Linux) | Disponible (Debian) | Non disponible sous DSM (Docker/Container Manager Synology tourne dans une couche réseau propriétaire) — nécessite le mapping de ports classique + redirection sur la box |
| Port forwarding | Déjà maîtrisé (nginx, certbot, ufw) | Dépend de la box du FAI, potentiellement CGNAT résidentiel |
| Exposition déjà en place | 34 containers en prod, expérience du durcissement (incident du 9 juin 2026) | Usage actuel = uniquement syncs rclone sortants vers kDrive, pas de service entrant exposé |
| Impact en cas d'indisponibilité | VPS pro, uptime élevé | Dépend de l'alimentation/connexion internet du domicile |

**Conclusion** : le VPS reste le choix le plus robuste pour un usage "accès à distance depuis n'importe où". Le NAS serait une option seulement si l'IP publique/DDNS et le port forwarding sont déjà fiables — ce qui n'est pas le cas aujourd'hui d'après le comportement SSH observé.

## Prochaine étape proposée

Ajouter la stack `rustdesk` sur le VPS (Portainer, comme les autres services), avec ufw restreint aux ports 21115-21119 (TCP+UDP sur 21116) et 21118/21119 fermés tant que le client web n'est pas nécessaire.

## Incident client Windows — BSOD à l'installation (2026-07-31)

**Contexte** : installation du client RustDesk sur le PC Windows 10 (`eliob`). L'installation s'est terminée par plusieurs écrans bleus consécutifs.

### Diagnostic

- Analyse de l'Observateur d'événements (`Microsoft-Windows-WER-SystemErrorReporting`) : crash à 06:27:20 avec bugcheck **`0x50` (PAGE_FAULT_IN_NONPAGED_AREA)**, dump complet dans `C:\WINDOWS\MEMORY.DMP` (2,4 Go).
- Corrélation temporelle exacte avec l'extraction de deux composants pilotes bundlés par le client RustDesk :
  - `C:\Program Files\RustDesk\usbmmidd_v2` — pilote d'**écran virtuel USBMMIDD** (permet le contrôle à distance sans moniteur physique branché)
  - `C:\Program Files\RustDesk\drivers\RustDeskPrinterDriver` — pilote d'**imprimante virtuelle** (impression à distance)
- Vérification : ni l'un ni l'autre n'était enregistré comme périphérique actif (`Get-PnpDevice`, `pnputil /enum-drivers`) après coup → l'installation du driver a fait planter le noyau **avant** de s'enregistrer. Un problème connu et documenté côté communauté RustDesk : le driver `usbmmidd` (ancien, non WHQL sur les builds récentes de Windows 10) provoque des BSOD à l'installation sur certaines configs.
- **Point distinct identifié en passant** : la machine a un historique chronique de BSOD `0x9f` (DRIVER_POWER_STATE_FAILURE) récurrent environ une fois par mois depuis janvier 2026 (`Kernel-Power` event 41), sans lien avec RustDesk — probablement un driver qui répond mal à la mise en veille. Non résolu, à creuser séparément si besoin.

### Fix appliqué

Neutralisation des deux dossiers de drivers sans désinstaller RustDesk (le contrôle à distance standard, moniteur physique branché, ne dépend pas d'eux) :

```powershell
Stop-Service -Name "RustDesk" -Force
Stop-Process -Name "rustdesk" -Force -ErrorAction SilentlyContinue
Rename-Item "C:\Program Files\RustDesk\usbmmidd_v2" "usbmmidd_v2.disabled"
Rename-Item "C:\Program Files\RustDesk\drivers\RustDeskPrinterDriver" "RustDeskPrinterDriver.disabled"
Start-Service -Name "RustDesk"
```

**Note importante** : ces commandes nécessitent une session PowerShell réellement élevée (clic droit → "Exécuter en tant qu'administrateur", accepter l'UAC). Une session non élevée renvoie la même erreur `Impossible d'ouvrir le service` aussi bien pour `Stop-Service` que pour le renommage des dossiers dans `Program Files` — ça peut faire croire à tort qu'on est admin alors que non.

### Résultat

- Service `RustDesk Service` : `Running`
- Contrôle à distance classique opérationnel (vérifié : process `RustDesk.exe` actif, service démarré)
- Écran virtuel et impression à distance désactivés (fonctionnalités non utilisées) — évite que RustDesk retente d'installer ces drivers automatiquement
- **Mot de passe permanent + 2FA activés** par Julien le 2026-07-31 (menu **Sécurité** de RustDesk) → accès non attendu opérationnel : ce PC est joignable via RustDesk sans présence devant l'écran, ID + mot de passe permanent (2FA en complément).

## Traversée VPS — client configuré (2026-07-31)

Le client RustDesk du PC eliob passe désormais par le serveur auto-hébergé (`hbbs`/`hbbr` sur le VPS Jux, voir plus haut) au lieu des relais publics RustDesk. Confirmé côté serveur : containers `hbbs`/`hbbr` up, ufw ouvert sur 21115-21117 (v4+v6), clé publique `id_ed25519.pub` en place. Tout le trafic de contrôle à distance de ce PC transite donc par une infrastructure maîtrisée plutôt que par un tiers.

# D_la solution contacts et calendrier

Solution d'unification des contacts et de calendrier de Julien par Claude

Solution Contacts et Calendrier — Baïkal + Roundcube  
Objectif  
Unifier la base de contacts et calendriers dispersée entre plusieurs sources (Google, Infomaniak, téléphone) autour d'un point central self-hosté sur le VPS juxjux.ovh, synchronisé vers tous les clients existants.  
Vue d'ensemble de l'architecture  
Composant  
Rôle  
Emplacement  
Baïkal  
Serveur CardDAV + CalDAV — stockage central des contacts et calendriers  
Docker, VPS juxjux.ovh  
Roundcube  
Interface web de saisie/lecture (contacts + calendrier)  
Docker, VPS juxjux.ovh  
Nginx  
Reverse proxy HTTPS pour les deux services  
Hôte VPS  
DAVx5  
Pont de synchronisation CardDAV/CalDAV vers Android  
Téléphone  
Fossify Agenda  
Client calendrier  
Téléphone (via DAVx5)  
Thunderbird  
Client mail (indépendant de ce circuit)  
Téléphone  
vdirsyncer (à mettre en place)  
Agrège les contacts Google et Infomaniak vers Baïkal  
VPS, cron  
Schéma de flux  
Code  
Baïkal est la source de vérité unique. Roundcube et DAVx5 en sont des clients ; vdirsyncer est le seul composant qui écrit depuis l'extérieur (Google/Infomaniak) vers Baïkal.  
Pourquoi ce choix  
Radicale a été écarté (stockage fichier brut, pas de vraie gestion) — clarification : la stack Radicale/InfCloud initialement envisagée n'a finalement pas été mise en place.  
Nextcloud a été écarté : trop lourd pour l'usage visé (PHP-FPM + DB + Redis + écosystème complet), alors que le VPS fait déjà tourner PostGIS, Metabase, BookStack, FreshRSS.  
Baïkal retenu : léger (PHP + SQLite/MariaDB, quelques dizaines de Mo de RAM), CardDAV + CalDAV natifs, interface d'admin suffisante pour la gestion des carnets/calendriers.  
Roundcube retenu comme interface de saisie/lecture (Baïkal n'a pas de vraie UI de consultation) : léger, traduit en français, projet actif (dernière version majeure 1.7.0, mises à jour de sécurité régulières).  
Alternative envisagée puis écartée : Thunderbird containerisé (VNC/noVNC) — fonctionnel mais plus lourd en ressources et moins adapté au multi-accès qu'un vrai webmail.  
Déploiement — Stack Docker  
Fichiers de référence : docker-compose.yml, config/carddav.php, nginx/baikal.conf, nginx/roundcube.conf.  
1\. Lancer les conteneurs  
Bash  
Services démarrés :  
baikal (image ckulka/baikal:nginx) — exposé en local sur 127.0.0.1:8081  
roundcube-db (MariaDB) — base de données Roundcube  
roundcube (image roundcube/roundcubemail) — exposé en local sur 127.0.0.1:8082  
⚠️ Remplacer les valeurs CHANGE\_ME\_... du compose (mots de passe DB) avant le premier démarrage.  
2\. Configuration initiale Baïkal  
Aller sur https://baikal.juxjux.ovh/admin/  
Créer le compte administrateur  
Créer un utilisateur  
Créer pour cet utilisateur :  
un carnet de contacts (ex. default)  
un calendrier (ex. default)  
Noter les URLs générées :  
Contacts : https://baikal.juxjux.ovh/dav.php/addressbooks/USERNAME/default/  
Calendrier : https://baikal.juxjux.ovh/dav.php/calendars/USERNAME/default/  
3\. Reverse proxy Nginx  
Deux vhosts à activer sur l'hôte (/etc/nginx/sites-available/) :  
baikal.juxjux.ovh → proxy vers 127.0.0.1:8081  
mail.juxjux.ovh → proxy vers 127.0.0.1:8082  
Bash  
Point d'attention : CardDAV/CalDAV envoient les identifiants en Basic Auth à chaque synchronisation (DAVx5 notamment) → HTTPS obligatoire, jamais de HTTP nu au-delà du proxy local.  
4\. Plugins Roundcube  
Deux plugins activés via ROUNDCUBEMAIL\_PLUGINS dans le compose : carddav et calendar.  
Contacts (carddav) — config dans config/carddav.php, monté dans le conteneur :  
URL pointée vers le carnet de contacts Baïkal créé à l'étape 2  
%u / %p réutilisent les identifiants de connexion Roundcube (si mêmes comptes que Baïkal)  
Calendrier (calendar) — configuration depuis l'interface :  
Se connecter à Roundcube  
Réglages → Calendrier → Calendriers  
Ajouter une source CalDAV avec l'URL calendrier Baïkal  
Côté téléphone — DAVx5  
Ajouter un compte avec l'URL de base : https://baikal.juxjux.ovh/dav.php/  
DAVx5 découvre automatiquement le carnet de contacts et le calendrier  
Activer la synchronisation vers :  
Fossify Agenda (calendrier)  
App Contacts Android (contacts)  
Thunderbird sur le téléphone reste indépendant de ce circuit (gère uniquement les mails)  
Agrégation Google / Infomaniak — vdirsyncer (étape suivante, non encore déployée)  
Objectif : faire remonter dans Baïkal les contacts existants sur les comptes Google et Infomaniak, pour que Baïkal devienne le point central réel et pas seulement un nouveau silo.  
Google Contacts : accès CardDAV via https://www.google.com/carddav/v1/principals/EMAIL/ — nécessite un mot de passe d'application (compte avec 2FA)  
Infomaniak : CardDAV natif, identifiants standards du compte mail  
vdirsyncer : outil CLI léger, une paire de synchronisation par source (Google ↔ Baïkal, Infomaniak ↔ Baïkal), exécuté via cron sur le VPS  
Décision à prendre au moment de la mise en place : synchronisation one-way (Baïkal source de vérité, lecture seule depuis Google/Infomaniak) ou two-way (modifications propagées dans les deux sens)  
Sécurité — checklist  
\[ \] Tous les mots de passe CHANGE\_ME\_... remplacés avant mise en production  
\[ \] HTTPS forcé sur les deux vhosts (redirection 80 → 443 en place)  
\[ \] Certificats Let's Encrypt valides et renouvellement automatique vérifié  
\[ \] Mot de passe d'application dédié pour l'accès CardDAV Google (pas le mot de passe principal du compte)  
\[ \] Sauvegarde régulière des volumes baikal-config, baikal-data, roundcube-db  
Statut du projet Baïkal (pour référence)  
Développé aujourd'hui par des bénévoles sous l'organisation sabre-io (mainteneurs de SabreDAV, la librairie sous-jacente). Pas de société commerciale derrière, mais communauté active et outil considéré comme robuste pour un usage personnel/petite structure sur la durée.  
Statut du projet Roundcube (pour référence)  
Projet actif, version majeure 1.7.0 sortie en mai 2026, mises à jour de sécurité régulières. A rejoint la famille Nextcloud en 2023 tout en restant indépendant (licence GPL). Interface traduite en français en natif.

# E_la gestion du SWAP du VPS par Claude

# REX 260803 — Session Claude sur le VPS Jux

Session du 2026-08-02 (soir) au 2026-08-03 (matin). Quatre chantiers, tous appliqués et vérifiés.
Le sujet principal de cette page — le swap — est traité en partie 1 ; les autres chantiers suivent
car ils s'expliquent mutuellement (l'allègement JVM est ce qui a fait apparaître la question du swap).

| # | Chantier | État | Gain / résultat |
|---|---|---|---|
| 1 | Swap saturé à 95 % | Résolu | 4 Go → 8 Go, `swappiness` 60 → 10 |
| 2 | Allègement JVM Komga + StirlingPDF | Appliqué | Komga −292 Mio (−41 %), Stirling borné à 2 Go |
| 3 | OCR StirlingPDF impossible sur PNG | Résolu | Cause trouvée + script de contournement |
| 4 | Connexion Claude Code sur le VPS Alteris | Résolu | Identifiants recopiés depuis le VPS Jux |

---

## 1. Swap saturé — le vrai diagnostic

### Symptôme

Swap à **3,8 / 4,0 Go (95 %)**, alors que ~4,6 Gi de RAM restaient disponibles. Il se remplissait
nuit après nuit et ne se vidait jamais.

### Ce que ce n'était PAS

Un manque de mémoire. `vmstat 2 3` montrait `si`/`so` ≈ 0 : **aucun thrashing**, rien ne ramait.
C'est le point contre-intuitif de ce diagnostic — un swap plein n'est pas synonyme de machine à genoux.

Le risque réel était ailleurs : il ne restait que **253 Mio de swap libre**. En cas de pic, l'OOM killer
aurait commencé à tuer des containers.

### Cause

`vm.swappiness = 60` (valeur par défaut). Pendant les batchs de nuit — backup 2h, scan Komga 4h
(230 lignes de scan cette nuit-là), scans Audiobookshelf 4h et Navidrome 4h30 — le noyau préférait
pousser les pages anonymes des applications vers le swap plutôt que de réclamer son cache de pages.

Une fois en swap, ces pages **n'en ressortent jamais d'elles-mêmes** : elles n'y reviennent que si le
processus les retouche. D'où une accumulation qui ne fait que croître, nuit après nuit.

### Fixes appliqués

**a) `vm.swappiness = 10`**, persisté dans `/etc/sysctl.d/99-swap.conf`. Le noyau réclame désormais
son cache de pages avant de swapper. C'est ce qui empêche l'accumulation de recommencer.

**b) Second fichier de swap `/swapfile2` de 4 Go** → swap total **8 Go**, persisté dans `/etc/fstab`
(sauvegarde : `/etc/fstab.bak-260803`), validé par `sudo swapon -a` pour garantir un redémarrage sûr.

Méthode choisie délibérément : ajouter un second fichier **évite tout `swapoff`**, donc tout risque.
Un `swapoff -a` aurait dû recharger 3,8 Go dans 4,6 Go disponibles — faisable mais serré, plusieurs
minutes d'I/O intense, et un pic pendant l'opération aurait pu faire tuer un container.

### État après intervention

| | Avant | Après |
|---|---|---|
| Swap total | 4,0 Go | **8,0 Go** |
| Swap libre | 253 Mio | **4,2 Go** |
| `vm.swappiness` | 60 | **10** |
| Disque libre | 39 Go | 35 Go |

### Ce qui reste

Les **3,8 Go de pages froides restent en swap**. C'est assumé : elles ne coûtent rien en performance
et se libéreront au fil des redémarrages. Un `docker restart` libère instantanément le swap du
container concerné.

Top détenteurs au 2026-08-03 : **komga 954 Mio**, yourls-db 389, stirling-pdf 354, Immich-SERVER 212,
Immich-DB 197, mealie 189, Kavita 158, jellyfin 131.

Le redémarrage de Komga rendra donc presque un giga à lui seul.

### Commandes de diagnostic

```bash
swapon --show                      # taille et occupation de chaque zone
vmstat 2 3                         # si/so : y a-t-il un swap ACTIF ?
cat /proc/sys/vm/swappiness
```

Swap par container :

```bash
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect NOM --format '{{.Id}}').scope/memory.swap.current
```

Swap par processus :

```bash
for p in /proc/[0-9]*; do s=$(awk '/^VmSwap:/{print $2}' $p/status 2>/dev/null); \
  [ -n "$s" ] && [ "$s" -gt 0 ] && echo "$s $(tr -d '\0' < $p/cmdline | cut -c1-60)"; done | sort -rn | head
```

### À surveiller

Le lendemain matin, après une nuit de batchs : si le swap utilisé a peu bougé, `swappiness=10` a fait
son travail. S'il remonte malgré tout, la piste suivante est de réduire les consommateurs réels
plutôt que de rejouer sur les réglages noyau.

---

## 2. Allègement JVM Komga + StirlingPDF

Appliqué le 2026-08-02 à 22h, après vérification du backup quotidien (BILAN 5/5 OK).

| Service | Avant | Après | Résultat |
|---|---|---|---|
| **Komga** (stack 7) | `-Xmx4g -Xms2g -XX:MaxRAMPercentage=70.0`, limits 4500M / reservations 3000M, 707 Mio | `-Xmx1g`, limits 1500M / reservations 256M | **415 Mio (−292, −41 %)** |
| **StirlingPDF** (stack 89) | JVM sans limite, 722 Mio | `-Xmx512m`, limits 2g | 785 Mio — **pas de réduction** |

**Bilan hôte** : swap 3,7 → 2,2 Go juste après l'opération, mémoire disponible 4,4 → 4,6 Gi.
L'essentiel du gain vient de Komga : c'est le `-Xms2g` qui pré-allouait 2 Go de heap au démarrage.

### Pourquoi StirlingPDF ne baisse pas

À dire franchement plutôt que de maquiller le résultat : le process `java` conserve **799 Mio de RSS**
malgré `-Xmx512m`. Le heap n'est qu'une partie du total (metaspace, code cache, piles de threads),
et Stirling lance en plus LibreOffice (`soffice.bin`, ~98 Mio), `unoserver` et `Xvfb` pour ses conversions.

Le bénéfice obtenu n'est pas une baisse mais un **plafond** : la consommation ne peut plus déborder,
alors qu'elle était non bornée.

### La limite portée de 1 Go à 2 Go — décision critique

Le plan initial prévoyait 1 Go. Il a été corrigé **avant** application, grâce au chantier OCR mené le
même jour : l'OCR fait tourner ocrmypdf et tesseract comme processus **Python, hors JVM**. `-Xmx` ne
les borne pas — seul le plafond cgroup du container s'applique.

Pic mesuré : **894 à 969 Mio pour une seule page A4 300 dpi**. Un plafond de 1 Go aurait provoqué un
OOM kill dès le premier OCR. La version 1 Go est conservée en
`/home/debian/stirling-compose-new.yml.orig1g` mais **ne doit pas être utilisée**.

### Vérifications après déploiement

- Komga répond 200, API `/api/v1/libraries` renvoie bien les bibliothèques
- StirlingPDF : `compress-pdf` OK (workflows komga-pdf et nas_geo_compress) **et** OCR OK
  (page A4 300 dpi, pic 969 Mio, aucun OOM kill, aucun redémarrage)

### Piège de déploiement

Les projets compose s'appellent **`7` et `89`** — les IDs de stack Portainer — et non `komga` /
`stirlingpdf`. La procédure documentée initialement aurait échoué dessus.

```bash
sudo docker compose -p 7 -f /var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml up -d
```

---

## 3. OCR StirlingPDF impossible sur les images PNG

### Symptôme

HTTP 500 sur tout OCR d'image PNG. L'interface web n'affiche **aucun détail exploitable** — le
diagnostic passe obligatoirement par `docker logs stirling-pdf`.

### Deux refus cumulés d'ocrmypdf 17.4.0

1. `UnsupportedImageFormatError: The input image has an alpha channel.` — tout PNG avec transparence
2. Une fois l'alpha retiré, un **second** blocage apparaît :
   `DpiError: Input file is an image, but has no resolution (DPI) in its metadata.`
   StirlingPDF ne transmet pas `--image-dpi` à ocrmypdf

Le point à retenir : les erreurs sont **séquentielles**. Corriger la transparence seule ne suffit pas,
le DPI bloque juste après — ce qui explique pourquoi aucun réglage de l'interface ne pouvait s'en sortir.

### Solution sans outil (interface web)

Convert → **Image to PDF**, puis OCR sur le PDF obtenu. Les deux problèmes disparaissent puisque
l'entrée n'est plus une image. Validé en test, HTTP 200.

### Solution scriptée

`Jux-scripts/Stirling-OCR/ocr_image.py` — aplatit l'alpha sur fond blanc et force 300 dpi avant envoi.

```bash
py "D:\Syncthing\Jux_univers\Jux-scripts\Stirling-OCR\ocr_image.py" mon_image.png
```

Accepte un fichier ou un dossier. Options : `-l fra+eng`, `-o sortie.pdf`, `--dpi 400`, `--skip-text`.
Testé depuis le PC Windows **et** depuis le VPS ; texte restitué à l'identique.

Chemin sur le VPS : `/home/debian/Documents/Jux_univers/Jux-scripts/` (et non `~/Syncthing/...`).

### Détails techniques

- Endpoint : `POST /api/v1/misc/ocr-pdf` — multipart `fileInput`, champs `languages` (liste),
  `ocrType` (`Force-OCR` / `skip-text`), `outputType`
- Langues tesseract installées (6) : `fra`, `eng`, `deu`, `por`, `chi_sim`, `osd`
- Versions : ocrmypdf 17.4.0, tesseract 5.3.4

---

## 4. Connexion Claude Code sur le VPS Alteris

### Symptôme

Au lancement de `claude` en SSH (PuTTY / CMD / PowerShell), Claude Code demande de se connecter et
affiche une URL. Impossible de la copier : `Ctrl+C`, clic droit, rien ne fonctionnait. La mention
verte « copied » s'affichait pourtant.

### Cause

Le « copied » venait de Claude Code **tournant sur le VPS** : il copiait l'URL dans le presse-papier
du serveur Linux, qui n'a aucun lien avec celui du PC Windows à travers SSH. Le presse-papier Windows
restait donc vide, d'où le collage à blanc dans le navigateur.

À noter au passage : dans un terminal SSH, `Ctrl+C` envoie un signal d'interruption au programme —
il peut tuer le processus de login au lieu de copier.

### Cause réelle du re-login

Le fichier `~/.claude/.credentials.json` d'Alteris avait `expiresAt: 0` — jeton invalide.
Le VPS Jux, lui, disposait d'identifiants sains (compte Pro, refresh token valide).

### Solution retenue

Recopier les identifiants depuis le VPS Jux, commande lancée **depuis Alteris** :

```bash
scp debian@51.77.141.54:.claude/.credentials.json ~/.claude/.credentials.json && chmod 600 ~/.claude/.credentials.json
```

Vérifié : 504 octets, permissions 600, jeton complet. Claude Code ne redemande plus de login et
rafraîchit le token seul au démarrage (l'access token expiré n'est pas un problème, le refresh token
est valide).

**Conséquence** : les deux VPS partagent désormais le même jeu d'identifiants. Si l'un redemande un
login, refaire le même `scp` depuis celui qui fonctionne encore.

Alternative si les deux tombent : `claude setup-token` depuis le PC Windows (le navigateur s'ouvre en
local), puis `export CLAUDE_CODE_OAUTH_TOKEN=...` dans le `~/.bashrc` du serveur.

---

## 5. Découverte annexe — port PostgreSQL 5432 bloqué sur Alteris

`publier_recherche.py` échoue sur sa partie PostgreSQL : `Connection timed out (10060)`.

- ufw est **actif** sur Alteris **sans règle pour 5432**
- Le container `alteris_postgis` tourne et `pg_isready` répond en local
- Vérifié : le port est injoignable depuis le PC **et** depuis le VPS Jux

**Contournement sans toucher au pare-feu** — exécuter le SQL en local sur Alteris :

```bash
pscp fichier.sql debian@79.137.14.202:/tmp/
sudo docker cp /tmp/fichier.sql alteris_postgis:/tmp/i.sql
sudo docker exec alteris_postgis psql -U alteris_admin -d alteris_geo -f /tmp/i.sql
```

Rouvrir le port exposerait à nouveau une base de données directement sur internet. Décision à prendre
sciemment, surtout après l'incident du 2026-06-09.

---

## Fichiers, sauvegardes et rollbacks

| Élément | Chemin | Rôle |
|---|---|---|
| Compose Komga (avant) | `/var/lib/docker/volumes/portainer_data/_data/compose/7/docker-compose.yml.bak-260802` | Rollback Komga |
| Compose Stirling (avant) | `/var/lib/docker/volumes/portainer_data/_data/compose/89/docker-compose.yml.bak-260802` | Rollback Stirling |
| Version Stirling 1 Go | `/home/debian/stirling-compose-new.yml.orig1g` | **Ne pas utiliser** (OOM sur OCR) |
| fstab (avant) | `/etc/fstab.bak-260803` | Rollback swap |
| Réglage swappiness | `/etc/sysctl.d/99-swap.conf` | `vm.swappiness = 10` |
| Second swap | `/swapfile2` (4 Go) | Marge de swap |
| Script OCR | `Jux-scripts/Stirling-OCR/ocr_image.py` + `README.md` | Contournement OCR images |

**Rollback JVM** : restaurer le `.bak-260802` de la stack et redéployer avec
`sudo docker compose -p {7|89} -f ... up -d`.

---

## Références

- Page **177** — 00_Récapitulatif : section « 260802 - Allègement JVM Komga + StirlingPDF »
- Page **211** — REX StirlingPDF : entrée `RCH-20260802-0001` (également en base `recherches` sur Alteris)
- Page **208** — 25_StirlingPDF
- `CLAUDE.md` du projet : sections « Swap », « Alléger Komga », « Alléger StirlingPDF », StirlingPDF/OCR

# 01_Les recherches de Claude

Pages de publication des résultats d'analyse et de production de Claude Code sur le contenu du VPS

# 01A_Kdrive_les explorations

## RCH-20260529-0003 — Livres et ressources evoquant la ville de Genes dans Foxy

<table id="bkmrk-date2026-05-29-servi"><tbody><tr><th style="width:160px;">Date</th><td>2026-05-29</td></tr><tr><th>Service</th><td>kDrive Infomaniak</td></tr><tr><th>Contexte</th><td>Constituer un corpus documentaire autour de Genes (Genovese, Ligurie) dans la bibliotheque kDrive — dossier SYNC-pour\_VPS/Sync\_NAS-Maison/Foxy</td></tr><tr><th>Outils utilisés</th><td>API REST Infomaniak kDrive v3 — search + metadata v2 | PowerShell</td></tr><tr><th>Requête</th><td>`GET /3/drive/591617/files/search?query={Genes|Genova|Genovese|Genoa|Ligurie}&limit=20 | filtre manuel sur résultats`</td></tr></tbody></table>

### Résultats

3 livres directement sur Gênes (la ville), 1 presentation Ligurie, des photos de Ligurie (2011), et des recettes genovese (cuisine). Recherche couvrant les termes : Genes, Genova, Genovese, Genoa, Ligurie.

### Points clés

- 3 livres historiques sur Gênes trouvés : Graziani (5.2 MB), Vincens (0.9 MB), Histoire anonyme (0.8 MB)
- 1 présentation PowerPoint Ligurie (31.9 MB, mai 2021) — probablement riche en images et contenu
- Photos de Ligurie 2011 (Ognelia et Imperia) — 20+ photos personnelles
- Ressources culinaires genovese : Focaccia Genovese, Ravioli alla genovese (videos kDrive)
- Les livres sont dans Foxy (ID:401926) — dossier probable : Histoire ou Culture Italie
- L'API search kDrive retourne des faux positifs (Genèse, Gens, Genève) — filtrage manuel nécessaire

### Limites

L'API v2 ne retourne pas le chemin (path) des fichiers — impossible de localiser précisément le sous-dossier sans navigation manuelle. Le champ path est vide dans la réponse.

### Localisation des ressources

<table id="bkmrk-urls%E2%80%94-chemins%5B%22kdriv"><tbody><tr><th style="width:160px;">URLs</th><td>—</td></tr><tr><th style="width:160px;">Chemins</th><td>\["kDrive 591617 / Private (5) / SYNC-pour\_VPS (534292) / Sync\_NAS-Maison (534293) / Foxy (401926) / \[sous-dossier inconnu\]"\]</td></tr><tr><th style="width:160px;">IDs</th><td>{"531552": "Antoine-Marie Graziani - Histoire de Genes.epub (5.2 MB)", "531550": "Histoire de de Genes - Histoire.epub (0.8 MB)", "531549": "Histoire de la République de Gênes - Emile Vincens - Histoire.epub (0.9 MB)", "501392": "210526-Ligurie.pptx (31.9 MB)"}</td></tr><tr><th style="width:160px;">Auteurs / Source</th><td>\["Antoine-Marie Graziani (Histoire de Genes)", "Emile Vincens (Histoire de la République de Gênes)"\]</td></tr><tr><th style="width:160px;">Métadonnées</th><td>{"formats": \["epub", "pptx", "jpg", "mp4"\], "livres\_genes": 3, "photos\_ligurie": 20, "videos\_recettes\_genovese": 2, "dossier\_foxy\_id": 401926, "kdrive\_id": 591617}</td></tr></tbody></table>

### Tags

**\#Genes** **\#Gênes** **\#Ligurie** **\#Italie** **\#histoire** **\#kDrive** **\#epub** **\#bibliotheque**

### Suite / Pistes

1/ Explorer le dossier Culture Italie (ID:1185062) pour trouver d'autres ressources sur Genes. 2/ Verifier dans Calibre (ID:1211295) si des livres Genes y sont catalogues. 3/ Corriger l'API v2 pour obtenir le chemin des fichiers (utiliser /3/ au lieu de /2/). 4/ Croiser avec Kavita si ces epubs y sont importes.

---

## RCH-20260529-0004 — Approfondissement corpus Gênes — Culture Italie et Bibliotheque Calibre

<table id="bkmrk-date2026-05-29-servi-1"><tbody><tr><th style="width:160px">Date</th><td>2026-05-29</td></tr><tr><th>Service</th><td>kDrive Infomaniak</td></tr><tr><th>Contexte</th><td>Suite de RCH-20260529-0003. Explorer Culture Italie (ID:1185062) et Bibliotheque Calibre (ID:1211295) pour compléter le corpus #Genes.</td></tr><tr><th>Outils utilisés</th><td>API REST kDrive v3 — navigation par ID + listing sous-dossiers | PowerShell</td></tr><tr><th>Requête</th><td>`GET /3/drive/591617/files/{1185194|1185151|1185105|1185085|1211295}/files?limit=100 + filtres regex Genes/Ligurie`</td></tr></tbody></table>

### Résultats

Culture Italie contient un dossier Ligurie (Cuisine Italie/Ligurie) avec 2 fichiers. Calibre contient Graziani mais uniquement pour Pascal Paoli (Corse), pas Genes. Vincens absent de Calibre. Plusieurs livres sur l'Italie générale potentiellement exploitables.

### Points clés

- Dossier Ligurie trouvé dans Cuisine Italie (ID:1185345) : PPTX 31.9MB + IMG\_3782.pdf
- Calibre/Graziani (ID:1362307) = Pascal Paoli uniquement — Histoire de Genes est dans Foxy seulement
- Vincens (Histoire de la République de Gênes) absent de Calibre — epub uniquement dans Foxy
- Culture Italie / Art de vivre : 5 ressources générales sur l'Italie (Bella Italia, Continent Italia, Sacrés Italiens, Portraits d'Italie, Geo Dolce Vita)
- Histoire Italie : Les guerres d'Italie (conflit européen) — contexte historique pertinent pour Gênes
- Le corpus Gênes dans kDrive est concentré dans Foxy/Histoire — Calibre ne l'a pas indexé

### Limites

Calibre n'a pas les livres sur Gênes de Vincens et de la version anonyme. Seul Graziani y est mais pour un autre ouvrage. Les 3 epubs Genes sont uniquement dans Foxy, non indexés dans Calibre. La recherche ne couvre pas les sous-sous-dossiers de Calibre (trop nombreux).

### Localisation des ressources

<table id="bkmrk-urls%E2%80%94-chemins%5B%22foxy%2F"><tbody><tr><th style="width:160px">URLs</th><td>—</td></tr><tr><th style="width:160px">Chemins</th><td>\["Foxy/Culture Italie/Cuisine Italie/Ligurie", "Foxy/Culture Italie/Histoire Italie", "Foxy/Culture Italie/Art de vivre Italie", "Foxy/Bibliotheque Calibre/Antoine-Marie Graziani"\]</td></tr><tr><th style="width:160px">IDs</th><td>{"1185345": "Dossier Ligurie dans Cuisine Italie", "1185347": "210526-Ligurie.pptx (31.9 MB) — dans Cuisine Italie/Ligurie", "1185349": "IMG\_3782.pdf — dans Cuisine Italie/Ligurie", "1362307": "Calibre/Antoine-Marie Graziani (Pascal Paoli — pas Gênes)", "1185194": "Histoire Italie (4 livres generaux)", "1185085": "Art de vivre Italie (5 ressources)", "1185201": "L'Italie de Botticelli à Bonaparte.epub", "1185199": "Les guerres d'Italie — Un conflit européen.epub", "1185196": "Bella Italia - Un itinéraire amoureux (Christiane Rance).epub", "1185090": "Sacrés Italiens (Alberto Toscano).epub", "1185089": "Portraits d'Italie (Laurent Bolard).epub", "1185087": "Geo Hors-Serie Dolce Vita Avril-Mai 2025.pdf"}</td></tr><tr><th style="width:160px">Auteurs / Source</th><td>—</td></tr><tr><th style="width:160px">Métadonnées</th><td>{"corpus\_genes\_directs": 3, "ressources\_ligurie": 2, "livres\_italie\_generale": 9, "calibre\_graziani\_titre": "Pascal Paoli - Pere de la patrie corse", "vincens\_dans\_calibre": false}</td></tr></tbody></table>

### Tags

**\#Genes** **\#Genes** **\#Ligurie** **\#Italie** **\#Calibre** **\#kDrive** **\#Culture Italie** **\#histoire**

### Suite / Pistes

1/ Importer les 3 epubs Genes (IDs 531549-531552) dans Calibre pour les indexer. 2/ Lire le PPTX Ligurie (ID:1185347) pour en extraire le contenu. 3/ Explorer 'Bella Italia' et 'Les guerres d'Italie' pour mentions de Genes. 4/ Rechercher 'Genes' dans le dossier Histoire (ID:503138) de Foxy.

---

# 01_Portainer - les explorations

Journal des recherches réalisées avec Claude Code sur le service **Portainer**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/152](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/152)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 02_Bookstack_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Bookstack**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/153](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/153)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 03_Homarr_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Homarr**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/154](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/154)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 04_Audiobookshelf_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Audiobookshelf**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/155](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/155)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 05_BentoPDF_les explorations

Journal des recherches réalisées avec Claude Code sur le service **BentoPDF**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/156](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/156)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 06_Cadvisor_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Cadvisor**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/157](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/157)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 07_Calibre-web_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Calibre-web**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/158](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/158)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 08_Dozzle_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Dozzle**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/159](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/159)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 09_FileBrowser_les explorations

Journal des recherches réalisées avec Claude Code sur le service **FileBrowser**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/160](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/160)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 10_FreshRSS_les explorations

---

## RCH-20260529-0002 — Articles Inkscape dans la categorie claude\_foss

<table id="bkmrk-date2026-05-29-servi-1"><tbody><tr><th style="width: 160px;">Date</th><td>2026-05-29</td></tr><tr><th>Service</th><td>FreshRSS</td></tr><tr><th>Contexte</th><td>Second passage apres creation de la categorie claude\_foss et ajout du flux Inkscape News. Verifier si des articles sur Inkscape sont desormais indexes.</td></tr><tr><th>Outils utilisés</th><td>API GReader FreshRSS directe — stream/contents/user/-/label/claude\_foss — search\_foss.py</td></tr><tr><th>Requête</th><td>`GET /reader/api/0/stream/contents/user/-/label/claude_foss?n=100&q=Inkscape`</td></tr></tbody></table>

### Résultats

100 articles retournes depuis la categorie claude\_foss (7 flux). 10 articles provenant du flux Inkscape News (feed/615) sont presents. Note : le parametre q= de l'API GReader ne filtre pas reellement par mot-cle — il retourne tous les articles du stream. Le filtrage Inkscape est donc a faire cote client.

### Points clés

- 10 articles Inkscape indexés depuis l'ajout du flux feed/615 (inkscape.org/news)
- Dernière release : Inkscape 1.4.4 (2026-05-06) — ameliorations performances et corrections crashes
- Inkscape soutient une pétition allemande pour la reconnaissance des bénévoles Open Source (2026-05-13)
- Interview artiste : court-métrage animé réalisé entièrement sous Inkscape (2026-04-02)
- L'API GReader q= ne filtre pas par mot-clé : retourne tous les articles du stream — filtrage client nécessaire
- Flux claude\_foss opérationnel : 7 sources (Inkscape, LinuxFr, Planet GNOME, Blender, LibreOffice, Libre Arts)

### Limites

Le parametre q= de l'API GReader FreshRSS ne filtre pas par mot-cle. Pour une recherche thematique precise, il faut recuperer tous les articles et filtrer cote client sur title + content. A corriger dans search\_foss.py.

### Localisation des ressources

<table id="bkmrk-urls%5B%22https%3A%2F%2Finksca"><tbody><tr><th style="width: 160px;">URLs</th><td>\["https://inkscape.org/news/2026/05/13/inkscape-supports-german-petition-to-recognize-ope/", "https://inkscape.org/news/2026/05/06/inkscape-144-boosts-performance-and-crushes-crashe/", "https://inkscape.org/news/2026/04/02/artist-interview-meet-jorge-who-made-a-short-film/", "https://inkscape.org/news/2026/03/02/inkscape-is-hiring-2026-1/", "https://inkscape.org/news/2025/12/26/bugs-banished-inkscape-143-is-out/", "https://inkscape.org/news/2025/10/12/indiafoss-2025/", "https://inkscape.org/news/2025/06/08/libre-graphics-meeting-2025/", "https://inkscape.org/news/2025/06/01/inkscape-summit-nuremberg/", "https://inkscape.org/news/2025/05/12/2-in-1-release-inkscape-142-is-out/", "https://inkscape.org/news/2025/02/05/inkscape-summit-frankfurt-2025/"\]</td></tr><tr><th style="width: 160px;">Chemins</th><td>—</td></tr><tr><th style="width: 160px;">IDs</th><td>\["feed/615 (Inkscape News)", "user/-/label/claude\_foss"\]</td></tr><tr><th style="width: 160px;">Auteurs / Source</th><td>\["Inkscape Project"\]</td></tr><tr><th style="width: 160px;">Métadonnées</th><td>{"articles\_inkscape": 10, "articles\_total\_stream": 100, "flux\_claude\_foss": 7, "derniere\_version": "Inkscape 1.4.4", "date\_derniere\_version": "2026-05-06", "periode\_couverte": "2025-02 a 2026-05"}</td></tr></tbody></table>

### Tags

**\#Inkscape** **\#logiciel-libre** **\#SVG** **\#dessin-vectoriel** **\#FOSS** **\#FreshRSS** **\#claude\_foss**

### Suite / Pistes

1/ Corriger search\_foss.py pour filtrer cote client sur title+content. 2/ Ajouter flux Libre Graphics Meeting et Planet Inkscape si existants. 3/ Relancer apres quelques jours pour capter les nouveaux articles. 4/ Croiser avec Kavita (livres SVG/Inkscape) et kDrive (tutoriels eventuels).

---

# 11_Gitea_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Gitea**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/162](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/162)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 12_Grafana_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Grafana**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/163](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/163)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 13_Immich_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Immich**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/164](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/164)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 14_Jellyfin_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Jellyfin**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/165](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/165)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 15_Joplin_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Joplin**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/166](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/166)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 16_Kavita_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Kavita**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/167](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/167)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 17_Komga_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Komga**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/168](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/168)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 18_Mealie_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Mealie**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/169](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/169)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 19_Navidrome_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Navidrome**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/170](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/170)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 20_NodeExporter_les explorations

Journal des recherches réalisées avec Claude Code sur le service **NodeExporter**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/171](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/171)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 21_Prometheus_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Prometheus**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/172](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/172)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 22_Readeck_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Readeck**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/173](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/173)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 23_Syncthing_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Syncthing**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/174](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/174)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 24_Yourls_les explorations

Journal des recherches réalisées avec Claude Code sur le service **Yourls**.  
Documentation technique : [https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/175](https://bookstack.juxjux.ovh/books/le-livre-de-claude/page/175)  
Chaque entrée est automatiquement enregistrée dans la table `recherches` (PostgreSQL Alteris, DB 35 Metabase).

---

## RCH-AAAAMMJJ-NNNN — \[Objet de la recherche\]

<table id="bkmrk-dateaaaa-mm-jj-servi"><tbody><tr><th style="width:160px">Date</th><td>AAAA-MM-JJ</td></tr><tr><th>Service</th><td>\[nom du service\]</td></tr><tr><th>Contexte</th><td>\[Pourquoi cette recherche — quelle question, quel besoin, quel problème\]</td></tr><tr><th>Outils utilisés</th><td>\[MCP utilisé / API directe / PowerShell / Python / recherche web...\]</td></tr><tr><th>Requête</th><td>`[query exacte, paramètres, filtres, commandes]`</td></tr></tbody></table>

### Résultats

\[Description des résultats obtenus — texte libre, liste, tableau selon le volume\]

### Points clés

- \[Insight 1 — ce qui est important ou surprenant\]
- \[Insight 2\]
- \[Insight 3\]

### Limites

\[Ce qui manque, erreurs rencontrées, données absentes, pistes non abouties\]

### Localisation des ressources

<table id="bkmrk-urls%5Bliens-directs-v"><tbody><tr><th style="width:160px">URLs</th><td>\[liens directs vers les ressources trouvées\]</td></tr><tr><th>Chemins</th><td>\[chemins fichiers, répertoires, arborescences\]</td></tr><tr><th>IDs</th><td>\[IDs containers, pages, assets, items...\]</td></tr><tr><th>Auteurs / Source</th><td>\[auteurs, éditeurs, provenance\]</td></tr><tr><th>Métadonnées</th><td>\[dates, formats, tailles, langues, coordonnées...\]</td></tr></tbody></table>

### Tags

**\#tag1** **\#tag2** **\#tag3**

### Suite / Pistes

\[Questions ouvertes, actions à entreprendre, recherches complémentaires à lancer\]

---

# 25_StirlingPDF

## RCH-20260802-0001 — Echec OCR sur images PNG — deux refus cumules d'ocrmypdf (canal alpha + DPI absent)

<table id="bkmrk-date2026-08-02-servi"><tbody><tr><th style="width:160px">Date</th><td>2026-08-02</td></tr><tr><th>Service</th><td>StirlingPDF</td></tr><tr><th>Contexte</th><td>Julien signale une erreur HTTP 500 lors d'un OCR sur une image PNG via StirlingPDF. L'interface web n'affiche aucun detail exploitable, le diagnostic passe par les logs du container.</td></tr><tr><th>Outils utilisés</th><td>docker logs stirling-pdf, API /api/v1/misc/ocr-pdf, Pillow, tesseract --list-langs</td></tr><tr><th>Requête</th><td>`POST /api/v1/misc/ocr-pdf (multipart fileInput, languages=[fra], ocrType=Force-OCR) sur PNG RGBA, puis sur variantes aplaties et converties, avec mesure docker stats en parallele.`</td></tr></tbody></table>

### Résultats

Deux erreurs distinctes et cumulees dans ocrmypdf 17.4.0, revelees seulement dans les logs : (1) UnsupportedImageFormatError — The input image has an alpha channel ; (2) une fois l'alpha retire, DpiError — Input file is an image, but has no resolution (DPI) in its metadata. StirlingPDF ne transmet pas l'option --image-dpi a ocrmypdf, donc tout PNG sans DPI dans ses metadonnees echoue. Deux contournements valides en test : voie interface web (Convert &gt; Image to PDF puis OCR sur le PDF, HTTP 200) et voie scriptee (aplatissement de l'alpha sur fond blanc + DPI force a 300, HTTP 200). Texte reconnu restitue a l'identique sur une page de test en francais. Mesure memoire : pic a 894 Mio pour une seule page A4 300 dpi.

### Points clés

- L'interface web ne remonte pas la cause : le diagnostic exige docker logs stirling-pdf
- Les deux erreurs sont sequentielles — corriger l'alpha seul ne suffit pas, le DPI bloque ensuite
- Convertir l'image en PDF avant l'OCR neutralise les deux problemes sans outil local
- 6 langues tesseract installees : fra, eng, deu, por, chi\_sim, osd
- ocrmypdf et tesseract sont des process Python hors JVM : -Xmx ne les borne pas, seul le plafond cgroup du container s'applique
- La limite de 1 Go prevue pour l'allegement du 2026-08-02 aurait provoque un OOM kill pendant l'OCR — portee a 2 Go

### Limites

Mesure realisee sur une page A4 300 dpi generee synthetiquement ; un document multi-pages ou un scan haute resolution consommera davantage. Le pic de 894 Mio est un plancher, pas un maximum.

### Localisation des ressources

<table id="bkmrk-urls%5B%22https%3A%2F%2Fspdf.j"><tbody><tr><th style="width:160px">URLs</th><td>\["https://spdf.juxjux.ovh", "https://spdf.juxjux.ovh/swagger-ui/index.html"\]</td></tr><tr><th style="width:160px">Chemins</th><td>\["D:\\\\Syncthing\\\\Jux\_univers\\\\Jux-scripts\\\\Stirling-OCR\\\\ocr\_image.py", "D:\\\\Syncthing\\\\Jux\_univers\\\\Jux-scripts\\\\Stirling-OCR\\\\README.md", "/home/debian/stirling-compose-new.yml", "/home/debian/stirling-compose-new.yml.orig1g"\]</td></tr><tr><th style="width:160px">IDs</th><td>\["stack Portainer 89", "container stirling-pdf", "page BookStack 211"\]</td></tr><tr><th style="width:160px">Auteurs / Source</th><td>—</td></tr><tr><th style="width:160px">Métadonnées</th><td>{"ocrmypdf": "17.4.0", "tesseract": "5.3.4", "endpoint\_ocr": "POST /api/v1/misc/ocr-pdf", "pic\_memoire\_ocr": "894 MiB / page A4 300 dpi", "limite\_memoire\_retenue": "2g"}</td></tr></tbody></table>

### Tags

**\#StirlingPDF** **\#OCR** **\#ocrmypdf** **\#tesseract** **\#PNG** **\#alpha** **\#DPI** **\#memoire** **\#Docker**

### Suite / Pistes

Verifier apres l'application du compose allege (2026-08-02 19h) que compress-pdf ET l'OCR fonctionnent toujours avec memory=2g et -Xmx512m.

---

## RCH-20260530-0001 — Mise en place API StirlingPDF pour compression PDF automatisée (workflow geo\_loud)

<table id="bkmrk-date2026-05-30-servi"><tbody><tr><th style="width:160px;">Date</th><td>2026-05-30</td></tr><tr><th>Service</th><td>StirlingPDF</td></tr><tr><th>Contexte</th><td>Étape 3 du workflow geo\_loud : automatiser la compression des 127 PDFs lourds (&gt;75 Mo) déplacés dans \\\\NASMAISON\\foxy\\geo\_loud\\. Objectif : appeler l'API StirlingPDF depuis le PC, écraser chaque fichier avec sa version compressée, mettre à jour la DB SQLite. Fichier de test : 000209\_L'inde.pdf (314 Mo).</td></tr><tr><th>Outils utilisés</th><td>StirlingPDF API REST (JWT Bearer) | curl.exe | plink (PuTTY) pour SSH nginx | Python 3.14 + requests | SQLite nas\_geographie.db</td></tr><tr><th>Requête API</th><td>`POST https://spdf.juxjux.ovh/api/v1/misc/compress-pdf — multipart/form-data champ fileInput, header Authorization: Bearer <token>`</td></tr></tbody></table>

### Résultats

Auth JWT résolue. nginx corrigé (client\_max\_body\_size 500M). Test de compression réussi sur 000209\_L'inde.pdf : 314 Mo → 311.7 Mo (0.7% de gain — PDF déjà optimisé en images JPEG). Script `nas_geo_compress.py` opérationnel pour traitement en batch de tous les fichiers.

### Points clés

- **Auth imposée :** malgré `DOCKER_ENABLE_SECURITY=false` dans la stack Docker, StirlingPDF impose un compte admin au premier lancement. Compte créé : **admin / Motdepasse18!**
- **Endpoint de login :** `POST /api/v1/auth/login` avec body JSON `{"username":"admin","password":"Motdepasse18!"}` → réponse : JWT dans `.session.access_token`, valable 24h
- **Utilisation du token :** header `Authorization: Bearer <token>` sur chaque appel API
- **nginx :** client\_max\_body\_size par défaut = 1 Mo → erreur 413 sur gros fichiers. Correction : ajout de `client_max_body_size 500M;` dans `/etc/nginx/sites-enabled/spdf.juxjux.ovh` (via plink/SSH), puis `sudo nginx -s reload`
- **Endpoint compression :** `POST /api/v1/misc/compress-pdf` — multipart avec champ `fileInput` — retourne le PDF compressé directement dans le corps de la réponse (binary)
- **Gain variable :** PDFs avec images JPEG déjà compressées → gain faible (&lt;1%). PDFs texte/vectoriel ou images PNG → gain potentiellement important (30–70%)
- **PowerShell inadapté aux gros fichiers :** concaténation de byte arrays → OutOfMemoryException sur 314 Mo. Utiliser curl.exe ou Python requests
- **Spec API :** `/v3/api-docs` retourne le HTML de la SPA React. Documentation disponible dans la Swagger UI interactive : `https://spdf.juxjux.ovh/swagger-ui/index.html` (après login)

### Limites

- Token JWT expire après 24h — pour des batchs très longs, prévoir un re-login automatique
- La compression StirlingPDF n'expose pas de paramètre de niveau dans cette version — niveau par défaut uniquement
- Le fichier transite en RAM sur le VPS pendant le traitement — fichiers &gt;500 Mo potentiellement problématiques selon la RAM disponible

### Script nas\_geo\_compress.py

**Emplacement :** `C:\Users\eliob\.claude\nas_geo_compress.py`  
**Lancement :** `py C:\Users\eliob\.claude\nas_geo_compress.py`  
**Dépendances :** `pip install requests` (sqlite3 et os natifs Python)

Le script ajoute automatiquement les colonnes `taille_compresse_octets` et `date_compression` à la table `fichiers` si elles n'existent pas encore.

```
"""
Étape 3 du workflow geo_loud : compression PDF via StirlingPDF.
- Lit les fichiers statut='deplace' dans nas_geographie.db
- Envoie chaque PDF à l'API StirlingPDF
- Écrase le fichier d'origine avec la version compressée
- Met à jour la DB (taille_compresse_octets, date_compression)
"""
import sqlite3
import requests
import os
from datetime import datetime

DB_PATH = r"C:\Users\eliob\Documents\nas_geographie.db"
GEO_LOUD = r"\\NASMAISON\foxy\geo_loud"
STIRLING_URL = "https://spdf.juxjux.ovh"
STIRLING_USER = "admin"
STIRLING_PASS = "Motdepasse18!"


def get_token():
    r = requests.post(
        f"{STIRLING_URL}/api/v1/auth/login",
        json={"username": STIRLING_USER, "password": STIRLING_PASS},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["session"]["access_token"]


def init_db_columns(conn):
    cur = conn.cursor()
    cols = {row[1] for row in cur.execute("PRAGMA table_info(fichiers)")}
    if "taille_compresse_octets" not in cols:
        cur.execute("ALTER TABLE fichiers ADD COLUMN taille_compresse_octets INTEGER")
    if "date_compression" not in cols:
        cur.execute("ALTER TABLE fichiers ADD COLUMN date_compression TEXT")
    conn.commit()


def get_pending(conn):
    cur = conn.cursor()
    cur.execute("""
        SELECT id, nom, chemin_geo_loud, taille_octets
        FROM fichiers
        WHERE statut = 'deplace'
          AND extension IN ('.pdf', '.PDF')
          AND (date_compression IS NULL)
        ORDER BY taille_octets DESC
    """)
    return cur.fetchall()


def compress_file(token, filepath):
    with open(filepath, "rb") as f:
        r = requests.post(
            f"{STIRLING_URL}/api/v1/misc/compress-pdf",
            headers={"Authorization": f"Bearer {token}"},
            files={"fileInput": (os.path.basename(filepath), f, "application/pdf")},
            timeout=600,
            stream=True,
        )
    r.raise_for_status()
    return r.content


def update_db(conn, file_id, taille_compresse):
    conn.execute("""
        UPDATE fichiers
        SET taille_compresse_octets = ?, date_compression = ?
        WHERE id = ?
    """, (taille_compresse, datetime.now().isoformat(), file_id))
    conn.commit()


def fmt_mo(octets):
    return f"{octets / 1_048_576:.1f} Mo"


def main():
    print("Connexion à StirlingPDF...")
    token = get_token()
    print("Token JWT OK")

    conn = sqlite3.connect(DB_PATH)
    init_db_columns(conn)
    pending = get_pending(conn)
    print(f"{len(pending)} fichier(s) PDF à compresser\n")

    if not pending:
        print("Rien à faire.")
        conn.close()
        return

    total_avant = sum(r[3] for r in pending)
    total_apres = 0
    ok = 0
    errors = []

    for i, (file_id, nom, chemin_geo_loud, taille_avant) in enumerate(pending, 1):
        filepath = chemin_geo_loud or os.path.join(GEO_LOUD, nom)
        if not os.path.exists(filepath):
            print(f"[{i}/{len(pending)}] ABSENT  {nom}")
            errors.append((nom, "fichier absent"))
            continue

        taille_reel_avant = os.path.getsize(filepath)
        print(f"[{i}/{len(pending)}] {nom}")
        print(f"    avant : {fmt_mo(taille_reel_avant)}", end=" ", flush=True)

        try:
            compressed = compress_file(token, filepath)
            taille_apres_compression = len(compressed)
            gain = (taille_reel_avant - taille_apres_compression) / taille_reel_avant * 100

            tmp = filepath + ".tmp"
            with open(tmp, "wb") as f:
                f.write(compressed)
            os.replace(tmp, filepath)

            update_db(conn, file_id, taille_apres_compression)
            total_apres += taille_apres_compression
            ok += 1
            print(f"-> après : {fmt_mo(taille_apres_compression)} (gain {gain:.1f}%)")

        except Exception as e:
            print(f"-> ERREUR : {e}")
            errors.append((nom, str(e)))
            tmp = filepath + ".tmp"
            if os.path.exists(tmp):
                os.remove(tmp)

    conn.close()

    print(f"\n{'='*50}")
    print(f"Terminé : {ok}/{len(pending)} compressés")
    if ok:
        gain_total = (total_avant - total_apres) / total_avant * 100
        print(f"Volume avant : {fmt_mo(total_avant)}")
        print(f"Volume après : {fmt_mo(total_apres)}")
        print(f"Gain total   : {gain_total:.1f}%  ({fmt_mo(total_avant - total_apres)} récupérés)")
    if errors:
        print(f"\nErreurs ({len(errors)}) :")
        for nom, msg in errors:
            print(f"  {nom} : {msg}")


if __name__ == "__main__":
    main()

```

### Localisation des ressources

<table id="bkmrk-urlshttps%3A%2F%2Fspdf.jux"><tbody><tr><th style="width:160px;">URLs</th><td>https://spdf.juxjux.ovh (UI) | https://spdf.juxjux.ovh/swagger-ui/index.html (API docs, après login)</td></tr><tr><th style="width:160px;">Chemins</th><td>Script : C:\\Users\\eliob\\.claude\\nas\_geo\_compress.py | DB : C:\\Users\\eliob\\Documents\\nas\_geographie.db | Fichiers source : \\\\NASMAISON\\foxy\\geo\_loud\\ | nginx vhost : /etc/nginx/sites-enabled/spdf.juxjux.ovh</td></tr><tr><th style="width:160px;">IDs</th><td>Stack Portainer : stirlingpdf (ID 89) | Container : stirling-pdf | Port interne : 8090</td></tr><tr><th style="width:160px;">Métadonnées</th><td>{"fichiers\_a\_traiter": 127, "volume\_total\_go": 13.577, "test\_fichier": "000209\_L-inde.pdf", "test\_avant\_mo": 314, "test\_apres\_mo": 311.7, "test\_gain\_pct": 0.7, "nginx\_max\_body": "500M", "token\_duree\_h": 24}</td></tr></tbody></table>

### Tags

**\#StirlingPDF** **\#compression** **\#PDF** **\#geo\_loud** **\#API** **\#JWT** **\#nginx** **\#Python** **\#NAS** **\#workflow**

### Suite / Pistes

1/ Lancer le script sur l'ensemble des 127 fichiers — surveiller le gain réel par catégorie de PDF.  
2/ Mettre à jour la page BookStack 210 avec les colonnes DB ajoutées (taille\_compresse\_octets, date\_compression) et le bilan de compression une fois le batch terminé.  
3/ Si le gain moyen est insuffisant, explorer d'autres niveaux de compression StirlingPDF ou un outil alternatif (Ghostscript direct).  
4/ Après compression de tous les fichiers : lancer l'étape 4 (restauration) via nas\_geo\_loud.py restaurer.

# 02_Claude et le NAS

# 260801 - Mon Linux OS sur SASNEXTE

Claude prend la main en MCP pour monter et manager une distribution Linux ubiquiste - disponible

# 260528_Essai sur \\NASMAISON\foxy\Géographie\

Workflow geo\_loud — Optimisation des fichiers lourds  
Contexte

Le dossier \\\\NASMAISON\\foxy\\Géographie\\ contient 1 312 fichiers (PDF et EPUB) pour un total de 32,9 Go. Parmi eux, 127 fichiers dépassent 75 Mo et représentent 13,6 Go — soit 41 % du volume total concentré sur moins de 10 % des fichiers.

L'objectif est de sortir ces fichiers lourds pour les optimiser (compression PDF), puis de les remettre exactement à leur emplacement d'origine sans perdre l'arborescence.  
Architecture du système  
Fichier Rôle  
nas\_indexer.py Scanne le NAS et crée la base SQLite  
nas\_geographie.db Référentiel de tous les fichiers avec métadonnées et statut  
nas\_geo\_loud.py Script checkout/checkin — déplace et restaure les fichiers lourds

La base SQLite est la source de vérité : elle connaît à tout moment l'emplacement original de chaque fichier et son statut.  
Colonnes de traçabilité (table fichiers)  
Colonne Description  
chemin\_absolu Chemin d'origine complet sur le NAS  
chemin\_geo\_loud Chemin dans le dossier de travail après déplacement  
statut original / deplace / restaure  
date\_deplacement Horodatage du déplacement  
date\_restauration Horodatage de la restauration  
Workflow complet  
Étape 1 — Indexation initiale  
1  
python nas\_indexer.py "\\\\NASMAISON\\foxy\\Géographie" --output nas\_geographie.db

Résultat : 1 312 fichiers indexés en ~22 secondes, 0 erreur.  
Étape 2 — Export (checkout)

Déplace les 127 fichiers &gt; 75 Mo vers \\\\NASMAISON\\foxy\\geo\_loud\\ :  
1  
2  
3  
4  
python nas\_geo\_loud.py export \\  
\--db nas\_geographie.db \\  
\--dest \\\\NASMAISON\\foxy\\geo\_loud \\  
\--confirmer

Ce que fait le script :

 Interroge la base pour tous les fichiers statut = 'original' et taille &gt; 75 Mo  
 Renomme chaque fichier {id:06d}\_{nom\_original} pour éviter les collisions de noms  
 Déplace physiquement le fichier vers geo\_loud/  
 Met à jour la base : statut = 'deplace', chemin\_geo\_loud, date\_deplacement

 Le préfixe numérique garantit l'unicité même si deux sous-dossiers contiennent un fichier de même nom.

Étape 3 — Optimisation PDF

Traiter les fichiers dans \\\\NASMAISON\\foxy\\geo\_loud\\ avec l'outil d'optimisation. Les fichiers peuvent être traités dans n'importe quel ordre et en plusieurs sessions.  
Étape 4 — Restauration (checkin)  
1  
2  
3  
python nas\_geo\_loud.py restaurer \\  
\--db nas\_geographie.db \\  
\--dest \\\\NASMAISON\\foxy\\geo\_loud

Ce que fait le script :

 Lit tous les enregistrements statut = 'deplace' dans la base  
 Pour chaque fichier présent dans geo\_loud/ : déplace vers son chemin\_absolu d'origine  
 Recrée les sous-dossiers si nécessaire  
 Met à jour : statut = 'restaure', date\_restauration  
 Ignore les fichiers absents de geo\_loud/ (pas encore optimisés)

Étape 5 — Vérification du statut  
1  
python nas\_geo\_loud.py statut --db nas\_geographie.db

Affiche :  
1  
2  
3  
4  
Statut Fichiers Total Go  
\--------------------------------------  
 deplace 127 13.577  
 original 1 185 19.275  
Vues SQL utiles (Metabase / DB Browser)  
1  
2  
3  
4  
5  
6  
7  
8  
\-- Fichiers encore dans geo\_loud  
SELECT nom, ROUND(taille\_octets/1048576.0,1) AS mo, date\_deplacement, chemin\_absolu  
FROM fichiers WHERE statut = 'deplace'  
ORDER BY taille\_octets DESC;

\-- Bilan par statut  
SELECT statut, COUNT(\*) AS nb, ROUND(SUM(taille\_octets)/1073741824.0,3) AS go  
FROM fichiers GROUP BY statut;  
Paramètres disponibles  
Paramètre Défaut Description  
\--db nas\_geographie.db Chemin vers la base SQLite  
\--dest \\\\NASMAISON\\foxy\\geo\_loud Dossier de travail  
\--seuil 75 Seuil en Mo pour la sélection  
\--confirmer (off) Bypass la confirmation interactive  
Ré-indexation après optimisation  
1  
python nas\_indexer.py "\\\\NASMAISON\\foxy\\Géographie" --output nas\_geographie.db --vider  
Fichiers du projet  
Fichier Emplacement  
nas\_indexer.py C:\\Users\\eliob\\Documents\\nas\_indexer.py  
nas\_geo\_loud.py C:\\Users\\eliob\\Documents\\nas\_geo\_loud.py  
nas\_rapport.py C:\\Users\\eliob\\Documents\\nas\_rapport.py  
nas\_geographie.db C:\\Users\\eliob\\Documents\\nas\_geographie.db

# 260611_procédure Komga-PDF par Claude sur StirlingPDF

## Présentation

La procédure Komga-PDF est un script de compression de fichiers PDF pour réduire considérablement la taille du stockage des bibliothèques d'ouvrages de la collection de Julien.

L'acquisition de fichiers issus de bases de données Internet accumule des fichiers PDF en haute résolution (images surtout). Ces fichiers sont synchronisés entre les NAS Synology et un disque dur kDrive Infomaniak de 6 To.

## Contexte

Des points de montage Rclone relient les répertoires kDrive et les containers Docker installés sur le VPS OVH juxjux.ovh. Ces containers lisent les PDF à la volée — permettant ainsi de construire une infrastructure de très forte densité de connaissances digitales (epub, pdf, images, vidéos, musiques...) avec une solution serveur d'entrée de gamme (10 €/mois tout inclus).

La lecture réseau est multi-support : PC, tablette, téléphone. Elle est aussi nomade, séquentielle et pressée. La compacité des fichiers PDF devient donc nécessaire pour diffuser rapidement sur les réseaux. Un magazine ou un ouvrage informatique ne doit pas peser 130 Mo sur un écran de 10 pouces.

## Procédure

- Les nouveaux PDF sont déposés dans le dossier Syncthing : `Syncthing/komga-pdf/` depuis n'importe quelle machine (PC Elio+Jux, PC Nexte, Ubuntu, Xiaomi...)
- Syncthing synchronise automatiquement vers le VPS : `/home/debian/Documents/komga-pdf/`
- Le service `komga-watch` (systemd VPS) détecte l'arrivée via inotifywait local
- Dès détection, `komga_compress_vps.py` compresse le PDF via StirlingPDF et dépose le résultat dans `/home/debian/Documents/komga-compressed/`
- Julien range manuellement les PDF compressés vers sasnexte puis dans le dossier thématique de son choix
- Les originaux ne sont jamais supprimés du VPS — Julien valide et conserve si besoin (haute résolution souhaitée)

## Architecture technique

| Élément | Chemin / URL |
|---|---|
| Dépôt (toutes machines) | `Syncthing/komga-pdf/` |
| Dossier VPS (Syncthing) | `/home/debian/Documents/komga-pdf/` |
| Destination VPS | `/home/debian/Documents/komga-compressed/` |
| API compression | `https://spdf.juxjux.ovh/api/v1/misc/compress-pdf` |
| Scripts VPS | `/home/debian/komga_compress_vps.py` + `/home/debian/komga_watch_vps.sh` |
| Logs | `journalctl -u komga-watch -f` (sur le VPS) |

## Scripts

Le service tourne entièrement sur le VPS — plus de dépendance Ubuntu ni de SSH persistant.

| Fichier | Rôle |
|---|---|
| `komga_compress_vps.py` | Compression : liste les PDFs locaux, envoie à StirlingPDF, écrit dans `komga-compressed/`. Idempotent (ignore les fichiers déjà compressés). |
| `komga_watch_vps.sh` | Surveillance : traite le backlog au démarrage, puis boucle inotifywait locale. |
| `/etc/systemd/system/komga-watch.service` | Service system (pas user), actif au boot, `Restart=always`. |

### Gérer le service (VPS)

```bash
sudo systemctl status komga-watch
sudo systemctl restart komga-watch
journalctl -u komga-watch -f
```

## Retour d'expérience (2026-06-13) — Refactorisation VPS

**Problème de l'architecture Ubuntu** : le service tournait sur Ubuntu avec un SSH persistant vers le VPS. Deux défauts structurels :
- `inotifywait` ne détecte pas les fichiers déjà présents au redémarrage du service (backlog silencieux)
- Impossible à contrôler depuis Windows/Claude Code

**Solution** : service systemd sur le VPS lui-même. inotifywait local, pas de SSH persistant. Le script traite le backlog à chaque démarrage avant d'entrer dans la boucle de surveillance.

**Résultats de compression (2026-06-13)** :

| Fichier | Original | Compressé | Gain |
|---|---|---|---|
| Beaux Arts - Juin 2026.pdf | 75.8 Mo | 61.1 Mo | -19% |
| Connaissance des Arts - Juin 2026.pdf | 57.3 Mo | 35.2 Mo | -39% |
| La Revue du Vin de France - Juin 2026.pdf | 93.3 Mo | 39.9 Mo | -57% |
| Livre lacto fermentation.pdf | 96.6 Mo | 19.6 Mo | **-80%** |
| Monde Gourmand N°93 - Juin 2026.pdf | 41.2 Mo | 17.4 Mo | -58% |

**Points techniques** :
- Dossier VPS avec **D majuscule** : `/home/debian/Documents/` (Syncthing sensible à la casse)
- Race condition inotifywait/Syncthing : attente 3s après événement, script idempotent
- Python : `/usr/bin/python3` (système, `requests` 2.28.1 disponible)
- StirlingPDF auth : JWT via `POST /api/v1/auth/login` → `session.access_token`, valable 24h
- Fichiers `sync-conflict` Syncthing filtrés automatiquement par le script

## Retour d'expérience (2026-06-12)

**Résultats de compression :**

| Fichier | Original | Compressé | Gain |
|---|---|---|---|
| Monde Gourmand N°93 - Juin 2026.pdf | 42 Mo | 17 Mo | -58% |
| Connaissance des Arts - Juin 2026.pdf | 57 Mo | 35 Mo | -39% |

# 260614 - procedure Joplin-compression

## Contexte — instructions de Julien (260614)

J'utilise l'application Joplin sur tous mes appareils. C'est ma mémoire de tout (travail, hobbies, maison...) et donc à force, la base de données se remplit. Elle se compose de notes à l'intérieur desquelles on trouve des images. Même en n'important que des captures d'écran, le poids de ces images est devenu important — de l'ordre de 300 Mo initialement estimé (476 Mo constatés en réalité, voir ci-dessous).

**Appareils synchronisés sous Joplin :**

- VPS Juxjux.OVH (serveur de sync)
- PC Nexte (PC du travail de Julien)
- PC Elio+Jux (PC maison de Julien)
- Mobile Xiaomi T15pro de Julien
- Tablette Samsung S5 de Julien
- Session Ubuntu sur clé SSD de Julien

**Objectif de la procédure :**

1. Compresser le stock d'images contenues dans la base de données Joplin via un process fiable de remplacement
2. Monter un système de compression automatique quotidienne des nouvelles images

**Principes définis par Julien :**

1. Tenir un carnet de bord (observatoire) du poids digital de la BDD Joplin dans la page BookStack Joplin, avec les 15 pièces jointes les plus lourdes
2. Mettre en place sur le VPS une procédure duplication → compression → remplacement d'images, qui se propage via la sync Joplin sur tous les appareils

---

## Exploration technique — Claude, 14/06/2026

### Infrastructure Joplin sur le VPS

Contrairement à ce qu'on pourrait attendre, Joplin Server **n'utilise pas SQLite** mais **PostgreSQL**.

<table id="bkmrk-container-image-r%C3%B4le"><thead><tr><th>Container</th><th>Image</th><th>Rôle</th></tr></thead><tbody><tr><td>`joplin`</td><td>`joplin/server:latest`</td><td>Serveur de sync Joplin</td></tr><tr><td>`joplin-db`</td><td>`postgres:15-alpine`</td><td>Base de données</td></tr><tr><td>`joplin-nginx`</td><td>`nginx:alpine`</td><td>Reverse proxy interne</td></tr><tr><td>`joplin_to_obsidian`</td><td>image custom</td><td>Container migration (actif, sans impact)</td></tr></tbody></table>

**Volume de données :** `/home/debian/joplin-data` → `/home/joplin/.config/joplin` (bind mount)

**Connexion DB :** `POSTGRES_HOST=joplin-db`, `POSTGRES_DATABASE=joplin`, `POSTGRES_USER=joplin`

**Important :** le port 5432 de joplin-db n'est **pas exposé** à l'extérieur du réseau Docker. Tout script de manipulation doit tourner sur le VPS et se connecter via l'IP interne Docker.

### Structure de la base de données

La table centrale est `items` (23 tables au total). Chaque note, ressource et paramètre Joplin est une ligne dans cette table.

Colonnes clés :

- `content` (bytea) — données binaires brutes
- `content_size` (integer) — taille en octets
- `content_storage_id` = 1 → stockage de type `Database` (tout est dans PostgreSQL, pas de fichiers externes)
- `jop_type` — type d'item Joplin
- `updated_time` — timestamp de dernière modification (utilisé par les clients pour détecter les changements à sync)

**Répartition par type :**

<table id="bkmrk-jop_type-significati"><thead><tr><th>jop\_type</th><th>Signification</th><th>Nombre</th><th>Poids total</th></tr></thead><tbody><tr><td>0</td><td>Ressource (image/fichier joint)</td><td>736</td><td>**476 MB**</td></tr><tr><td>1</td><td>Note</td><td>699</td><td>8,7 MB</td></tr><tr><td>4</td><td>Tag</td><td>733</td><td>4,5 MB</td></tr><tr><td>13</td><td>NoteTag (relation note↔tag)</td><td>250</td><td>3,9 MB</td></tr><tr><td>2</td><td>Carnet (Folder)</td><td>94</td><td>707 KB</td></tr><tr><td>6</td><td>Master Key</td><td>87</td><td>19 KB</td></tr><tr><td>5</td><td>Setting</td><td>39</td><td>—</td></tr></tbody></table>

### Analyse des ressources (jop\_type = 0)

Les ressources sont stockées comme **bytes bruts** dans la colonne `content`. Le format est détectable via les magic bytes :

- **PNG** (`\x89PNG`) — majorité des ressources
- **JPEG** (`\xff\xd8`) — portion significative
- **ZIP** (`PK\x03\x04`) — cas particulier : ZIP contenant plusieurs images `page_1.png`, `page_2.png`... (documents multi-pages)

La colonne `mime_type` est vide pour toutes les ressources — le type est implicite dans les bytes du contenu.

**Top 15 ressources les plus lourdes (état initial) :**

<table id="bkmrk-rang-id-taille-forma"><thead><tr><th>Rang</th><th>ID</th><th>Taille</th><th>Format</th></tr></thead><tbody><tr><td>1</td><td>0xh87pWrRt82z0DbO9n3yQ</td><td>12,2 MB</td><td>ZIP (page\_1.png 7MB + page\_2.png 5MB)</td></tr><tr><td>2</td><td>M0C32hKC2hMqPAxpRGiVgp</td><td>7,2 MB</td><td>PNG</td></tr><tr><td>3</td><td>UbAqQY3cEbH62vioIHU6Pj</td><td>6,0 MB</td><td>PNG</td></tr><tr><td>4</td><td>ZPQJVSjptMSxE71pV7JbAt</td><td>5,9 MB</td><td>PNG</td></tr><tr><td>5</td><td>h4Lhw1Trx9wgmD7doX9NyZ</td><td>5,9 MB</td><td>PNG</td></tr><tr><td>6</td><td>sbktcNb4IUj0yIovgDt0fL</td><td>5,3 MB</td><td>PNG</td></tr><tr><td>7</td><td>jtzuGpvrRTR12iLzwhcSNn</td><td>5,2 MB</td><td>PNG</td></tr><tr><td>8</td><td>VasIoF2e9EGuNQt38aOFMx</td><td>4,9 MB</td><td>JPEG</td></tr><tr><td>9</td><td>ZACDcQWzQzDLdnV7Qnf933</td><td>4,3 MB</td><td>PNG</td></tr><tr><td>10</td><td>hExoJEEWT2tHz1demE5Nhm</td><td>4,3 MB</td><td>PNG</td></tr><tr><td>11</td><td>veu4HT3bStx07gRUlAEYvG</td><td>4,2 MB</td><td>PNG</td></tr><tr><td>12</td><td>bz9Twmb2F5lj0mPIQi48IB</td><td>4,2 MB</td><td>JPEG</td></tr><tr><td>13</td><td>TzWK21r4n0yvbEtJh02DGB</td><td>4,2 MB</td><td>JPEG</td></tr><tr><td>14</td><td>eD165w1bdEHJg0tq3qWok5</td><td>4,2 MB</td><td>PNG</td></tr><tr><td>15</td><td>HD4SeqIx252nP9nh8HDVnH</td><td>4,1 MB</td><td>PNG</td></tr></tbody></table>

---

## Architecture retenue

### Choix de compression — décision Julien, 14/06/2026

**PNG → JPEG 85%** (lossy). Toutes les images, qu'elles soient PNG ou JPEG à l'origine, sont converties/re-sauvegardées en JPEG qualité 85. Gain estimé : 50–75% par image. Acceptable pour des captures d'écran.

Pour les ZIP multi-pages : chaque image interne est convertie en JPEG 85%, le ZIP est reconstruit.

### Phase 1 — Observatoire

Script `joplin_observatoire.py` sur le VPS :

- Connexion psycopg2 à joplin-db via IP réseau Docker interne
- Calcul des stats globales (taille totale, nombre d'items par format)
- Liste des 15 ressources les plus lourdes avec format et taille
- Mise à jour de la page BookStack Joplin (page 166) avec ces informations

### Phase 2 — Compression (script principal)

Script `joplin_compress.py` sur le VPS :

**Connexion :** psycopg2 → IP Docker interne de `joplin-db` : 5432

**Traitement par ressource :**

1. Lire le blob `content` depuis `items` (jop\_type=0)
2. Détecter le format (magic bytes)
3. Ouvrir avec Pillow, convertir en JPEG 85 (`quality=85, optimize=True`)
4. Pour les ZIP multi-pages : dézipper → compresser chaque image → reconstruire le ZIP
5. Si le gain est &gt; 5% : mettre à jour `content`, `content_size`, `updated_time` en base
6. Logger le résultat (ID, taille avant, taille après, ratio)

**Tracking des items traités :** fichier JSON local `/home/debian/joplin_compress_log.json` — évite de retraiter les ressources déjà compressées lors des passages quotidiens.

**Propagation sync :** Joplin détecte les changements via `updated_time`. Lors de la prochaine synchronisation de chaque client, les ressources compressées sont re-téléchargées automatiquement.

### Phase 3 — Service systemd (cron quotidien)

Timer systemd `joplin-compress.timer` → `joplin-compress.service` :

- Déclenchement quotidien (3h du matin)
- Traite uniquement les nouvelles ressources (non présentes dans le log JSON)
- Met à jour l'observatoire BookStack après chaque passage

---

## Mise en production — 14/06/2026

### Résultat du premier run (stock complet)

<table id="bkmrk-ressources-trait%C3%A9es7"><tbody><tr><th>Ressources traitées</th><td>736 au total</td></tr><tr><th>Compressées</th><td>424</td></tr><tr><th>Ignorées (gain &lt; 5%)</th><td>312</td></tr><tr><th>Erreurs</th><td>0</td></tr><tr><th>Poids avant</th><td>476 Mo</td></tr><tr><th>Poids après</th><td>119,7 Mo</td></tr><tr><th>Économie</th><td>**<span style="color:#008000;">356 Mo (-78,9%)</span>**</td></tr></tbody></table>

### Scripts déployés sur le VPS

<table id="bkmrk-scriptr%C3%B4leoptions-%2Fh"><thead><tr><th>Script</th><th>Rôle</th><th>Options</th></tr></thead><tbody><tr><td>`/home/debian/joplin_compress.py`</td><td>Compression Pillow PNG/JPEG → JPEG 85%, ZIP multi-pages, mise à jour PostgreSQL</td><td>`--dry-run` (simulation) / `--limit N` (N ressources max)</td></tr><tr><td>`/home/debian/joplin_observatoire.py`</td><td>Stats DB + top 15 → mise à jour page BookStack Joplin (ID 166)</td><td>—</td></tr></tbody></table>

**Log tracking :** `/home/debian/joplin_compress_log.json` — liste des ressources déjà traitées, évite les doublons aux runs suivants.

### Timer systemd

<table id="bkmrk-servicejoplin-compre"><tbody><tr><th>Service</th><td>`joplin-compress.service`</td></tr><tr><th>Timer</th><td>`joplin-compress.timer`</td></tr><tr><th>Déclenchement</th><td>Chaque nuit à 3h UTC (`OnCalendar=*-*-* 03:00:00`)</td></tr><tr><th>Logs</th><td>`/var/log/joplin-compress.log`</td></tr><tr><th>Statut</th><td><span style="color:#008000;">active (waiting)</span> — prochain run : 15/06/2026 03:00 UTC</td></tr></tbody></table>

### Notes techniques

- joplin-db IP Docker interne : `172.27.0.4` (peut changer si le container est recréé — vérifier avec `docker inspect joplin-db -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'`)
- La compression modifie `content`, `content_size` et `updated_time` dans la table `items`
- Les clients Joplin re-téléchargent les ressources modifiées lors de la prochaine synchronisation (détection via `updated_time`)
- Les images à fond transparent (RGBA/LA/P) sont aplaties sur fond blanc avant conversion JPEG

# 260615 - Immich performance

<p class="callout info">260615 -instructions pour la procédure Immich Performance  
Les photos de famille (et des vidéos) sont un patrimoine important pour notre famille. Donc elles font l'objet de beaucoup d'attention....et de volume de stockage. Les photos sont stockées sur les 2 NAS - Nasmaison et Sasnexte synchronisées à travers les outils Synology. A partir de Sasnexte, un script journalier Synology les propulse sur le VPS Kdrive pour être lues en lecture seule par toute la famille (elles sont également sur deux autres disques durs USB....).   
  
Aujourd'hui, le dossier photos du Sasnexte que l'on doit considérer comme le cœur de ce dispositif nécessite une observation un peu plus fine car :   
- des compressions vidéos doivent être faites pour les rendre plus faciles en lecture sur les portables en mobilité  
- des compressions images lorsque le poids est aberrant pour l'usage  
- des doublons existent forcément.  
  
Immich performance est une procédure importante du livre de Claude. </p>

<p class="callout warning">Réponse de Claude</p>

---

#### **Inventaire par Claude Code le 01/10/2025**

  
SAS\_NEXTE@NEXTE:~$ sudo du -h --max-depth=2 /volume1/photo/ | sort -h   
0 /volume1/photo/1968-1994 - photos famille dont Noumea/1982   
0 /volume1/photo/2009-mariage Zymny   
0 /volume1/photo/2014- été/140714-Lyon chez Pierre   
0 /volume1/photo/2020 - Automne Noel/noel2020   
0 /volume1/photo/2024/202401 - Hiver Automne   
0 /volume1/photo/2025/DCIM   
0 /volume1/photo/@eaDir/clientd.tmp.dir   
0 /volume1/photo/@eaDir/cloud.tmp.dir   
0 /volume1/photo/@eaDir/@recycle   
0 /volume1/photo/@eaDir/@tmp   
4.0K /volume1/photo/@eaDir/@drive.queues   
24K /volume1/photo/@eaDir/sharesnap\_share\_configuration   
32K /volume1/photo/2010 - été/@eaDir   
40K /volume1/photo/2011- Ete/@eaDir   
52K /volume1/photo/2021-été covidé/@eaDir   
84K /volume1/photo/@eaDir/980710-photo CV julien.jpg   
264K /volume1/photo/@eaDir/131124-elio pas content.jpg   
352K /volume1/photo/2009 Nouvel an Réveillon/@eaDir   
432K /volume1/photo/@eaDir/2015-soirée mexicaine.jpg   
440K /volume1/photo/1968-1994 - photos famille dont Noumea/Givet   
548K /volume1/photo/@eaDir/150314-Zoee en 18X24.png   
616K /volume1/photo/2009 Nouvel an Réveillon   
656K /volume1/photo/1968-1994 - photos famille dont Noumea/1977   
656K /volume1/photo/@eaDir/7b06435c-6bad-4eb0-aa38-af03bdfbfbc8.jpg   
672K /volume1/photo/@eaDir/PhotoLab445379.jpg   
792K /volume1/photo/@eaDir/160220-elio en 18X24.png   
848K /volume1/photo/2011 - printemps/@eaDir   
900K /volume1/photo/2016 ACDC/@eaDir   
1.5M /volume1/photo/1968-1994 - photos famille dont Noumea/1976   
1.7M /volume1/photo/1968-1994 - photos famille dont Noumea/Pierre-001   
2.1M /volume1/photo/1968-1994 - photos famille dont Noumea/1969   
3.0M /volume1/photo/1968-1994 - photos famille dont Noumea/1978   
3.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1968   
3.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1980   
3.5M /volume1/photo/2014-mars-repas chez maman/@eaDir   
4.1M /volume1/photo/1999/@eaDir   
4.3M /volume1/photo/2014 - 4 ans Zoée/@eaDir   
4.9M /volume1/photo/1968-1994 - photos famille dont Noumea/1979   
4.9M /volume1/photo/2016 ACDC   
5.3M /volume1/photo/1986 - Californie/@eaDir   
5.3M /volume1/photo/Cartes de voeux/@eaDir   
5.5M /volume1/photo/2010-hiver/@eaDir   
6.0M /volume1/photo/1968-1994 - photos famille dont Noumea/1992   
6.6M /volume1/photo/1930-2016 - Photos BERTRAND MER/Elio   
6.6M /volume1/photo/2016-best photos pour 70 ans/Elio   
6.7M /volume1/photo/1999   
6.9M /volume1/photo/1968-1994 - photos famille dont Noumea/Etats-Unis 1986   
7.4M /volume1/photo/2015 - Noël/@eaDir   
7.6M /volume1/photo/1930-2016 - Photos BERTRAND MER/Les communions solennelle s   
7.6M /volume1/photo/2016-best photos pour 70 ans/Les communions solennelles   
7.8M /volume1/photo/1968-1994 - photos famille dont Noumea/1994   
7.9M /volume1/photo/2013-Serbie/@eaDir   
8.0M /volume1/photo/2014/@eaDir   
8.4M /volume1/photo/1968-1994 - photos famille dont Noumea/1990   
8.5M /volume1/photo/2004 - été/@eaDir   
8.5M /volume1/photo/2022-Noel/@eaDir   
8.6M /volume1/photo/2015 - Automne/@eaDir   
8.9M /volume1/photo/1930-2016 - Photos BERTRAND MER/Les amis, la famille en n oir et blanc   
8.9M /volume1/photo/2016-best photos pour 70 ans/Les amis, la famille en noir et blanc   
9.5M /volume1/photo/1968-1994 - photos famille dont Noumea/1981   
9.9M /volume1/photo/2018 - Noel/@eaDir   
10M /volume1/photo/#recycle/2016 - 70 ans maman\_DiskStation\_Nov-04-1745-2020 \_CaseConflict   
11M /volume1/photo/1930-2016 - Photos BERTRAND MER/Album de la famille de Re née Campanella   
11M /volume1/photo/2010 - naissance Zoée/@eaDir   
11M /volume1/photo/2014/Noël 2014   
11M /volume1/photo/2016-best photos pour 70 ans/Album de la famille de Renée Campanella   
12M /volume1/photo/2013 Marseille/@eaDir   
12M /volume1/photo/2014-mars-repas chez maman   
12M /volume1/photo/2015-Hiver/@eaDir   
12M /volume1/photo/2015-inventaire maison assurances/@eaDir   
13M /volume1/photo/1968-1994 - photos famille dont Noumea/1975   
14M /volume1/photo/1968-1994 - photos famille dont Noumea/1983   
15M /volume1/photo/2005 - été/@eaDir   
16M /volume1/photo/2016-mai juin/@eaDir   
16M /volume1/photo/2016 - Valras/@eaDir   
17M /volume1/photo/2004 - été   
17M /volume1/photo/2010 - naissance Zoée   
18M /volume1/photo/1968-1977/@eaDir   
18M /volume1/photo/2014 - 4 ans Zoée   
18M /volume1/photo/2014/Anniversaire\_Elio\_2014   
18M /volume1/photo/2016-avril avant crète/@eaDir   
19M /volume1/photo/1930-2016 - Photos BERTRAND MER/Grand-père Emile et mamie Rosa   
19M /volume1/photo/2016-best photos pour 70 ans/Grand-père Emile et mamie Ro sa   
21M /volume1/photo/1930-2016 - Photos BERTRAND MER/@eaDir   
21M /volume1/photo/1930-2016 - Photos BERTRAND MER/L'album de Papa et Maman   
21M /volume1/photo/2016-best photos pour 70 ans/L'album de Papa et Maman   
21M /volume1/photo/2016- photos Maman Papa/@eaDir   
22M /volume1/photo/2011 - Automne/@eaDir   
22M /volume1/photo/2013 Noël/@eaDir   
22M /volume1/photo/2014-Hiver Printemps/@eaDir   
23M /volume1/photo/2014 - Automne Noel/@eaDir   
24M /volume1/photo/2011 - jour de l'an/@eaDir   
24M /volume1/photo/2014-mur effondré - Ville de Toulon/@eaDir   
25M /volume1/photo/2009 - Papa/@eaDir   
25M /volume1/photo/2010-hiver   
25M /volume1/photo/2021-été covidé/2021 - après vacances   
25M /volume1/photo/Cartes de voeux   
26M /volume1/photo/1968-1994 - photos famille dont Noumea/1984   
27M /volume1/photo/1930-2016 - Photos BERTRAND MER/Enfants Mer et cousins   
27M /volume1/photo/2008 Toscane/@eaDir   
27M /volume1/photo/2016 - 70 ans Maman/@eaDir   
27M /volume1/photo/2016-best photos pour 70 ans/Enfants Mer et cousins   
27M /volume1/photo/2022-automne a Noel/@eaDir   
29M /volume1/photo/2018 - Noel   
30M /volume1/photo/2008 - mariage Héléna et Jérome/@eaDir   
30M /volume1/photo/2012 - Eté/@eaDir   
30M /volume1/photo/#recycle/2016 - 70 ans maman\_DiskStation\_Nov-04-1745-2020 \_CaseConflict\_1   
31M /volume1/photo/2025/2501 à 2502   
32M /volume1/photo/2015 - Noël   
33M /volume1/photo/2014/Carnaval 2014   
34M /volume1/photo/2016-best photos pour 70 ans/@eaDir   
35M /volume1/photo/2014-Barcelone/@eaDir   
36M /volume1/photo/2013/@eaDir   
36M /volume1/photo/2016-Parc Vert Coteau/soirée janvier 2016   
36M /volume1/photo/2024/2024 - Nouvel an Arriège   
37M /volume1/photo/2015 - Automne   
38M /volume1/photo/2014/Février 2014   
39M /volume1/photo/2011 - Noel/@eaDir   
39M /volume1/photo/2020 - Automne Noel/@eaDir   
40M /volume1/photo/2014/Sept\_2014\_4ans\_Zoée   
40M /volume1/photo/@eaDir/SYNO@.fileindexdb   
41M /volume1/photo/2016-Parc Vert Coteau/avril 2016 état   
41M /volume1/photo/2022-Noel   
43M /volume1/photo/@eaDir   
44M /volume1/photo/2009 - Papa   
44M /volume1/photo/2012/@eaDir   
45M /volume1/photo/1930-2016 - Photos BERTRAND MER/Papa juin 2009 - Le livre d'Alain   
45M /volume1/photo/2016-best photos pour 70 ans/Papa juin 2009 - Le livre d' Alain   
47M /volume1/photo/2005 - été   
47M /volume1/photo/2008 Toscane   
50M /volume1/photo/2019-Cabaret Vert/@eaDir   
51M /volume1/photo/2015 - Juillet Valras/@eaDir   
52M /volume1/photo/2021-hiver printemps/@eaDir   
53M /volume1/photo/2015-Hiver   
53M /volume1/photo/2018-défi Genes/@eaDir   
54M /volume1/photo/2008 - été Hautes Alpes/@eaDir   
54M /volume1/photo/2009 - Elio/@eaDir   
55M /volume1/photo/2013-Serbie   
58M /volume1/photo/2013 Marseille   
58M /volume1/photo/2015-inventaire maison assurances   
62M /volume1/photo/2007-1er janvier/@eaDir   
62M /volume1/photo/2016 - Valras   
64M /volume1/photo/2014- été/@eaDir   
67M /volume1/photo/2009 - été Irlande/@eaDir   
67M /volume1/photo/2016-mai juin   
70M /volume1/photo/1968-1994 - photos famille dont Noumea/Nouméa   
70M /volume1/photo/2011- Ete/GARD juillet 2011   
71M /volume1/photo/2020 - Hiver Confinement COVID/@eaDir   
73M /volume1/photo/2022-hiver à Paques/@eaDir   
73M /volume1/photo/2024/202412 - Automne Noel   
75M /volume1/photo/2013 - Printemps/@eaDir   
76M /volume1/photo/2016-Parc Vert Coteau   
76M /volume1/photo/2024/@eaDir   
79M /volume1/photo/2012 - Eté/2012 - Bretagne   
79M /volume1/photo/2014-Hiver Printemps   
81M /volume1/photo/2013 Noël   
82M /volume1/photo/2017-Voyage à Turin/@eaDir   
84M /volume1/photo/2016-Venasque/@eaDir   
86M /volume1/photo/1986 - Californie   
88M /volume1/photo/2023-ete/@eaDir   
91M /volume1/photo/2009 - été Ardèche/@eaDir   
93M /volume1/photo/2016-avril avant crète   
94M /volume1/photo/2007-1er janvier   
96M /volume1/photo/2021-Automne et Noel/@eaDir   
97M /volume1/photo/2008 - été Hautes Alpes   
99M /volume1/photo/PhotoLibrary/2025   
100M /volume1/photo/2014- Porto - Primavera/@eaDir   
107M /volume1/photo/2014-mur effondré - Ville de Toulon   
108M /volume1/photo/2023 - Automne Noel/@eaDir   
111M /volume1/photo/2009 - été Irlande   
111M /volume1/photo/2015- printemps/@eaDir   
114M /volume1/photo/2025/2504 et 2505   
125M /volume1/photo/2010 - été   
125M /volume1/photo/2010 - été/Beauduc   
125M /volume1/photo/2014 - Automne Noel   
130M /volume1/photo/2016-Crete/@eaDir   
131M /volume1/photo/2011 - jour de l'an   
138M /volume1/photo/2021-été covidé/2021 avant vacances   
139M /volume1/photo/2013   
140M /volume1/photo/2018 - Valras/@eaDir   
143M /volume1/photo/2016-Automne Noel/@eaDir   
145M /volume1/photo/2013-Pays Bas/@eaDir   
146M /volume1/photo/2014-Barcelone   
150M /volume1/photo/2023-Hiver à Paques/@eaDir   
152M /volume1/photo/2008 - mariage Héléna et Jérome   
153M /volume1/photo/2017-Automne Noel/@eaDir   
154M /volume1/photo/2014/Mai\_Juin 2014   
157M /volume1/photo/2014/Avril 2014   
159M /volume1/photo/2022-automne a Noel   
162M /volume1/photo/2009 - été Ardèche   
173M /volume1/photo/2014 - 5 jours en Corse/@eaDir   
178M /volume1/photo/2016-best photos pour 70 ans/Ma famille pour mes 70 ans   
178M /volume1/photo/2020 -Printemps/@eaDir   
179M /volume1/photo/1930-2016 - Photos BERTRAND MER   
180M /volume1/photo/1968-1994 - photos famille dont Noumea   
181M /volume1/photo/2019- Hiver Printemps/@eaDir   
181M /volume1/photo/2022 - été Flandres NL Paris/@eaDir   
183M /volume1/photo/2012   
184M /volume1/photo/2009 - Elio   
186M /volume1/photo/2014/2014-été   
192M /volume1/photo/2016- photos Maman Papa   
203M /volume1/photo/1968-1977   
206M /volume1/photo/1967 à 2000 - photos famille Bertrand/@eaDir   
213M /volume1/photo/2023-Mai à Vacances Eté/@eaDir   
214M /volume1/photo/2019-Automne/@eaDir   
222M /volume1/photo/2015 - Juillet Valras   
229M /volume1/photo/2020 - Automne Noel   
230M /volume1/photo/2018-printemps/@eaDir   
258M /volume1/photo/2021-hiver printemps   
281M /volume1/photo/2014- été   
282M /volume1/photo/2018 - automne noel/@eaDir   
323M /volume1/photo/2011 - Noel   
325M /volume1/photo/2018-défi Genes   
348M /volume1/photo/2005 - naissance Elio/@eaDir   
354M /volume1/photo/2011 - printemps   
368M /volume1/photo/2011 - Automne   
381M /volume1/photo/2017-Hiver-Printemps/@eaDir   
384M /volume1/photo/2016-Venasque   
407M /volume1/photo/2020 -Printemps   
409M /volume1/photo/2016-best photos pour 70 ans   
419M /volume1/photo/2016 - 70 ans Maman   
434M /volume1/photo/2020 - Hiver Confinement COVID   
439M /volume1/photo/2017-Voyage à Turin   
460M /volume1/photo/2023-Mai à Vacances Eté   
462M /volume1/photo/2011- Ete/LIGURIE aout 2011   
500M /volume1/photo/2013 - Printemps   
511M /volume1/photo/2023-ete   
515M /volume1/photo/2022-hiver à Paques   
520M /volume1/photo/2012 - Eté/2012 - été Buis   
525M /volume1/photo/2016-Crete   
528M /volume1/photo/2014- Porto - Primavera   
531M /volume1/photo/2011- Ete   
535M /volume1/photo/2023-Vacances D NL B/@eaDir   
573M /volume1/photo/2023 - Automne Noel   
575M /volume1/photo/2016-été Ré Gers/@eaDir   
580M /volume1/photo/2018-Barcelone Primavera Sound/@eaDir   
618M /volume1/photo/2019-Cabaret Vert   
629M /volume1/photo/2019 Bretagne Alpes/@eaDir   
635M /volume1/photo/2013-Pays Bas   
663M /volume1/photo/2021-Automne et Noel   
667M /volume1/photo/2014   
685M /volume1/photo/2015- printemps   
700M /volume1/photo/2017-été Scandinavie/@eaDir   
718M /volume1/photo/2024/2024 - Eté Italie Autriche   
759M /volume1/photo/2018 - Valras   
809M /volume1/photo/#recycle/2025   
817M /volume1/photo/2016-Automne Noel   
846M /volume1/photo/2025/2506 à 2509   
860M /volume1/photo/#recycle   
907M /volume1/photo/2019-Automne   
920M /volume1/photo/2017-Automne Noel   
935M /volume1/photo/2023-Hiver à Paques   
941M /volume1/photo/2024/2024-Porto   
944M /volume1/photo/cecile tri 2022/@eaDir   
945M /volume1/photo/PhotoLibrary/DCIM   
956M /volume1/photo/2005 - naissance Elio   
964M /volume1/photo/2020 - été Vienne Venise/@eaDir   
991M /volume1/photo/2025   
1.1G /volume1/photo/2014 - 5 jours en Corse   
1.1G /volume1/photo/2015-Croatie Autriche/@eaDir   
1.1G /volume1/photo/2018-the Alpen/@eaDir   
1.1G /volume1/photo/PhotoLibrary   
1.2G /volume1/photo/2021-été covidé/2021 - vacances Aout Mont Blanc Cantal   
1.2G /volume1/photo/2022 - été Flandres NL Paris   
1.3G /volume1/photo/2019- Hiver Printemps   
1.3G /volume1/photo/2021-été covidé   
1.4G /volume1/photo/2018-printemps   
1.5G /volume1/photo/2016-été Ré Gers/Vidéo Aveyron Ré et Gers   
1.5G /volume1/photo/2024/2024-Via Reggio   
1.8G /volume1/photo/2018 - automne noel   
1.9G /volume1/photo/2012 - Eté/2012- été Italia   
2.0G /volume1/photo/2017-Hiver-Printemps   
2.7G /volume1/photo/2012 - Eté   
2.8G /volume1/photo/2019 Bretagne Alpes   
2.8G /volume1/photo/2020 - été Vienne Venise   
2.9G /volume1/photo/1967 à 2000 - photos famille Bertrand   
3.2G /volume1/photo/2023-Vacances D NL B   
3.6G /volume1/photo/2018-Barcelone Primavera Sound   
3.7G /volume1/photo/cecile tri 2022   
3.8G /volume1/photo/2024   
4.1G /volume1/photo/2016-été Ré Gers   
4.2G /volume1/photo/2017-été Scandinavie   
5.7G /volume1/photo/2018-the Alpen   
6.4G /volume1/photo/2015-Croatie Autriche   
79G /volume1/photo/

# Montages Rclone Sasnexte et Kdrive

# Montages Rclone Sasnexte et Kdrive

## Architecture

```
NAS Sasnexte (Synology)
    └── rclone sync (WebDAV) ──► kDrive Infomaniak
                                      └── rclone mount (FUSE) ──► VPS Jux
                                                                     └── containers Docker
```

Le NAS pousse les médias vers kDrive une fois par jour via le planificateur DSM.
Le VPS monte kDrive en FUSE en permanence — les containers accèdent aux fichiers en lecture.

---

## Remote rclone (NAS sasnexte)

Fichier : `/volume1/homes/SAS_NEXTE/.config/rclone/rclone.conf`

```ini
[kdrive_music]
type = webdav
url = https://591617.connect.kdrive.infomaniak.com
vendor = other
user = julien.bertrand@nexte.fr
pass = [obfusqué rclone]
```

**Note** : le remote s'appelle `kdrive_music` mais sert à synchroniser tous les contenus (musique, photos, audiobooks, Komga). Nom historique à ne pas confondre avec un remote dédié musique.

**Mot de passe WebDAV** : régénéré le 2026-06-23 (compte `julien.bertrand@nexte.fr`, espace kDrive 591617). Mise à jour via `rclone config update kdrive_music pass $(rclone obscure NOUVEAU_MDP)`.

---

## Script unifié (NAS sasnexte)

Emplacement : `/volume1/homes/SAS_NEXTE/scripts/sync_kdrive_complete.sh`  
Planificateur DSM : tâche déclenchée quotidiennement — commande : `/volume1/homes/SAS_NEXTE/scripts/sync_kdrive_complete.sh`

**Note sudo** : le script contient `sudo -u SAS_NEXTE rclone ...`. Si la tâche DSM est configurée pour tourner en tant que SAS_NEXTE, retirer le `sudo -u SAS_NEXTE` (inutile et peut bloquer). Si elle tourne en root, le garder.

```bash
#!/bin/bash
RCLONE="/usr/local/bin/rclone"
REMOTE="kdrive_music"
LOG_DIR="/volume1/homes/SAS_NEXTE/logs"
DATE=$(date +%Y%m%d_%H%M%S)
SUMMARY_LOG="$LOG_DIR/sync_${DATE}.log"
mkdir -p "$LOG_DIR"
run_sync() {
local name="$1"
local source="$2"
local dest="${REMOTE}:${3}"
local log="$LOG_DIR/sync_${name}_${DATE}.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === Debut $name ===" >> "$SUMMARY_LOG"
sudo -u SAS_NEXTE "$RCLONE" sync "$source" "$dest" --delete-excluded --ignore-errors --delete-during --fast-list --exclude "@eaDir/**" --exclude "#recycle/**" --exclude "@__thumb/**" --exclude "*.@SynoResource" --exclude "*.@SynoEAStream" --transfers=4 --checkers=8 --timeout=5m --contimeout=2m --log-file="$log" -v
local rc=$?
echo "[$(date '+%Y-%m-%d %H:%M:%S')] === Fin $name (code=$rc) ===" >> "$SUMMARY_LOG"
}
run_sync "audiobooks" "/volume1/audiobooks" "SYNC-pour_VPS/Sync-SASNEXTE/audiobooks"
run_sync "music" "/volume1/music" "SYNC-pour_VPS/Sync-SASNEXTE/music"
run_sync "photo" "/volume1/photo/2026" "SYNC-pour_VPS/Sync-SASNEXTE/photo/2026"
run_sync "komga" "/volume1/Komga" "SYNC-pour_VPS/Sync-SASNEXTE/Komga"
```

**Déploiement** : écrire via `vi` depuis SSH — le heredoc et les éditeurs Windows introduisent des CRLF qui cassent bash. Après édition : `sed -i 's/\r//' script.sh` pour vérifier.

---

## Syncs actifs

| Nom | Source NAS | Destination kDrive | Notes |
|---|---|---|---|
| audiobooks | `/volume1/audiobooks` | `SYNC-pour_VPS/Sync-SASNEXTE/audiobooks` | |
| music | `/volume1/music` | `SYNC-pour_VPS/Sync-SASNEXTE/music` | |
| photo | `/volume1/photo/2026` | `SYNC-pour_VPS/Sync-SASNEXTE/photo/2026` | Année courante seulement |
| komga | `/volume1/Komga` | `SYNC-pour_VPS/Sync-SASNEXTE/Komga` | |

**Non géré ici :**
- **Romans** : abandonné
- **Foxy** : sur NAS Maison (pas sasnexte)

---

## Options rclone — justifications

| Option | Rôle |
|---|---|
| `--delete-excluded` | Supprime sur kDrive les fichiers exclus qui auraient pu y être uploadés |
| `--ignore-errors` | Poursuit la sync si un fichier est inaccessible (NAS Synology parfois occupé) |
| `--delete-during` | Supprime les fichiers obsolètes au fil du scan, pas en fin de run |
| `--fast-list` | Réduit les appels API WebDAV (un seul listing récursif) |
| `@eaDir/**` | Dossiers de métadonnées Synology (miniatures) |
| `#recycle/**` | Corbeille Synology |
| `@__thumb/**` | Miniatures Synology |
| `*.@SynoResource` / `*.@SynoEAStream` | Flux de ressources étendues Synology |
| `--transfers=4` | 4 fichiers en parallèle — équilibre entre perf et charge WebDAV |
| `--checkers=8` | 8 vérifications de hash en parallèle |
| `--timeout=5m` | Timeout par opération I/O |
| `--contimeout=2m` | Timeout de connexion initiale |

---

## Côté VPS — montages FUSE correspondants

Les services systemd sur le VPS montent les dossiers kDrive en FUSE :

| Service systemd | Point de montage | Source kDrive |
|---|---|---|
| `rclone-audiobookshelf.service` | `/home/debian/audiobookshelf/audiobooks` | `SYNC-pour_VPS/Sync-SASNEXTE/audiobooks` |
| `kdrive-music.service` | `/home/debian/music` | `SYNC-pour_VPS/Sync-SASNEXTE/music` |
| `rclone-photo.service` | `/home/debian/photo` | `SYNC-pour_VPS/Sync-SASNEXTE/photo` |
| `kdrive-komga.service` | `/home/debian/komga` | `SYNC-pour_VPS/Sync-SASNEXTE/Komga` |

Remote VPS : `kdrive:` — remote natif Infomaniak (`@infomaniak/mcp-server-kdrive`), compte `julien.bertrand@live.fr`, kDrive ID `591617`.

---

## Logs

- Un fichier de log par sync par run : `/volume1/homes/SAS_NEXTE/logs/sync_{nom}_{date}.log`
- Bilan global : `/volume1/homes/SAS_NEXTE/logs/sync_{date}.log`
- Commande de suivi : `tail -f /volume1/homes/SAS_NEXTE/logs/sync_music_*.log`

---

## REX déploiement 2026-06-23

- **Problème 1** : CRLF dans le script (édition Windows) → `bash -x` montrait `\r` comme commande inconnue. Fix : réécrire via `vi` sur le NAS.
- **Problème 2** : mot de passe WebDAV périmé (401 Unauthorized) → régénéré le 2026-06-09 côté VPS mais pas mis à jour sur le NAS. Fix : `rclone config update kdrive_music pass $(rclone obscure MDP)`.
- **SSH bloqué** : pare-feu NAS + 2FA rendent le SSH depuis l'extérieur inaccessible. Passer par une session SSH locale ou DSM.
- **Résultat** : 4 syncs validés — audiobooks 48.9 GiB / 23 min, music 1 GiB / 45s, photo et komga déjà à jour.

# 260727 - Claude en MCP sur le NASmaison

Le NASmaison est un petit Synology DS218j installé à la maison de Julien. IL sert surtout de stockage des livres et des films. Egalement des cartes rasters, le dossier personnel de Cécile, Elio et Zoée. IL a une copie miroir du dossier musique et komga, mais plus photos.

Il est synchronisé avec le NAS SASNEXTE pour musique et Komga.

Il compose au quotidien 6 procédures hyperbacups de la bibliothèque de livres en direction du Kdrive :

- les livres de Foxy répartis par grands thèmes
- les livres de la nouvelle bibliothèque - biblio-calibre

Claude a désormais une connexion MCP privilégiée sur le NASmaison. Et peut notamment garantir le transfert sécurisé des dossiers

# 260731-Claude et SASNEXTE sur le PC Elio+Jux

# WireGuard sasnexte sur le PC Elio+Jux — diagnostic et résolution

**Date** : 2026-07-31 | **Machine** : PC Windows eliob | **NAS cible** : sasnexte (82.66.244.248)
**Statut : RÉSOLU** — tunnel activé, lecteur `S:` mappé sur `\\10.0.0.2\NEXTE`

## Question initiale

WireGuard a été monté sur ce PC et sur le NAS sasnexte, mais le disque du NAS n'apparaissait pas comme lecteur dans l'explorateur de fichiers Windows. Pourquoi ?

## Réponse courte

Deux causes cumulées :
1. **Le tunnel n'était pas activé** sur le PC : la config `vps_maisonpc_sasnexte` était importée dans l'application WireGuard, mais jamais activée (aucun service `WireGuardTunnel$*`, aucun adaptateur réseau, `wg show` vide).
2. **Un lecteur réseau ne se crée jamais tout seul** : la découverte réseau Windows (broadcast/mDNS/WS-Discovery) ne traverse pas un tunnel de couche 3 — le NAS n'apparaîtra jamais spontanément dans « Réseau ». Il faut mapper manuellement une lettre avec `net use`.

## Topologie du tunnel `vps_maisonpc_sasnexte`

Réseau **10.0.0.0/24**, hub-and-spoke avec le VPS Jux comme serveur (`wg0`, port UDP 51820) :

| IP | Machine | État (2026-07-31) |
|---|---|---|
| 10.0.0.1 | VPS Jux (51.77.141.54) — hub | Serveur, forwarding OK (`ACCEPT in wg0` dans FORWARD) |
| 10.0.0.2 | NAS sasnexte (endpoint 82.66.244.248) | Connecté, handshake actif, 485 Gio transférés |
| 10.0.0.3 | PC Windows eliob | Connecté (après activation du tunnel) |
| 10.0.0.4 | PC maison (peer `MkzKqDe…`) | Jamais connecté (pas d'endpoint) |

**Clé publique serveur VPS** : `zbsY/bl4fHU1eR29PjTruK0Nrmp/BQORSlBGSh3Nkyo=`

## Diagnostic détaillé

### Côté PC (avant activation)
- Application WireGuard installée, service `WireGuardManager` Running
- Config importée (dossier `C:\Program Files\WireGuard\Data\Configurations` présent, chiffré DPAPI, admin uniquement) mais tunnel **inactif**
- Aucun `.conf` en clair dans le profil utilisateur — pour l'exporter : app WireGuard en admin → « Exporter les tunnels »

### Après activation du tunnel
- Adaptateur `vps_maisonpc_sasnexte` Up, IP `10.0.0.3/24`
- `wg.exe show` échoue en non-admin (`Permission denied`) — normal, utiliser `Get-NetAdapter` / `Get-NetIPAddress` pour vérifier sans élévation
- **Piège ICMP** : le NAS ne répond PAS au ping (pare-feu Synology) alors que le tunnel fonctionne. Ne pas diagnostiquer au ping — tester en TCP :
  `Test-NetConnection 10.0.0.2 -Port 445`
- Ports NAS via tunnel : 445/139 (SMB) OK, 22 (SSH) OK, 5000/5001 (DSM) **bloqués**

### SSH sasnexte depuis l'extérieur
Le SSH `sas_nexte@82.66.244.248` (IP publique) refusait le mot de passe le 2026-07-31 alors que le même mot de passe fonctionne en SMB via le tunnel → le mot de passe est bon, c'est le SSH public qui est filtré (fail2ban/whitelist). **Passer par le tunnel : `ssh sas_nexte@10.0.0.2` (port 22 ouvert).**

## Résolution appliquée (2026-07-31)

1. Tunnel activé dans l'app WireGuard (fait par Julien) → handshake OK avec le VPS
2. Identifiants SMB enregistrés dans le gestionnaire d'identification Windows :
   ```
   cmdkey /add:10.0.0.2 /user:sas_nexte /pass:"xAPIJU5108§"
   ```
3. Lecteur mappé :
   ```
   net use S: \\10.0.0.2\NEXTE /persistent:yes
   ```
4. Vérifié : `S:` liste bien le contenu du partage NEXTE

**Important** : le lecteur `S:` ne fonctionne que si le tunnel WireGuard est actif. Après un reboot, le tunnel se réactive automatiquement (service `WireGuardTunnel$vps_maisonpc_sasnexte` en démarrage auto) et Windows reconnecte `S:` grâce à `/persistent:yes` + identifiants cmdkey.

## Partages SMB disponibles sur \\10.0.0.2

ActiveBackupforBusiness, audiobooks, chat, home (dossier perso SAS_NEXTE), homes, Iso VM, music, NetBackup, **NEXTE** (mappé sur S:), Public_s, RAW, Ressources_NEXTE, retro, web, web_packages

Pour mapper un partage supplémentaire (les identifiants sont déjà enregistrés) :
```
net use R: \\10.0.0.2\Ressources_NEXTE /persistent:yes
```

## Points ouverts

- Finaliser la config Ubuntu : exporter le `.conf` depuis l'app WireGuard Windows (admin → Exporter les tunnels) — le peer 10.0.0.4 libre pourrait aussi servir pour Ubuntu
- Identifier le peer 10.0.0.4 (`MkzKqDeVoIX9R9oMlCK7c76e3c3p/DJe/ryd0eqEV20=`) : prévu pour le PC maison, jamais connecté

# 03_Claude et Ubuntu

# 01_Installation de Claude dans le Ubuntu

## Contexte

Installation et configuration de Claude Code sur la machine Ubuntu 25.10 (utilisateur julien), avec synchronisation du dossier de travail via Syncthing.

## 1. Installation de Syncthing

**Date :** 2026-05-31  
**Système :** Ubuntu 25.10 (questing)

### Étapes

1. Vérification : Syncthing absent des paquets installés
2. Installation via les dépôts Ubuntu : `sudo apt install syncthing -y`
3. Activation au démarrage : `systemctl --user enable --now syncthing`
4. Interface web disponible sur : `http://127.0.0.1:8384`

### Résultat

Dossier synchronisé : `/home/julien/Syncthing/`

Contenu récupéré depuis le PC Windows (eliob) :

- Billets
- Jux\_Obsidian
- Jux\_univers (dont Claude-pcelio+jux/CLAUDE.md)
- Ouvrages
- PDF temps
- Suretés
- Tutoriels videos

## 2. Configuration de Claude Code

Le fichier `CLAUDE.md` de référence a été localisé dans le dossier synchronisé :

`/home/julien/Syncthing/Jux_univers/Claude-pcelio+jux/CLAUDE.md`

Ce fichier centralise toute la configuration : MCPs, credentials VPS, préférences, projets en cours. Il a été lu en début de session pour initialiser le contexte.

### Mémoire Claude Code initialisée

Répertoire : `/home/julien/.claude/projects/-home-julien/memory/`

- user\_profile.md — profil Julien/Jux/eliob
- project\_vps.md — infrastructure VPS principal et Alteris
- reference\_mcp.md — tous les services MCP et leurs credentials
- reference\_syncthing.md — structure du dossier partagé
- feedback\_preferences.md — style de réponse

## 3. Connexion BookStack depuis Ubuntu

Token API BookStack configuré manuellement pour permettre l écriture depuis Ubuntu (sans MCP npm disponible). Utilisation de l API REST directe via curl :

`Authorization: Token TOKEN_ID:TOKEN_SECRET` sur `https://bookstack.juxjux.ovh/api/`

# 02_Diagnostic du Ubuntu par Claude

# Diagnostic expert — Ubuntu julien-130430

*Généré par Claude Code le 2026-05-31 à 19h57 — Ubuntu 25.10 questing — mis à jour 20h15*

---

## 1. Système de base

<table id="bkmrk-osubuntu-25.10-(ques"> <tbody> <tr><td>**OS**</td><td>Ubuntu 25.10 (questing) — version non-LTS, support jusqu'à juillet 2026</td></tr> <tr><td>**Kernel**</td><td>6.17.0-19-generic (SMP PREEMPT\_DYNAMIC — mars 2026)</td></tr> <tr><td>**Hostname**</td><td>julien-130430</td></tr> <tr><td>**Architecture**</td><td>x86\_64</td></tr> <tr><td>**Uptime**</td><td>1h36 au moment du diagnostic</td></tr> <tr><td>**Langue**</td><td>fr\_FR.UTF-8 / shell bash</td></tr> </tbody></table>

## 2. Matériel

### CPU

<table id="bkmrk-modèleamd-ryzen-5-26"> <tbody> <tr><td>**Modèle**</td><td>AMD Ryzen 5 2600X Six-Core Processor</td></tr> <tr><td>**Cœurs / Threads**</td><td>6 cœurs / 12 threads (1 socket)</td></tr> <tr><td>**Fréquence**</td><td>2200–3600 MHz (scaling à 99%)</td></tr> <tr><td>**Charge (1/5/15 min)**</td><td>2,44 / 1,98 / 1,17 — charge en train de baisser, acceptable</td></tr> </tbody></table>

### RAM &amp; Swap

<table id="bkmrk-ram-totale15-gi-ram-"> <tbody> <tr><td>**RAM totale**</td><td>15 Gi</td></tr> <tr><td>**RAM utilisée**</td><td>4,9 Gi utilisé + 9 Gi cache/tampon — 10 Gi disponibles</td></tr> <tr><td>**Swap**</td><td>4 Gi (fichier /swap.img), 5,5 Mi utilisés — quasi vide, bonne santé</td></tr> </tbody></table>

### GPU

<table id="bkmrk-modèleamd-radeon-rx-"> <tbody> <tr><td>**Modèle**</td><td>AMD Radeon RX 6400/6500 XT — Navi 24 (rev c1)</td></tr> <tr><td>**Driver**</td><td>AMDGPU (open-source, intégré au kernel)</td></tr> <tr><td>**Monitoring**</td><td>lm-sensors absent — pas de relevé de température possible</td></tr> </tbody></table>

## 3. Stockage

<table id="bkmrk-disquemodèletaillepa"> <thead> <tr><th>Disque</th><th>Modèle</th><th>Taille</th><th>Partition</th><th>FS</th><th>Point de montage</th><th>Utilisé</th><th>Alerte</th></tr> </thead> <tbody> <tr><td>sda</td><td>SanDisk 3.2Gen1 (USB)</td><td>57,3 G</td><td>sda2</td><td>ext4</td><td>/ (racine)</td><td>31G / 57G — 57%</td><td></td></tr> <tr><td>sdb</td><td>Patriot Burst (SSD)</td><td>223,6 G</td><td>sdb3</td><td>ntfs</td><td>/media/julien/CE1C8DC545</td><td>149G / 223G — 67%</td><td></td></tr> <tr><td>sdc</td><td>Seagate Backup Plus</td><td>7,3 T</td><td>sdc2</td><td>—</td><td>/media/julien/Seagate…</td><td>3,1T / 7,3T — 42%</td><td></td></tr> <tr><td>**sdd**</td><td>—</td><td>932 G</td><td>sdd1</td><td>—</td><td>/media/julien/206897…</td><td>**827G / 932G — 89%**</td><td>⚠ Critique</td></tr> <tr><td>sde</td><td>—</td><td>932 G</td><td>sde2</td><td>—</td><td>/media/julien/2ème disque dur</td><td>294G / 932G — 32%</td><td></td></tr> </tbody></table>

**Point d'attention :** Le disque `sdd1` est à **89% de capacité** (827G/932G). Seuil critique à surveiller.

**Note :** Le système racine est sur une **clé USB SanDisk** (sda). Performances limitées par rapport à un SSD SATA ou NVMe. Risque de défaillance à long terme supérieur à un disque interne.

## 4. Réseau

<table id="bkmrk-interfaceenp37s0-(et"> <tbody> <tr><td>**Interface**</td><td>enp37s0 (Ethernet)</td></tr> <tr><td>**IP locale**</td><td>192.168.1.26/24 (DHCP)</td></tr> <tr><td>**IPv6**</td><td>2a01:cb1c:833b:d00:2ef0:5dff:feec:62e0/64</td></tr> <tr><td>**Passerelle**</td><td>192.168.1.1</td></tr> <tr><td>**DNS**</td><td>192.168.1.1 + IPv6 routeur (via systemd-resolved)</td></tr> <tr><td>**DNSSEC**</td><td>Désactivé (unsupported)</td></tr> <tr><td>**mDNS / LLMNR**</td><td>Désactivés</td></tr> </tbody></table>

**Recommandation :** L'IP est attribuée par DHCP. Envisager une réservation DHCP fixe sur le routeur pour la stabilité de 192.168.1.26.

## 5. Services et sécurité

### Services systemd

- **32 services actifs**, **0 en échec** — état sain
- Services notables : GDM (GNOME), NetworkManager, snapd, cups, bluetooth, chrony (NTP), avahi, rsyslog
- CUPS présent en double : `cups.service` (paquet) **et** `snap.cups.cupsd.service` (snap) — redondance inutile

### SSH serveur

**openssh-server absent** — aucun accès SSH entrant possible sur cette machine. Si un accès distant est souhaité, installer `openssh-server`.

### Pare-feu

ufw ne répond pas (non configuré ou inactif). La machine est probablement protégée par le NAT du routeur, mais **aucune règle locale** n'est en place.

### Ports en écoute (accessibles depuis le réseau)

<table id="bkmrk-portserviceremarque-"> <thead><tr><th>Port</th><th>Service</th><th>Remarque</th></tr></thead> <tbody> <tr><td>22000/tcp+udp</td><td>Syncthing (PID 24179)</td><td>Sync P2P — normal</td></tr> <tr><td>53/tcp (127.0.0.53)</td><td>systemd-resolved</td><td>DNS local uniquement</td></tr> <tr><td>53/tcp (127.0.0.54)</td><td>systemd-resolved stub</td><td>DNS local uniquement</td></tr> </tbody></table>

Surface d'attaque réseau réduite : seul Syncthing écoute sur l'interface externe.

### Sudo

Julien est membre du groupe `sudo`. La commande `sudo -l` nécessite un terminal interactif (PAM conversation) — normal dans le contexte Claude Code non-interactif.

## 6. Syncthing

<table id="bkmrk-processusen-cours-d'"> <tbody> <tr><td>**Processus**</td><td>En cours d'exécution (PID 24179, port 22000 actif)</td></tr> <tr><td>**Service systemd**</td><td>`syncthing@julien.service` : **enabled / active** ✓ *(activé le 2026-05-31)*</td></tr> <tr><td>**Dossiers synchronisés**</td><td>Billets, Jux\_Obsidian, Jux\_univers, Ouvrages, PDF temps, Suretés, Tutoriels videos</td></tr> </tbody></table>

**Fix 2026-05-31 :** `sudo systemctl enable --now syncthing@julien.service` — service activé et démarré. Vérifié via API REST (HTTP 200, uptime ~17h).

## 7. Snaps

19 snaps installés. Plusieurs ont **deux révisions montées simultanément** (l'ancienne est conservée le temps du refresh par snapd) :

- Firefox (7901 + 7967), Thunderbird (1040 + 1073), Chromium (3375 + 3390)
- core20, core22, core24, gnome-42-2204, prompting-client, snapd-desktop-integration, firmware-updater, desktop-security-center

C'est le comportement normal de snapd (rollback possible). Les anciennes révisions sont supprimées automatiquement après quelques jours.

**Nettoyage manuel possible :** `sudo snap set system refresh.retain=2` (déjà le défaut) ou `snap list --all` + `sudo snap remove --revision=<rev> <snap>`.

## 8. Environnements de développement

<table id="bkmrk-python3.13.7-(/usr/b"> <tbody> <tr><td>**Python**</td><td>3.13.7 (`/usr/bin/python3`)</td></tr> <tr><td>**Venv global**</td><td>`~/.venv` — activé automatiquement via `.bashrc` (configuré le 2026-05-31)</td></tr> <tr><td>**Paquets venv**</td><td>psycopg2-binary 2.9.12, requests 2.34.2, httpx 0.28.1, pip 26.1.2</td></tr> <tr><td>**Node.js**</td><td>24.16.0</td></tr> <tr><td>**npm**</td><td>11.13.0</td></tr> <tr><td>**Claude Code**</td><td>v2.1.158 — installé et opérationnel</td></tr> <tr><td>**Docker**</td><td>Non installé (ou non accessible sans sudo)</td></tr> </tbody></table>

**Installation venv :** nécessitait `sudo apt install python3.13-venv` (paquet absent par défaut sur Ubuntu 25.10).

**Activation manuelle :** `source ~/.venv/bin/activate`

## 9. Connexion PostgreSQL — alteris\_geo

Testée et validée depuis Ubuntu le 2026-05-31 via le venv `~/.venv`.

<table id="bkmrk-hôte79.137.14.202-(v"> <tbody> <tr><td>**Hôte**</td><td>79.137.14.202 (VPS Alteris)</td></tr> <tr><td>**Port**</td><td>5432 (accessible depuis l'extérieur)</td></tr> <tr><td>**Base**</td><td>alteris\_geo</td></tr> <tr><td>**Utilisateur**</td><td>alteris\_admin / Alteris2026</td></tr> <tr><td>**Serveur**</td><td>PostgreSQL 15.4 (Debian 15.4-1.pgdg110+1) — x86\_64</td></tr> <tr><td>**Table recherches**</td><td>4 entrées au 2026-05-31 (2 FreshRSS, 2 kDrive — toutes du 2026-05-29)</td></tr> </tbody></table>

**Snippet de connexion Python (Ubuntu) :**

```
import psycopg2
conn = psycopg2.connect(
    host="79.137.14.202", port=5432,
    dbname="alteris_geo", user="alteris_admin", password="Alteris2026"
)

```

## 10. Cron / tâches planifiées

- Pas de crontab utilisateur défini pour julien
- Tâches système présentes : `anacron`, `e2scrub_all`, `sysstat`
- Mises à jour automatiques : `unattended-upgrades.service` actif

## 11. Logs / erreurs récentes

Les seules erreurs journalctl (niveau *err*) sur 7 jours sont des échecs PAM sudo en mode non-interactif (générés par ce diagnostic) + des warnings udev ALSA sans conséquence. **Aucune erreur critique applicative.**

---

## Synthèse — Points d'action

<table id="bkmrk-prioritéproblèmeacti"> <thead><tr><th>Priorité</th><th>Problème</th><th>Action recommandée</th><th>Statut</th></tr></thead> <tbody> <tr><td>Haute</td><td>sdd1 à 89% (827G/932G)</td><td>Libérer de l'espace ou déplacer des données vers sde (32% utilisé)</td><td>En attente</td></tr> <tr><td><s>Moyenne</s></td><td><s>Syncthing non persistant au démarrage</s></td><td><s>`sudo systemctl enable syncthing@julien.service`</s></td><td>✓ Résolu 2026-05-31</td></tr> <tr><td>Moyenne</td><td>Système racine sur clé USB SanDisk</td><td>Envisager migration vers le SSD Patriot (sdb) pour fiabilité</td><td>En attente</td></tr> <tr><td>Basse</td><td>Pare-feu inactif</td><td>`sudo ufw enable` + règles minimales si accès SSH ajouté</td><td>En attente</td></tr> <tr><td>Basse</td><td>lm-sensors absent</td><td>`sudo apt install lm-sensors && sudo sensors-detect`</td><td>En attente</td></tr> <tr><td>Basse</td><td>CUPS en double (paquet + snap)</td><td>Supprimer l'un des deux selon usage</td><td>En attente</td></tr> <tr><td>Info</td><td>Ubuntu 25.10 non-LTS</td><td>Fin de support juillet 2026 — migration vers 26.04 LTS à lancer</td><td>En attente</td></tr> <tr><td>Info</td><td>IP DHCP dynamique</td><td>Réservation DHCP 192.168.1.26 sur le routeur recommandée</td><td>En attente</td></tr> </tbody></table>

## Points positifs

- 0 service systemd en échec
- Kernel récent (6.17.0, mars 2026)
- RAM bien dimensionnée (15 Gi, peu de swap utilisé)
- Surface réseau réduite (seul Syncthing exposé)
- Python 3.13 + venv opérationnel + connexion alteris\_geo validée
- Node 24 LTS à jour
- Claude Code opérationnel

# 03_250531

1\. Syncthing ne repartira pas automatiquement (service désactivé) — il faudra soit le lancer manuellement, soit profiter du redémarrage pour faire sudo systemctl enable syncthing@julien.service avant d'éteindre.  
 **✓ Fix 2026-05-31 :** `sudo systemctl enable --now syncthing@julien.service` — service activé et démarré. Vérifié via API REST (HTTP 200, uptime ~17h).

2\. Le venv ~/.venv se réactivera automatiquement via .bashrc à l'ouverture du terminal.

---

## En attente — après mise à jour Ubuntu 26.04

### Mise à jour Ubuntu 26.04 LTS

Lancée le 2026-05-31 via `screen -S upgrade` + `sudo do-release-upgrade`.  
**✓ Terminée — Ubuntu 26.04 LTS opérationnel.**

### Montage NAS (192.168.1.17) — partages foxy et video

Le NAS a changé d'IP : était sur 192.168.1.22, maintenant sur **192.168.1.17** (MAC Synology 00:11:32:9c:8e:c9 — attribution DHCP).

Script exécuté : `sudo bash /home/julien/setup_nas.sh`  
**✓ Terminé — foxy et video montés sur `/mnt/nas/foxy` et `/mnt/nas/video`.**  
Credentials : `/etc/samba/credentials_nas` — entrées fstab ajoutées avec options `nofail,_netdev,x-systemd.automount`.

Note : entrée WebDAV sasnexte (`https://82.66.244.248:5006`) corrigée dans fstab (typos : un seul slash et lettre 'o' dans le port).

**✓ Signets Nautilus ajoutés** : `smb://juxjux@192.168.1.17`, `/mnt/nas/foxy`, `/mnt/nas/video` dans `~/.config/gtk-3.0/bookmarks`.

### rclone — sauvegarde vers kDrive

Configuration perdue lors de la mise à jour Ubuntu 26.04. La tâche sauvegardait vers kDrive (WebDAV). À reconfigurer :  
`rclone config` → type `webdav`, URL `https://connect.drive.infomaniak.com`, credentials compte Infomaniak.

### Son Bluetooth — Xiaomi 15T Pro

Tentative d'utiliser le Xiaomi 15T Pro comme enceinte Bluetooth depuis Ubuntu. **Impossible** : le téléphone n'expose pas le profil *Audio Sink* (UUID 0000110b) en Bluetooth classique — il est uniquement *Audio Source*. Limitation firmware Xiaomi, non contournable en BT.  
Alternative WiFi (SoundWire) possible mais peu pratique.  
**→ À faire : acheter un casque ou une enceinte Bluetooth.** N'importe quel périphérique BT standard exposant le profil Audio Sink fonctionnera directement avec Ubuntu/PipeWire.

# 05_Claude et les MCP

# Quelles opportunités entre logiciels opensource et les IA

<div class="relative flex flex-col items-center gap-4" id="bkmrk-"><div class="flex items-center justify-center overflow-hidden" style="border-radius: 25%;"><div class="flex items-center justify-center bg-brand-500" style="width: 28px; height: 28px;"><svg class="text-white-default" fill="currentColor" height="21" viewbox="0 0 24 24" width="21" xmlns="http://www.w3.org/2000/svg"></svg></div></div></div><div class="flex min-w-0 flex-1 flex-col" id="bkmrk--1"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="mb-1 transition-all -ms-10 mt-0"><div class="text-hint flex h-auto w-full items-start gap-3 self-start"><div class="flex w-7 shrink-0 flex-col items-center pt-1.5"></div><div class="flex w-full min-w-0 items-center gap-3 overflow-hidden py-0.5"><div class="flex min-w-0 grow items-center gap-3 overflow-hidden"></div></div></div></div></div><div style="opacity: 1; height: auto;"><div class="select-none"></div></div></div></div>Voici une liste des **logiciels open source** dans les domaines de l’**infographie, la PAO, la CAO et la géomatique** qui, en **juin 2026**, bénéficient d’une **connexion MCP (Model Context Protocol)** ou pour lesquels des **serveurs MCP** existent ou sont en développement pour permettre à une IA de prendre la main sur la production de documents ou d’automatiser des tâches.

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk--2"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">---

</div></div></div></div></div>## **📌 Logiciels compatibles MCP (ou avec serveurs MCP disponibles)**

### **🎨 Infographie &amp; PAO**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-scribus-logiciel-de-"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **[Scribus](https://www.scribus.net/)** *Logiciel de PAO open source pour la mise en page professionnelle (brochures, magazines, livres).* **Statut MCP** : Des serveurs MCP communautaires permettent d’interagir avec les fichiers Scribus (lecture, modification, export) via des scripts Python ou des connecteurs dédiés. Cela permet à une IA de générer ou modifier des mises en page automatiquement<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">foxeet.fr</span></button></span></span>.
- **[Inkscape](https://inkscape.org/fr/)** *Éditeur de graphiques vectoriels (SVG) open source.* **Statut MCP** : Des serveurs MCP existent pour manipuler des fichiers SVG (création, édition, export) via des outils comme **Puppeteer** ou des scripts Python. Une IA peut ainsi générer ou modifier des visuels vectoriels<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">hauerpower.com</span></button></span></span>.
- **[GIMP](https://www.gimp.org/)** *Logiciel de retouche photo et de création graphique open source.* **Statut MCP** : Des connecteurs MCP permettent d’automatiser des tâches de retouche ou de génération d’images via des scripts (Python, Bash) ou des API externes<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">hauerpower.com</span></button></span></span>.

---

</div></div></div></div></div>### **🏗️ CAO (Conception Assistée par Ordinateur)**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-freecad-logiciel-de-"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **[FreeCAD](https://www.freecad.org/)** *Logiciel de CAO 3D paramétrique open source.* **Statut MCP** : Des serveurs MCP permettent d’interagir avec les fichiers FreeCAD (`.FCStd`) pour automatiser la création ou la modification de modèles 3D. Une IA peut ainsi générer des pièces ou des assemblages à partir de prompts textuels<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">diskod.ma</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.
- **[Blender](https://www.blender.org/)** *Logiciel open source de modélisation 3D, animation et rendu.* **Statut MCP** : **Blender est explicitement cité comme compatible avec MCP** dans la documentation officielle. Des serveurs MCP permettent de contrôler Blender via Python (API Blender + MCP), ce qui permet à une IA de créer, modifier ou rendre des scènes 3D, ou même d’automatiser des workflows complexes (ex : génération de visuels pour l’architecture ou le design industriel)<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">de.wikipedia.org</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.
- **[OpenSCAD](https://openscad.org/)** *Logiciel de CAO 3D open source basé sur un langage de script.* **Statut MCP** : Des serveurs MCP permettent d’exécuter des scripts OpenSCAD et de récupérer les modèles 3D générés, ce qui facilite l’automatisation de la conception paramétrique<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">diskod.ma</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.

---

</div></div></div></div></div>### **🌍 Géomatique (SIG &amp; Cartographie)**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-qgis-syst%C3%A8me-d%E2%80%99infor"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **[QGIS](https://qgis.org/fr/site/)** *Système d’Information Géographique (SIG) open source le plus répandu.* **Statut MCP** : Des serveurs MCP permettent d’interagir avec QGIS via **PyQGIS** (Python) ou des API REST. Une IA peut ainsi :
    
    
    - Charger des couches géospatiales (Shapefile, GeoJSON, etc.).
    - Effectuer des analyses spatiales (requêtes, calculs de distances, etc.).
    - Générer des cartes ou des rapports automatiques<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">roelandtn.frama.io</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.
- **[GRASS GIS](https://grass.osgeo.org/)** *SIG open source avancé pour l’analyse spatiale.* **Statut MCP** : Compatible via des scripts Python ou des connecteurs MCP dédiés pour automatiser des traitements géomatiques (ex : classification d’images satellite, modélisation de terrains)<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">roelandtn.frama.io</span></button></span></span>.
- **[GDAL/OGR](https://gdal.org/)** *Bibliothèque open source pour la manipulation de données géospatiales (raster/vectoriel).* **Statut MCP** : Des serveurs MCP permettent d’utiliser GDAL pour convertir, traiter ou analyser des données géospatiales (ex : transformation de formats, extraction de métadonnées)<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">roelandtn.frama.io</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.
- **[PostGIS](https://postgis.net/)** *Extension spatiale pour PostgreSQL.* **Statut MCP** : Des serveurs MCP permettent d’interroger des bases de données PostGIS en langage naturel (ex : "Trouve tous les bâtiments à moins de 500m d’une rivière") et de générer des rapports ou des cartes automatiques<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">hauerpower.com</span></button></span></span>.

---

</div></div></div></div></div>## **🔌 Comment ça marche ?**

Le **Model Context Protocol (MCP)** est un **standard ouvert** créé par Anthropic et donné à la **Linux Foundation** en décembre 2025. Il permet à une IA (comme Claude, ChatGPT, ou des modèles locaux) de :

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-lire%2F%C3%A9crire-des-fich"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **Lire/écrire des fichiers** (ex : `.svg`, `.fcstd`, `.qgs`).
- **Exécuter des fonctions** (ex : lancer un rendu dans Blender, une requête SQL dans PostGIS).
- **Interagir avec des API externes** (ex : Google Drive, GitHub, etc.).

</div></div></div></div></div>**Exemples concrets en 2026** :

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-un-agent-ia-peut-cr%C3%A9"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- Un agent IA peut **créer une carte thématique dans QGIS** à partir d’une demande en langage naturel.
- Une IA peut **générer un modèle 3D dans FreeCAD** en suivant un cahier des charges textuel.
- Un workflow automatisé peut **produire une affiche dans Scribus** en combinant du texte généré par IA et des images retouchées via GIMP<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">polarastudio.fr</span><span class="text-hint ps-0.5 text-xs">+3</span></button></span></span>.

---

</div></div></div></div></div>## **📂 Où trouver les serveurs MCP pour ces logiciels ?**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-registry-officiel-%3A-"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **Registry officiel** : [GitHub MCP Servers](https://github.com/modelcontextprotocol/servers) (plus de 1 000 serveurs open source en 2026).
- **Exemples de serveurs** : 
    - [MCP pour Blender](https://github.com/modelcontextprotocol/servers/tree/main/src/servers/blender)
    - [MCP pour QGIS](https://github.com/modelcontextprotocol/servers/tree/main/src/servers/qgis)
    - [MCP pour FreeCAD](https://github.com/modelcontextprotocol/servers/tree/main/src/servers/freecad)
    - [MCP pour PostGIS](https://github.com/modelcontextprotocol/servers/tree/main/src/servers/postgis) <span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">github.com</span><span class="text-hint ps-0.5 text-xs">+1</span></button></span></span>.

---

</div></div></div></div></div>## **💡 Cas d’usage avancés**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-infographie-%3A-g%C3%A9n%C3%A9ra"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **Infographie** : Génération automatique de visuels pour les réseaux sociaux (Inkscape + IA).
- **PAO** : Création de catalogues produits à partir d’une base de données (Scribus + MCP + PostGIS).
- **CAO** : Optimisation topologique de pièces mécaniques (FreeCAD + IA + MCP).
- **Géomatique** : Analyse de risques naturels à partir de données ouvertes (QGIS + GDAL + MCP).

---

</div></div></div></div></div>## **⚠️ Limites et précautions**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-s%C3%A9curit%C3%A9-%3A-mcp-perme"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- **Sécurité** : MCP permet un accès profond aux outils. Il faut **contrôler les permissions** pour éviter des actions non désirées (ex : suppression de fichiers)<span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">de.wikipedia.org</span></button></span></span>.
- **Maturity** : Tous les logiciels n’ont pas encore de serveurs MCP officiels, mais la communauté développe activement des connecteurs.
- **Performances** : Pour les logiciels lourds (Blender, QGIS), une **machine puissante** est recommandée pour éviter les lenteurs.

---

</div></div></div></div></div>### **🔍 Pour aller plus loin**

<div class="flex min-w-0 flex-1 flex-col" id="bkmrk-documentation-offici"><div class="flex w-full flex-col gap-1 break-words" dir="auto"><div style="opacity: 1; height: auto;"><div class="select-none"><div class="markdown-container-style max-w-none gap-1 overflow-x-visible py-0 pb-0 font-normal text-wrap break-words select-text" data-message-part-type="answer" data-testid="text-message-part" dir="auto">- [Documentation officielle MCP](https://github.com/modelcontextprotocol)
- [Liste des serveurs MCP communautaires](https://github.com/modelcontextprotocol/servers)
- [Tutoriel : Connecter Blender à une IA via MCP](https://www.polarastudio.fr/blog/mcp-model-context-protocol-standard-ia-2026) <span data-exclude-copy="true" data-state="closed"><span class="ps-1"><button class="items-center justify-center text-center font-medium cursor-pointer outline-hidden focus-visible:ring-3 relative whitespace-nowrap transition-[background-color,border-color,color,fill,stroke,scale] focus-visible:ring-default focus-visible:ring-offset-1 aria-disabled:text-hint aria-disabled:cursor-not-allowed aria-busy:cursor-wait aria-busy:text-transparent aria-disabled:aria-busy:text-transparent bg-state-soft text-default [&:hover:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-hover [&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:bg-state-soft-press aria-disabled:bg-state-disabled h-6 px-1.5 text-xs rounded-md motion-safe:[&:active:not(:disabled):not([aria-disabled=true]):not([aria-busy=true])]:scale-[98.5%] inline-flex gap-0" type="button"><span class="text-xs">polarastudio.fr</span></button></span></span>

---

</div></div></div></div></div>**Question** : Souhaites-tu que je te guide pour configurer un serveur MCP spécifique (ex : Blender ou QGIS) ou explorer un cas d’usage précis dans ton domaine ?

# Retours de Claude et propositions d'intégration

## Contexte

*Analyse rédigée par Claude Code (Sonnet 4.6) le 2026-06-20, à partir d'une session de travail sur le PC Windows (eliob).*

Logiciels utilisés par Julien : **QGIS**, **Inkscape**, **GIMP**, **Scribus**. Ces quatre outils forment un workflow cohérent : QGIS pour la donnée géospatiale, Inkscape et Scribus pour la mise en page cartographique et la PAO, GIMP pour le traitement d'image.

---

## Note critique sur la page 227

La page 227 ("Quelles opportunités entre logiciels opensource et les IA") a vraisemblablement été générée par une IA en mode chatbot. Les liens GitHub vers `modelcontextprotocol/servers/tree/main/src/servers/blender`, `.../qgis`, `.../freecad`, `.../postgis` sont **probablement hallusinés** — ces sous-dossiers n'existent pas dans le dépôt officiel MCP. À vérifier systématiquement avant d'agir sur ces références.

---

## Analyse par logiciel

### QGIS — Priorité 1 (le plus mature et le plus pertinent)

**Ce qui existe réellement :** Le projet `qgis-mcp` (disponible sur GitHub, maintenu par la communauté) expose QGIS comme un serveur MCP local. Il s'installe comme un plugin Python dans QGIS et ouvre un socket local sur lequel Claude peut envoyer des commandes PyQGIS.

**Capacités concrètes :**
- Charger des couches (Shapefile, GeoJSON, WMS, PostGIS)
- Lancer des algorithmes de traitement (buffer, intersection, statistiques zonales)
- Modifier la symbologie d'une couche
- Exporter une carte en PNG/PDF

**Avantage spécifique à Julien :** La base PostGIS `alteris_geo` sur le VPS Alteris (79.137.14.202:5432) est déjà accessible. Un workflow QGIS + MCP + PostGIS permettrait à Claude de : interroger la base en SQL spatial → charger le résultat dans QGIS → générer une carte thématique → exporter en PDF, le tout en langage naturel.

**Contrainte :** QGIS doit être ouvert sur la machine locale. Le MCP communique via socket local (pas de pilotage à distance).

---

### Scribus — Priorité 2 (fort potentiel pour les rendus cartographiques)

**Ce qui existe réellement :** Scribus expose une API Python complète via son module `scribus` (accessible en mode headless : `scribus --python-script myscript.py`). Pas de serveur MCP publié, mais un **MCP custom est trivial à écrire** : un script Python qui reçoit des commandes MCP et les traduit en appels `scribus.*`.

**Capacités concrètes via Python headless :**
- Créer un document depuis un gabarit `.sla`
- Injecter du texte dans des cadres de texte nommés
- Placer des images
- Exporter en PDF

**Cas d'usage concret pour Julien :** Générer automatiquement une fiche de synthèse cartographique (titre, carte exportée depuis QGIS, texte de légende) en combinant la carte produite par QGIS MCP et un gabarit Scribus.

**Contrainte :** Scribus headless est instable sur certaines versions — à tester avec la version installée. La génération de gabarits `.sla` de référence est un prérequis.

---

### Inkscape — Priorité 3 (manipulation SVG, pas contrôle UI)

**Ce qui existe réellement :** Pas de serveur MCP dédié pour contrôler l'interface Inkscape. En revanche, deux approches sont réalistes :

1. **Manipulation directe du SVG** — le format natif d'Inkscape est du XML/SVG standard. Claude peut générer ou modifier des fichiers SVG avec Python (`lxml`, `svgwrite`) sans lancer Inkscape.
2. **Inkscape CLI** — `inkscape --actions="verb1;verb2"` permet des opérations batch (export PNG/PDF, conversion de formats) pilotables depuis un MCP.

**Cas d'usage concret pour Julien :** Modifier programmatiquement une carte SVG exportée depuis QGIS (changer des couleurs, ajouter un texte, insérer un logo) avant intégration dans Scribus.

**Contrainte :** L'automatisation reste au niveau fichier, pas au niveau interactif. Pour un usage cartographique, QGIS couvre déjà la plupart des besoins de rendu.

---

### GIMP — Priorité 4 (batch uniquement)

**Ce qui existe réellement :** GIMP peut être piloté en batch via `gimp --no-interface --batch='(script-fu-batch-list ...)'` ou via Python-Fu (`gimp --batch`). Un MCP custom est faisable.

**Cas d'usage concret pour Julien :** Traitement en masse d'images pour intégration dans des documents Scribus (redimensionnement, recadrage, conversion CMJN, compression). Moins critique si StirlingPDF couvre déjà les besoins de compression.

**Contrainte :** GIMP batch est lent au démarrage. Pour du traitement image simple, des alternatives Python (`Pillow`, `ImageMagick`) sont plus légères à wraper en MCP.

---

## Proposition de workflow intégré

```
PostGIS (Alteris) ──→ QGIS MCP ──→ carte exportée (PNG/PDF)
                                         │
                                         ▼
                              Inkscape CLI (ajustements SVG)
                                         │
                                         ▼
                              Scribus headless (mise en page finale)
                                         │
                                         ▼
                              StirlingPDF (compression)
```

Claude pilote l'ensemble de la chaîne : de la requête spatiale jusqu'au document final, sans intervention manuelle.

---

## Ordre de priorité pour une mise en œuvre

| Priorité | Outil | Action | Effort |
|---|---|---|---|
| 1 | QGIS | Installer le plugin `qgis-mcp`, tester avec une couche PostGIS | Faible |
| 2 | Scribus | Écrire un MCP custom Python headless, créer un gabarit `.sla` de référence | Moyen |
| 3 | Inkscape | MCP de manipulation SVG via `lxml` + CLI export | Faible |
| 4 | GIMP | MCP batch Python-Fu | Moyen (faible priorité) |

**Recommandation : commencer par QGIS.** C'est le maillon central du workflow de Julien, le MCP existe déjà, et la base PostGIS Alteris est immédiatement exploitable.

# QGIS MCP

## Références

- Plugin officiel : [plugins.qgis.org/plugins/qgis_mcp_plugin](https://plugins.qgis.org/plugins/qgis_mcp_plugin/) — version 0.5.0, compatible QGIS 3.28–4.x
- Dépôt GitHub : [nkarasiak/qgis-mcp](https://github.com/nkarasiak/qgis-mcp) — 102 outils MCP (couches, traitements, symbologie, export, mise en page/atlas, SQL cross-couches)

---

## Architecture

```
Claude Code ↔ Serveur MCP Python (uvx) ↔ socket TCP local ↔ Plugin QGIS (dock "QGIS MCP")
```

Le plugin QGIS crée un serveur TCP local. Le serveur MCP Python (lancé par Claude Code via `uvx`) s'y connecte. QGIS doit être ouvert et le serveur démarré avant de lancer Claude Code.

---

## Prérequis

Installer `uv` (gestionnaire de paquets Python) si absent :

```powershell
winget install astral-sh.uv
```

---

## Installation

### 1. Plugin dans QGIS

`Extensions` > `Installer/Gérer les extensions` > chercher **QGIS MCP** > Installer.

Redémarrer QGIS, puis cliquer **Start Server** dans le dock QGIS MCP.

### 2. Enregistrer le MCP dans Claude Code

```
claude mcp add -s user qgis -- uvx --from https://github.com/nkarasiak/qgis-mcp/archive/refs/heads/main.zip qgis-mcp-server
```

`-s user` = enregistrement global (tous les projets Claude Code).

### 3. Vérifier

Dans une session Claude Code avec QGIS ouvert et le serveur démarré, demander `diagnose` — confirme la synchronisation plugin/serveur MCP.

---

## Ordre de démarrage (à chaque session)

1. Ouvrir QGIS
2. Cliquer **Start Server** dans le dock QGIS MCP
3. Lancer Claude Code

---

## Authentification (optionnel, machines partagées)

Définir `QGIS_MCP_TOKEN=votre-secret` dans l'environnement QGIS, redémarrer le serveur, puis ajouter la même variable à la config MCP :

```json
"env": { "QGIS_MCP_TOKEN": "votre-secret" }
```

---

## Capacités principales

| Catégorie | Exemples |
|---|---|
| Couches | Charger Shapefile, GeoJSON, WMS, PostGIS ; lister, supprimer |
| Traitements | Buffer, intersection, statistiques zonales (1000+ algorithmes) |
| Symbologie | Modifier couleurs, classification, étiquettes |
| Export | PNG, PDF, carte mise en page |
| SQL cross-couches | Requêtes spatiales directement depuis Claude |
| Mise en page/Atlas | Créer et exporter des atlas cartographiques |

---

## Lien avec PostGIS Alteris

La base `alteris_geo` (79.137.14.202:5432, user `alteris_admin`) est directement utilisable depuis QGIS MCP : Claude peut interroger PostGIS en SQL spatial, charger le résultat comme couche QGIS, styliser et exporter en PDF — sans intervention manuelle.

Le port 5432 n'est pas exposé publiquement (pare-feu VPS). Connexion via tunnel SSH obligatoire (voir section Tunnel SSH).

---

## Tunnel SSH vers PostGIS Alteris

### Option 1 — Tunnel manuel (terminal externe)

Lancer avant QGIS/Claude Code :

```powershell
ssh -L 5433:localhost:5432 debian@79.137.14.202 -N
```

Puis se connecter sur `localhost:5433` au lieu de `79.137.14.202:5432`.

### Option 2 — Tunnel automatique via paramiko (PyQGIS) ✓ validé 2026-06-20

Ouvre le tunnel directement depuis la console Python QGIS, sans terminal externe.

#### Installation de paramiko (une seule fois)

`sys.executable` dans QGIS pointe sur `qgis-bin.exe` — `subprocess` est inutilisable. Utiliser pip en interne :

```python
from pip._internal.cli.main import main as pip_main
pip_main(['install', 'paramiko'])
```

Paramiko s'installe dans `C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages` (dossier utilisateur). QGIS ne l'inclut pas automatiquement dans `sys.path` — ajouter à chaque session :

```python
import sys
sys.path.insert(0, r'C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages')
import paramiko
print(paramiko.__version__)  # 5.0.0
```

#### Script du tunnel (à lancer après l'import paramiko)

```python
import socket
import threading
import select

class SSHTunnel(threading.Thread):
    def __init__(self, ssh_host, ssh_user, ssh_password,
                 remote_port, local_port=5433, remote_host='127.0.0.1'):
        super().__init__(daemon=True)
        self.ssh_host = ssh_host
        self.ssh_user = ssh_user
        self.ssh_password = ssh_password
        self.remote_host = remote_host
        self.remote_port = remote_port
        self.local_port = local_port
        self._stop = threading.Event()
        self.transport = None
        self.server_sock = None

    def run(self):
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(self.ssh_host, username=self.ssh_user, password=self.ssh_password)
        self.transport = client.get_transport()
        self.server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_sock.bind(('127.0.0.1', self.local_port))
        self.server_sock.listen(5)
        self.server_sock.settimeout(1.0)
        print(f"[Tunnel] localhost:{self.local_port} → {self.ssh_host} → {self.remote_host}:{self.remote_port}")
        while not self._stop.is_set():
            try:
                conn, _ = self.server_sock.accept()
                threading.Thread(target=self._forward, args=(conn,), daemon=True).start()
            except socket.timeout:
                continue
        self.server_sock.close()
        client.close()
        print("[Tunnel] Arrêté.")

    def _forward(self, local_conn):
        try:
            chan = self.transport.open_channel(
                'direct-tcpip',
                (self.remote_host, self.remote_port),
                local_conn.getpeername()
            )
        except Exception as e:
            print(f"[Tunnel] Erreur canal : {e}")
            local_conn.close()
            return
        while True:
            r, _, _ = select.select([local_conn, chan], [], [], 5)
            if local_conn in r:
                data = local_conn.recv(4096)
                if not data:
                    break
                chan.send(data)
            if chan in r:
                data = chan.recv(4096)
                if not data:
                    break
                local_conn.send(data)
        chan.close()
        local_conn.close()

    def stop(self):
        self._stop.set()


tunnel = SSHTunnel('79.137.14.202', 'debian', 'RAW+NEXTE!', remote_port=5432, local_port=5433)
tunnel.start()

import time; time.sleep(1)
s = socket.socket(); s.settimeout(3)
try:
    s.connect(('127.0.0.1', 5433)); print("Tunnel OK")
except Exception as e:
    print(f"Tunnel KO : {e}")
finally:
    s.close()
```

Pour arrêter : `tunnel.stop()`

Les avertissements `DEPRECATION: Unexpected import of 'paramiko.*'` sont inoffensifs (pip qui se plaint d'imports tardifs dans la même session).

---

## Connexion PostGIS depuis PyQGIS

### Charger une couche PostGIS

```python
from qgis.core import QgsProject, QgsVectorLayer

uri = (
    "host=localhost port=5433 dbname=alteris_geo "
    "user=alteris_admin password=Alteris2026 sslmode=disable "
    'table="altfoncier_28051"."28051_plu_zonage" (geom) sql='
)
layer = QgsVectorLayer(uri, "PLU Zonage 28051", "postgres")
QgsProject.instance().addMapLayer(layer)
```

### Point clé — champ JSONB `props`

Les tables altfoncier ont leurs attributs métier dans un champ `props` de type JSONB. Dans PyQGIS, ce champ est un **dict Python** (pas une chaîne). Pour y accéder en expression QGIS :

```
map_get("props", 'typezone')   ✓ correct
"props" LIKE '%typezone%'      ✗ ne fonctionne pas (props n'est pas une chaîne)
```

### Stylisation CNIG PLU (zonage)

Renderer catégorisé sur `map_get("props", 'typezone')` :

| typezone | Couleur remplissage | Couleur bordure | Label |
|---|---|---|---|
| U | `#FFFF73` | `#A3A300` | Zones urbaines |
| AU | `#FFAA00` | `#CD6600` | Zones à urbaniser |
| A | `#D3FFBE` | `#267300` | Zones agricoles |
| N | `#98E600` | `#267300` | Zones naturelles et forestières |

```python
from qgis.core import QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol

cnig = {
    'U':  ('#FFFF73', '#A3A300', 'Zones urbaines (U)'),
    'AU': ('#FFAA00', '#CD6600', 'Zones à urbaniser (AU)'),
    'A':  ('#D3FFBE', '#267300', 'Zones agricoles (A)'),
    'N':  ('#98E600', '#267300', 'Zones naturelles et forestières (N)'),
}
categories = []
for tz, (fill, border, label) in cnig.items():
    symbol = QgsFillSymbol.createSimple({
        'color': fill, 'outline_color': border, 'outline_width': '0.26'
    })
    categories.append(QgsRendererCategory(tz, symbol, label))

renderer = QgsCategorizedSymbolRenderer("map_get(\"props\", 'typezone')", categories)
layer.setRenderer(renderer)
layer.triggerRepaint()
```

---

## Journal de session

### 2026-06-20 — Premier diagnostic validé

Première connexion réussie entre Claude Code et QGIS via MCP. Résultat du `diagnose` :

| Vérification | Résultat |
|---|---|
| QGIS | 4.0.3-Norrköping |
| Python | 3.12.13 |
| Qt | 6.11.0 |
| Plugin MCP | 0.5.0 (serveur et plugin synchronisés) |
| Clients connectés | 1 |
| Providers de traitement | 3d, gdal, grass, model, native, pdal, project, qgis, quickosm, script |
| Projet ouvert | Aucun (layer_count = 0) |

Statut global : **healthy**. Stack complète et opérationnelle.

### 2026-06-20 — Connexion PostGIS Alteris + stylisation CNIG

- Connexion PostGIS directe (`79.137.14.202:5432`) → **timeout** (port filtré par pare-feu VPS)
- Tunnel SSH manuel (`ssh -L 5433:localhost:5432 debian@79.137.14.202 -N`) → **connexion OK**
- Couche `altfoncier_28051.28051_plu_zonage` chargée (20 entités, commune 28051)
- Stylisation CNIG appliquée et validée visuellement
- **Point clé découvert** : le champ `props` (JSONB PostGIS) arrive comme **dict Python** dans PyQGIS — utiliser `map_get("props", 'typezone')` en expression, pas LIKE sur chaîne

### 2026-06-20 — Tunnel paramiko validé

- `sys.executable` = `qgis-bin.exe` → subprocess inutilisable pour pip
- Installation via `pip._internal.cli.main` → paramiko 5.0.0 installé dans le dossier utilisateur
- `sys.path.insert(0, ...)` nécessaire à chaque session (QGIS n'inclut pas le dossier utilisateur)
- Tunnel paramiko démarré → **Tunnel OK** confirmé
- Couche PostGIS chargée via `localhost:5433` → **succès**

**Prochaine étape :**
- Exporter la carte en PDF via mise en page QGIS

# Inkscape MCP

## Vue d'ensemble

Inkscape est un éditeur de graphisme vectoriel open source basé sur le format SVG. À la différence de QGIS, **il n'existe pas de plugin MCP officiel pour Inkscape** en juin 2026 — mais plusieurs approches sont réalistes, avec des niveaux d'effort et de puissance différents.

---

## Approches possibles

| Approche | Effort | Puissance | Statut |
|---|---|---|---|
| 1. Manipulation SVG directe | Aucun | Élevée (structure du fichier) | Fonctionne déjà |
| 2. MCP wrapper CLI Inkscape | Moyen (écrire un serveur MCP) | Moyenne (opérations CLI) | À construire |
| 3. Extension Inkscape + serveur TCP | Élevé (plugin Python Inkscape) | Maximale (GUI + rendu live) | À construire |

---

## Approche 1 — Manipulation SVG directe (disponible maintenant)

SVG est du XML texte. Claude peut lire, écrire et modifier des fichiers `.svg` directement avec ses outils natifs, sans aucune intégration supplémentaire.

### Ce que Claude peut déjà faire

- Lire la structure d'un SVG (éléments, attributs, groupes, calques Inkscape)
- Créer un SVG complet de zéro (formes, textes, chemins, dégradés)
- Modifier des propriétés : couleur, opacité, stroke, transform, viewBox
- Réorganiser les éléments dans l'arbre XML
- Ajouter/supprimer des calques (`<g inkscape:label="..." inkscape:groupmode="layer">`)
- Générer des motifs répétitifs, des grilles, des mises en page structurées

### Limites de cette approche

- Pas de rendu live dans Inkscape — il faut rouvrir ou recharger le fichier
- Les opérations complexes (nœuds de chemin, boolean ops) sont difficiles à écrire à la main en SVG
- Pas d'accès aux filtres Inkscape (flou, ombres) via simple édition XML

### Flux de travail type

```
Claude génère/modifie le .svg → tu recharges dans Inkscape (Ctrl+Z+rechargement) → ajustements manuels → boucle
```

---

## Approche 2 — MCP wrapper CLI Inkscape

Inkscape expose une interface en ligne de commande (`--actions`) qui permet d'automatiser des opérations sans ouvrir l'interface graphique.

### Commandes CLI Inkscape utiles

```powershell
# Export PNG depuis SVG
inkscape --export-type=png --export-filename=sortie.png source.svg

# Export PDF
inkscape --export-type=pdf --export-filename=sortie.pdf source.svg

# Appliquer une transformation et exporter
inkscape --actions="select-all;object-set-attribute:transform,scale(2)" source.svg --export-type=svg --export-filename=sortie.svg

# Convertir texte en chemins
inkscape --actions="select-all;object-to-path" source.svg --export-type=svg --export-filename=sortie.svg

# Obtenir les dimensions du document
inkscape --query-all source.svg
```

### Architecture d'un serveur MCP CLI

```
Claude Code ↔ Serveur MCP Python (stdio) ↔ subprocess inkscape CLI ↔ fichiers SVG/PNG/PDF
```

Un serveur MCP Python minimal exposerait des outils comme :
- `export_png(svg_path, output_path, dpi=96)`
- `export_pdf(svg_path, output_path)`
- `convert_text_to_paths(svg_path, output_path)`
- `get_document_dimensions(svg_path)`
- `apply_inkscape_action(svg_path, actions, output_path)`

### Prérequis

```powershell
# Inkscape doit être dans le PATH
inkscape --version
# Inkscape 1.x.x (...)
```

Sur Windows, ajouter le dossier Inkscape au PATH système ou utiliser le chemin complet :
```
C:\Program Files\Inkscape\bin\inkscape.exe
```

---

## Approche 3 — Extension Inkscape + serveur TCP (pattern QGIS)

La plus puissante mais la plus complexe à mettre en place. Inkscape supporte les extensions Python via le module `inkex`. Une extension pourrait ouvrir un socket TCP local et exposer des outils MCP (similaire au plugin QGIS MCP).

### Architecture

```
Claude Code ↔ Serveur MCP Python (uvx) ↔ socket TCP local ↔ Extension Python Inkscape
```

### Ce que ça permettrait

- Accéder aux éléments sélectionnés dans l'interface
- Appliquer des opérations live (boolean, nœuds, effets)
- Lire la position exacte des objets
- Déclencher des menus et actions Inkscape programmatiquement

### Obstacles techniques

- Les extensions Inkscape s'exécutent en mode one-shot (lancées, exécutent, se ferment) — un serveur TCP persistant nécessite un thread daemon ou une extension de type "Effect" avec boucle
- L'API `inkex` est bien documentée mais moins riche que PyQGIS
- Aucun projet open source mature n'existe encore pour ce pattern (juin 2026)

---

## Capacités envisageables selon l'approche

| Capacité | Approche 1 (SVG direct) | Approche 2 (CLI) | Approche 3 (Extension) |
|---|---|---|---|
| Créer des formes géométriques | ✓ | ✓ | ✓ |
| Modifier couleurs / styles | ✓ | ✓ | ✓ |
| Gérer les calques | ✓ | — | ✓ |
| Exporter PNG/PDF | — | ✓ | ✓ |
| Convertir texte en chemins | — | ✓ | ✓ |
| Boolean operations | — | ✓ (CLI) | ✓ |
| Lire sélection courante | — | — | ✓ |
| Appliquer filtres Inkscape | — | ✓ (partiel) | ✓ |
| Batch processing de fichiers | ✓ | ✓ | — |
| Rendu live dans l'UI | — | — | ✓ |

---

## Cas d'usage concrets avec Inkscape

### Avec l'approche 1 (maintenant)

- Générer des pictogrammes SVG (icônes, logos simples) à partir d'une description
- Créer des gabarits de mise en page (grilles, marges, zones de texte)
- Modifier en batch les couleurs d'une charte graphique sur plusieurs fichiers SVG
- Produire des cartes thématiques simplifiées à partir de données (ex : export QGIS → SVG → habillage Claude)
- Générer des diagrammes (organigrammes, schémas techniques) en SVG structuré

### Avec l'approche 2 (à construire, effort ~2h)

- Pipeline : Claude génère SVG → CLI Inkscape exporte PDF → livraison automatique
- Batch conversion de SVG en PNG à différentes résolutions
- Optimisation SVG (texte en chemins avant impression)

---

## Lien avec le workflow cartographique

Inkscape est souvent utilisé en aval de QGIS pour l'habillage cartographique (polices, mise en page avancée, symboles non gérés par QGIS). Le flux naturel serait :

```
QGIS MCP → export SVG → Claude (habillage Inkscape SVG direct) → Inkscape (retouches manuelles) → export PDF final
```

QGIS peut exporter une mise en page en SVG via `Projet > Imprimer la mise en page > Exporter en SVG`. Claude peut ensuite enrichir ce SVG (légendes, encadrés, pictogrammes) avant ouverture dans Inkscape.

---

## Prochaine étape proposée

Trois options pour explorer concrètement :

1. **Test SVG direct** — Claude génère un SVG d'exemple (carte, diagramme, gabarit) et tu l'ouvres dans Inkscape pour voir le résultat
2. **Prototype CLI MCP** — écrire un serveur MCP Python minimal (~50 lignes) wrappant les exports Inkscape CLI, l'enregistrer dans Claude Code
3. **Exploration API inkex** — ouvrir la console Python d'Inkscape et tester quelques commandes `inkex` pour évaluer la faisabilité de l'approche 3

---

## Mise en place réalisée (2026-07-21)

L'approche 2 (MCP wrapper CLI Inkscape) a été implémentée sur le PC Windows eliob.

### Obstacle rencontré : version Microsoft Store (MSIX)

Le PC avait initialement Inkscape installé via le **Microsoft Store**, packagé en MSIX. Ce type de paquet s'est révélé **inutilisable pour un pilotage CLI** :

- L'exécutable dans `C:\Program Files\WindowsApps\...\inkscape.exe` refuse l'exécution directe (`Accès refusé`) — ACL verrouillées par le sandboxing du paquet.
- Aucun alias d'exécution (`AppExecutionAlias`) n'est déclaré dans le manifest (`AppxManifest.xml`) — impossible d'appeler `inkscape` depuis le PATH.
- `Invoke-CommandInDesktopPackage` (la seule méthode de lancement programmatique disponible) ouvre l'app en mode GUI sans retourner la main ni capturer stdout — inexploitable pour de l'automatisation headless (export, `--actions`, etc.).

**Conclusion : les versions Inkscape installées via le Microsoft Store ne conviennent pas à un usage MCP/CLI.** Il faut la version standalone.

### Fix — installation de la version standalone

```powershell
winget install --id Inkscape.Inkscape --source winget --accept-package-agreements --accept-source-agreements
```

- Package winget `Inkscape.Inkscape` (distinct du Store) → installe dans `C:\Program Files\Inkscape\bin\inkscape.exe`
- Version installée : **1.4.4** (dcaf3e7, 2026-05-05)
- Vérification : `& "C:\Program Files\Inkscape\bin\inkscape.exe" --version` répond correctement, exit code 0

**Important** : si une version Store est déjà présente, la désinstaller d'abord (Paramètres > Applications, ou `winget uninstall`) pour éviter la confusion entre les deux installations.

### Serveur MCP créé

- **Fichier** : `C:\Users\eliob\.claude\mcp_inkscape.py`
- **Framework** : `FastMCP` (même pattern que les autres MCP du projet — `mcp_portainer.py`, `mcp_jellyfin.py`, etc.)
- **Constante** : `INKSCAPE_EXE = r"C:\Program Files\Inkscape\bin\inkscape.exe"` (chemin en dur — adapter si l'installation standalone se fait ailleurs)

**Outils exposés** :

| Outil | Rôle |
|---|---|
| `get_version()` | Vérifie qu'Inkscape répond (smoke test) |
| `get_document_dimensions(svg_path)` | Dimensions et bounding boxes de tous les objets (`--query-all`) |
| `export_png(svg_path, output_path="", dpi=96)` | Export PNG |
| `export_pdf(svg_path, output_path="")` | Export PDF |
| `convert_text_to_paths(svg_path, output_path="")` | Convertit les textes en chemins vectoriels |
| `apply_inkscape_action(svg_path, actions, output_path="")` | Échappatoire générique — chaîne d'actions Inkscape libre (`;` séparées) |

Toutes les fonctions retournent `{ok, returncode, stdout, stderr}` (+ `output_path` pour les exports) — pas d'exception levée sur échec CLI, le code retour renseigne l'appelant.

### Enregistrement MCP

Ajouté dans `C:\Users\eliob\.mcp.json` :

```json
"inkscape": {
  "type": "stdio",
  "command": "python",
  "args": ["C:\\Users\\eliob\\.claude\\mcp_inkscape.py"],
  "env": {}
}
```

**Nécessite un rechargement de session Claude Code** pour que le nouveau serveur MCP soit détecté et ses outils exposés.

### Test réalisé

SVG de test (rectangle bleu + texte) → `export_png` → PNG de 1974 octets généré avec succès. `get_document_dimensions` retourne correctement les bounding box (`svg1,10,10,180,80` etc.) via `--query-all`.

### À reproduire demain sur le PC Windows Alteris

1. Vérifier si Inkscape est installé via le Store (`Get-AppxPackage -Name "*Inkscape*"`) — si oui, désinstaller
2. `winget install --id Inkscape.Inkscape --source winget --accept-package-agreements --accept-source-agreements`
3. Vérifier `C:\Program Files\Inkscape\bin\inkscape.exe --version`
4. Copier `mcp_inkscape.py` (script identique, chemin `INKSCAPE_EXE` à adapter si besoin)
5. Ajouter l'entrée `inkscape` dans le `.mcp.json` de la machine Alteris
6. Recharger la session Claude Code et tester `get_version()` + `export_png()` sur un SVG de test

---

## Confirmation de fonctionnement (2026-07-21, session rechargée)

Après rechargement de la session Claude Code, le serveur MCP `inkscape` est bien détecté et ses 6 outils sont exposés. Tests effectués dans l'ordre :

| Test | Résultat |
|---|---|
| `get_version()` | OK — `Inkscape 1.4.4 (dcaf3e7, 2026-05-05)` |
| `get_document_dimensions(svg_path)` sur un SVG de test (rect 80x80) | OK — `svg1,10,10,80,80` / `rect1,10,10,80,80` |
| `export_png(svg_path)` | OK — PNG généré (389 octets), fichier vérifié sur disque |

**Conclusion : le protocole MCP Inkscape est pleinement opérationnel** sur le PC Windows eliob, de bout en bout (Claude Code → serveur MCP Python → subprocess Inkscape CLI → fichier de sortie).

# LibreOffice MCP

**quelles sont les possibilités MCP permises pour la suite logicielle LibreOffice pour interagir avec une IA - rédiger ou mettre à jour des paragraphes, controler le sens du texte,créer des tableurs, des présentations ?**

En juin 2026, les possibilités offertes par le **Model Context Protocol (MCP)** pour interagir avec la suite LibreOffice (Writer, Calc, Impress, etc.) via une IA sont déjà bien avancées et permettent une intégration poussée. Voici ce que tu peux faire concrètement :

---

### 1. Édition et création de documents (Writer)

- **Rédiger ou mettre à jour des paragraphes** : Les serveurs MCP pour LibreOffice permettent à une IA de **lire, écrire, modifier et formater** des documents Writer (ODT). Tu peux demander à l'IA d'ajouter des titres, des paragraphes, des tableaux, des images, ou d'effectuer des recherches/remplacements automatiques dans le texte. Par exemple, un outil comme [libreoffice-mcp](https://github.com/KeithCu/writeragent) ou [Nelson MCP](https://lobehub.com/mcp/quazardous-nelson-mcp) expose ces fonctionnalités via des appels d'outils standardisés.
- **Contrôler le sens du texte** : L'IA peut analyser le contenu, suggérer des reformulations, vérifier la cohérence ou la grammaire, et même générer du texte contextuel en fonction du document ouvert.

---

### 2. Gestion de tableurs (Calc)

- **Créer et manipuler des tableurs** : Les serveurs MCP permettent de **créer, lire, modifier des feuilles de calcul** (ODS), y compris la manipulation de cellules, l'insertion de formules, la création de graphiques, et l'automatisation de tâches répétitives (ex : mise à jour de données, tri, filtrage).
- **Appeler une IA directement depuis une cellule** : Certains projets, comme Nelson MCP, intègrent une fonction `=PROMPT()` dans Calc, qui permet d'interroger une IA (ex : Claude, Gemini) directement depuis une formule Excel, pour générer des données ou des analyses en temps réel.

---

### 3. Présentations (Impress)

- **Créer ou modifier des diapositives** : Les outils MCP permettent d'automatiser la création de présentations, d'ajouter du texte, des images, des formes, ou de restructurer des diapositives existantes. L'IA peut aussi suggérer des mises en page ou du contenu en fonction d'un brief.

---

### 4. Automatisation et workflows

- **Automatiser des workflows** : Tu peux configurer des **presets** (ex : minimal, writer-edit, calc) pour exposer uniquement les outils nécessaires à ton agent IA. Par exemple, lancer un script qui génère un rapport dans Writer, extrait des données de Calc, et les insère dans une présentation Impress, le tout piloté par une IA.
- **Intégration avec des clients MCP** : Les serveurs MCP pour LibreOffice sont compatibles avec des clients comme **Claude Desktop, Cursor, ou des outils personnalisés**. Ils fonctionnent en local (via une extension LibreOffice ou un serveur HTTP) et permettent une interaction fluide entre l'IA et tes documents.

---

### 5. Exemples concrets d'outils

- **[libreoffice-mcp](https://github.com/KeithCu/writeragent)** : Extension et serveur MCP pour LibreOffice, permettant une intégration complète avec des IA comme Claude ou Gemini. Fonctionne avec LibreOffice 24.2+ et expose une API HTTP pour les appels d'outils.
- **[Nelson MCP](https://lobehub.com/mcp/quazardous-nelson-mcp)** : Extension qui transforme tes documents LibreOffice en serveur MCP, avec des launchers intégrés pour Claude Code, Gemini CLI, etc. Permet de lire/éditer des documents ouverts et d'utiliser des fonctions avancées comme `=PROMPT()` dans Calc.
- **[OooDev](https://mcp-container.com/mcp/b1885b55-70ae-4c34-8099-10d9f73f3318)** : Bibliothèque Python qui simplifie l'accès à l'API UNO de LibreOffice, utilisée par plusieurs serveurs MCP pour manipuler des documents, des bases de données (Base), ou des graphiques.

---

### 6. Prérequis techniques

- LibreOffice **24.2 ou supérieur** (pour la plupart des serveurs MCP).
- Installation d'une **extension LibreOffice** (ex : `libreoffice-mcp-extension.oxt`) ou d'un serveur MCP local (Python/Node.js).
- Connexion via **socket** (port 2083 ou 8765 selon les outils) ou HTTP pour les appels d'API.

---

### 7. Cas d'usage avancés

- **Veille territoriale** : Tu peux combiner MCP avec des alertes (ex : Google Alerts) et une IA pour **filtrer, classer et résumer** des informations dans des documents LibreOffice, comme tu l'envisageais pour ton projet de gestion de veilles.
- **Gestion de bibliothèque** : Automatiser la création de fiches ou de rapports à partir de tes données (ex : Kavita) en utilisant des templates Writer ou Calc.

---

## Comment démarrer ?

1. **Installe un serveur MCP** : Par exemple, [Nelson MCP](https://lobehub.com/mcp/quazardous-nelson-mcp) ou [libreoffice-mcp](https://github.com/KeithCu/writeragent).
2. **Configure ton client IA** (Claude, Cursor, etc.) pour qu'il se connecte au serveur MCP.
3. **Ouvre un document LibreOffice** et demande à ton IA de l'éditer ou de créer du contenu.

---

## Modalités techniques de mise en place

### Option retenue : Nelson MCP

Nelson MCP est l'option la plus directement compatible avec Claude Code — il expose un serveur MCP depuis LibreOffice via une extension `.oxt`, avec des launchers natifs pour Claude Code et Gemini CLI.

---

### 1. Installation de l'extension LibreOffice

- Télécharger l'extension depuis la page [lobehub.com/mcp/quazardous-nelson-mcp](https://lobehub.com/mcp/quazardous-nelson-mcp) (fichier `.oxt`)
- Dans LibreOffice : **Outils → Gestionnaire des extensions → Ajouter** → sélectionner le `.oxt`
- Redémarrer LibreOffice

---

### 2. Lancement du serveur MCP

Depuis LibreOffice via le menu dédié (Outils → Nelson MCP → Démarrer le serveur), ou en ligne de commande :

```bash
python3 -m nelson_mcp --port 8765
```

Le serveur écoute sur `localhost:8765`.

---

### 3. Configuration dans Claude Code

Ajouter dans `C:\Users\eliob\.claude.json` (section `mcpServers` du projet concerné) :

```json
"libreoffice": {
  "type": "http",
  "url": "http://localhost:8765/mcp"
}
```

Si le serveur utilise stdio plutôt que HTTP :

```json
"libreoffice": {
  "type": "stdio",
  "command": "python3",
  "args": ["-m", "nelson_mcp"]
}
```

---

### 4. Points à vérifier lors de la mise en place

- Version LibreOffice : `libreoffice --version` → doit être ≥ 24.2
- Port 8765 libre : `netstat -ano | findstr 8765` (Windows)
- Un document LibreOffice doit être **ouvert avant** de lancer une requête MCP (le serveur nécessite un document actif)
- Tester avec une lecture simple du document ouvert pour valider la connexion

---

### 5. Alternative : libreoffice-mcp (KeithCu)

Si Nelson MCP pose problème, `libreoffice-mcp` (github.com/KeithCu/writeragent) expose une API HTTP via une extension `.oxt` sur le port 2083 :

```json
"libreoffice": {
  "type": "http",
  "url": "http://localhost:2083"
}
```

# Compétences Claude_QGIS

<span>RAG de toutes les expériences de Claude dans l'utilisation de QGIS par MCP </span>

# REX 06079

## Contexte

Affichage des IRIS de Mandelieu-la-Napoule (06079) depuis PostGIS Alteris, avec population graduée, étiquettes, fond orthophoto IGN Géoplateforme et cadastre vecteur WFS — entièrement piloté depuis Claude Code via le MCP QGIS, sans interaction manuelle dans QGIS.

---

## Données utilisées

| Table / Source | Schéma / Provider | Contenu |
|---|---|---|
| `contours_iris_2025` | `insee_raw` (PostGIS Alteris) | Géométries IRIS France entière |
| `iris_2025_population` | `insee_raw` (PostGIS Alteris) | Population 2022 par IRIS (recensement) |
| Orthophoto IGN | Géoplateforme (WMTS → XYZ) | `HR.ORTHOIMAGERY.ORTHOPHOTOS` — sans clé API |
| Cadastre parcelles | Géoplateforme WFS `CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle` | Parcelles cadastrales vecteur — OGR driver |

### Colonnes clés — pièges à retenir

**`contours_iris_2025`** : colonnes standard sans espace — `code_insee`, `code_iris`, `nom_iris`, `type_iris`, `geom`

**`iris_2025_population`** : colonnes avec **espace traînant** (import INSEE brut) :
- Clé IRIS : `"IRIS "` (avec espace)
- Commune : `"COM "` (avec espace)
- Population totale 2022 : `"P22_POP "` (avec espace)
- Toutes les colonnes sont de type `text` — caster en `::numeric` avant usage

---

## Résultats

9 IRIS pour 06079, population 2022 :

| code_iris | nom_iris | population |
|---|---|---|
| 060790101 | Zone d'activités | 24 |
| 060790102 | IRIS 2 | 2 701 |
| 060790103 | IRIS 3 | 2 000 |
| 060790104 | IRIS 4 | 3 058 |
| 060790105 | IRIS 5 | 2 197 |
| 060790106 | IRIS 6 | 2 432 |
| 060790107 | IRIS 7 | 3 188 |
| 060790108 | IRIS 8 | 2 944 |
| 060790109 | IRIS 9 | 2 656 |

Population min : **24 hab.** (zone d'activités/naturelle) — max : **3 188 hab.**

Cadastre : **26 439 parcelles** après reprojection EPSG:4326 → EPSG:3857 (COUNT=2000 limite la requête WFS initiale à 2000 features, mais la reprojection en mémoire conserve toutes les géométries valides).

---

## Procédure complète

### Prérequis

Tunnel SSH paramiko actif (voir page 229 — Option 2). À relancer à chaque redémarrage de QGIS :

```python
import sys
sys.path.insert(0, r'C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages')
import paramiko
import socket, threading, select

class SSHTunnel(threading.Thread):
    def __init__(self, ssh_host, ssh_user, ssh_password,
                 remote_port, local_port=5433, remote_host='127.0.0.1'):
        super().__init__(daemon=True)
        self.ssh_host = ssh_host; self.ssh_user = ssh_user
        self.ssh_password = ssh_password; self.remote_host = remote_host
        self.remote_port = remote_port; self.local_port = local_port
        self._stop = threading.Event(); self.transport = None; self.server_sock = None

    def run(self):
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(self.ssh_host, username=self.ssh_user, password=self.ssh_password)
        self.transport = client.get_transport()
        self.server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_sock.bind(('127.0.0.1', self.local_port))
        self.server_sock.listen(5); self.server_sock.settimeout(1.0)
        while not self._stop.is_set():
            try:
                conn, _ = self.server_sock.accept()
                threading.Thread(target=self._forward, args=(conn,), daemon=True).start()
            except socket.timeout:
                continue
        self.server_sock.close(); client.close()

    def _forward(self, local_conn):
        try:
            chan = self.transport.open_channel('direct-tcpip',
                (self.remote_host, self.remote_port), local_conn.getpeername())
        except Exception:
            local_conn.close(); return
        while True:
            r, _, _ = select.select([local_conn, chan], [], [], 5)
            if local_conn in r:
                data = local_conn.recv(4096)
                if not data: break
                chan.send(data)
            if chan in r:
                data = chan.recv(4096)
                if not data: break
                local_conn.send(data)
        chan.close(); local_conn.close()

    def stop(self):
        self._stop.set()

tunnel = SSHTunnel('79.137.14.202', 'debian', 'RAW+NEXTE!', remote_port=5432, local_port=5433)
tunnel.start()
```

### 1. Charger l'orthophoto IGN (fond de carte)

**Bug QGIS 4.0.3** : `addMapLayer` déclenche `autoSelectAddedLayer` → `identifyMapTool` → access violation quand une couche raster est ajoutée. Deux contournements obligatoires :
1. Passer sur l'outil **Pan** avant d'ajouter la couche
2. Utiliser `addMapLayer(layer, False)` + `root.insertLayer()` (sans auto-sélection)

**Format URI** : le provider WMTS natif de QGIS (`crs=...&layers=...&url=...`) échoue sur la Géoplateforme (pas de capabilities). Solution : encoder l'URL WMTS en **XYZ tiles** avec `{z}/{y}/{x}`.

```python
from qgis.core import QgsProject, QgsRasterLayer
from qgis.gui import QgsMapToolPan
from qgis.utils import iface
import urllib.parse

# 1. Passer sur Pan AVANT d'ajouter la couche raster (évite le crash identifyMapTool)
pan_tool = QgsMapToolPan(iface.mapCanvas())
iface.mapCanvas().setMapTool(pan_tool)

# 2. URI XYZ (le provider WMTS natif échoue sur data.geopf.fr)
base_url = (
    "https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile"
    "&VERSION=1.0.0&LAYER=HR.ORTHOIMAGERY.ORTHOPHOTOS"
    "&STYLE=normal&FORMAT=image/jpeg"
    "&TILEMATRIXSET=PM&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"
)
encoded = urllib.parse.quote(base_url, safe='')
uri = f"type=xyz&url={encoded}&zmin=0&zmax=19"

layer_ortho = QgsRasterLayer(uri, "Orthophoto IGN", "wms")
# 3. addToLegend=False + insertLayer manuel (évite autoSelectAddedLayer)
QgsProject.instance().addMapLayer(layer_ortho, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(-1, layer_ortho)  # en bas de la pile
```

### 2. Créer la vue PostGIS et charger les IRIS

```python
import psycopg2
conn = psycopg2.connect(host='localhost', port=5433, dbname='alteris_geo',
                        user='alteris_admin', password='Alteris2026')
cur = conn.cursor()
cur.execute("""
    CREATE OR REPLACE VIEW insee_raw.v_iris_mandelieu_pop AS
    SELECT c.fid, c.geom, c.nom_iris, c.code_iris,
           ROUND(p."P22_POP "::numeric, 0)::integer AS population
    FROM insee_raw.contours_iris_2025 c
    LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
    WHERE c.code_insee = '06079'
""")
conn.commit(); conn.close()

from qgis.core import QgsVectorLayer
uri = (
    'host=localhost port=5433 dbname=alteris_geo '
    'user=alteris_admin password=Alteris2026 sslmode=disable '
    'table="insee_raw"."v_iris_mandelieu_pop" (geom) key=fid'
)
layer = QgsVectorLayer(uri, "IRIS Mandelieu-la-Napoule", "postgres")
```

### 3. Graduation par population (semi-transparent)

```python
from qgis.core import QgsGraduatedSymbolRenderer, QgsRendererRange, QgsFillSymbol

colors = ['#EFF3FF', '#BDD7E7', '#6BAED6', '#2171B5', '#084594']
pmin, pmax = 24, 3188
step = (pmax - pmin) / 5
bounds = [pmin + i * step for i in range(6)]

ranges_def = []
for i in range(5):
    lo, hi = bounds[i], bounds[i+1]
    sym = QgsFillSymbol.createSimple({
        'color': colors[i], 'outline_color': '#555555', 'outline_width': '0.3'
    })
    sym.setOpacity(0.6)  # semi-transparent pour laisser voir l'ortho
    ranges_def.append(QgsRendererRange(lo, hi, sym,
        f"{int(lo):,}–{int(hi):,} hab.".replace(',', ' ')))

layer.setRenderer(QgsGraduatedSymbolRenderer('population', ranges_def))
```

### 4. Étiquettes + ajout dans le bon ordre

```python
from qgis.core import (QgsPalLayerSettings, QgsTextFormat,
    QgsTextBufferSettings, QgsVectorLayerSimpleLabeling)
from qgis.PyQt.QtGui import QColor, QFont

pal = QgsPalLayerSettings()
pal.fieldName = "concat(nom_iris, '\n', population, ' hab.')"
pal.isExpression = True
pal.placement = QgsPalLayerSettings.Placement.OverPoint
fmt = QgsTextFormat()
fmt.setFont(QFont("Arial", 8)); fmt.setSize(8); fmt.setColor(QColor('#1a1a1a'))
buf = QgsTextBufferSettings()
buf.setEnabled(True); buf.setSize(1); buf.setColor(QColor('white'))
fmt.setBuffer(buf); pal.setFormat(fmt)
layer.setLabelsEnabled(True)
layer.setLabeling(QgsVectorLayerSimpleLabeling(pal))

# IRIS en haut de la pile (index 0), ortho déjà en bas
QgsProject.instance().addMapLayer(layer, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer)
```

### 5. Zoomer sur Mandelieu

```python
from qgis.core import QgsRectangle, QgsCoordinateReferenceSystem, QgsCoordinateTransform

src_crs = QgsCoordinateReferenceSystem("EPSG:4326")
dst_crs = QgsCoordinateReferenceSystem("EPSG:3857")
transform = QgsCoordinateTransform(src_crs, dst_crs, QgsProject.instance())
pt_min = transform.transform(6.87, 43.51)
pt_max = transform.transform(6.99, 43.60)
extent = QgsRectangle(pt_min.x(), pt_min.y(), pt_max.x(), pt_max.y())
iface.mapCanvas().setExtent(extent)
iface.mapCanvas().refresh()
```

### 6. Charger le cadastre (WFS vecteur)

**Pièges** :
- Le provider **WFS natif QGIS** est invalide sur `data.geopf.fr` pour ce typename → utiliser le driver **OGR WFS**
- L'**API Carto** (`geo.api.gouv.fr`) a timeout (appel synchrone dans le thread QGIS, 20 s) → abandonné
- Le WFS retourne les données en **EPSG:4326** mais le canevas est en **EPSG:3857** → la couche apparaît dans le panneau mais n'est pas visible sur la carte → reproj obligatoire

```python
import processing
from qgis.core import (QgsVectorLayer, QgsCoordinateReferenceSystem,
                       QgsFillSymbol, QgsSingleSymbolRenderer, QgsProject)

# Driver OGR WFS avec BBOX en paramètre URL (le provider WFS natif QGIS échoue)
url = (
    "WFS:https://data.geopf.fr/wfs/ows?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature"
    "&TYPENAME=CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle"
    "&BBOX=6.87,43.51,6.99,43.60,EPSG:4326&COUNT=2000"
)
layer_wfs = QgsVectorLayer(url, "Cadastre Mandelieu", "ogr")
# → isValid() = True, 2000 features, EPSG:4326

# Reprojection en mémoire EPSG:3857 (sinon couche invisible dans le canevas)
result = processing.run("native:reprojectlayer", {
    'INPUT': layer_wfs,
    'TARGET_CRS': QgsCoordinateReferenceSystem('EPSG:3857'),
    'OUTPUT': 'memory:'
})
layer_cad = result['OUTPUT']
layer_cad.setName("Cadastre Mandelieu")
# → 26 439 features, EPSG:3857

# Symbologie : contour orange, remplissage quasi-transparent
sym = QgsFillSymbol.createSimple({
    'color': '204,68,0,30',      # orange très transparent (alpha 30/255)
    'outline_color': '#CC4400',
    'outline_width': '0.5'
})
layer_cad.setRenderer(QgsSingleSymbolRenderer(sym))

# Ajouter au-dessus des IRIS (index 0)
QgsProject.instance().addMapLayer(layer_cad, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer_cad)
```

**Ordre final des couches (haut → bas)** :
1. Cadastre Mandelieu (vecteur WFS, EPSG:3857)
2. IRIS Mandelieu-la-Napoule (PostGIS, gradué population)
3. Orthophoto IGN (XYZ, fond)

**Note cadastre** : le BBOX rectangulaire déborde sur les communes voisines (Cannes à l'est, Pégomas au nord). Comportement attendu — pour restreindre au territoire communal strict, il faudrait une intersection post-chargement (pas de filtre `code_commune` disponible côté WFS Géoplateforme).

---

## Points clés et pièges

| Sujet | Constat |
|---|---|
| **Bug QGIS 4.0.3 — raster + identifyMapTool** | `addMapLayer` sur une couche raster → access violation si l'outil Identifier est actif. Fix : passer sur Pan + `addMapLayer(layer, False)` + `insertLayer()` |
| **Ne pas cliquer sur la couche raster dans le panneau** | Même après ajout réussi, cliquer sur la couche raster dans le panneau des couches déclenche `onActiveLayerChanged` → crash. Rester sur l'outil Pan. |
| **Provider WMTS natif QGIS invalide** | `crs=...&layers=...&url=https://data.geopf.fr/wmts` → couche invalide. Fix : encoder en XYZ avec `type=xyz&url=...{z}/{y}/{x}` |
| **Canvas au zoom mondial au démarrage** | Les tuiles ne se chargent pas. Toujours zoomer sur la zone cible après ajout. |
| **Provider WFS natif QGIS invalide** | `QgsVectorLayer(url, name, "WFS")` → couche invalide pour `CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle`. Fix : driver OGR WFS `QgsVectorLayer("WFS:https://...", name, "ogr")` |
| **API Carto timeout** | `geo.api.gouv.fr` : appel HTTP synchrone dans le thread QGIS → 20 s de blocage puis timeout. Driver OGR WFS Géoplateforme préférable. |
| **CRS mismatch WFS** | WFS retourne EPSG:4326, canevas EPSG:3857 → couche présente dans le panneau mais invisible sur la carte. Fix : `processing.run("native:reprojectlayer", ...)` vers EPSG:3857 en mémoire. |
| **Colonnes INSEE avec espace** | `"IRIS "`, `"COM "`, `"P22_POP "` — espace traînant partout dans `iris_2025_population` |
| **Types text** | Toutes les valeurs numériques INSEE sont en `text` — caster avec `::numeric` |
| **Sous-requête URI QGIS** | `QgsDataSourceUri.setDataSource()` sur-échappe les guillemets → couche invalide. Fix : créer une vue PostgreSQL |
| **`sys.executable` QGIS** | Pointe sur `qgis-bin.exe` — pip via subprocess inutilisable. Fix : `pip._internal.cli.main` |
| **`sys.path` paramiko** | QGIS n'inclut pas le dossier utilisateur Python. Ajouter `sys.path.insert(0, ...)` à chaque session |

---

## Généralisation à d'autres communes

```python
code_insee = '06079'  # remplacer par le code cible
cur.execute(f"""
    CREATE OR REPLACE VIEW insee_raw.v_iris_pop AS
    SELECT c.fid, c.geom, c.nom_iris, c.code_iris, c.nom_commune,
           ROUND(p."P22_POP "::numeric, 0)::integer AS population
    FROM insee_raw.contours_iris_2025 c
    LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
    WHERE c.code_insee = '{code_insee}'
""")
```

Pour le cadastre, adapter le BBOX à l'emprise de la commune cible.

---

## REX — 2026-06-21 (second run)

**Résultat : 0 crash — procédure validée reproductible.**

Run complet depuis un projet QGIS vide, piloté intégralement via MCP Claude Code → QGIS :

| Étape | Résultat |
|---|---|
| Tunnel SSH paramiko | OK — PostGIS Alteris accessible localhost:5433 |
| Orthophoto IGN (XYZ) | Valide — rendu fond de carte immédiat |
| Vue PostGIS + couche IRIS | 9 features, graduation 5 classes bleu, étiquettes population |
| Zoom sur Mandelieu | Cadrage correct EPSG:3857 |
| Cadastre WFS OGR + reprojection | 26 439 parcelles EPSG:3857, symbologie orange |

**Conclusion** : la procédure est stable et reproductible. Base solide pour une routine généralisable à n'importe quelle commune (`code_insee` + BBOX comme seuls paramètres variables). Potentiel : automatiser la production de fiches communales IRIS + cadastre + fond ortho à la demande depuis Claude Code.

# Expertises Topologie - Claude et Qgis

## Contexte PLU

Pour une couche de zones PLU topologiquement correcte, trois règles sont non-négociables :
1. **Pas de gaps** — tout le territoire communal doit être couvert, sans trou entre zones
2. **Pas d'overlaps** — une parcelle n'appartient qu'à une seule zone
3. **Géométries valides** — pas de self-intersection, pas de géométrie nulle

Ces trois vérifications + corrections sont pilotables intégralement depuis Claude Code via le MCP QGIS, sans manipulation manuelle.

---

## Bloc 1 — Configuration du snapping avant saisie

À lancer en début de session d'édition sur une couche PLU. Configure l'environnement QGIS pour que la saisie soit topologiquement propre dès le départ.

```python
from qgis.core import QgsSnappingConfig, QgsTolerance, QgsProject

proj = QgsProject.instance()
snap_cfg = proj.snappingConfig()

snap_cfg.setEnabled(True)
snap_cfg.setMode(QgsSnappingConfig.SnappingMode.AllLayers)
snap_cfg.setType(QgsSnappingConfig.SnappingType.VertexAndSegment)
snap_cfg.setTolerance(10.0)
snap_cfg.setUnits(QgsTolerance.UnitType.Pixels)
snap_cfg.setIntersectionSnapping(True)   # accrochage sur les intersections

proj.setSnappingConfig(snap_cfg)
proj.setTopologicalEditing(True)          # partage de noeuds entre couches
proj.setAvoidIntersectionsMode(
    QgsProject.AvoidIntersectionsMode.AvoidIntersectionsLayers
)  # évite automatiquement les overlaps lors de la saisie
```

**Paramètres clés** :

| Paramètre | Valeur | Effet |
|---|---|---|
| `AllLayers` | mode | snap sur toutes les couches visibles |
| `VertexAndSegment` | type | accroche vertex ET bord |
| `10 px` | tolérance | adapté à la saisie courante PLU |
| `TopologicalEditing` | True | noeuds partagés entre polygones adjacents |
| `AvoidIntersectionsLayers` | mode | saisie d'un polygone qui "découpe" automatiquement ses voisins |

**Piège** : `setType()` attend `QgsSnappingConfig.SnappingType` — pas `Qgis.SnappingType` ni `Qgis.SnappingTypes`.

---

## Bloc 2 — Audit topologique

Routine complète : validité + overlaps + gaps sur n'importe quelle couche polygone.

```python
import processing
from qgis.core import QgsProject

def audit_topo(layer, unique_id='fid', gap_threshold=0, min_overlap_area=0):
    """
    Audit topologique d'une couche polygone PLU.
    Retourne un dict avec les couches d'erreurs et un résumé.
    """
    rapport = {}

    # 1. Validité géométrique (GEOS)
    r_val = processing.run("native:checkvalidity", {
        'INPUT_LAYER': layer,   # NOTE : INPUT_LAYER, pas INPUT
        'METHOD': 2,            # GEOS
        'IGNORE_RING_SELF_INTERSECTION': False,
        'VALID_OUTPUT': 'memory:',
        'INVALID_OUTPUT': 'memory:',
        'ERROR_OUTPUT': 'memory:'
    })
    rapport['validite'] = {
        'valides': r_val['VALID_COUNT'],
        'invalides': r_val['INVALID_COUNT'],
        'erreurs': r_val['ERROR_COUNT'],
        'layer_invalides': r_val['INVALID_OUTPUT'],
        'layer_erreurs': r_val['ERROR_OUTPUT']
    }

    # 2. Overlaps
    r_ov = processing.run("native:checkgeometryoverlap", {
        'INPUT': layer,
        'UNIQUE_ID': unique_id,
        'MIN_OVERLAP_AREA': min_overlap_area,
        'TOLERANCE': 8,
        'ERRORS': 'memory:',
        'OUTPUT': 'memory:'
    })
    rapport['overlaps'] = {
        'count': r_ov['ERRORS'].featureCount(),
        'layer_errors': r_ov['ERRORS'],
        'layer_features': r_ov['OUTPUT']
    }

    # 3. Gaps
    r_gap = processing.run("native:checkgeometrygap", {
        'INPUT': layer,
        'UNIQUE_ID': unique_id,
        'GAP_THRESHOLD': gap_threshold,
        'TOLERANCE': 8,
        'NEIGHBORS': 'memory:',
        'ERRORS': 'memory:',
        'OUTPUT': 'memory:'
    })
    rapport['gaps'] = {
        'count': r_gap['OUTPUT'].featureCount(),
        'layer_gaps': r_gap['OUTPUT'],
        'layer_neighbors': r_gap['NEIGHBORS'],  # requis pour fixgeometrygap
        'layer_errors': r_gap['ERRORS']
    }

    # Résumé lisible
    print(f"=== Audit topo : {layer.name()} ({layer.featureCount()} features) ===")
    print(f"Validité  : {rapport['validite']['valides']} OK / "
          f"{rapport['validite']['invalides']} invalides")
    print(f"Overlaps  : {rapport['overlaps']['count']} erreur(s)")
    print(f"Gaps      : {rapport['gaps']['count']} trou(s)")
    ok = (rapport['validite']['invalides'] == 0 and
          rapport['overlaps']['count'] == 0 and
          rapport['gaps']['count'] == 0)
    print(f"Résultat  : {'PROPRE' if ok else 'ERREURS DETECTEES'}")

    return rapport
```

**Usage** :
```python
from qgis.core import QgsProject
layer = QgsProject.instance().mapLayersByName("zones_plu")[0]
rapport = audit_topo(layer, unique_id='fid')
```

**Piège critique** : `native:checkvalidity` → paramètre `INPUT_LAYER` (pas `INPUT`). Erreur silencieuse sinon.

---

## Bloc 3 — Correction automatique

S'appuie sur les couches d'erreurs produites par le Bloc 2.

### 3a. Corriger les overlaps

```python
r_fix_ov = processing.run("native:fixgeometryoverlap", {
    'INPUT': layer,
    'ERRORS': rapport['overlaps']['layer_errors'],
    'UNIQUE_ID': 'fid',
    'OVERLAP_FEATURE_UNIQUE_IDX': 'gc_overlap_fid',  # champ produit par checkgeometryoverlap
    'ERROR_VALUE_ID': 'gc_error',
    'OUTPUT': 'memory:',
    'REPORT': 'memory:',
    'TOLERANCE': 8
})
layer_corrige = r_fix_ov['OUTPUT']
print(f"Overlaps corrigés : {r_fix_ov['REPORT'].featureCount()} opérations")
```

### 3b. Combler les gaps

**3 méthodes disponibles** :

| Valeur | Méthode | Usage recommandé |
|---|---|---|
| `0` | Ajouter à la plus longue bordure en commun | PLU — zone voisine qui partage le plus de frontière |
| `1` | Créer une nouvelle entité | si le gap est une zone à part entière |
| `2` | Ajouter à la plus grande zone voisine | quand la surface prime |

```python
r_fix_gap = processing.run("native:fixgeometrygap", {
    'INPUT': layer,
    'NEIGHBORS': rapport['gaps']['layer_neighbors'],  # issu de checkgeometrygap
    'GAPS': rapport['gaps']['layer_gaps'],
    'METHOD': 0,    # 0 = plus longue bordure (recommandé PLU)
    'UNIQUE_ID': 'fid',
    'ERROR_ID_IDX': 'gc_errorid',
    'OUTPUT': 'memory:',
    'REPORT': 'memory:',
    'TOLERANCE': 8
})
layer_sans_gap = r_fix_gap['OUTPUT']
print(f"Gaps comblés : {r_fix_gap['REPORT'].featureCount()} opérations")
```

### 3c. Corriger les géométries invalides (self-intersections, anneaux)

```python
r_fix_val = processing.run("native:fixgeometries", {
    'INPUT': rapport['validite']['layer_invalides'],
    'METHOD': 1,    # 1 = structure linéaire (robuste)
    'OUTPUT': 'memory:'
})
layer_valide = r_fix_val['OUTPUT']
```

---

## Bloc 4 — Accrochage post-saisie (snapgeometries)

Quand une couche a été saisie sans snapping actif, ou importée avec de micro-décalages entre polygones adjacents. Accroche les géométries d'une couche sur une couche de référence (ex : limites communales, autre zonage).

**8 comportements disponibles** :

| Valeur | Comportement | Usage |
|---|---|---|
| `0` | Aligner les nœuds, ajoute sommets si besoin | **défaut recommandé** |
| `1` | Point le plus proche, ajoute sommets | si nœuds mal alignés |
| `2` | Aligner les nœuds, sans ajout de sommet | quand on veut conserver la densité |
| `4` | Déplacer uniquement les extrémités (nœuds) | micro-corrections de bord |
| `6` | Extrémités sur extrémités uniquement | lignes/filaires |

```python
r_snap = processing.run("native:snapgeometries", {
    'INPUT': layer_a_corriger,
    'REFERENCE_LAYER': layer_reference,
    'TOLERANCE': 0.5,    # en unités de la couche (mètres si Lambert 93)
    'BEHAVIOR': 0,
    'OUTPUT': 'memory:'
})
layer_snapped = r_snap['OUTPUT']
```

**Recommandation PLU** : tolérance 0.1–0.5 m en EPSG:2154 (Lambert 93). Trop grande → déformation des géométries.

---

## Bloc 5 — Reconstruction automatique depuis le cadastre

Quand une zone (ex : périmètre PLU, emprise de projet) a été saisie grossièrement et doit être recalée exactement sur les limites parcellaires cadastrales. Claude reconstruit le polygone par dissolution des parcelles qui chevauchent la zone rough ; l'opérateur complète ensuite manuellement les parties sans référence cadastrale (domaine public non-parcellaire : voiries, cours d'eau).

**Validé le 2026-06-21** sur `06079-Minelle.gpkg` (Mandelieu-la-Napoule) : 11 parcelles intersectantes → 2 retenues (overlap ≥ 50%) → 137 004 m², 31 nœuds, géométrie valide.

### Principe

1. Fixer les géométries du cadastre (WFS souvent invalide)
2. Extraire les parcelles qui intersectent la zone rough
3. Calculer le % de chevauchement pour chaque parcelle → garder celles à ≥ 50%
4. Dissoudre → multiparttosingleparts → garder la plus grande part
5. Écrire dans le GeoPackage en retirant d'abord les couches QGIS (file locking Windows)

### Code complet

```python
import processing
import urllib.parse
from qgis.core import (
    QgsProject, QgsVectorFileWriter, QgsWkbTypes,
    QgsFields, QgsMemoryProviderUtils
)

# Pré-requis : layer_cad (cadastre WFS reprojeté EPSG:3857)
#              layer_zone (zone rough à recaler)
#              gpkg_path (chemin du GeoPackage à écrire)

# 1. Fixer les géométries cadastrales (WFS Géoplateforme souvent invalide)
cad_fixed = processing.run("native:fixgeometries", {
    'INPUT': layer_cad,
    'METHOD': 1,    # structure linéaire, robuste
    'OUTPUT': 'memory:'
})['OUTPUT']

# 2. Extraire les parcelles qui intersectent la zone rough
parcelles_in = processing.run("native:extractbylocation", {
    'INPUT': cad_fixed,
    'PREDICATE': [0],   # intersects
    'INTERSECT': layer_zone,
    'OUTPUT': 'memory:'
})['OUTPUT']

# 3. Calculer le % de chevauchement et retenir celles ≥ 50%
geom_zone = next(layer_zone.getFeatures()).geometry()
a_inclure = []
for f in parcelles_in.getFeatures():
    inter = f.geometry().intersection(geom_zone)
    pct = inter.area() / f.geometry().area() * 100
    if pct >= 50:
        a_inclure.append(f['gid'])

print(f"{parcelles_in.featureCount()} parcelles intersectantes → "
      f"{len(a_inclure)} retenues (overlap ≥ 50%)")
print(f"GIDs retenus : {a_inclure}")

# 4. Sélectionner + dissoudre
ids_str = ', '.join(str(i) for i in a_inclure)
parcelles_sel = processing.run("native:extractbyexpression", {
    'INPUT': cad_fixed,
    'EXPRESSION': f'"gid" IN ({ids_str})',
    'OUTPUT': 'memory:'
})['OUTPUT']

dissolved = processing.run("native:dissolve", {
    'INPUT': parcelles_sel,
    'FIELD': [],
    'SEPARATE_DISJOINT': False,
    'OUTPUT': 'memory:'
})['OUTPUT']

# 5. Single part → garder la plus grande
single = processing.run("native:multiparttosingleparts", {
    'INPUT': dissolved,
    'OUTPUT': 'memory:'
})['OUTPUT']

largest = max(single.getFeatures(), key=lambda f: f.geometry().area())
print(f"Résultat : {largest.geometry().area():.0f} m², "
      f"{largest.geometry().constGet().nCoordinates()} nœuds")

layer_main = QgsMemoryProviderUtils.createMemoryLayer(
    "main", QgsFields(), QgsWkbTypes.Type.Polygon, single.crs()
)
layer_main.dataProvider().addFeature(largest)

# 6. Écrire dans le GeoPackage
# CRITIQUE : retirer toutes les couches QGIS référençant le fichier avant écriture
for name in ["06079-Minelle"]:
    for lyr in QgsProject.instance().mapLayersByName(name):
        QgsProject.instance().removeMapLayer(lyr)

options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = "GPKG"
options.layerName = "06079-Minelle"
options.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer

# writeAsVectorFormatV3 retourne un tuple de 4 valeurs
res = QgsVectorFileWriter.writeAsVectorFormatV3(
    layer_main, gpkg_path, QgsCoordinateTransformContext(), options
)
# res = (error_code, error_message, filename, layername)
if res[0] == 0:
    print(f"Écrit : {gpkg_path} → couche '{options.layerName}'")
else:
    print(f"ERREUR {res[0]} : {res[1]}")

# 7. Recharger dans QGIS pour vérification
layer_reload = QgsVectorLayer(
    f"{gpkg_path}|layername={options.layerName}",
    options.layerName, "ogr"
)
QgsProject.instance().addMapLayer(layer_reload, False)
root = QgsProject.instance().layerTreeRoot()
root.insertLayer(0, layer_reload)
iface.mapCanvas().setExtent(layer_reload.extent())
iface.mapCanvas().refresh()
print("Couche rechargée et zoomée.")
```

### Pièges spécifiques

| Sujet | Constat |
|---|---|
| **`writeAsVectorFormatV3` retourne 4 valeurs** | `(error_code, error_message, filename, layername)` — pas 2. Déstructurer en conséquence. |
| **File locking Windows** | QGIS garde un handle sur le fichier GeoPackage. Retirer toutes les couches référençant le fichier avec `removeMapLayer()` avant d'écrire. |
| **`CreateOrOverwriteLayer` pas `CreateOrOverwriteFile`** | `CreateOrOverwriteFile` supprime tout le fichier (détruisant les autres couches). `CreateOrOverwriteLayer` ne touche qu'à la couche cible. |
| **`native:savefeatures` échoue si fichier existe** | "A file system object already exists" — utiliser `writeAsVectorFormatV3` à la place. |
| **MultiPolygon → `asPolygon()` fail** | Si les parcelles retenues ne sont pas adjacentes, le dissolve produit un MultiPolygon. Appliquer `multiparttosingleparts` + `max(..., key=lambda f: f.geometry().area())` pour garder la plus grande part. |
| **Cadastre WFS invalide** | La Géoplateforme retourne parfois des géométries invalides (ex : feature 15026). Toujours fixer avec `native:fixgeometries METHOD=1` avant usage comme couche de référence. |

### Workflow collaboratif

Claude reconstruit le périmètre sur les limites parcellaires exactes. L'opérateur complète manuellement les parties manquantes non-parcellaires (domaine public : voiries, cours d'eau, espaces naturels non cadastrés). Les deux résultats sont complémentaires : la précision automatique sur le cadastre + le jugement humain sur le hors-cadastre.

---

## Routine principale — Audit + Rapport

Fonction complète prête à l'emploi. Appeler par Claude en une seule commande.

```python
import processing
from qgis.core import QgsProject, QgsSnappingConfig, QgsTolerance

def configurer_snapping_plu():
    proj = QgsProject.instance()
    snap_cfg = proj.snappingConfig()
    snap_cfg.setEnabled(True)
    snap_cfg.setMode(QgsSnappingConfig.SnappingMode.AllLayers)
    snap_cfg.setType(QgsSnappingConfig.SnappingType.VertexAndSegment)
    snap_cfg.setTolerance(10.0)
    snap_cfg.setUnits(QgsTolerance.UnitType.Pixels)
    snap_cfg.setIntersectionSnapping(True)
    proj.setSnappingConfig(snap_cfg)
    proj.setTopologicalEditing(True)
    proj.setAvoidIntersectionsMode(
        QgsProject.AvoidIntersectionsMode.AvoidIntersectionsLayers)
    print("Snapping PLU configuré")

def audit_topo(layer, unique_id='fid', gap_threshold=0, min_overlap_area=0):
    r_val = processing.run("native:checkvalidity", {
        'INPUT_LAYER': layer, 'METHOD': 2,
        'IGNORE_RING_SELF_INTERSECTION': False,
        'VALID_OUTPUT': 'memory:', 'INVALID_OUTPUT': 'memory:', 'ERROR_OUTPUT': 'memory:'
    })
    r_ov = processing.run("native:checkgeometryoverlap", {
        'INPUT': layer, 'UNIQUE_ID': unique_id,
        'MIN_OVERLAP_AREA': min_overlap_area, 'TOLERANCE': 8,
        'ERRORS': 'memory:', 'OUTPUT': 'memory:'
    })
    r_gap = processing.run("native:checkgeometrygap", {
        'INPUT': layer, 'UNIQUE_ID': unique_id,
        'GAP_THRESHOLD': gap_threshold, 'TOLERANCE': 8,
        'NEIGHBORS': 'memory:', 'ERRORS': 'memory:', 'OUTPUT': 'memory:'
    })
    rapport = {
        'layer': layer,
        'unique_id': unique_id,
        'validite': {
            'valides': r_val['VALID_COUNT'],
            'invalides': r_val['INVALID_COUNT'],
            'layer_invalides': r_val['INVALID_OUTPUT']
        },
        'overlaps': {
            'count': r_ov['ERRORS'].featureCount(),
            'layer_errors': r_ov['ERRORS'],
            'layer_features': r_ov['OUTPUT']
        },
        'gaps': {
            'count': r_gap['OUTPUT'].featureCount(),
            'layer_gaps': r_gap['OUTPUT'],
            'layer_neighbors': r_gap['NEIGHBORS'],
            'layer_errors': r_gap['ERRORS']
        }
    }
    ok = (r_val['INVALID_COUNT'] == 0 and
          r_ov['ERRORS'].featureCount() == 0 and
          r_gap['OUTPUT'].featureCount() == 0)
    print(f"\n=== Audit topo : {layer.name()} ===")
    print(f"  Géométries invalides : {r_val['INVALID_COUNT']}")
    print(f"  Overlaps             : {r_ov['ERRORS'].featureCount()}")
    print(f"  Gaps                 : {r_gap['OUTPUT'].featureCount()}")
    print(f"  => {'PROPRE' if ok else 'ERREURS — voir rapport'}")
    return rapport

# Usage type
# layer = QgsProject.instance().mapLayersByName("zones_plu")[0]
# configurer_snapping_plu()
# rapport = audit_topo(layer)
```

---

## Pièges à retenir

| Sujet | Constat |
|---|---|
| **`INPUT_LAYER` vs `INPUT`** | `native:checkvalidity` exige `INPUT_LAYER`, tous les autres utilisent `INPUT`. Erreur silencieuse sinon. |
| **`QgsSnappingConfig.SnappingType`** | `setType()` attend ce type précis — pas `Qgis.SnappingType` ni `Qgis.SnappingTypes`. |
| **NEIGHBORS obligatoire pour fixgeometrygap** | La couche `NEIGHBORS` produite par `checkgeometrygap` doit être conservée et passée à `fixgeometrygap`. |
| **Tolérance snapgeometries en unités couche** | Si la couche est en Lambert 93 (mètres), 0.5 = 50 cm. Ne pas confondre avec la tolérance en pixels du snapping canvas. |
| **METHOD 0 pour PLU gaps** | "Plus longue bordure en commun" est la méthode la plus cohérente pour les zonages PLU (le gap va à la zone avec laquelle il partage le plus de frontière). |
| **AvoidIntersectionsLayers** | Mode le plus adapté PLU — évite les overlaps lors de la saisie mais uniquement sur les couches cochées dans les paramètres du projet. |
| **`writeAsVectorFormatV3` retourne 4 valeurs** | `(error_code, error_message, filename, layername)` — pas 2. |
| **File locking GeoPackage Windows** | Retirer toutes les couches QGIS référençant le fichier avant écriture, utiliser `CreateOrOverwriteLayer`. |

---

## Statut

- **Validé le 2026-06-21** : Blocs 1–5 testés sur QGIS 4.0.3 via MCP Claude Code.
  - Bloc 1 : snapping PLU
  - Bloc 2 : `checkvalidity`, `checkgeometryoverlap`, `checkgeometrygap`
  - Bloc 5 : reconstruction `06079-Minelle.gpkg` depuis cadastre WFS → 137 004 m², 31 nœuds, valide
- **À tester** : `fixgeometryoverlap`, `fixgeometrygap`, `snapgeometries` sur une vraie couche PLU avec erreurs.

# Competences Claude Libre Office

# 04_Claude et le PC Windows Elio+Jux

# 260803-suivi des logs de dysfonctionnement du PC - écrans bleus de la mort

# Suivi des dysfonctionnements du PC eliob — écrans bleus

**Machine** : PC Windows `eliob` (pcelio)
**Analyse initiale** : 2026-08-03 — Claude Code
**Fenêtre observée** : 29/10/2025 → 03/08/2026 (Windows réinstallé le 28/10/2025, le journal ne remonte pas plus loin)

---

## 1. Configuration matérielle

| Élément | Valeur |
|---|---|
| Carte mère | MSI **A320M-A PRO** (MS-7C51), BIOS AMI **1.40** du **08/12/2020** |
| Processeur | AMD **Ryzen 5 2600X** — 6 cœurs, 3,6 GHz |
| Mémoire | **1 seule barrette** 16 Go TEAMGROUP UD4-2666 (`DIMM 0`, canal B) — cadencée à **2400 MHz** (sous sa fréquence nominale de 2666) |
| Disque système | SSD SATA **Patriot Burst** 240 Go (C: — 71 Go libres) |
| Disque secondaire | HDD SATA **Toshiba HDWD110** 1 To (D:) |
| Périphériques USB | ASMT 2115 1 To (E:), Seagate Backup+ Hub 8 To (F:), SanDisk 3.2Gen1 64 Go |
| OS | Windows 10 Famille 22H2 — build **19045**, installé le **28/10/2025** |
| Boîtier / assemblage | Megaport, modèle 130430 |

> **Remarque sur l'âge** : Julien évalue le PC à 9 ans d'usage intensif. Le Ryzen 2600X date de 2018 et la carte A320M-A PRO de 2019-2020 — **le cœur de la machine a donc plutôt 6-7 ans**. Le boîtier, l'alimentation et les ventilateurs peuvent être plus anciens s'ils ont été repris d'une configuration précédente. **L'alimentation n'a pas pu être identifiée par logiciel** — c'est une information à relever physiquement (marque, modèle, wattage, année), elle est déterminante pour la suite du diagnostic.

---

## 2. Méthode

Sources interrogées sur le poste, sans installation d'outil tiers :

- Journal `System` — événements `Kernel-Power 41` (arrêt inattendu), `BugCheck 1001` (code d'erreur BSOD), `WHEA-Logger` (erreurs matérielles remontées par le firmware), `volmgr`, `Ntfs`, `disk`
- Propriétés internes des événements 41 (`BugcheckCode`, `BugcheckParameter1`, `PowerButtonTimestamp`) — ce sont elles qui permettent de distinguer un vrai BSOD d'une coupure sèche
- Corrélation temporelle événement par événement (dernier événement journalisé avant chaque redémarrage, présence ou non d'un arrêt propre `1074`/`13` juste avant)
- Inventaire matériel WMI/CIM, état SMART exposé par Windows, configuration d'alimentation et de vidage mémoire, dates et versions des pilotes tiers

**Point de méthode important** : les événements `41` et `1001` sont **horodatés au redémarrage suivant**, pas à l'instant du crash. Comme le redémarrage automatique est activé (`AutoReboot=1`), les deux coïncident à la minute près pour les BSOD — mais il ne faut jamais lire ces horodatages comme « l'heure de la panne » sans cette vérification.

---

## 3. Chiffres clés

| Indicateur | Valeur |
|---|---|
| Arrêts anormaux (`Kernel-Power 41`) | **45** en 9 mois |
| dont **écrans bleus réels** (avec code bugcheck) | **15** (33 %) |
| dont **coupures sèches sans BSOD** (`BugcheckCode = 0`) | **30** (67 %) |
| Erreurs matérielles `WHEA-Logger` | **0** |
| Erreurs disque / NTFS critiques (90 j) | 2 `Ntfs 50`, 3 `volmgr 161` (échec d'écriture du dump) |
| Bouton d'alimentation maintenu (arrêt forcé manuel) | **1 seul cas** — 20/05/2026 20:35 |
| Arrêt propre demandé (`1074`/`13`) juste avant le crash | **0 cas sur 45** |

**Fréquence** : environ **1 arrêt anormal tous les 6 jours** en moyenne, avec des grappes (2 crashes le même jour à 5 reprises).

---

## 4. Deux populations de pannes bien distinctes

### Population A — 30 coupures sèches, sans écran bleu (67 %)

`BugcheckCode = 0`, `PowerButtonTimestamp = 0` : le système s'est arrêté **sans produire de vérification d'erreur, sans que le bouton d'alimentation ait été maintenu, et sans qu'un arrêt ait été demandé**. Le dernier événement journalisé précède le redémarrage de moins d'une minute dans la quasi-totalité des cas.

C'est le profil d'une **coupure d'alimentation, d'un reset matériel ou d'un gel total du noyau** — Windows n'a pas eu le temps d'écrire quoi que ce soit.

Ces 30 événements sont **répartis sur toute la période** (octobre 2025 → juillet 2026), sans lien avec les vagues de BSOD. **C'est la population la plus préoccupante pour une hypothèse matérielle**, et c'est aussi celle sur laquelle les logs sont, par construction, muets.

### Population B — 15 écrans bleus avec code d'erreur (33 %)

| Code | Nb | Nom | Signification |
|---|---|---|---|
| `0x0000009F` | **10** | DRIVER_POWER_STATE_FAILURE | Un pilote bloque une requête de changement d'état d'alimentation (mise en veille, reprise, arrêt). Paramètre 1 = `0x3` dans les 10 cas : un objet de périphérique bloque une IRP trop longtemps. |
| `0x00000050` | **3** | PAGE_FAULT_IN_NONPAGED_AREA | Accès à une adresse mémoire invalide. Paramètre 4 = `0x2` : la faute survient sur une **tentative d'exécution de code**, pas une lecture/écriture de données. |
| `0x0000003B` | 1 | SYSTEM_SERVICE_EXCEPTION | Exception `0xC0000005` (violation d'accès) en mode noyau. |
| `0x000000A0` | 1 | INTERNAL_POWER_ERROR | Erreur interne du gestionnaire d'alimentation. |

**12 des 15 BSOD (80 %) sont des erreurs liées à une transition d'alimentation** (`0x9F` + `0xA0`). Aucun n'est précédé d'une demande d'arrêt propre → il s'agit de transitions **veille S3 / reprise / démarrage rapide**, pas d'un arrêt lancé depuis le menu Démarrer.

---

## 5. Chronologie — trois régimes successifs

| Période | Régime dominant |
|---|---|
| **29/10/2025 → 23/12/2025** | Uniquement des coupures sèches (2 événements) |
| **25/12/2025 → 29/03/2026** | **Vague de 10 × `0x9F`** — DRIVER_POWER_STATE_FAILURE, souvent 2 le même jour, entremêlée de coupures sèches |
| **16/04/2026 → 19/05/2026** | 1 × `0xA0`, 1 × `0x3B` — puis les BSOD cessent |
| **19/05/2026 → 28/07/2026** | Retour aux seules coupures sèches (7 événements) |
| **31/07/2026 → 03/08/2026** | **Nouvelle vague : 3 × `0x50`** en 4 jours |

Les BSOD ne sont donc pas un phénomène continu : ce sont **des vagues qui apparaissent et disparaissent**, ce qui est le comportement typique d'une **cause logicielle** (installation ou mise à jour d'un pilote). Les coupures sèches, elles, sont présentes en continu du premier au dernier jour — comportement typique d'une **cause matérielle**.

---

## 6. Suspect principal de la vague en cours : le pilote réseau VirtualBox

**`VBoxNetLwf` — VirtualBox NDIS6 Bridged Networking Driver, version 7.2.14.174565**

Le journal `System` contient **20 erreurs `VBoxNetLwf` (ID 12)** : *« Le pilote a détecté une erreur de pilote interne sur \Device\VBoxNetLwf »*.

**Toutes** sont comprises entre le **24/07/2026 06:55** et le **03/08/2026 07:43** — soit exactement depuis l'installation d'**Oracle VirtualBox 7.2.14 le 24/07/2026** (fichiers pilotes datés du 17/07/2026). Aucune avant.

Le rythme est de **deux erreurs par jour** — une le matin, une le soir :

| Date | Matin | Soir |
|---|---|---|
| 24/07 | 06:55 | 18:02 |
| 27/07 | 08:02 | 18:22 |
| 29/07 | 06:27 | 17:36 |
| 30/07 | 07:25 | 19:10 |
| 02/08 | 06:36 | 21:54 |

C'est-à-dire **à chaque allumage et à chaque extinction** — exactement le symptôme décrit par Julien.

**Corrélation avec les 3 écrans bleus `0x50` :**

| Erreur `VBoxNetLwf` | Écran bleu correspondant | Écart |
|---|---|---|
| 31/07/2026 **06:27:21** | BugCheck `0x50` à 06:27:34 | 13 s |
| 31/07/2026 **08:54:01** | BugCheck `0x50` à 08:54:14 | 13 s |
| 03/08/2026 **07:43:26** | BugCheck `0x50` à 07:43:37 | 11 s |

Et le 28/07/2026 07:52:02, une erreur `VBoxNetLwf` coïncide à la seconde près avec une **coupure sèche sans BSOD**.

**Élément technique qui renforce fortement l'hypothèse** : les trois `0x50` partagent le **même déplacement `0x3ae` dans l'adresse d'instruction fautive** (`…3c5903ae`, `…1db903ae`, `…091903ae`), pour des adresses de base différentes. Autrement dit : **la même ligne de code d'un même pilote plante à chaque fois**, à une adresse de chargement différente selon le démarrage. C'est la signature d'un **défaut logiciel reproductible**, et non d'une cellule mémoire défectueuse — une RAM défaillante produirait des adresses dispersées et aléatoires.

`VBoxNetLwf` est un filtre NDIS léger : il s'insère dans la pile réseau et est sollicité à chaque transition d'alimentation. C'est un candidat cohérent à la fois pour les `0x50` récents et, dans son principe, pour la famille `0x9F`.

### Correction d'une attribution antérieure

Le fichier `CLAUDE.md` attribue les écrans bleus `0x50` du 31/07/2026 aux pilotes RustDesk (écran virtuel `usbmmidd_v2` et imprimante virtuelle), désactivés le jour même par renommage en `.disabled`.

**Cette explication ne tient plus** : un quatrième `0x50` s'est produit le **03/08/2026 à 07:43**, avec la même signature `0x3ae`, alors que `usbmmidd_v2` était désactivé depuis trois jours. La désactivation des pilotes RustDesk n'a donc **pas** résolu le problème. Les deux logiciels ayant été installés dans la même fenêtre (VirtualBox le 24/07, RustDesk le 31/07), la coïncidence de dates avait masqué le vrai suspect. À noter toutefois que le dossier `C:\Program Files\RustDesk\drivers` est **toujours présent** et n'a pas été désactivé.

---

## 7. Ce que les logs ne permettent PAS d'accuser

Il faut être clair sur ce point : **à ce stade, aucune donnée ne désigne un composant électronique défectueux.**

| Vérification | Résultat | Interprétation |
|---|---|---|
| `WHEA-Logger` (erreurs machine remontées par le firmware : CPU, mémoire, bus PCIe, cache) | **0 événement sur 9 mois** | Aucune erreur matérielle corrigible ou fatale détectée par le processeur. C'est un signal négatif fort contre une défaillance CPU ou mémoire franche. |
| État de santé des 5 disques | Tous `Healthy` / `OK` | Aucune alerte |
| Prédiction de panne SMART (WMI) | Aucune remontée | Voir la limite ci-dessous |
| Erreurs disque / NTFS | 2 `Ntfs 50` + 3 `volmgr 161` en 90 jours | Les `volmgr 161` sont des **conséquences** des crashes (échec d'écriture du fichier de vidage), pas des causes |

**Nuance importante sur WHEA** : l'absence d'erreur WHEA ne disculpe pas le matériel pour la Population A. Une coupure d'alimentation brutale ou un gel total ne laisse par définition **aucune trace**, puisque le système n'a plus le temps d'écrire. WHEA ne couvre pas non plus les défaillances d'alimentation, de VRM ou de connectique.

**Limite sur SMART** : Windows n'expose **aucun compteur SMART** pour ces disques via l'API standard (`Get-StorageReliabilityCounter` ne renvoie rien, y compris la température, les heures de fonctionnement et les secteurs réalloués). Le contrôleur SATA du chipset A320 ne relaie pas ces données. **L'état réel du SSD Patriot Burst — notamment son taux d'usure et ses secteurs réalloués — est donc à ce jour inconnu.** C'est une lacune à combler en priorité : ce SSD est le disque système, c'est un modèle d'entrée de gamme, et une usure avancée expliquerait des gels au démarrage.

---

## 8. Facteurs aggravants identifiés dans la configuration

### Démarrage rapide activé (`HiberbootEnabled = 1`)

Le **démarrage rapide** (Fast Startup) est actif. Avec ce réglage, « Arrêter » n'éteint pas réellement Windows : le noyau et les pilotes sont **mis en hibernation dans un fichier**, puis rechargés tels quels au démarrage suivant.

Conséquences directes sur ce cas :

1. C'est la **première cause connue des écrans bleus `0x9F`** — qui représentent 10 des 15 BSOD relevés ici.
2. Cela explique qu'**aucun crash ne soit précédé d'un arrêt propre** dans les logs : les transitions concernées sont des hibernations/reprises, pas de vrais arrêts.
3. Un état de pilote corrompu (celui de `VBoxNetLwf`, par exemple) est **réinjecté à chaque démarrage** au lieu d'être réinitialisé — ce qui transforme un bug ponctuel en panne récurrente.

### Mémoire : une seule barrette, sous-cadencée

Un seul module de 16 Go occupant `DIMM 0` (canal B) — donc **pas de double canal**, et la barrette tourne à **2400 MHz au lieu de 2666**. Ce n'est pas une cause de panne en soi, mais c'est une configuration à connaître. Point positif pour le diagnostic : **avec une seule barrette, un test mémoire est simple à interpréter** et il n'y a pas de problème d'appairage possible.

### BIOS de 2020

Version 1.40 datée du 08/12/2020, jamais mise à jour depuis. MSI a publié des révisions ultérieures pour l'A320M-A PRO, comportant des correctifs AGESA sur la gestion de l'alimentation et la compatibilité mémoire — directement pertinents pour des erreurs `0x9F` et `0xA0`.

### Espace disque système

71 Go libres sur 223 Go (C:) — suffisant, mais à surveiller : le fichier `MEMORY.DMP` occupe à lui seul **2,4 Go**.

---

## 9. Diagnostic de synthèse

**Il y a très probablement deux problèmes distincts, pas un seul.**

**Problème 1 — logiciel, actif en ce moment, identifié avec un bon niveau de confiance.**
Le pilote réseau `VBoxNetLwf` de VirtualBox 7.2.14 échoue à chaque transition d'alimentation depuis son installation le 24/07/2026, et a provoqué 3 écrans bleus `0x50` en 4 jours. La signature d'adresse identique (`0x3ae`) confirme un défaut de code reproductible. Le démarrage rapide amplifie le phénomène. **C'est traitable immédiatement et sans risque.**

**Problème 2 — cause encore indéterminée, présent en continu depuis au moins octobre 2025.**
30 coupures sèches réparties sur 9 mois, sans aucune trace exploitable. La vague de 10 × `0x9F` de l'hiver 2025-2026 relève probablement aussi d'un pilote (autre que VirtualBox, installé bien plus tard), mais **les coupures sèches restent inexpliquées**. Les hypothèses ouvertes, par ordre de vraisemblance sur une machine de cet âge :

1. **Alimentation vieillissante** — condensateurs fatigués, tension instable sous charge. C'est l'hypothèse n°1 pour des coupures nettes sans trace, et c'est le composant le plus âgé et le plus sollicité de la machine.
2. **Thermique** — pâte thermique sèche après 6-7 ans, ventilateur de CPU encrassé, coupure de protection.
3. **SSD système** — un Patriot Burst d'entrée de gamme en fin de vie peut provoquer des gels totaux au démarrage. **État actuellement inconnu, faute de données SMART.**
4. **Connectique / oxydation** — barrette mémoire, connecteurs d'alimentation, câbles SATA. Neuf ans de poussière.
5. **Mémoire** — moins probable (aucune erreur WHEA, signature `0x50` non aléatoire), mais **non écartée** tant qu'un test complet n'a pas été passé.

---

## 10. Actions recommandées, par ordre de priorité

### Priorité 1 — sans risque, à faire tout de suite

| # | Action | Objectif |
|---|---|---|
| 1 | **Désactiver le filtre réseau VirtualBox** : décocher « VirtualBox NDIS6 Bridged Networking Driver » dans les propriétés de la carte réseau. Si VirtualBox n'est pas utilisé au quotidien, le désinstaller purement et simplement. | Traite le suspect n°1 de la vague en cours |
| 2 | **Désactiver le démarrage rapide** : Panneau de configuration → Options d'alimentation → « Choisir l'action des boutons » → décocher « Activer le démarrage rapide ». | Supprime la cause n°1 des `0x9F` et évite de réinjecter un état de pilote corrompu à chaque démarrage |
| 3 | **Activer les mini-vidages mémoire** en complément du vidage noyau (`MinidumpsCount` → 50). | Aujourd'hui seul `MEMORY.DMP` est écrit et **il est écrasé à chaque crash** : l'historique des dumps est perdu. Sans mini-vidages, chaque nouveau crash détruit la preuve du précédent. |
| 4 | **Désactiver aussi le dossier `C:\Program Files\RustDesk\drivers`**, resté actif. | Écarter définitivement la piste RustDesk |

### Priorité 2 — nécessite une installation ou un redémarrage

| # | Action | Objectif |
|---|---|---|
| 5 | **Installer `smartmontools`** (`winget install smartmontools`) et relever le SMART complet du SSD Patriot Burst et du HDD Toshiba : heures de fonctionnement, usure, secteurs réalloués, erreurs CRC. | **Comble la principale lacune du diagnostic.** Windows n'expose rien ; c'est la seule façon de savoir si le SSD système est en fin de vie. |
| 6 | **Installer WinDbg** (`winget install Microsoft.WinDbg`) et analyser `C:\Windows\MEMORY.DMP` (2,4 Go, crash du 03/08 07:43) avec `!analyze -v`. | **Passe de « suspect fortement corrélé » à « coupable nommé »** : le dump contient le nom exact du module fautif. C'est l'étape qui authentifie formellement la cause. |
| 7 | **Test mémoire complet** : MemTest86 sur clé USB, **au moins 4 passes complètes**, de préférence une nuit entière. L'outil intégré à Windows est insuffisant. | Écarte ou confirme la RAM de façon définitive. Simple ici : une seule barrette. |
| 8 | **Mettre à jour le BIOS** MSI A320M-A PRO (actuel : 1.40 de 2020). | Correctifs AGESA sur la gestion d'alimentation, directement liés aux `0x9F`/`0xA0` |

### Priorité 3 — intervention physique, pour la Population A

| # | Action | Objectif |
|---|---|---|
| 9 | **Relever les références de l'alimentation** (marque, modèle, wattage, année). | Information manquante et déterminante |
| 10 | **Dépoussiérer** : ventilateur et radiateur CPU, ventilateurs de boîtier, filtres, bloc d'alimentation. | Cause thermique |
| 11 | **Réextraire et réinsérer** la barrette mémoire et les connecteurs d'alimentation ATX 24 broches et EPS 8 broches. Nettoyer les contacts. | Cause connectique / oxydation |
| 12 | **Refaire la pâte thermique du processeur** si elle n'a pas été changée depuis l'assemblage. | Cause thermique |
| 13 | **Surveiller les températures et les tensions** en fonctionnement (HWiNFO64), en particulier les rails 12 V, 5 V et 3,3 V sous charge. | Détecte une alimentation qui décroche |
| 14 | Si les coupures sèches persistent après tout ce qui précède : **tester avec une autre alimentation**. | Test décisif de l'hypothèse n°1 |

---

## 11. Limites de cette analyse

À mentionner pour que les conclusions soient lues à leur juste valeur :

- **L'historique ne remonte qu'au 29/10/2025** (réinstallation de Windows la veille). Les 9 années d'usage antérieures sont invisibles. On ne sait pas si le problème est ancien ou récent.
- **Le vidage mémoire du 03/08 n'a pas été analysé** : WinDbg n'est pas installé sur la machine. `VBoxNetLwf` reste donc un suspect **corrélé**, pas un coupable **prouvé**.
- **Le dossier `C:\Windows\Minidump` et les rapports WER sont inaccessibles** sans élévation de privilèges. Deux rapports `Kernel_50` du 31/07 n'ont pas pu être lus.
- **Aucune donnée SMART réelle** n'a pu être obtenue (voir §7).
- **Aucune donnée de température ni de tension** n'est disponible sans capteur logiciel dédié.
- La corrélation `VBoxNetLwf` ↔ `0x50` est temporellement très forte, mais l'erreur `VBoxNetLwf` se produit **à chaque transition** (20 fois) alors que seuls **3** crashes en ont résulté. Le pilote est donc **un facteur nécessaire mais pas suffisant** : il faut probablement un déclencheur supplémentaire (charge, séquence, état) pour que l'erreur dégénère en écran bleu.

---

## 12. Journal des relevés

À compléter à chaque passage. Un relevé toutes les 1 à 2 semaines devrait suffire à mesurer l'effet des actions engagées.

| Date du relevé | Arrêts anormaux depuis le dernier relevé | dont BSOD | Codes rencontrés | Erreurs `VBoxNetLwf` | WHEA | Actions faites depuis | Observations |
|---|---|---|---|---|---|---|---|
| 2026-08-03 | 45 (cumul 9 mois) | 15 | 10×`9F`, 3×`50`, 1×`3B`, 1×`A0` | 20 | 0 | — (état initial) | Analyse initiale. Deux populations distinctes identifiées. |
| 2026-08-03 | 1 | 1 | 1x`0x50` | 1 | 0 | (a completer) | demarrage rapide TOUJOURS actif ; filtre VBoxNetLwf TOUJOURS actif |

---

## 13. Indicateur de succès

Le suivi doit permettre de trancher entre les deux problèmes :

- **Si les BSOD cessent** après les actions de priorité 1 mais que **les coupures sèches continuent** → le problème logiciel est réglé, le problème matériel est confirmé et isolé. On passe à la priorité 3.
- **Si tout cesse** → la cause était entièrement logicielle. L'hypothèse du composant défectueux tombe.
- **Si les BSOD persistent** → il faut le dump analysé sous WinDbg (action 6) pour nommer le module fautif.

---

*Page tenue à jour par Claude Code. Analyse initiale du 2026-08-03.*