0057 — Kiosque : accès néophytes en apps marimo hébergées, package séparé
- Status: accepted (amendé le 2026-08-24 — voir « Amendements »)
- Date: 2026-08-11
Contexte
Les deux accès existants à ElectriCore supposent tous deux un humain technique : le
module Odoo (l'ERP tire les données, ADR-0027) suppose un déploiement Odoo, et les
Notebooks (electricore-notebooks, marimo edit/run local, ADR-0009) supposent un
poste de travail, une installation uv, un .env. Un troisième public existe — des
néophytes qui veulent consulter leurs propres données (exports, relevés, facturation) sans
rien installer, juste un navigateur. Ni Odoo ni les notebooks locaux ne répondent à ce
besoin.
Contraintes du public visé :
- Navigateur seul — pas de checkout, pas de .env, pas de ligne de commande.
- Pas de comptes — un service self-hosted par petite structure (« entité »), pas
d'inscription/mot de passe à gérer côté ElectriCore.
- Lecture seule — le Kiosque ne doit jamais écrire (dans Enedis, dans un ERP, nulle
part) ; c'est un tableau de bord, pas un outil d'exploitation.
- Zéro secret côté service — le service qui sert les pages web ne doit détenir aucune
clé applicative pour le compte de l'utilisateur·ice.
Décision
1. Un paquet workspace de plus, même patron qu'electricore-client
packages/electricore-kiosque/ (src-layout), membre du workspace uv racine
([tool.uv.workspace] members = ["packages/*"], glob déjà en place — ADR-0043), pyproject
et version propres. Dépendances : marimo, fastapi, uvicorn, electricore-client
(workspace) — jamais le moteur electricore (pas de polars/duckdb, cf. ADR-0043).
Le Kiosque est un consommateur de l'API au même titre qu'un intégrateur externe, pas un
sous-module du moteur.
2. Apps marimo run hébergées, une image / N configs
Chaque app métier (exports, facturation lisible…) est un notebook marimo servi en mode
run (lecture seule, pas d'édition possible depuis le navigateur — même garde que les
notebooks opérateur). Une seule image Docker sert toutes les entités clientes ; ce
qui varie par déploiement est la configuration (catalogue actif, titre), jamais le code.
Assemblage ASGI par chaînage marimo.create_asgi_app().with_app(path=..., root=...) :
l'accueil est lui-même un notebook monté à la racine (path=""), chaque app active du
catalogue est montée sous /{nom}.
3. La clé API est la seule identité — zéro secret côté serveur
Pas de comptes, pas de base utilisateurs. L'utilisateur·ice colle sa clé API dans le
notebook (saisie navigateur, tranche #705) ; le service Kiosque ne la stocke jamais côté
serveur, ne la voit qu'en transit vers l'API electricore via electricore-client. La clé
est l'identité et le périmètre de données — même modèle que le bot Telegram et les
notebooks opérateur, poussé jusqu'au bout : aucun état d'authentification propre au Kiosque.
4. Config par entité, sous-domaine dédié
Deux variables d'environnement pilotent une instance : KIOSQUE__APPS (liste de noms
séparés par virgules, sélection dans le catalogue) et KIOSQUE__TITRE (nom affiché par
l'accueil). Fail-fast au démarrage si KIOSQUE__APPS contient un nom hors catalogue —
une faute de frappe se détecte au déploiement, pas en production face à l'utilisateur·ice.
Déploiement visé : sous-domaine kiosque.<slug>.electricore.fr par entité (même patron de
nommage que le reste de l'infra multi-provider, ADR-0044).
Alternatives écartées
- Export WASM/Pyodide (notebooks marimo exportés statiques) : marimo peut exporter en HTML/WASM exécuté côté navigateur. Écarté : empreinte mémoire ~2 Go par onglet (Pyodide + runtime Python complet chargé client-side) intenable sur le matériel modeste visé par des néophytes, et empaquetage des dépendances (polars/httpx) dans le bundle WASM non maîtrisé.
- Repo séparé : fragmenterait le code alors que l'infra workspace uv + release découplée
existe déjà pour exactement ce cas (
electricore-client, ADR-0043) — un repo de plus n'apporte rien qu'un membrepackages/*de plus n'apporte pas, avec la CI et le versioning à reconstruire à côté. - Clé API "baked" côté serveur (une image par config avec la clé en dur ou en secret d'infra) : réinvente des comptes par la bande — il faudrait alors gérer qui a accès à quelle image/config, exactement le problème que « la clé est l'identité » évite.
- Une image Docker par client : chaque nouvelle entité imposerait un build + une image à maintenir en plus de la config — enfer de maintenance à l'échelle de N entités, alors qu'une image partagée + config par variables d'environnement scale sans y toucher.
Conséquences
- Troisième accès externe acté dans CONTEXT-MAP.md aux côtés du
module Odoo et des Notebooks, tous via
api+electricore-client. - Le catalogue d'apps réelles (exports…) et la saisie de clé côté navigateur arrivent en tranche suivante (#705) ; ce document couvre le squelette d'assemblage (#704).
electricore-notebookscesse d'être qualifié de « pont transitoire » : son cycle de vie devient explicite — notebook exploratoire (dev, marimoedit) → app opérateur locale (electricore-notebooks, marimorunsur poste) → app Kiosque hébergée (marimorunmulti-tenant) — trois étapes assumées du même objet, pas un pont à démolir.- Un intégrateur Kiosque n'installe jamais
polars/duckdb/fastapidu moteur — mêmes garanties de légèreté qu'electricore-client(dont il dépend).
Statut
Implémenté par #703 (cet ADR + carte des trois accès) et #704 (squelette
packages/electricore-kiosque : assemblage ASGI, accueil, config par entité, fail-fast).
Tranches suivantes : #705 (catalogue d'apps réelles + saisie de clé API navigateur),
706-#708 (PRD #702).
S'appuie sur ADR-0043 (electricore-client, paquet workspace séparé), ADR-0009
(architecture API-centrique, notebooks comme état transitoire du dev local), ADR-0027
(« Odoo tire »), ADR-0044 (secrets-as-code, nommage par slug d'entité).
Amendements
2026-08-24 — polars admis via electricore-client[arrow], le moteur reste interdit
L'extension du notebook exports aux relevés (mart canonique, ADR-0029) et aux
flux bruts exige des tableaux volumineux dans le process kiosque. Le seul chemin
client existant est ElectricoreArrowClient (extra [arrow]), qui tire polars —
en contradiction avec la lettre de la décision 1 (« pas de polars/duckdb »).
Amendement : le Kiosque peut dépendre de electricore-client[arrow] (donc de
polars) ; c'est l'extra public du client, consommé comme le ferait tout intégrateur.
L'invariant qui portait la décision est réaffirmé et inchangé : jamais le moteur
electricore (ni DuckDB, ni accès direct aux données — tout passe par l'API). La
« légèreté » cède d'un cran (image plus lourde) ; la frontière d'architecture, elle,
ne bouge pas.