---
issueRef: "#138"
version: 4
updatedBy: {"kind":"agent","agent_id":"b4730d7f-c54d-4736-8a04-c6203aa2fd49"}
updatedAt: 1785703680849
---
## Décision d'architecture (2026-08-02)

Documentée dans `ARCHITECTURE.md` §22.2 (même nouvelle section que #133).

**Constat vérifié dans le code :** `sdk/IdeaSDK/src/runtime.ts` déclare déjà `ActivateContext.storage?: PluginStorage` (`get/set/delete`, clé-valeur JSON-serializable), et l'exemple `hello-plugin` s'en sert (`ctx.storage?.get<string>("helloPlugin.ownerAgentId")`). Mais ce champ n'est **jamais peuplé** : `frontend/src/plugins/runtime/loader.ts` (~lignes 249-256) ne câble que `logger`, `subscriptions`, `services` — `ctx.storage` vaut toujours `undefined` en exécution. Côté Rust : zéro port, zéro commande, zéro répertoire pour cette primitive (recherché, rien trouvé). Faute d'API réelle, l'exemple détourne `ctx.services.workspace`/`ctx.services.config` pour écrire son état interne sous `.ideai/hello-plugin.txt` et `.ideai/hello-plugin.json`.

**Décision — séparation noir sur blanc :**
- **Project-owned** : fichiers du workspace que le plugin modifie *volontairement* pour l'utilisateur/le projet → reste `ctx.services.workspace.*`/`ctx.services.config.*`, sandbox projet existant inchangé.
- **Plugin-owned** : préférences/cache/sélection/index/config interne → ne vit **jamais** dans le project root ni sous `.ideai/`. Nouveau répertoire **frère** de `plugins/installed/<id>/` : `app_data/plugins/data/<pluginId>/`. Séparé de `installed/` pour que les mises à jour de package ne touchent jamais aux données utilisateur, et pour donner à la désinstallation une deuxième racine univoque à purger.

**API canonique tranchée : `ctx.storage` seul, pas de second API document.** `ctx.storage.set(key, value)` avec des valeurs JSON couvre déjà le besoin de document structuré — une deuxième API "document plugin-scopé" ferait doublon. `ctx.services.config` reste réservé au project-owned.

**Cycle de vie figé :**
- `ctx.storage.get/set/delete` → commandes Tauri (ex. `plugin_storage_get/set/delete`) → store scopé par `pluginId` sous `plugins/data/<pluginId>/` (format interne — JSON unique ou par clé — laissé à #139, seule la frontière de répertoire est un contrat figé).
- `plugin_uninstall` (`crates/app-tauri/src/plugins.rs:142`) doit purger `plugins/data/<id>/` en plus de `plugins/installed/<id>` + registre (déjà couvert par #135). Les fichiers project-owned écrits par le plugin dans le workspace ne sont **jamais** touchés par l'uninstall.

## Débloque #139

1. Implémenter `ctx.storage` de bout en bout : port domaine + adapter infra scopés à `plugins/data/<pluginId>/`, commandes Tauri, câblage réel dans `loader.ts` (absent aujourd'hui), confinement en esprit identique à #133/#135.
2. Réaligner `hello-plugin` : migrer les compteurs internes (`launches`, `enabled`, `ownerAgentId`) vers `ctx.storage`. Garder au plus un exemple clairement étiqueté "fichier projet réel" via `workspace`/`config`, pas comme pattern par défaut.
3. `sdk/IdeaSDK/README.md` section "Structured Config Documents" à corriger : ne plus donner `.ideai/hello-plugin.json` comme exemple d'état interne, remplacer par un exemple `ctx.storage`, documenter la séparation project-owned/plugin-owned.
4. Preuve requise : test de purge (installer → écrire via `ctx.storage` → désinstaller → `plugins/data/<id>/` disparu) + absence de tout chemin `.ideai/...` dans les exemples SDK par défaut.

Aucun changement de code applicatif dans ce ticket (portée strictement architecture/API, conforme à l'objectif du ticket). Fichier touché : `ARCHITECTURE.md` (§22.2 ajouté).