Commit b73cc10a authored by Kourser's avatar Kourser
Browse files

L'installateur parle deux langues, la configuration une seule

Kastell s'auto-héberge, et rien ne dit que celui qui l'installe lit le
français. L'installateur pose donc sa première question dans les deux langues
et poursuit dans celle qu'on choisit. Le .env qu'il écrit, lui, est en
anglais : un fichier de configuration se lit par-dessus l'épaule de
quelqu'un, se colle dans un ticket, se cherche dans un moteur — il n'a pas à
choisir un camp.

L'entretien
  La langue est devinée depuis LC_ALL, LC_MESSAGES ou LANG avant tout
  affichage, parce que les refus de prérequis tombent avant la première
  question et qu'un message qu'on ne lit pas n'aide personne. Ce n'est qu'un
  défaut : la première question le confirme, et rien n'est déduit en silence.

  Trois fonctions portent la bascule — dire, demander_b, oui_non_b — et
  chaque texte garde ses deux versions côte à côte, là où il sert. Un
  catalogue à clés aurait éloigné les phrases de leur contexte, et c'est le
  contexte qui les rend justes. 155 paragraphes, 27 invites.

  Les invites oui/non suivent : [O/n] en français, [Y/n] en anglais.

Ce que le .env dit désormais
  Les commentaires du fichier écrit sont en anglais, ceux de
  docker/livekit.local.yaml aussi, et l'en-tête que preparer-env.mjs ajoute
  également. .env.example reste la référence longue et devient bilingue :
  chaque bloc en français, puis le même en anglais préfixé « EN — ». Les 42
  clés et leurs valeurs par défaut sont inchangées, et le contrôle de dérive
  de l'installateur le vérifie.

Contrôlé
  Une passe complète en anglais et une en français, sur une copie isolée :
  la bascule de langue, les trois voies du serveur média, le conflit de ports
  et le repli, l'écriture du .env et du fichier LiveKit. Aucune dérive contre
  .env.example. « pnpm preparer-env » dit « à jour », tsc passe, la pile
  répond.

Deux défauts trouvés en route, dans mon propre outillage d'essai plutôt que
dans le script : le garde-fou qui empêchait mes essais de lever une
composition reconnaissait la question en français et cessait de protéger dès
que l'installateur a su parler anglais — il a réellement tenté un
démarrage, sans conséquence faute de Dockerfile dans la copie. Et le défaut
du menu média restait sur l'option qui venait d'échouer, si bien qu'une
entrée vide y bouclait : il bascule maintenant sur « autres ports ».

Co-Authored-By: default avatarClaude Opus 5 <noreply@anthropic.com>
parent 96d9521f
Loading
Loading
Loading
Loading
Loading
+102 −7
Changes for .env.example: 102 added lines, 7 removed lines.
Original line number Diff line number Diff line
# ── Kastell de crise — configuration ────────────────────────────────────────
# ── Kastell de crise — configuration / configuration ───────────────────────
#
# Copier en .env puis remplacer TOUTES les valeurs marquées CHANGEZ-MOI.
# Le serveur refuse de démarrer si une valeur par défaut subsiste (EX-26, EX-27).
#
# EN — Copy to .env, then replace EVERY value marked CHANGEZ-MOI. The server
# EN   refuses to start while a default value survives (EX-26, EX-27).
#
# Chaque bloc est en français puis en anglais. Les noms de variables, eux, sont
# en anglais : ils sont lus par des gens qui n'ont pas écrit ce logiciel.
#
# EN — Every block is French first, then English. The variable names themselves
# EN   are English: they are read by people who did not write this software.

# Identité de l'instance
# Identité de l'instance / Instance identity
KASTELL_PUBLIC_URL=http://localhost:8080

# Où trouver le code source de cette instance (AGPL-3.0, section 13). Si vous
# avez modifié Kastell, faites pointer cette adresse vers votre dépôt : elle
# s'affiche dans l'interface et la licence le demande.
#
# EN — Where to find this instance's source (AGPL-3.0, section 13). If you have
# EN   modified Kastell, point this at your own repository: it is shown in the
# EN   interface, and the licence requires it.
KASTELL_SOURCE_URL=https://git.cythin.eu/cythin/kastell

# Base utilisée par « pnpm verif », qui la réinitialise à chaque exécution.
# À défaut : le nom de la base courante suffixé de « _verif », créée au besoin.
#
# EN — Database used by "pnpm verif", which resets it on every run. Failing
# EN   that: the current database name suffixed with "_verif", created if need
# EN   be.
# KASTELL_DB_VERIF=kastell_verif
KASTELL_PORT=8080
KASTELL_ENV=developpement

# Base de données
# Base de données / Database
POSTGRES_USER=kastell
POSTGRES_PASSWORD=CHANGEZ-MOI-mot-de-passe-base
POSTGRES_DB=kastell
# URL vue depuis la machine hôte (outillage : pnpm migrate, pnpm verif).
# Dans la composition, l'application reconstruit la sienne avec l'hôte "postgres".
#
# EN — URL as seen from the host machine (tooling: pnpm migrate, pnpm verif).
# EN   Inside the composition, the application rebuilds its own with host
# EN   "postgres".
DATABASE_URL=postgres://kastell:CHANGEZ-MOI-mot-de-passe-base@localhost:5432/kastell

# Cache et files
# Cache et files / Cache and queues
REDIS_URL=redis://localhost:6379

# Stockage objet (S3)
# Stockage objet (S3) / Object storage (S3)
S3_ENDPOINT=http://localhost:9000
S3_REGION=eu-west-1
S3_BUCKET=kastell
@@ -38,24 +60,39 @@ S3_SECRET=CHANGEZ-MOI-secret-stockage
# L'adresse est celle que le NAVIGATEUR compose, pas le serveur : elle doit
# rester joignable depuis les postes de la cellule.
# Laisser LIVEKIT_URL vide désactive la visioconférence ; le produit l'annonce.
#
# EN — Video conferencing, started by default with the composition. The address
# EN   is the one the BROWSER dials, not the server: it must stay reachable
# EN   from the cell's workstations. An empty LIVEKIT_URL disables video
# EN   conferencing; the product says so.
LIVEKIT_URL=ws://localhost:7880
# Adresse de l'API média vue depuis le serveur. Dans la composition Docker,
# l'hôte est le nom du service : « localhost » y désigne le conteneur
# applicatif lui-même. Laissez vide hors conteneur.
#
# EN — Address of the media API as seen from the server. In the Docker
# EN   composition the host is the service name: "localhost" there means the
# EN   application container itself. Leave empty outside a container.
LIVEKIT_INTERNAL_URL=http://livekit:7880
LIVEKIT_KEY=kastell
LIVEKIT_SECRET=CHANGEZ-MOI-secret-media-au-moins-32-caracteres

# ── Où vit le serveur média ────────────────────────────────────────────────
# ── Où vit le serveur média / Where the media server lives ─────────────────
#
# « livre » : celui de la composition. « mutualise » : un LiveKit que vous
# exploitez déjà, auquel cas le service n'est pas levé et seules les adresses
# ci-dessus comptent. Vide désactive la visioconférence.
#
# EN — "livre": the composition's own. "mutualise": a LiveKit you already run,
# EN   in which case the service is not started and only the addresses above
# EN   matter. Empty disables video conferencing.
LIVEKIT_MODE=livre
# Lever l'enregistreur de réunions. Il ne sert à rien sans serveur média.
#
# EN — Start the meeting recorder. It is useless without a media server.
LIVEKIT_EGRESS=oui

# ── Ports du serveur média ─────────────────────────────────────────────────
# ── Ports du serveur média / Media server ports ────────────────────────────
#
# À ne déplacer que si la machine porte déjà un LiveKit. Hôte et conteneur
# gardent le MÊME numéro : le TURN et les candidats RTC annoncent aux
@@ -65,6 +102,15 @@ LIVEKIT_EGRESS=oui
# Ces numéros vivent aussi dans le fichier de configuration de LiveKit. Les
# changer ici seul ne suffit pas : LIVEKIT_CONFIG doit désigner un fichier qui
# porte les mêmes, ce que l'installateur écrit pour vous.
#
# EN — Move these only if the machine already carries a LiveKit. Host and
# EN   container keep the SAME number: TURN and the RTC candidates announce to
# EN   browsers the port LiveKit believes it occupies, and a translation would
# EN   make them wrong — the room would open and nobody would see anyone.
# EN
# EN   These numbers also live in LiveKit's own configuration file. Changing
# EN   them here alone is not enough: LIVEKIT_CONFIG must name a file carrying
# EN   the same ones, which the installer writes for you.
LIVEKIT_PORT=7880
LIVEKIT_PORT_RTC_TCP=7881
LIVEKIT_PORT_TURN=3478
@@ -73,6 +119,7 @@ LIVEKIT_PORTS_MEDIA=50000-50100
LIVEKIT_CONFIG=../docker/livekit.yaml

# ── Enregistreur : par où lui parvient le travail ──────────────────────────
# ── Recorder: where its work comes from ────────────────────────────────────
#
# L'enregistreur ne reçoit pas ses tâches par HTTP : il s'inscrit sur le Redis
# qu'utilise le serveur média, et c'est de là que le travail vient. Avec le
@@ -83,6 +130,17 @@ LIVEKIT_CONFIG=../docker/livekit.yaml
# au moment précis où l'on enregistre, c'est-à-dire en crise. Conséquence
# assumée : l'autre déploiement pourra confier ses propres enregistrements à
# cet enregistreur.
#
# EN — The recorder does not receive its jobs over HTTP: it registers on the
# EN   Redis the media server uses, and that is where the work comes from. With
# EN   the shipped server that is the composition's Redis, and there is nothing
# EN   to do.
# EN
# EN   With a shared server you must name ITS OWN — otherwise video will work
# EN   and recording will fail on "no egress workers available", at the precise
# EN   moment one records, that is, during a crisis. Accepted consequence: the
# EN   other deployment will be able to hand its own recordings to this
# EN   recorder.
LIVEKIT_REDIS=redis:6379
LIVEKIT_WS_INTERNAL=ws://livekit:7880

@@ -91,13 +149,21 @@ LIVEKIT_WS_INTERNAL=ws://livekit:7880
# marqués « non analysée », jamais « saine ».
# Au premier démarrage, ClamAV télécharge ses signatures — quelques minutes
# pendant lesquelles les dépôts restent possibles, mais non analysés.
#
# EN — Antivirus scanning of uploads, started by default with the composition.
# EN   An empty CLAMAV_HOST disables it: documents are then marked "not
# EN   scanned", never "clean". On first start ClamAV downloads its signatures
# EN   — a few minutes during which uploads remain possible, but unscanned.
CLAMAV_HOST=clamav
CLAMAV_PORT=3310

# Secrets applicatifs — générer avec: openssl rand -hex 32
#
# EN — Application secrets — generate with: openssl rand -hex 32
SESSION_SECRET=CHANGEZ-MOI-secret-session-64-caracteres-hexadecimaux

# ── Notification mobile : le relais de heurtoir (EM-82 à EM-84) ─────────────
# ── Mobile notification: the knocker relay (EM-82 to EM-84) ────────────────
#
# Sans lui, l'instance reste entière : lecture, consignation, appel. Elle ne
# réveille personne, et le dit — à sa sonde d'état, et donc à l'application au
@@ -105,12 +171,23 @@ SESSION_SECRET=CHANGEZ-MOI-secret-session-64-caracteres-hexadecimaux
# canaux de mobilisation de premier rang.
#
# Pour le lancer avec la composition : docker compose --profile mobile up -d
#
# EN — Without it the instance stays whole: reading, logging, calling. It wakes
# EN   nobody, and says so — to its health probe, and therefore to the app at
# EN   the moment one picks an instance. SMS and voice calls remain the
# EN   first-rank mobilisation channels.
# EN
# EN   To start it with the composition: docker compose --profile mobile up -d
KASTELL_PUSH_RELAY=http://relais:8081
KASTELL_RELAY_KEY=CHANGEZ-MOI

# La clé .p8 remise par Apple, en PEM, sur une seule ligne avec des \n.
# Sans elle, le relais démarre et refuse chaque heurtoir avec un motif clair —
# plutôt que d'accepter en silence et de laisser croire qu'un téléphone sonnera.
#
# EN — The .p8 key Apple issues, in PEM, on a single line with \n. Without it
# EN   the relay starts and refuses every knock with a clear reason — rather
# EN   than accepting silently and letting someone believe a phone will ring.
APNS_KEY=
APNS_KEY_ID=
APNS_TEAM_ID=
@@ -121,9 +198,15 @@ APNS_ENVIRONMENT=bac_a_sable
# d'habilitation d'alerte critique. Son obtention n'est jamais présumée : sans
# elle, la notification ne franchit pas le mode silencieux, et l'application le
# dit à l'installation plutôt que de le laisser découvrir la nuit venue.
#
# EN — EM-12: leave this on "false" until Apple has granted the critical alert
# EN   entitlement. It is never presumed: without it the notification does not
# EN   get past silent mode, and the app says so at install time rather than
# EN   letting it be discovered when night falls.
APNS_CRITICAL_ALERT=false

# ── Android : le compte de service Firebase ────────────────────────────────
# ── Android: the Firebase service account ─────────────────────────────────
#
# Les trois champs viennent du fichier JSON que la console Firebase remet. Les
# trois ou aucun : un relais à moitié configuré refuserait la moitié des
@@ -136,6 +219,18 @@ APNS_CRITICAL_ALERT=false
# Android n'a pas d'équivalent de l'alerte critique d'Apple : franchir le mode
# « Ne pas déranger » est une autorisation que la personne accorde au canal de
# notification, appareil par appareil. Aucun réglage ici ne l'obtient.
#
# EN — The three fields come from the JSON file the Firebase console hands
# EN   over. All three or none: a half-configured relay would refuse half the
# EN   phones without anyone knowing which.
# EN
# EN   The private key is PEM, on a single line with \n, like Apple's. Without
# EN   it the relay starts, serves iOS, and refuses every Android knock with a
# EN   clear reason — the channel then falls back to SMS.
# EN
# EN   Android has no equivalent of Apple's critical alert: getting past "Do
# EN   Not Disturb" is a permission the person grants to the notification
# EN   channel, device by device. No setting here obtains it.
FCM_PROJECT=
FCM_ACCOUNT=
FCM_KEY=
+515 −283

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Changes for outils/preparer-env.mjs: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ if (!existsSync(racine(".env"))) {
  }
  if (manquantes.length > 0) {
    lignes.splice(lignes.length - manquantes.length, 0,
      "", "# ── Ajouté par « pnpm demarrer » ────────────────────────────────────────");
      "", "# ── Added by \"pnpm demarrer\" ───────────────────────────────────────────");
  }
  sortie = lignes.join("\n");
}