--- name: spaces-adalan description: "Publier sur Spaces, la plateforme d'adalan (spaces.adalan.ai), une présentation HTML, un site statique ou une application (POC Node, Python, agent IA, avec base PostgreSQL), puis gérer ses sites en ligne (lister, mettre à jour, protéger par mot de passe ou en accès interne, réafficher le mot de passe, prolonger ou rendre permanent, inviter par e-mail, variables, journal, supprimer), par le connecteur adalan ou, depuis Claude Code, par SSH. À utiliser dès qu'un(e) collaborateur(trice) adalan demande de mettre en ligne, publier, déployer ou partager par un lien un livrable web, ou parle de son Space ou de ses sites sur spaces.adalan.ai." compatibility: "Demande l'accès à spaces.adalan.ai : le connecteur adalan (MCP, https://spaces.adalan.ai/mcp) dans claude.ai, Claude Desktop et l'application mobile, ou, depuis Claude Code, SSH avec une clé enregistrée sur la plateforme, bash et tar. Réservé aux collaborateurs et freelances adalan qui ont un Space." metadata: author: adalan version: "1.0" --- # Spaces : publier sur spaces.adalan.ai Chaque collaborateur(trice) a un Space `https://spaces.adalan.ai//` : le slug est le segment de son adresse, par défaut son prénom et son nom (`jean-durand`) ; le nom du Space est celui de la personne (« Jean Durand »). Chaque site y reçoit sa propre adresse, `https://spaces.adalan.ai///`, en HTTPS, exclue des moteurs de recherche (`noindex`) et en ligne 90 jours, prolongeables. Tous les sites partagent l'adresse `spaces.adalan.ai` : chacun est servi sous son chemin `///`, pas à la racine. Ses liens doivent donc être relatifs (voir les vérifications ci-dessous). La documentation en ligne, à indiquer à la personne quand elle cherche à comprendre ou à s'installer : https://spaces.adalan.ai/docs/ (onboarding, connecteur claude.ai, Claude Code, publication, gestion des sites, dépannage). ## Par où passer - **claude.ai, Claude Desktop, application mobile : le connecteur adalan** (outils `deploy_site`, `list_sites`, `info`…, adresse `https://spaces.adalan.ai/mcp`). S'il manque, expliquer à la personne comment l'ajouter puis le relier à son Space : https://spaces.adalan.ai/docs/claude-ai. - **Claude Code : SSH**, avec la clé du poste et l'alias `adalan`. L'archive part du disque sans passer par la conversation : c'est le chemin des projets construits, des applications et des gros sites. Sans clé SSH, le connecteur, s'il est ajouté à Claude Code. Voir « Depuis Claude Code, par SSH », à la fin. Les deux mènent au même Space, avec les mêmes contrôles, le même quota et le même journal : un site publié par l'un se met à jour par l'autre. La suite nomme les outils du connecteur, avec l'équivalent SSH quand il diffère. ## Publier ou mettre à jour un site 1. **Nom du site.** Le convenir avec la personne : 3 à 40 caractères, minuscules, chiffres et tirets. `www`, `admin`, `api`, `mail` et `portail` sont réservés. Le nom figure dans l'adresse transmise aux visiteurs : jamais de nom de client pour un contenu confidentiel. Publier sous un nom existant remplace le site. Pour une adresse introuvable sans son lien, ou si la personne demande un nom tiré au hasard : `random_name` (SSH : `--token` à la place du nom) ; le serveur tire un nom comme `k7mqd-2xpt9-wfb3h-nc8ra-4mxpq` et le renvoie dans `project`, à reprendre pour toute mise à jour. 2. **Fichiers à publier.** `index.html` à la racine : une adresse qui ne nomme pas de fichier ouvre l'`index.html` du dossier (`…//annexes/` ouvre `annexes/index.html`), et un dossier sans `index.html` répond 404. Un site statique n'exécute pas de PHP : un `index.php` n'y sert pas de page d'accueil et son code partirait en clair ; pour du PHP, publier une application. Pour un projet à construire, lancer la construction et prendre le dossier de sortie (`dist/`, `build/`, `out/`, `_site/`…). Pour une présentation en un seul fichier, la nommer `index.html` (par SSH, dans un dossier dédié). 3. **Vérifications avant envoi.** Elles sont obligatoires : - aucun secret : fichier `.env`, clé, jeton d'API écrit dans le JavaScript ; le serveur refuse les fichiers sensibles connus, mais pas un jeton caché dans le code ; - aucune donnée personnelle réelle ni donnée client confidentielle sans accord écrit (charte d'usage) ; en cas de doute, demander ; - liens et ressources relatifs, présents dans le site (pas de `file://`, pas de `C:\`) : `css/style.css`, `img/logo.png`, `page.html`, jamais `/css/style.css`, qui mènerait à la racine de `spaces.adalan.ai`, hors du site. Seules les ressources de la charte s'écrivent en absolu (`/_adalan/…`, ci-dessous). Pour un projet construit, régler le chemin de base de l'outil : `base: './'` (Vite), `basePath: '//'` (Next.js en export statique), `baseurl` (Jekyll, Hugo). Le serveur signale les liens absolus qu'il trouve dans les pages et les feuilles de style (`warning`) ; - habillage aux couleurs d'adalan si c'est demandé : skill `charte-graphique-adalan`, ou ce que sert la plateforme, à lier tel quel : la feuille de style `/_adalan/adalan.css` (couleurs encre et pêche, typographies, composants `.btn`, `.card`, `.kicker`…) et les logos `/_adalan/logos/logo.svg` et `/_adalan/logos/logo-label.svg`. 4. **Accès.** Public par défaut. Proposition commerciale, document client : proposer `access="password"` (SSH : `--protect`), qui met le site en ligne déjà protégé par mot de passe. Outil interne à adalan : proposer `access="interne"` (SSH : `--interne`), qui réserve le site aux collaborateurs (connexion avec leur compte Microsoft 365) et aux freelances inscrits dans Grace (code reçu par e-mail), sans mot de passe partagé. `sso` en est l'ancien nom, toujours accepté. 5. **Envoi.** `deploy_site` avec tous les fichiers (`files` : chemin relatif et contenu, `encoding: "base64"` pour les images, polices et PDF), `project` ou `random_name`, et `access`. 16 Mo et 1 000 fichiers au plus par appel : au-delà, publier en plusieurs fois (un premier envoi, puis des envois avec `merge=true`), ou passer par SSH. L'outil attend que le site réponde (quelques secondes), puis renvoie `project`, `url`, `access`, `expires_at`, `online`, `warning` s'il y a lieu et, si le site vient d'être protégé par mot de passe, `password`. 6. **Contrôle.** `online` doit valoir `true` ; sinon, réessayer une minute plus tard (`list_sites`, ou `curl -sI ` depuis un terminal : 200 attendu pour un site public, 302 vers la page de connexion pour un site protégé ou interne). Si `warning` signale des liens absolus, les corriger et republier ; des fichiers PHP, les retirer ou publier une application. 7. **Retouche d'un site en ligne.** Pour changer quelques fichiers sans renvoyer tout le site : `read_site_files` sans chemin liste les fichiers en ligne, avec des chemins il en renvoie le texte. Ensuite, `deploy_site` avec `merge=true` et les seuls fichiers modifiés ; `remove` retire des fichiers ou des dossiers. 8. **Compte rendu à la personne.** Donner l'adresse et la date d'expiration. Si le site est protégé, donner le mot de passe, que le visiteur saisit sur une page adalan : à transmettre au visiteur par un autre canal que l'adresse si possible ; `site_password` le réaffiche. Pour l'envoyer à des destinataires que la personne nomme : `invite_to_site` (voir « Gérer les sites »). Un site interne n'a rien à transmettre : les collaborateurs se connectent avec Microsoft, les freelances demandent un code par e-mail sur la page de connexion. ## Publier une application Pour un POC dynamique (Node, Python, PHP, agent IA avec clé d'API) : même envoi, avec `kind="docker"` (SSH : `--type docker`). 1. **Conditions.** Un `Dockerfile` à la racine. L'application écoute sur `0.0.0.0`, au port donné par la variable `PORT` (8080). Elle a droit à 512 Mo de mémoire et un demi-processeur. Chaque Space compte au plus 3 applications. 2. **Chemin.** L'application est servie sous `https://spaces.adalan.ai///`. Caddy retire ce préfixe : elle reçoit `/`, `/api/items`… comme si elle était à la racine. Le préfixe arrive dans la variable `BASE_PATH` (`//`) et l'en-tête `X-Forwarded-Prefix`. Dans ses pages et son JavaScript, les liens sont relatifs (`api/items`, `static/app.css`) ou préfixés par `BASE_PATH`, jamais `/api/items`. Les redirections vers `/…` et les cookies posés pour `/` sont ramenés sous son chemin par le serveur. Selon le cadriciel : FastAPI `FastAPI(root_path=os.environ.get("BASE_PATH", ""))`, Flask `ProxyFix(app.wsgi_app, x_prefix=1)` puis `url_for`, Express : liens relatifs dans les gabarits. 3. **Secrets.** Jamais de clé d'API dans le code ni dans l'image : le serveur refuse les fichiers `.env`. Les définir avec `set_app_env` (`values`, et `unset` pour en retirer), qui relance l'application ; sans l'un ni l'autre, il liste les variables, jamais leurs valeurs. Par SSH, toujours par l'entrée standard (voir la fin). 4. **Envoi.** La construction peut prendre quelques minutes au premier envoi. La plateforme construit l'image, lance le conteneur et vérifie qu'il répond. Si la nouvelle version échoue, la précédente est remise en service et le journal montre l'erreur. 5. **Base de données.** `create_database` (SSH : `db create `) crée une base PostgreSQL dédiée. Elle ajoute `DATABASE_URL` et les variables `PG*` à l'application, qui redémarre. L'application doit créer ses tables elle-même. 6. **Diagnostic.** `app_logs` (SSH : `logs --lines 100`). Une application en accès interne reçoit l'adresse du visiteur dans l'en-tête `X-Adalan-Email`, son nom dans `X-Adalan-Name` (encodé en URL) et sa connexion dans `X-Adalan-Auth` (`microsoft` pour un collaborateur, `email` pour un freelance) : elle peut s'en servir pour personnaliser l'accueil, tracer les actions ou réserver une page aux collaborateurs, sans gérer de mots de passe. Si l'application a besoin d'une clé pour démarrer, le premier envoi peut échouer faute de clé : définir alors la clé, ce qui relance l'application. ## Gérer les sites | Besoin | Connecteur | SSH : `ssh adalan adalan …` | | --- | --- | --- | | Le Space, ses adresses, le disque utilisé | `info` | `info` | | Voir ses sites | `list_sites` | `list` (ou `--json`) | | Protéger par mot de passe (nouveau mot de passe généré) | `protect_site` | `protect ` | | Protéger par un mot de passe choisi (8 à 128 caractères) | `protect_site` avec `password` | `protect --password-stdin` (voir la fin) | | Réafficher le mot de passe d'un site | `site_password` | `password ` | | Réserver à l'accès interne | `protect_site` avec `access="interne"` | `protect --interne` | | Retirer la protection | `protect_site` avec `access="public"` | `protect --off` | | Prolonger (durée comptée à partir d'aujourd'hui, 1 à 365 jours) | `extend_site` avec `days` | `extend --days 90` | | Fixer le dernier jour d'accès (un an au plus) | `extend_site` avec `until` | `extend --until 2026-12-31` | | Rendre permanent (plus de date de fin) | `extend_site` avec `permanent` | `extend --permanent` | | Envoyer le lien (et le mot de passe) par e-mail | `invite_to_site` ; `include_password=false` pour ne pas joindre le mot de passe | `invite --to client@exemple.fr` ; `--no-password`, message par `--message-stdin` | | Fichiers en ligne, ou contenu d'un fichier | `read_site_files` | `files [chemin…]` | | Supprimer (hors ligne tout de suite, fichiers, conteneur et base effacés) | `delete_site` | `delete ` | | Journal d'une application | `app_logs` | `logs ` | | Variables d'une application | `set_app_env` | `env ` (voir la fin pour les définir) | | Base PostgreSQL d'une application | `create_database` | `db create ` | Dans le navigateur, la page du Space, `https://spaces.adalan.ai//` (adresse donnée par `info`), liste ses sites. Celle d'un Space collaborateur s'ouvre avec le compte Microsoft, un code par e-mail ou le code d'accès du connecteur ; son bouton « Gérer le site » donne les informations, les fichiers, l'accès, le mot de passe, la durée, l'invitation et la suppression. Celle d'un Space éphémère ou public, géré par l'administrateur, est ouverte à qui a son lien. Demander confirmation avant de supprimer : la suppression est définitive. N'envoyer d'invitation qu'aux adresses que la personne a données pour ce site, après lui avoir dit ce qui partira (lien, date de fin, mot de passe) ; 10 destinataires par envoi, 50 par Space sur 24 heures. ## Erreurs fréquentes | Message | Que faire | | --- | --- | | `fichiers sensibles refusés : …` | Retirer ces fichiers et republier. Par SSH seulement, `--force` si la personne confirme que ce ne sont pas des secrets ; le connecteur ne force jamais. | | `pas d'index.html à la racine` | Le site répondra 404 : ajouter ou renommer la page d'accueil en `index.html`. | | `liens absolus vers la racine (/…)`, ou site en ligne sans styles ni images | Rendre relatifs les liens des fichiers cités (`css/style.css` au lieu de `/css/style.css`), ou régler le chemin de base de l'outil de construction, puis republier. | | `fichiers PHP dans …` | Le site statique sert ces fichiers en clair, code source compris : les retirer et republier, ou publier une application (Dockerfile qui exécute le PHP). | | `16 Mo au plus par envoi`, `1000 fichiers au plus par envoi` | Publier en plusieurs fois : un premier envoi, puis des envois avec `merge=true` ; ou passer par SSH. | | `limite de 20 sites atteinte` | Lister les sites et en supprimer un, avec l'accord de la personne. | | `quota du Space atteint` | 5 Go par Space : supprimer des sites, ou alléger (images, vidéos). | | `Dockerfile absent à la racine` | Ajouter un Dockerfile, ou publier en site statique. | | `construction de l'image en échec` | Lire les dernières lignes affichées (dépendance introuvable, commande en erreur), corriger, republier. | | `la nouvelle version ne répond pas` | L'application doit écouter sur `0.0.0.0` et le port `PORT` ; lire le journal affiché. La version précédente reste en ligne. | | Application en ligne, mais pages sans styles, appels d'API en 404 | Liens absolus dans ses pages ou son JavaScript : les rendre relatifs ou les préfixer par `BASE_PATH`. | | `limite de 3 applications atteinte` | Supprimer une application, avec l'accord de la personne. | | `le mot de passe … a été posé avant que la plateforme garde les mots de passe` | Il ne peut pas être réaffiché : en poser un nouveau (`protect_site`), avec l'accord de la personne, puis le lui donner. | | `les courriels ne sont pas encore configurés sur la plateforme` | Les invitations attendent l'administrateur : donner le lien et le mot de passe à la personne, qui les transmet elle-même. | | Connecteur refusé, ou SSH en `Permission denied (publickey)`, alors que l'accès fonctionnait | L'administrateur a peut-être désactivé le Space, ou coupé l'accès de Claude : la personne s'adresse à lui. | ## Durée de vie et limites - Un site ou une application vit 90 jours. La personne reçoit un rappel 7 jours avant l'échéance. À l'échéance, le site est mis hors ligne (page « contenu expiré »), puis supprimé 30 jours plus tard. Une prolongation le remet en ligne à tout moment avant la suppression. Un site rendu permanent n'expire pas : à réserver à ce qui doit durer, la charte d'usage demandant de ne pas laisser traîner les livrables. - Par envoi : 16 Mo et 1 000 fichiers par le connecteur, 2 Go et 20 000 fichiers par SSH. Par Space : 5 Go et 20 sites, dont 3 applications. - Pas de nom de domaine personnalisé. - Une adresse de projet mal tapée donne la page 404 adalan. - Tous les sites partagent l'adresse `spaces.adalan.ai` : le stockage du navigateur (`localStorage`) est commun à tous les sites de la plateforme. Un site ou une application n'y range rien de confidentiel. ## Depuis Claude Code, par SSH Claude Code passe par SSH, avec la clé du poste, vers `spaces.adalan.ai`. Le serveur n'accepte que les commandes `adalan` : pas de shell, pas de scp, pas de rsync. Les fichiers partent en archive tar dans le flux SSH, depuis bash, ou Git Bash sous Windows : PowerShell 5 corrompt les flux binaires. ### Accès (à vérifier une fois par poste) ```bash ssh adalan adalan info ``` - Réponse avec le Space et le quota : tout est prêt. - `Could not resolve hostname adalan` : l'alias manque. Demander le slug du Space de la personne, celui de son adresse (`jean-durand` pour `spaces.adalan.ai/jean-durand/`, en général son prénom et son nom), puis ajouter dans `~/.ssh/config` (avec son accord) : ```text Host adalan HostName spaces.adalan.ai User jean-durand ``` Ajouter `IdentityFile ~/.ssh/` si la clé enregistrée n'est pas la clé par défaut du poste. - `Permission denied (publickey)` : la clé du poste n'est pas enregistrée. La personne envoie sa clé publique (`cat ~/.ssh/id_ed25519.pub`, ou `ssh-keygen -t ed25519` pour en créer une) à l'administrateur de la plateforme. Ne jamais transmettre la clé privée. Si l'accès fonctionnait jusque-là, le Space a peut-être été désactivé par l'administrateur : le lui demander. ### Publier ```bash COPYFILE_DISABLE=1 tar -czf - -C . | ssh adalan adalan deploy --json ``` Ajouter `--protect` ou `--interne` pour l'accès, `--type docker` pour une application (construction : quelques minutes). `--token` à la place du nom tire un nom au hasard (pas avec `--merge`). La commande attend que le site réponde, puis renvoie les mêmes champs que `deploy_site`. Retouche : `ssh adalan adalan files ` liste les fichiers en ligne, `ssh adalan adalan files index.html` en affiche un. N'envoyer ensuite que les fichiers modifiés, avec `--merge` ; `--remove ` retire un fichier : ```bash COPYFILE_DISABLE=1 tar -czf - -C . | ssh adalan adalan deploy --merge --json ``` ### Secrets et mots de passe Toujours par l'entrée standard, pour qu'ils n'apparaissent dans aucune ligne de commande : ```bash printf 'OPENAI_API_KEY=%s\n' "$CLE" | ssh adalan adalan env --stdin printf '%s\n' '' | ssh adalan adalan protect --password-stdin ``` `ssh adalan adalan env ` liste les variables sans leurs valeurs ; `--unset NOM` en retire une. ### Erreurs propres à SSH | Message | Que faire | | --- | --- | | `l'archive contient seulement le dossier « dist »` | Refaire l'archive depuis l'intérieur du dossier : `tar -czf - -C dist .` | | `lien non pris en charge` | Remplacer les liens symboliques par de vrais fichiers. |