claude BotandClaude Opus 5.5 d04350df7a Explorateur : vignettes, sélection et déplacement multiples
- vue vignettes/liste, miniatures générées à la sauvegarde et à la demande
- multi-sélection (cases, Ctrl/Maj+clic, Ctrl+A, Échap, Suppr)
- glisser-déposer de la sélection, dialogue « Déplacer vers… » tactile

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CZ78TqR7fgtRx3rvpNUbAL
2026-10-07 12:46:37 +02:00

excalidraw-go

Excalidraw auto-hébergé avec un gestionnaire de fichiers intégré : arborescence de dossiers, création, renommage, déplacement (glisser-déposer ou menu), duplication, suppression (corbeille), recherche, import/export de fichiers .excalidraw, sauvegarde automatique côté serveur. Interface web unique, responsive (l'explorateur devient un tiroir sur mobile).

  • Backend : Go 1.24, bibliothèque standard uniquement (aucune dépendance externe), API REST/JSON, stockage en fichiers .excalidraw sur un volume.
  • Frontend : React 19 + composant officiel @excalidraw/excalidraw 0.18.1 (licence MIT), build Vite embarqué dans le binaire Go (embed).
  • Image : multi-stage, finale en distroless/static:nonroot (~53 Mo), un seul conteneur, aucun accès Internet requis à l'exécution (polices Excalidraw servies localement).

Architecture

Navigateur ──HTTP──▶ conteneur excalidraw-go (:8080, uid 65532, rootfs read-only)
                       ├─ /            SPA React + Excalidraw (embarquée dans le binaire)
                       ├─ /api/...     API fichiers (Go net/http)
                       └─ /healthz     sonde
                              │
                              ▼
                       volume /data
                         ├─ projets/réseau/sdn.excalidraw   ← fichiers JSON Excalidraw standards
                         ├─ .library.excalidrawlib          ← bibliothèque partagée
                         └─ .trash/<horodatage>/...         ← éléments supprimés

Les schémas restent des fichiers .excalidraw standards : ils s'ouvrent tels quels dans excalidraw.com, VS Code (extension Excalidraw) ou Obsidian, et se sauvegardent/versionnent comme n'importe quel répertoire (rsync, restic, git...).

Démarrage

cp .env.example .env        # optionnel : port, authentification Basic
docker compose up -d --build
# http://localhost:8080
Variable Défaut Rôle
LISTEN_ADDR :8080 Adresse d'écoute
DATA_DIR /data Racine des schémas
MAX_BODY_MB 50 Taille max d'un schéma (images embarquées en base64 comprises)
AUTH_USER / AUTH_PASSWORD vide Active une authentification HTTP Basic si les deux sont définis

Bind mount au lieu du volume nommé : - ./data:/data puis chown -R 65532:65532 ./data.

Utilisation

  • + Schéma / + Dossier : création dans le dossier courant.
  • ⋯ sur une ligne : renommer, déplacer, dupliquer, télécharger, supprimer.
  • Glisser-déposer (souris) d'un élément sur un dossier, sur .. ou sur le fil d'Ariane pour le déplacer. Sur écran tactile : menu ⋯ → Déplacer…
  • Importer : envoie un ou plusieurs .excalidraw locaux dans le dossier courant.
  • Sauvegarde : automatique 1,5 s après la dernière modification, immédiate avec Ctrl/Cmd+S. Le statut (Modifié / Enregistrement… / Enregistré) est affiché dans la barre du haut.
  • Lien direct : l'URL http://hôte:8080/#/dossier/schema.excalidraw ouvre le schéma.
  • Bibliothèque Excalidraw : persistée côté serveur, partagée entre tous les schémas.

Concurrence

Chaque lecture renvoie un ETag (SHA-256 tronqué du contenu) ; chaque sauvegarde l'envoie en If-Match. Si le fichier a été modifié ailleurs (autre onglet, autre poste), le serveur répond 412 et l'interface propose d'écraser ou de recharger. Il n'y a pas d'édition collaborative temps réel (voir Évolutions).

API

Tous les chemins sont relatifs à DATA_DIR, en notation /. Les composants commençant par . sont refusés, et les liens symboliques sortant de la racine sont bloqués.

Méthode Route Corps / paramètres Réponse
GET /api/list?path=dir [Entry] (dossiers puis schémas)
GET /api/search?q=texte [Entry] (200 max)
GET /api/file?path=x.excalidraw JSON du schéma + ETag
PUT /api/file?path=x.excalidraw JSON ; If-Match: <etag> ou If-None-Match: * (création) Entry + ETag ; 409 existe, 412 conflit
POST /api/folder {"path":"a/b"} Entry
POST /api/move {"from":"a.excalidraw","to":"d/b.excalidraw"} Entry (renommage / déplacement, fichier ou dossier)
POST /api/copy {"from":"…","to":"…"} Entry
DELETE /api/entry?path=x[&recursive=true] 204 (déplacé dans .trash/)
GET/PUT /api/library bibliothèque excalidrawlib
GET /healthz ok (hors authentification)

Entry = {"name","path","isDir","size","modTime"}.

Exemple d'automatisation (génération de schémas par script) :

curl -X PUT 'http://localhost:8080/api/file?path=auto/inventaire.excalidraw' \
     -H 'If-None-Match: *' --data-binary @inventaire.excalidraw

Développement

# Terminal 1 : API
go run ./cmd/server                 # DATA_DIR=./data par défaut
# Terminal 2 : frontend avec rechargement à chaud (proxy /api -> :8080)
cd frontend && npm install && npm run dev

# Tests et build complet hors Docker
go test ./...
cd frontend && npm run build && cd .. && go build -o server ./cmd/server

Arborescence :

cmd/server/main.go          serveur HTTP, SPA embarquée, auth Basic, healthcheck
internal/storage/           accès disque : sécurité des chemins, écriture atomique, ETag, corbeille
internal/api/               routes REST
web/embed.go                embarque web/dist (produit par le build Vite)
frontend/src/App.tsx        éditeur Excalidraw, sauvegarde auto, conflits, bibliothèque
frontend/src/Explorer.tsx   gestionnaire de fichiers

Sécurité

  • Conteneur non-root, rootfs en lecture seule, cap_drop: ALL, no-new-privileges.
  • L'authentification Basic intégrée suffit pour un usage local ; en exposition réseau, placer le service derrière un reverse proxy TLS (Traefik, Caddy, nginx) avec SSO (Authelia, oauth2-proxy, Authentik) et laisser AUTH_* vides.
  • Écritures atomiques (fichier temporaire + fsync + rename) : pas de schéma tronqué en cas d'arrêt brutal.
  • Aucune suppression physique : la purge de .trash/ est à la charge de l'exploitant (ex. find /data/.trash -mindepth 1 -maxdepth 1 -mtime +30 -exec rm -rf {} +).

Limites et évolutions possibles

  • Collaboration temps réel : nécessiterait le serveur excalidraw-room (WebSocket) et la logique de réconciliation (reconcileElements) côté client.
  • Miniatures dans l'explorateur : générables côté client via exportToSvg et stockées à côté du fichier.
  • Historique de versions : commit git automatique dans DATA_DIR à chaque sauvegarde, ou snapshots du volume (ZFS/Btrfs).
  • Multi-utilisateurs avec espaces privés : identité transmise par le reverse proxy (X-Forwarded-User) et racine par utilisateur.
  • Les schémas avec beaucoup d'images embarquées sont volumineux (base64 dans le JSON) ; ajuster MAX_BODY_MB.
S
Description
No description provided
Readme MIT
1.5 MiB
0 Stars 0 Watchers 0 Forks
Languages
Go 59.1%
TypeScript 33.4%
CSS 7%
Dockerfile 0.3%
HTML 0.1%