BlockLucky Documentation officielle GitHub

Variables d'environnement

Cette page est la référence des variables lues par le backend. Le tableau est généré à la construction de la documentation depuis backend/src/config/env.config.ts : type, valeur par défaut et contraintes viennent directement du schéma Zod, il ne peut donc pas diverger du code. Le chargement, la validation et les règles propres à la production sont expliqués sur la page Configuration.

Les mêmes variables servent aux deux process, l'API (server.ts) et le worker (worker.ts). Une valeur incohérente entre les deux, par exemple deux REDIS_KEY_PREFIX différents, casse le relais Socket.IO et l'idempotence. Dans la stack Docker, l'ancre x-backend-env de docker-compose.yml garantit qu'ils reçoivent les mêmes valeurs.

Générer les secrets

Quatre variables sont des secrets refusés en production s'ils gardent leur valeur de développement. Les commandes suivantes utilisent Node, déjà requis par le projet. La dernière s'exécute depuis backend/, où ethers est installé.

Variable Format attendu Commande
JWT_SECRET au moins 16 caractères node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"
ENCRYPTION_KEY exactement 64 caractères hexadécimaux node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
WEBHOOK_SECRET au moins 8 caractères node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
RELAYER_PRIVATE_KEY 0x suivi de 64 caractères hexadécimaux node -e "console.log(require('ethers').Wallet.createRandom().privateKey)"
METRICS_TOKEN chaîne non vide en production node -e "console.log(require('crypto').randomBytes(24).toString('base64url'))"

Danger

ENCRYPTION_KEY chiffre en AES-256-GCM la clé privée de chaque portefeuille intégré (User.walletEncryptedKey), les secrets TOTP et les images des pièces d'identité en attente. Si elle est perdue ou changée, les portefeuilles ne peuvent plus signer : les ethers fictifs et les tickets qu'ils détiennent deviennent inaccessibles, les citoyens doivent reconfigurer leur 2FA et les pièces en attente ne peuvent plus être examinées. Sauvegardez-la hors du serveur avant la mise en service et ne la faites jamais tourner sans plan de rechiffrement. Voir Clés et garde des portefeuilles.

Changer JWT_SECRET invalide toutes les sessions ouvertes : c'est un moyen radical de déconnecter tout le monde. Changer WEBHOOK_SECRET impose de mettre à jour l'émetteur du webhook en même temps.

Valeurs selon l'environnement

Développement local

cp .env.example .env suffit. Les valeurs visent l'infrastructure lancée par docker compose up -d --wait depuis la racine du dépôt.

Besoin Réglage
Travailler sans nœud blockchain BLOCKCHAIN_MODE=simulated : achats, tirages et pause sont simulés, /lottery/claim-prize répond 409
Lire le code de connexion sans ouvrir Mailpit rien à faire : en NODE_ENV=development, les réponses de /auth/login, /auth/signup et /auth/password/forgot contiennent devOtpPreview
Se connecter sans code email LOGIN_EMAIL_CODE_REQUIRED=false (refusé en production)
Utiliser l'administration sans 2FA ADMIN_MFA_REQUIRED=false (refusé en production)
Jouer sans faire vérifier son âge AGE_VERIFICATION_REQUIRED=false (refusé en production) ; les comptes du seed sont déjà vérifiés
Raccourcir la salle d'attente du tirage DRAW_REVEAL_DELAY_SECONDS=0 pour un tirage dès la fermeture des achats, ou une valeur courte pour une démonstration
Tester la connexion Google renseigner GOOGLE_CLIENT_IDS avec les identifiants client de l'application ; sans eux, la route répond 503
Voir les requêtes SQL DB_LOG_QUERIES=true
Tester l'application mobile sur un téléphone ajouter l'origine Expo à CORS_ORIGINS (voir Tester sur un téléphone)

Après un redémarrage du nœud Hardhat, la chaîne repart du bloc 0 alors que la base garde son curseur d'indexation : l'indexeur journalise alors que le curseur dépasse la tête de chaîne. Il faut réinitialiser la base avec npm run prisma:reset, comme décrit dans Blockchain locale.

Stack Docker

Le fichier docker-compose.yml fixe déjà les variables d'infrastructure dans l'ancre x-backend-env : NODE_ENV=production, DATABASE_URL sur postgres:5432, REDIS_URL sur redis:6379, BLOCKCHAIN_MODE=onchain, RPC_URL=http://blockchain:8545, CHAIN_ID=31337, les deux adresses de contrats, SMTP_HOST=mailpit et les origines CORS. Le service backend y ajoute RUN_WORKERS=false ; le service worker démarre dist/src/worker.js.

Comme la stack tourne en production, les règles de production s'appliquent. Les cinq secrets sont lus depuis un fichier .env placé à la racine du dépôt, lu par Docker Compose pour l'interpolation :

Configuration
JWT_SECRET=valeur-generee
ENCRYPTION_KEY=64-caracteres-hexadecimaux
RELAYER_PRIVATE_KEY=0x64-caracteres-hexadecimaux
WEBHOOK_SECRET=valeur-generee
METRICS_TOKEN=valeur-generee

Si l'une manque, backend et worker s'arrêtent au démarrage avec Configuration invalide. La même RELAYER_PRIVATE_KEY est transmise au conteneur blockchain sous le nom OPERATOR_PRIVATE_KEY pour habiliter ce compte sur les contrats déployés. Le détail est sur la page Stack complète en conteneurs.

Sepolia

Pour brancher le backend sur le déploiement public, reprendre les valeurs du fichier smart-contract/deployments/sepolia.json écrit par npm run deploy:sepolia (voir Déploiement sur Sepolia).

Variable Valeur
BLOCKCHAIN_MODE onchain
CHAIN_ID 11155111
RPC_URL URL d'un fournisseur RPC Sepolia avec clé d'API
FALLBACK_RPC_URL un second fournisseur ; la valeur par défaut est déjà un nœud public Sepolia
LOTTERY_CONTRACT_ADDRESS, POAP_CONTRACT_ADDRESS contracts.lottery et contracts.poap du fichier de déploiement
CHAIN_START_BLOCK deploymentBlock du fichier de déploiement, sans quoi l'indexeur parcourt Sepolia depuis le bloc 0 par tranches de 2 000 blocs
CHAIN_CONFIRMATIONS supérieur à 0 sur un réseau public, pour ne pas indexer un bloc qui serait réorganisé
EXPLORER_URL https://sepolia.etherscan.io
RELAYER_PRIVATE_KEY clé du compte operator habilité par le script de déploiement (rôles opérateur, pause et frappe)
WELCOME_GRANT_WEI à dimensionner selon les ethers de test dont dispose le compte opérateur : chaque nouveau citoyen en reçoit une fois
INDEXER_INTERVAL_MS, KEEPER_INTERVAL_MS à rallonger si le fournisseur RPC limite le nombre d'appels

Attention

Sur Sepolia, le compte opérateur paie le gaz des tirages, des annulations, de la frappe des POAP et des dotations. Un solde vide bloque silencieusement les dotations (journalisées en erreur) puis les achats des nouveaux citoyens, qui reçoivent 402 Solde d'ethers fictifs insuffisant.

POST /admin/treasury/withdraw appelle setTreasury sur le contrat quand l'adresse demandée diffère de la trésorerie actuelle. Cette fonction exige DEFAULT_ADMIN_ROLE. Sur Sepolia, le script de déploiement réserve ce rôle au multisig MAIRIE_ADMIN_ADDRESS : l'opérateur ne l'a pas, et seul un retrait vers la trésorerie configurée (MAIRIE_TREASURY_ADDRESS) fonctionne ; changer de trésorerie passe par le multisig. En local, deploy-local.ts laisse ce rôle à l'opérateur, sauf avec LOCAL_STRICT_ROLES=true.

Référence

Le schéma de configuration compte 59 variables, lues et validées au démarrage par backend/src/config/env.config.ts. Une valeur invalide arrête le processus avec la liste des erreurs.

Serveur HTTP

Variable Type Valeur par défaut Contraintes Rôle
PORT entier 2053 strictement positif Port d'écoute de l'API HTTP et de Socket.IO. Le process worker ouvre ses sondes sur PORT + 1 (2054 par défaut).
NODE_ENV énumération : development, production, test development - Environnement d'exécution. production active les contrôles de sécurité du schéma, test coupe Redis, les emails, S3 et les logs, development affiche les logs en couleur et renvoie devOtpPreview.
TRUST_PROXY chaîne false - Réglage trust proxy d'Express : true, false, un nombre de proxys ou une liste d'adresses. Indispensable derrière Caddy pour que le rate limiting voie l'IP du client.
HTTP_KEEP_ALIVE_TIMEOUT_MS entier 65000 strictement positif Durée de maintien des connexions keep-alive. headersTimeout vaut cette valeur plus une seconde.
HTTP_REQUEST_TIMEOUT_MS entier 30000 strictement positif Durée maximale de réception d'une requête complète par Node.
SHUTDOWN_TIMEOUT_MS entier 25000 strictement positif Délai laissé à l'arrêt propre avant sortie forcée avec le code 1.

Observabilité

Variable Type Valeur par défaut Contraintes Rôle
APP_VERSION chaîne version du package npm, sinon 1.0.0 - Version publiée dans chaque ligne de log (version) et dans la réponse de /health/deep. L'image Docker la fixe par l'argument de build APP_VERSION.
LOG_LEVEL énumération : error, warn, info, http, debug aucune (facultative) - Niveau minimal des logs Winston. Sans valeur : debug en développement, info ailleurs.
METRICS_ENABLED booléen (true, false, 1, 0) true - Active les métriques Prometheus (mesure HTTP et métriques Node par défaut).
METRICS_TOKEN chaîne chaîne vide production : METRICS_TOKEN est obligatoire en production pour protéger /metrics Jeton Bearer exigé sur /metrics de l'API et pour le détail de /health/deep. Vide : /metrics est ouvert.

Base de données

Variable Type Valeur par défaut Contraintes Rôle
DATABASE_URL URL postgresql://ether…a=public - Chaîne de connexion PostgreSQL utilisée par l'adaptateur @prisma/adapter-pg. La valeur par défaut pointe sur le conteneur local exposé sur le port 5434.
DB_POOL_MAX entier 10 strictement positif Nombre maximal de connexions du pool pg par process (API et worker ont chacun leur pool).
DB_CONNECTION_TIMEOUT_MS entier 5000 strictement positif Délai maximal pour obtenir une connexion du pool avant erreur.
DB_IDLE_TIMEOUT_MS entier 30000 strictement positif Durée après laquelle une connexion inutilisée est fermée par le pool.
DB_STATEMENT_TIMEOUT_MS entier 15000 strictement positif Paramètre PostgreSQL statement_timeout de chaque session. Une requête plus longue est annulée (code 57014, renvoyé en 503).
DB_LOG_QUERIES booléen (true, false, 1, 0) false - Journalise toutes les requêtes SQL de Prisma (niveau query). À réserver au diagnostic local.

Redis

Variable Type Valeur par défaut Contraintes Rôle
REDIS_URL URL redis://localhost:6380 - Connexion Redis pour le cache, les sessions révoquées, les codes OTP, l'idempotence, le rate limiting, les files BullMQ et le relais Socket.IO. La valeur par défaut vise le conteneur local exposé sur le port 6380.
REDIS_KEY_PREFIX chaîne blocklucky - Préfixe des clés applicatives, complété par NODE_ENV (blocklucky:development:...). Il préfixe aussi les clés du rate limiter et le canal du relais Socket.IO, pas les clés BullMQ.

Sécurité et sessions

Variable Type Valeur par défaut Contraintes Rôle
JWT_SECRET chaîne etherbay-super-sec…ppement) au moins 16 caractères ; production : la valeur de développement est refusée en production Secret HMAC de signature des jetons de session (HS256). Le changer invalide toutes les sessions en cours.
JWT_EXPIRES_IN chaîne 12h format /^\d+[smhd]$/ Durée de vie d'un jeton de session, au format nombre suivi de s, m, h ou d.
ENCRYPTION_KEY chaîne 0123456789abcdef01…89abcdef (développement) ENCRYPTION_KEY doit contenir 64 caractères hexadécimaux ; production : la valeur de développement est refusée en production Clé AES-256 (32 octets en hexadécimal) qui chiffre les clés privées des portefeuilles intégrés et les secrets TOTP, et dérive la clé HMAC des codes OTP. La perdre rend les portefeuilles inutilisables.
WEBHOOK_SECRET chaîne etherbay-webhook-secret (développement) au moins 8 caractères ; production : la valeur de développement est refusée en production Secret HMAC-SHA-256 qui signe l'en-tête x-webhook-signature du webhook blockchain (mode simulé).
LOGIN_EMAIL_CODE_REQUIRED booléen (true, false, 1, 0) true production : ne peut pas être désactivé en production Exige un code à 6 chiffres reçu par email avant toute ouverture de session. Désactivé seulement par la suite de tests.
ADMIN_MFA_REQUIRED booléen (true, false, 1, 0) true production : ne peut pas être désactivé en production Refuse les routes réservées à l'ADMIN tant que la double authentification n'est pas activée sur le compte.
AGE_VERIFICATION_REQUIRED booléen (true, false, 1, 0) true production : ne peut pas être désactivé en production Exige une pièce d'identité validée par la Mairie (ageVerificationStatus = VERIFIED) pour acheter ou offrir un ticket et échanger une récompense. Refusée à false en production ; désactivée seulement par la suite de tests.
GOOGLE_CLIENT_IDS liste séparée par des virgules chaîne vide - Identifiants client OAuth Google acceptés comme audience des jetons d'identité, séparés par des virgules. Vide par défaut : la connexion Google répond alors 503.

Email

Variable Type Valeur par défaut Contraintes Rôle
SMTP_HOST chaîne localhost - Serveur SMTP d'envoi des emails transactionnels (Mailpit en local).
SMTP_PORT entier 1025 strictement positif Port SMTP. La valeur 465 active TLS implicite (secure: true).
SMTP_USER chaîne chaîne vide - Identifiant SMTP. Vide : connexion sans authentification.
SMTP_PASS chaîne chaîne vide - Mot de passe SMTP, utilisé seulement si SMTP_USER est renseigné.
SMTP_FROM chaîne EtherBay Lottery <noreply@etherbay.fr> - Expéditeur affiché des emails.
SUPPORT_EMAIL chaîne support@etherbay.fr - Adresse qui reçoit les messages du formulaire de support (POST /user/support). L'email porte l'identifiant, l'adresse, le prénom et le nom du citoyen, et son adresse en réponse directe quand elle est connue.

Blockchain

Variable Type Valeur par défaut Contraintes Rôle
BLOCKCHAIN_MODE énumération : onchain, simulated onchain production : BLOCKCHAIN_MODE doit valoir onchain en production : la simulation est réservée au développement onchain : achats, tirages et pause passent par le smart contract. simulated : hachages aléatoires, aucun nœud requis, réservé au développement et aux tests.
RPC_URL URL http://127.0.0.1:8545 - Nœud JSON-RPC principal (nœud Hardhat local par défaut).
FALLBACK_RPC_URL URL https://ethereum-sepolia-rpc.publicnode.com - Nœud JSON-RPC de secours, utilisé après une bascule du client RPC.
CHAIN_ID entier 31337 strictement positif Identifiant de réseau attendu (31337 pour Hardhat, 11155111 pour Sepolia). Le fournisseur ethers est créé avec ce réseau statique.
CHAIN_START_BLOCK entier 0 minimum 0 Premier bloc lu par l'indexeur quand aucun curseur n'existe en base. Mettre le bloc de déploiement du contrat.
CHAIN_CONFIRMATIONS entier 0 minimum 0 ; maximum 64 Nombre de blocs de confirmation que l'indexeur laisse derrière la tête de chaîne.
EXPLORER_URL chaîne chaîne vide URL HTTPS attendue Racine HTTPS de l'explorateur de blocs pour les liens etherscanUrl et explorerUrl. Vide : aucun lien n'est produit.
WELCOME_GRANT_WEI chaîne 500000000000000000 format /^\d+$/ Dotation de bienvenue en wei versée une seule fois par le compte opérateur à chaque portefeuille intégré (0,5 ETH fictif par défaut, 0 la désactive).
LOTTERY_CONTRACT_ADDRESS chaîne 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 format /^0x[0-9a-fA-F]{40}$/ Adresse du contrat BlockLucky. La valeur par défaut correspond au déploiement local.
POAP_CONTRACT_ADDRESS chaîne 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 format /^0x[0-9a-fA-F]{40}$/ Adresse du contrat BlockLuckyPOAP. La valeur par défaut correspond au déploiement local.
RELAYER_PRIVATE_KEY chaîne 0xac0974bec39a17e3…f4f2ff80 (développement) format /^0x[0-9a-fA-F]{64}$/ ; production : la valeur de développement est refusée en production Clé privée du compte opérateur du backend : tirage, annulation, pause, frappe des POAP, retrait des commissions et dotations de bienvenue. La valeur par défaut est le compte 0 public de Hardhat.

Workers

Variable Type Valeur par défaut Contraintes Rôle
INDEXER_INTERVAL_MS entier 3000 minimum 500 Période de la boucle de l'indexeur d'événements du contrat.
KEEPER_INTERVAL_MS entier 10000 minimum 1000 Période du keeper qui demande le tirage ou clôt un tour expiré. Elle fixe aussi la durée du verrou Redis du keeper.
DRAW_REVEAL_DELAY_SECONDS entier 600 minimum 0 ; maximum 86400 Durée de la salle d'attente en secondes : délai que le keeper respecte entre le passage du tour à l'état prêt au tirage (fin du temps ou plafond atteint) et l'appel à requestDraw (600 par défaut, 0 la supprime).
RUN_WORKERS booléen (true, false, 1, 0) true - Démarre les workers BullMQ, l'indexeur et le keeper dans le process de l'API. Mettre false quand un process worker séparé tourne (stack Docker).
WORKER_CONCURRENCY entier 5 strictement positif Concurrence du worker d'emails. Les workers ledger et chain-actions restent à 1.

Stockage S3

Variable Type Valeur par défaut Contraintes Rôle
AWS_REGION chaîne eu-west-3 - Région du client S3 qui stocke les rapports exportés.
AWS_ACCESS_KEY_ID chaîne minioadmin - Identifiant d'accès S3 (MinIO en local).
AWS_SECRET_ACCESS_KEY chaîne minioadmin - Clé secrète S3.
AWS_S3_BUCKET chaîne blocklucky-assets - Bucket de dépôt des rapports reports/etherbay-report-*.csv.
AWS_S3_ENDPOINT URL http://localhost:9000 - Point d'accès S3 en style chemin. Il sert aussi à construire l'URL downloadUrl renvoyée par l'export.

Frontend et CORS

Variable Type Valeur par défaut Contraintes Rôle
FRONTEND_URL URL http://localhost:3000 - URL du site web : toujours ajoutée aux origines CORS, base des liens de parrainage, du lien RGPD et de external_url des POAP.
CORS_ORIGINS liste séparée par des virgules http://localhost:3000,http://localhost:8081 - Origines supplémentaires autorisées pour l'API et Socket.IO (le port 8081 correspond à Expo web).

Fonctionnalités

Variable Type Valeur par défaut Contraintes Rôle
MOBILE_MIN_VERSION chaîne 1.0.0 - Version minimale de l'application mobile publiée par GET /api/config.
MAINTENANCE_MODE booléen (true, false, 1, 0) false - Répond 503 avec Retry-After: 300 sur les routes /api/* sauf celles qui commencent par /api/admin.
SCRATCH_COST_VIOLET entier 50 strictement positif Prix en EtherPoints du ticket à gratter « violet » (POST /marketplace/scratch), qui attribue au hasard une récompense partenaire en stock (50 par défaut).
SCRATCH_COST_LUCKY entier 100 strictement positif Prix en EtherPoints du ticket à gratter « lucky » (POST /marketplace/scratch), qui attribue au hasard une récompense partenaire en stock (100 par défaut).