# Publier une app sur monappamoi.fr

Une app est un **unique fichier HTML** (CSS et JS inclus dedans). Elle est servie sur
son propre sous-domaine : `https://<slug>.monappamoi.fr`.

## ⚠ À vérifier AVANT de publier

**L'app conserve-t-elle quelque chose que l'utilisateur s'attend à retrouver plus tard ?**

Si oui, elle doit appeler `/api/data` — sinon ses données restent dans le navigateur
où elles ont été saisies et disparaissent au changement d'appareil ou au vidage du cache.
`localStorage` **seul ne suffit pas** : c'est un cache local, pas une sauvegarde.

Ces apps ont presque toujours besoin de `/api/data` : todo, liste de courses, notes,
compteur, votes ou sondage, scores, favoris, réservations, budget, suivi d'habitudes,
inventaire, planning — tout ce qui accumule des saisies.

Ces apps n'en ont pas besoin : convertisseur, calculatrice, minuteur, générateur,
visualisation de données fixes, jeu sans score conservé, page de présentation.

Dans le doute, câblez `/api/data` : c'est une vingtaine de lignes (voir le pattern
ci-dessous), et l'utilisateur n'aura pas à vous le redemander après coup.

## Où mettre les données

| Type de donnée | Où la mettre |
|---|---|
| Fixe, jamais modifiée (questions d'un quiz, contenu d'une page) | **Directement dans le HTML** (constante JS ou `<script type="application/json">`) |
| Propre à chaque visiteur (préférences, brouillon local) | `localStorage` |
| Modifiable et **partagée entre tous les visiteurs** (todo, compteur, votes) | L'API `/api/data` (voir ci-dessous) |

## L'API de données `/api/data`

Servie sur le sous-domaine de l'app elle-même : depuis le HTML, un simple
`fetch('/api/data')` suffit — même origine, aucune configuration, aucune clé.

- `GET /api/data` → le document JSON (`{}` si rien n'a encore été écrit).
- `PUT /api/data` → remplace le document complet. Renvoie `{saved, version}`.
- `DELETE /api/data` → efface le document.

Le document est **public et modifiable par tout visiteur de l'app** : n'y mettez
jamais de secret, mot de passe ou donnée personnelle sensible.

### Pattern recommandé : hybride localStorage + /api/data

Affichage instantané, tolérance au hors-ligne, et état partagé :

```js
let etat = { todos: [] };

async function charger() {
  const local = localStorage.getItem("etat");        // 1. affichage immédiat
  if (local) { try { etat = JSON.parse(local); afficher(); } catch {} }
  try {                                              // 2. rafraîchissement partagé
    const distant = await (await fetch("/api/data")).json();
    if (distant && Array.isArray(distant.todos)) { etat = distant; afficher(); }
  } catch { /* hors ligne : on garde l'état local */ }
}

async function sauver() {
  localStorage.setItem("etat", JSON.stringify(etat)); // toujours en local d'abord
  afficher();
  try {
    await fetch("/api/data", {
      method: "PUT",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(etat),
    });
  } catch { /* hors ligne : resynchronisation au prochain enregistrement */ }
}
```

Prévoyez toujours des valeurs par défaut : `GET /api/data` renvoie `{}` tant que
rien n'a été écrit.

### Écritures concurrentes (optionnel)

`GET` renvoie un en-tête `ETag: "<version>"`. Renvoyez-le en `If-Match` sur le
`PUT` pour refuser d'écraser une modification concurrente : réponse `412` si la
version a changé entre-temps. Sans `If-Match`, la dernière écriture gagne.

## Mettre à jour une app existante — À LIRE AVANT UN update_app

Republier ne touche **jamais** aux données déjà enregistrées par les utilisateurs :
le paramètre `data` n'a d'effet que si aucun document n'existe encore.

Si votre nouvelle version **change la structure** du JSON (renommage de champs,
nouvelle organisation) :

1. Appelez `get_app_data` pour lire la donnée réellement en place.
2. Soit vous écrivez un code qui accepte aussi l'ancienne forme, soit vous migrez
   la donnée vous-même avec `set_app_data` (transformez l'ancien JSON en nouveau).

Sinon les utilisateurs verront une app v2 qui ne comprend pas ses propres données.
`set_app_data` est la seule façon d'écraser volontairement le document.

## Après la publication

`publish_app` renvoie trois choses à transmettre à l'utilisateur :

- **l'URL publique** de l'app,
- **le jeton secret** (`maam_app_…`), affiché une seule fois, nécessaire pour
  modifier ou supprimer l'app plus tard — dites-lui de le conserver,
- **le lien de rattachement** (`claim_url`) : un clic + son email et l'app est
  liée à son compte, retrouvable dans son tableau de bord (le jeton devient alors
  facultatif). Présentez-lui toujours ce lien.

Si une **clé API** est configurée dans ce serveur MCP, les apps publiées sont
directement rattachées au compte : ni lien de rattachement à transmettre, ni
jeton à conserver, et \`list_my_apps\` retrouve toutes les apps du compte.
