Configuration — inventaire complet
Tous les points de configuration d'ElectriCore, en un seul endroit. Quand tu cherches
« où se règle X », c'est ici. Trois registres de savoir (ADR-0024) :
le runtime (cette section 1, module runtime.py), le structurel (code/modèles) et
le réglementaire (taux régulés, section 2).
1. Variables d'environnement — registre runtime (.env à la racine, gitignoré)
Lues par un seul module canonique, electricore/config/runtime.py (pydantic-settings,
141, ADR-0025). Un domaine indépendant
par groupe (sftp, aes, duckdb, api, bot, odoo), accédé par accessor mis en
cache (runtime.sftp(), …). Précédence env-système > .env (native pydantic-settings) :
en Docker, le bloc environment: du compose prime sur env_file: .env. Validation
fail-fast par point d'entrée via runtime.valider(*domaines) (l'API ne valide jamais le
bot ; le runner valide sftp+aes+duckdb).
Ingestion (mouvement des flux)
| variable | rôle | défaut |
|---|---|---|
SFTP__URL |
URL SFTP Enedis (sftp://user:pass@host/chemin ou file:///... pour des zips locaux) |
— (requis) |
AES__TROUSSEAU__<label>__KEY (+ __IV optionnel) |
une clé AES (hex) du trousseau ; 16 octets (AES-128) ou 32 (AES-256) ; <label> parlant choisi par l'opérateur (aes256_2026, aes128_2024…). __IV optionnel (ADR-0040) : présent ⇒ schéma IV-fixe ; absent ⇒ schéma IV-préfixé (AES-256) |
— (≥ 1 __KEY requis) |
Le délimiteur __ est l'env_nested_delimiter natif de pydantic-settings : AES__TROUSSEAU__aes256_2026__KEY
→ entrée trousseau["aes256_2026"].key. Le trousseau accepte un nombre arbitraire de clés ; la bonne
est sélectionnée par essai au déchiffrement (oracle PKCS7 + magic bytes ZIP), sans date ni protocole
(ADR-0037). Garder les anciennes clés préserve l'accès aux archives passées. Le support .dlt/secrets.toml
a été retiré (#141) — les clés vivent en variables d'environnement uniquement.
Bases de données
| variable | rôle | défaut |
|---|---|---|
DUCKDB__PATH |
la base DuckDB de production — résolue par le domaine duckdb du registre (runtime.duckdb().chemin, issue #146), consommé par les loaders core, l'API, le runner d'ingestion et les tools (reset_incremental_state). En Docker : /data/flux_enedis_pipeline.duckdb (volume) |
electricore/ingestion/flux_enedis_pipeline.duckdb (absolu, ancré sur le dépôt — indépendant du CWD) |
DBT_DUCKDB_PATH |
chemin vu par dbt (ingestion/dbt/profiles.yml) — seul pont os.environ (ADR-0025), positionné par le runner autour de l'invocation dbt (scopé try/finally) ; ne se règle pas à la main |
suit runtime.duckdb().chemin via le runner |
Schémas dans la base : flux_raw (brut JSON), flux_enedis (tables typées, lues par
les loaders — figé dans ingestion/dbt/profiles.yml).
API
Domaine api du registre (runtime.api()) ; electricore/api/config.py n'est plus
qu'une façade de compatibilité (settings) déléguant au registre.
| variable | rôle | défaut |
|---|---|---|
API__TROUSSEAU__<consommateur>__KEY |
trousseau de clés d'authentification (X-API-Key), une par consommateur — révocation ciblée + attribution (ADR-0046 §4) |
— |
API__TITLE / API__DESCRIPTION / API__VERSION |
métadonnées OpenAPI | version du paquet |
INSTANCE_SLUG |
identifiant d'instance (multi-déploiements) | "" |
Bot Telegram
| variable | rôle |
|---|---|
BOT__TOKEN |
token du bot |
BOT__ALLOWED_USERS |
allowlist d'IDs utilisateurs |
BOT__NOTIFY_CHAT_ID |
chat des alertes proactives (échec d'un job d'ingestion, scheduler compris) ; vide = désactivé |
API_BASE_URL a été supprimée (#141/ADR-0025) : le bot tourne dans le processus de
l'API et la joint en interne (localhost:8001) — aucune variable requise.
Odoo (intégration)
Domaine odoo du registre (runtime.odoo()) — bloc unique read-only
ODOO__{URL,DB,USERNAME,PASSWORD} (#439, ADR-0046 §5) ; charger_config_odoo() reste une
façade déléguant au registre. Plus de sélecteur test/prod (#190 clos) : une variable absente
lève ConfigurationManquante au boot (no-ERP servi tant que le bloc est entièrement absent).
Kiosque (packages/electricore-kiosque)
| variable | rôle |
|---|---|
KIOSQUE__APPS |
sélection d'apps à monter (noms du catalogue, séparés par virgules ; vide = accueil seul) |
KIOSQUE__TITRE |
nom de l'entité, affiché par l'accueil |
KIOSQUE__API_URL |
URL de l'API electricore interrogée par les notebooks (ex. exports) ; requise, aucun défaut codé en dur — fournie par le config.env du provider (electricore-secrets, ADR-0044), fail-fast sinon |
Déploiement provider (deploy/docker, #707) — service compose à part, désactivé par défaut :
| variable | rôle |
|---|---|
COMPOSE_PROFILES |
kiosque active le conteneur (profil Compose, config.env) ; absent/vide = pas de service kiosque |
KIOSQUE_VERSION |
tag GHCR à épingler (ghcr.io/energie-de-nantes/electricore-kiosque), même logique qu'ELECTRICORE_VERSION |
Voir docs/deploiement.md « Kiosque (optionnel) » pour l'activation/désactivation côté provider.
Exception assumée au registre runtime (ADR-0025/0049) : le Kiosque ne peut pas dépendre
du moteur (ADR-0057), donc pas de pydantic-settings — lecture directe de l'env dans
electricore_kiosque/config.py. Le nommage DOMAINE__CHAMP (ADR-0046) reste respecté.
Aucun secret : la clé API est saisie par l'utilisateur·ice dans l'app, jamais côté serveur.
Depuis l'amendement du 2026-08-24 à l'ADR-0057 (#720), le Kiosque dépend d'
electricore-client[arrow] : polars entre dans le package via cet extra public du client
(onglets Relevés/Flux bruts du notebook exports) — l'invariant qui reste : jamais le
moteur electricore ni DuckDB.
2. Fichiers de configuration versionnés
| fichier | rôle | quand y toucher |
|---|---|---|
electricore/ingestion/config/flux.yaml |
mouvement des flux : file_pattern (glob SFTP), format (xml/json), file_regex (fichiers extraits des zips) |
nouveau flux Enedis, changement de nommage des zips |
electricore/ingestion/dbt/profiles.yml |
connexion dbt→DuckDB (path via env), schéma cible flux_enedis |
jamais ou presque |
electricore/ingestion/dbt/dbt_project.yml |
matérialisations (staging=view, flux=table) | jamais ou presque |
electricore/ingestion/dbt/models/sources.yml |
déclaration des tables brutes raw_* |
nouveau flux |
electricore/ingestion/dbt/models/flux/schema.yml |
data tests not_null (joués à chaque build) |
durcir le filet, nouveau flux |
electricore/config/turpe_rules.csv |
règles tarifaires TURPE (fixe + variable) | publication CRE |
electricore/config/accise_rules.csv |
barème accise (TICFE) | loi de finances |
electricore/config/cta_rules.csv |
taux CTA | évolution réglementaire |
La sélection/typage des flux (ex-DSL de flux.yaml) n'est plus de la configuration :
ce sont les modèles SQL ingestion/dbt/models/ — voir ingestion.md.
3. Déploiement (deploy/docker/)
Depuis le cutover secrets-as-code (ADR-0044), il n'y a
plus de .env monolithique édité sur la box : la config d'instance est scindée en
config.env (clair, versionné) et secrets.env (chiffré SOPS + age, versionné) dans un
dépôt de déploiement privé, pullés dans providers/<slug>/. Détail complet des variables et de la
procédure : docs/deploiement.md.
| fichier | rôle |
|---|---|
docker-compose.yml |
services api/ingestion-scheduler/caddy ; env_file: ../../config.env (clair) + environment: (DUCKDB__PATH=/data/..., SOPS_AGE_KEY_FILE, SECRETS_ENV_FILE — TZ=Europe/Paris posé uniquement sur ingestion-scheduler) ; volumes secrets age.key (RO) et providers/<slug>/secrets.env (RO, chiffré) ; volume duckdb_data |
entrypoint.sh |
electricore-entrypoint : déchiffre secrets.env dans l'environnement du process (sops exec-env, jamais de clair sur disque) puis exec la commande — échec dur si secrets/clé absents (ELECTRICORE_DECRYPT=off en échappatoire dev/test) |
smoke.sh |
fumée d'une image déjà buildée : importabilité (entrypoint contourné) + déchiffrement réel via fixtures SOPS de test |
crontab (copié de crontab.example) |
planning : /ingestion/run all à 02:00 via l'API, backup à 03:30 |
Caddyfile (copié de .example) |
reverse proxy TLS |
backup_duckdb.sh |
sauvegarde quotidienne de la base |
Dockerfile |
image unique, uv sync --extra ingestion --extra dbt |
4. Outillage développeur (config de dev, pas de runtime)
| fichier | rôle |
|---|---|
pyproject.toml |
dépendances + extras (ingestion, dbt, viz), ruff, mypy (périmètre strict), pytest (markers), coverage |
.pre-commit-config.yaml |
ruff check/format + détection de secrets (et pytest en pre-push) |
.github/workflows/ci.yml |
lint, typecheck, tests py3.12/3.13 avec extras ingestion+dbt |
Régénérables (pas de la config, mais souvent cherchés ici)
- Fixtures XSD et golden :
tests/fixtures/flux/generer_fixtures_xsd.py(exige les XSD Enedis en local) etgenerer_golden.py(oracle = chemin dbt). - État incrémental dlt :
~/.dlt/+ tables_dlt_*— purge viaingestion.py resync.