# Modules d'application et CetteApplication

Source : https://docs.berkios.online/studio/modules-application/ · Section : Studio · Documentation officielle BERKIOS (https://docs.berkios.online)


Pour construire des applications robustes (client seul, serveur seul ou client-serveur offline-first), un projet peut contenir des **modules de code** et, au plus, un fichier **CetteApplication**. Les deux sont **optionnels**.

> **Vocabulaire.** Une **interface** est un écran (avant v0.7.297 le dossier de projet l'appelait « module »). Un **module** est un fichier de code Core. Dans le compilateur, `modules[]` désignait déjà des fichiers Core : ils gagnent un cycle de vie, rien n'y est renommé.

## Dans le Studio

- Panneau **MODULES** de la barre latérale (replié par défaut) : `＋` crée un module (nom → identifiant `gestionnaire_chemins`, fichier `modules/<id>.bk`, modèle de code valide), clic = éditeur de code, ⚙ = réglages (cible, dépendances, événements, tâches), ✎ renomme (l'identifiant reste), ✕ supprime (et retire le module des dépendances des autres). « Créer CetteApplication » ajoute le fichier unique `CetteApplication.bk`.
- L'éditeur de code ouvre un module ou CetteApplication en mode Core ; **Vérifier** et la vérification en direct utilisent l'analyseur du compilateur (syntaxe, types, imports `importer "./autre.bk"`), sans Bridge. Une pastille ⚠ signale un fichier en erreur (code, dépendance inconnue, cycle, événement ou tâche sans fonction, cibles incompatibles).
- Les modules sont enregistrés dans le projet (`appModules`, `application`) et suivent annuler / rétablir.

### Dossier de projet (format 2.1)

```
manifest.json            { interfaces: [...], modules: [...], application: { entry } }
interfaces/<nom>.interface.json  + <nom>.bk   (code BERKIOS CODE de l'interface)
modules/<id>.bk          modules de code
CetteApplication.bk      code partagé (facultatif)
```

`manifest.modules` et `manifest.application` ont exactement la forme que lit `loadProjectModules` du compilateur. Le format 2.0 (`modules/*.module.json`) reste lisible. Anciens noms conservés comme alias dépréciés : `moduleGraph`, `ModuleContract`, `module-contracts.ts`.

## Module = un fichier de code (`.bk`)

Déclaré dans `berkios.project.json` :

```json
{
  "application": { "entry": "CetteApplication.bk" },
  "modules": [
    { "id": "connection_manager", "entry": "modules/connection_manager.bk",
      "dependencies": ["gestionnaire_chemins"],
      "target": "client",
      "events": { "reseau:change": "surChangementReseau" },
      "tasks": [{ "function": "verifierReseau", "everyMs": 5000 }] }
  ]
}
```

| Champ | Rôle |
|---|---|
| `id`, `entry` | identifiant et fichier Core (obligatoires) |
| `dependencies` | modules à démarrer avant ; inconnu ou cycle = erreur au chargement |
| `target` | `client`, `serveur` ou `les-deux` (défaut). L'hôte ignore les modules d'une autre cible |
| `events` | événement → fonction du module appelée avec la charge utile |
| `tasks` | fonctions rappelées périodiquement (≥ 100 ms), jamais en double, erreurs isolées |

### Cycle de vie (tout est facultatif)

`initialiser()` → (abonnement aux événements) → `demarrer()` ; à l'arrêt `arreter()` dans l'ordre inverse des dépendances. Noms anglais acceptés : `initialize`, `start`, `stop`. Ces fonctions sont réservées à l'hôte : jamais importées ni appelables de l'extérieur.

### API publique

Une fonction marquée `publique` est appelable par l'hôte (`host.call`) et par les imports. Si aucune n'est marquée, toutes le sont (compatibilité) ; `privée` exclut. L'hôte n'expose jamais les fonctions qu'un module a importées d'un autre.

```
publique fonction verifierReseau() -> Texte
privée fonction aide() -> Entier
```

### Parler aux autres : état partagé et événements

Le Core n'a pas de variables globales. Les modules partagent :

- `etat_notifier("cle", valeur)` / `etat_observer("cle")` → `{key, value, exists}` (pas de valeur nulle en Core : absent = `exists` faux, `value` = `""`) ;
- `evenement_emettre("nom", {...})`, reçu par les modules qui déclarent l'événement dans `events`.

Événements système : `reseau:change`, `session:connexion`, `app:erreur`, `app:demarree`.

## CetteApplication = code partagé par toutes les interfaces

Fichier Core unique, optionnel. L'hôte appelle les procédures qui existent :

| Procédure | Moment |
|---|---|
| `configurerTheme()` | tout début |
| `auDemarrage()` | avant les modules |
| `quandPret()` | après démarrage de tous les modules |
| `surChangementReseau(info)` | événement `reseau:change` |
| `apresConnexion(info)` | événement `session:connexion` |
| `surErreur(erreur)` | toute erreur d'un module, d'une tâche ou d'un écouteur (`module`, `fonction`, `message`) |
| `avantFermeture()` | début de l'arrêt |

Noms anglais acceptés : `configureTheme`, `onStart`, `onReady`, `onNetworkChange`, `onLogin`, `onError`, `onClose`.

## Utiliser l'hôte

```js
import { loadProjectModules, createApplicationHost } from './compiler/src/index.mjs';
const loaded = loadProjectModules(manifest, manifestFile, { interfaces: [] });
const host = createApplicationHost({ modules: loaded.coreModules, application: loaded.application, target: 'client', commands });
await host.start();
host.call('sync_manager', 'enregistrerEcriture', ['clients', 'upsert', { id: 1 }, 1]);
await host.stop();
```

`commands(commande, args, {moduleId})` fournit les commandes système (réseau, SQL, disque…) : le Bridge en production, une plateforme simulée dans l'exemple. L'hôte traite lui-même `evenement-emettre`, `etat-notifier` et `etat-observer`.

## Correctifs du langage Core livrés avec cette fonctionnalité

- Une affectation à une variable déjà déclarée, faite dans un bloc `si` / `pour` / `essayer`, était **perdue** à la sortie du bloc. Elle est désormais conservée (un `soit` dans le bloc reste local).
- `retourner` dans un `essayer` n'est plus pris pour une erreur.
- Le mot `o` est un mot-clé (« ou » espagnol) : ne pas l'utiliser comme nom de variable.

## Limites connues

- Le Core est synchrone. Les commandes du Bridge sont asynchrones (HTTP) : l'hôte actuel les consomme via un adaptateur **synchrone** (`commands`). Brancher le vrai Bridge demande un exécuteur Core asynchrone, qui n'existe pas encore.
- Pas de valeur nulle ni de variables globales en Core ; les helpers privés de deux modules importés ensemble partagent un espace de noms plat (préfixer les noms).
- Le Studio édite et vérifie les modules mais ne les **exécute pas** dans l'Aperçu, et les actions des interfaces ne les appellent pas encore : l'API est `host.call(...)`.
- Le dossier de projet (format 2.1) n'est pas encore branché sur « Enregistrer / Ouvrir » du Studio (fonctions `splitProject` / `assembleProject`).

## Exemple complet

`examples/application/offline-first` : client offline-first avec les modules `gestionnaire_chemins`, `connection_manager`, `abonnement_manager`, `sync_manager`, `rapports` et un `CetteApplication.bk`. `node examples/application/offline-first/demo.mjs` déroule un scénario hors ligne → en ligne.
