24 KiB
Déploiement Production — Diagnostics multi-serveurs (T19/T20)
Statut : préparation (aucun déploiement réel effectué). Document de référence pour le futur déploiement contrôlé du Diagnostic Center central et de l'API métier/mobile chez chaque client. Aucune valeur de secret (clé, mot de passe) n'est contenue ici.
1. Responsabilités des composants (§30)
| Composant | Rôle | Installation |
|---|---|---|
| Omika.Api | API métier/mobile installée chez chaque client (licence, bootstrap, métier, POST /api/diagnostics). Le mobile ne connaît QUE cette API. |
Serveur du client |
| Omika.Diagnostics.Api | API centrale, installée uniquement sur le serveur Omika. Reçoit les lots des serveurs clients (POST /api/v1/diagnostics/batches), authentifie (ClientCode + ApiKey), impose le ClientCode authentifié, écrit le spool central. Aucune logique métier. |
Serveur central Omika |
| Omika.Diagnostics.Worker | Import du spool central JSONL → PostgreSQL (diagnostic_event). Déduplication par event_id. |
Serveur central Omika |
| Omika.Diagnostics.Web | Interface de consultation/administration (Dashboard, Diagnostics, Erreurs, Télémétrie, Référentiel, Clients Diagnostics, Système). | Serveur central Omika |
Le mobile ne connaît jamais Omika.Diagnostics.Api/Worker/Web, ni PostgreSQL Diagnostics, ni aucune
clé central. Le serveur client ne connaît jamais la ConnectionString PostgreSQL centrale
(§43) : seul le composant central autorisé détient cette configuration.
2. Architecture de flux
APPAREILS MOBILES ──HTTPS──▶ SERVEUR DU CLIENT
Omika.Api (+ Omika.Worker métier)
└─▶ Spool local borné (DiagnosticsForwarding.Spool)
└─▶ DiagnosticsForwarder (BackgroundService dans Omika.Api)
└─ HTTPS ──▶ SERVEUR OMIKA CENTRAL
Omika.Diagnostics.Api
└─▶ Spool central (Diagnostics:Central)
└─▶ Omika.Diagnostics.Worker
└─▶ PostgreSQL omika_diagnostics
└─▶ Omika.Diagnostics.Web
3. Services Windows cibles (§51)
Serveur client
OmikaApi(process Omika.Api ; contient le forwarder de diagnostics — aucun service dédié).OmikaWorker(Worker de synchronisation métier, service réel existant).- API Licence / service existant (inchangé).
Serveur central Omika
OmikaDiagnosticsApi(API centrale, Kestrel).OmikaDiagnosticsWorker(import JSONL → PostgreSQL).OmikaDiagnosticsWeb(interface, Kestrel derrière reverse proxy Apache).- PostgreSQL (
omika_diagnostics).
Les noms de services sont posés par les scripts d'activation serveur (sc.exe / New-Service)
et doivent correspondre aux valeurs UseWindowsService(...) du code.
4. Ports (§52)
| Service | Port local Développement | Port Production (à confirmer selon convention existante) |
|---|---|---|
| Omika.Api (client) | 5097 | défini par Kestrel:Endpoints / appsettings.Production.json (loopback derrière Apache) |
| Omika.Diagnostics.Api (central) | 5098 | à définir (loopback Kestrel derrière Apache/HTTPS) |
| Omika.Diagnostics.Web (central) | 5080 | à définir (loopback Kestrel derrière Apache/HTTPS) |
| PostgreSQL | 5432 | 5432 (loopback central uniquement) |
Règle : les services web sont exposés en HTTPS via le reverse proxy Apache ; Kestrel reste
en HTTP sur loopback. Aucun port n'est choisi arbitrairement : la convention Apache/Kestrel
existante de omika.applilogik.fr s'applique.
5. HTTPS (§37/§38)
- Le flux serveur client → API centrale est HTTPS uniquement en Production.
DiagnosticsForwarding:Endpointdoit être une URLhttps://….- Règle T20 : si l'environnement est Production et que l'Endpoint est en
http://, le forwarder refuse l'envoi (log explicite une fois), le métier continue (fail-open), le spool local est conservé.Omika.Apin'est jamais arrêté à cause de Diagnostics. - Le certificat TLS réel n'est pas configuré dans ce document (à poser sur le reverse proxy).
6. Configuration Omika.Api (§31/§32/§33/§34/§35)
Section DiagnosticsForwarding (dans src/Omika.Api/appsettings.json, surchargée par variables
d'environnement / appsettings.Production.json non versionné) :
| Clé | Défaut | Rôle |
|---|---|---|
DiagnosticsForwarding:Enabled |
false |
Kill switch. DiagnosticsForwarding__Enabled=true uniquement lors du déploiement serveur client. |
DiagnosticsForwarding:Endpoint |
"" |
URL centrale absolue HTTPS (ex. https://…/api/v1/diagnostics/batches). Laisser vide tant qu'aucune URL réelle. |
DiagnosticsForwarding:ApiKey |
"" |
Secret à installer sur le serveur client via DiagnosticsForwarding__ApiKey. Jamais dans Git/log/rapport. |
DiagnosticsForwarding:TimeoutSeconds |
10 |
Timeout réseau d'un envoi (le forwarder est background : jamais de blocage métier). |
DiagnosticsForwarding:BatchSize |
100 |
Événements max par lot. |
DiagnosticsForwarding:MaxBatchBytes |
524288 |
Taille max d'un lot (premier seuil). |
DiagnosticsForwarding:RetryInitialSeconds |
15 |
Backoff initial. |
DiagnosticsForwarding:RetryMaxMinutes |
30 |
Plafond du backoff. |
DiagnosticsForwarding:Spool:MaxFileSizeMb |
10 |
Rotation de fichier. |
DiagnosticsForwarding:Spool:MaxTotalSizeMb |
1024 |
Quota disque total. |
DiagnosticsForwarding:Spool:RetentionDays |
14 |
Rétention. |
Le défaut Enabled=false est volontaire (sécurité, opt-in). Aucun placeholder fictif
(https://diagnostics.exemple.fr) ne doit devenir une valeur réelle accidentellement.
7. Configuration Omika.Diagnostics.Api (§36)
Section Diagnostics (dans src/Omika.Diagnostics.Api/appsettings.json, surchargée par variables) :
| Clé | Défaut | Rôle |
|---|---|---|
ConnectionStrings:DiagnosticsDatabase (ou Diagnostics:ConnectionString) |
"" |
PostgreSQL central (secret, injecté serveur). |
Diagnostics:Central:Directory |
logs/diagnostics-central |
Spool central — en Production, chemin explicite (voir §9). |
Diagnostics:Central:MaxRequestBodyBytes |
524288 |
Corps de requête borné. |
Diagnostics:Central:MaxEventsPerBatch |
100 |
Événements max par lot. |
Diagnostics:Central:SchemaVersion |
1 |
Version de schéma de transport. |
URL/port : via ASPNETCORE_URLS (ou Kestrel:Endpoints) derrière le reverse proxy HTTPS.
8. Spool client — emplacement Production (§40)
Le service Windows peut démarrer depuis C:\Windows\System32 : ne jamais dépendre du current
working directory. Utiliser un chemin explicite configurable :
C:\ProgramData\Omika\Diagnostics\Spool
(via Observability:Remote:Directory / DiagnosticsForwarding — à poser dans la configuration
serveur client). Le quota (MaxTotalSizeMb) et la rétention (RetentionDays) évitent un
remplissage disque : à quota atteint, les fichiers les plus anciens sont supprimés (log du
nombre), jamais le fichier actif, jamais d'échec métier.
9. Spool central — emplacement Production (§41)
Même réflexion pour Omika.Diagnostics.Api :
C:\ProgramData\Omika\Diagnostics\Central
(via Diagnostics:Central:Directory). Le Worker central lit ce dossier (import JSONL → PostgreSQL,
checkpoint import-checkpoint.json).
10. Permissions Windows (§42)
Principe de moindre privilège (jamais Administrateur inutilement) :
| Compte service | Dossier | Droits |
|---|---|---|
OmikaApi |
C:\ProgramData\Omika\Diagnostics\Spool |
lecture + écriture |
OmikaDiagnosticsApi |
C:\ProgramData\Omika\Diagnostics\Central |
lecture + écriture |
OmikaDiagnosticsWorker |
C:\ProgramData\Omika\Diagnostics\Central |
lecture (checkpoint → écriture du checkpoint selon le dossier) |
11. PostgreSQL (§43/§54)
- Base dédiée
omika_diagnostics. PostgreSQL ne doit jamais être exposé aux serveurs clients : seuls les composants centraux autorisés y accèdent (firewall : loopback central uniquement). - Rôles : voir migrations
003/004/009/010(omika_diagnostics_owner,_worker,_web,_api).omika_diagnostics_api(LOGIN) : Omika.Diagnostics.Api —SELECT+UPDATE(last_seen_at_utc)surdiagnostics_clientsuniquement. Aucun droit surdiagnostics_users.omika_diagnostics_web(LOGIN) : Omika.Diagnostics.Web —SELECTsurdiagnostic_event;SELECT/INSERT/UPDATEsurdiagnostics_clients(admin/Clients) ;SELECT/INSERT/UPDATE(colonnespassword_hash,role,enabled,updated_at_utc,password_changed_at_utc,last_login_at_utc) +USAGEséquence surdiagnostics_users(admin/Users+ login).omika_diagnostics_worker(LOGIN) : Omika.Diagnostics.Worker —INSERT/SELECT/DELETEsurdiagnostic_event; aucun droit surdiagnostics_clientsnidiagnostics_users.
- Le serveur client NE DOIT PAS connaître la ConnectionString PostgreSQL centrale.
12. Migrations — inventaire (§44/§45/§46)
Ordre d'application sur le serveur central : 001 → 002 → 003 → 004 → 005 → 006 → 007 → 008 → 009 → 010.
| Fichier | But | Développement appliqué ? | Production nécessaire ? |
|---|---|---|---|
001_diagnostics_schema.sql |
diagnostic_event + telemetry_metric_hourly + index + déduplication event_id. |
Oui | Oui |
002_actor_key.sql |
Colonnes actor_key/actor_key_version (HMAC pseudonymisation). |
Oui | Oui |
003_diagnostics_roles.sql |
Rôles/grants serveur (owner/worker/web), moindre privilège. |
Non (à exécuter sur le serveur PostgreSQL Production, en superuser) | Oui |
004_diagnostics_retention.sql |
Grant SELECT, DELETE au worker pour la rétention bornée. |
Non (idem, serveur Production) | Oui |
005_diagnostics_client_context.sql |
Colonnes client_code/server_instance/environment. |
Oui | Oui |
006_diagnostics_device_license.sql |
Colonnes appareil/licence. | Oui | Oui |
007_diagnostics_usage.sql |
Colonnes screen_code/feature_code. |
Oui | Oui |
008_diagnostics_clients.sql |
Table diagnostics_clients (registre des serveurs clients, hash SHA-256). |
Oui | Oui |
009_diagnostics_clients_grants.sql |
Ownership + GRANT moindre privilège de diagnostics_clients (_api/_web), rôle omika_diagnostics_api. |
Non (serveur PostgreSQL Production, superuser) | Oui |
010_diagnostics_web_users.sql |
Table diagnostics_users (utilisateurs Web) + ownership omika_diagnostics_owner + GRANT moindre privilège _web uniquement (aucun droit API/Worker). |
Non (serveur PostgreSQL Production, superuser) | Oui |
003/004/009/010 : contiennent des CREATE ROLE / ALTER ROLE / GRANT au niveau serveur/instance.
Elles ne sont pas appliquées sur le PC de développement (elles exigent le superuser PostgreSQL
Production et fixent les comptes de service). Elles devront être exécutées sur le serveur
PostgreSQL Production, dans l'ordre, avant le pointage des comptes de service
Worker/Web/Api (omika_diagnostics_worker / omika_diagnostics_web / omika_diagnostics_api),
puis les mots de passe posés manuellement (\password, jamais dans un script/log).
Ne pas les exécuter localement « pour du vert ».
T22 :
008créediagnostics_clientsaprès003/004, donc sans ownership ni GRANT applicatif.009transfère la propriété àomika_diagnostics_owner(même propriétaire logique quediagnostic_event/telemetry_metric_hourly), crée le rôleomika_diagnostics_api(absent du modèle003), et pose les GRANT minimum identifiés par l'audit des consommateurs réels : API =SELECT+UPDATE(last_seen_at_utc); Web =SELECT/INSERT/UPDATE(enabled, api_key_hash, key_prefix, key_created_at_utc)+USAGEséquence ; Worker = aucun.009est idempotent (re-exécutable sans erreur) et utilisecurrent_database()pourGRANT CONNECT(portable, testé suromika_diagnostics_preprod).
13. Authentification ApiKey — audit final (§55/§56)
- Clé : 32 octets aléatoires, Base64Url, préfixe
omkdiag_. - Stockage : SHA-256 hexadécimal (64) uniquement (
diagnostics_clients.api_key_hash) +key_prefix. - Vérification :
CryptographicOperations.FixedTimeEquals; hash factice si client inconnu (anti-timing). - 401 : client inconnu OU mauvaise clé (indistinguables). 403 : client désactivé.
- Tenant autoritaire : tout ClientCode payload ≠ authentifié → 400 + anomalie (jamais de confiance au payload).
- Réponses sans fuite : jamais de hash, de clé, de stacktrace, ni l'existence précise d'un client.
14. Procédure — nouveau client Production (§73)
Omika.Diagnostics.Web→ Clients Diagnostics (Admin).- Nouveau client.
- Saisir le CodeClient exact (ex.
BATIK.01, normaliséUPPER(TRIM)). - Créer le client → la clé est générée.
- Copier immédiatement la clé (bouton « Copier »).
- Installer la clé sur le serveur client : variable
DiagnosticsForwarding__ApiKey. - Configurer
DiagnosticsForwarding__Endpoint(URL centrale HTTPS). - Activer :
DiagnosticsForwarding__Enabled=true. - Redémarrer
OmikaApi. - Vérifier
last_seen_at_utcdans Clients Diagnostics. - Vérifier un diagnostic réel (Dashboard / Diagnostics).
15. Clé perdue (§74)
La clé n'est pas récupérable (hash seul stocké). Si elle n'a pas été copiée : faire Régénérer la clé, puis mettre à jour le serveur client avec la nouvelle clé.
16. Rotation de clé (§75)
Version V1 : régénération → ancienne clé immédiatement invalide. Pendant l'intervalle où le
serveur client n'a pas encore la nouvelle clé, les envois échouent en 401 et le spool local
s'accumule (backlog borné, reprise automatique). Acceptable.
17. Panne centrale (§76)
- Ne pas arrêter
OmikaApi(le métier continue). - Ne pas vider le spool manuellement (les événements seront renvoyés).
- Vérifier l'espace disque (quota/rétention bornent le spool).
- Vérifier les logs du forwarder.
- Attendre le rétablissement : reprise automatique (backoff borné 15 s → 30 min).
18. Disque spool (§77)
MaxTotalSizeMb(défaut 1024) : quota disque total ; à dépassement, suppression des fichiers les plus anciens (jamais le fichier actif, log du nombre supprimé).RetentionDays(défaut 14) : purge des fichiers plus anciens.MaxFileSizeMb(défaut 10) : rotation de fichier.- Fail-open absolu : aucune de ces opérations ne bloque le métier.
Validation empirique T22 (pipeline réel, panne centrale simulée) :
- Quota
MaxTotalSizeMb=1: 6000 événements fake (~3,6 Mo) →DiagnosticsForwarder a abandonné 14 fichier(s) de spool, spool final 768 Ko (≤ 1 Mo), fichier actif préservé,/health200 (aucun crash métier), Working Set stable ~115–125 Mo (backlog sur disque ≠ RAM).- Rétention
RetentionDays=1: fichier ancien (-2 j) supprimé, fichier récent + fichier actif conservés, central DOWN pendant tout le test (la maintenance ne dépend pas du central).- Correctif T22 :
EnforceBounds(quota/rétention) était appelé uniquement quand le spool était vide ; pendant une panne centrale (backlog jamais vide), le quota n'était donc pas appliqué. Il est désormais appelé à chaque passe du forwarder, indépendamment du backlog. Test :ForwardOnce_BacklogOverQuota_StillEnforcesBounds.
19. Ordre de démarrage (reprise/rollback)
Démarrage central : PostgreSQL → OmikaDiagnosticsWorker → OmikaDiagnosticsApi →
OmikaDiagnosticsWeb.
Démarrage client : OmikaWorker (métier) → OmikaApi (métier + forwarder).
Rollback : DiagnosticsForwarding__Enabled=false + redémarrage OmikaApi coupe immédiatement
tout envoi central sans toucher au métier ni au spool (aucune perte de données).
20. Dépendance SQLite (mobile / Desktop local)
Mise à jour T22 — audit + correctif CVE.
- Version retenue :
Microsoft.Data.Sqlite 10.0.10(inchangé) +SQLitePCLRaw2.1.12 épinglé transitivement (Directory.Packages.props,CentralPackageTransitivePinningEnabled=true). - Raison :
SQLitePCLRaw.lib.e_sqlite3 2.1.11(transitif deMicrosoft.Data.Sqlite 10.0.10) embarque une bibliothèque SQLite native < 3.50.2, vulnérable à CVE-2025-6965 / GHSA-2m69-gcr7-jv3q (troncature d'entier dansfindOrCreateAggInfoColumn,resolve.c). Correctif = SQLite native 3.50.2, livré par le patch 2.1.12 (famille 2.x, drop-in, ABI-compatible). Pas de saut vers SQLitePCLRaw 3.x (breaking) ni versMicrosoft.Data.Sqlite 11(majeur). - Projets concernés :
Omika.App.Local(offline-first : cache métier, brouillons, sync,DiagnosticOutboxSqliteStore) →Omika.App→ têtesOmika.App.Desktop/Omika.App.Android/Omika.App.iOS. Aucun impact surOmika.Api,Omika.Workerni les projets Diagnostics. - Validation :
dotnet restoreOK ;dotnet list package --include-transitive --vulnerable→ « aucun package vulnérable » ; arbre confirméSQLitePCLRaw.* = 2.1.12.- Tests SQLite/Outbox ciblés : 148/148.
- Builds Release :
Omika.App.Desktop0 erreur,Omika.App.Android0 erreur. Omika.App.Desktop(Debug, flux dev) démarré réellement : ouvertureomika.dbOK + bootstrapDEV BOOTSTRAPOK (aucun crash SQLite).
Surface réellement exposée : la vulnérabilité nécessite une requête SQL construite avec un nombre extrême de termes d'agrégation ; Omika n'exécute que des requêtes applicatives fixes et paramétrées (jamais de SQL utilisateur), sur une base locale non accessible à distance. Le correctif 2.1.12 est néanmoins appliqué (moindre coût, aucun risque de régression constaté).
21. Gestion des utilisateurs Diagnostics.Web (T23)
21.1 Distinction fondamentale
| Concept | Définition | Identifiant | Stockage |
|---|---|---|---|
| Utilisateur Diagnostics | personne qui ouvre Omika.Diagnostics.Web |
username |
diagnostics_users (hash PBKDF2-SHA256) |
| Client Diagnostics | serveur client qui envoie des événements | ClientCode |
diagnostics_clients (hash SHA-256) |
Les deux registres sont totalement séparés et ne doivent jamais être confondus.
21.2 Modèle utilisateur
- Table
diagnostics_users(migration010) :id,username(unique, insensible à la casse),password_hash,role(Support/Admin),enabled,created_at_utc,updated_at_utc,password_changed_at_utc,last_login_at_utc. - Aucun mot de passe en clair : seule la colonne
password_hashexiste. Le hash est produit parDiagnosticPasswordHasher(PBKDF2-SHA256, 100 000 itérations, sel aléatoire). - Aucune suppression physique (V1) : un utilisateur est désactivé (
enabled=false), jamaisDELETE.
21.3 Rôles
| Rôle | Accès |
|---|---|
| Support | Dashboard, Diagnostics, Erreurs, Traces, Synchronisation, Telemetry, Parc, Versions, Référentiel, Mon compte. |
| Admin | Tout Support + Clients Diagnostics + Utilisateurs + Système. |
/System, /Clients et /Users sont Admin uniquement. Un Support y obtient un refus
(redirection /AccessDenied). Un Admin conserve tous les droits de consultation Support.
21.4 Actions d'administration (/Users, Admin uniquement)
- Création : saisie
username+password+confirmation+rôle. Le Web hache automatiquement (DiagnosticPasswordHasher.Hash) ; l'Admin ne génère/copie jamais un hash. - Désactivation / Réactivation (
enabled=false/true). - Changement de rôle
Support → Admin/Admin → Support. - Réinitialisation du mot de passe (nouveau mot de passe + confirmation → hash + UPDATE).
21.5 Protections
- Dernier Admin : impossible de désactiver ou rétrograder le dernier Admin actif (« Impossible de retirer le dernier administrateur actif. »).
- Auto-désactivation : un Admin ne peut pas désactiver son propre compte.
- Auto-rétrogradation : un Admin ne peut pas retirer son propre rôle Admin.
21.6 Règles de validation
- Username : obligatoire,
trim, unicité insensible à la casse, borné (≤ 64), caractèreslettres / chiffres / . / - / _. - Mot de passe : non vide, ≥ 12 caractères, confirmation identique. Pas de politique de complexité superflue (V1).
21.7 Connexion (login hybride)
- Si le
usernameexiste dansdiagnostics_users→ la DB est autoritaire (jamais de fallback).- Vérification PBKDF2 (
DiagnosticPasswordHasher.Verify) ;enabled=false→ refus.
- Vérification PBKDF2 (
- Sinon → fallback opérateurs
DiagnosticsAuth:Operators(bootstrap temporaire). - Message d'échec générique : « Identifiants invalides. » (jamais « inconnu » / « désactivé » / « mauvais mot de passe »).
last_login_at_utcest mis à jour (best-effort) après un login DB réussi.- Anti-bruteforce léger (in-memory, mono-instance) : 5 échecs / 5 min → blocage 10 min (clé = username + IP). Aucun Redis, aucune session distribuée.
- Anti-timing : hash factice calculé quand le username est inconnu (même principe que l'ApiKey).
- Cookie :
HttpOnly,SameSite=Lax,Secure=Alwayshors Développement, expiration 12 h (glissante). Production = HTTPS. - Un utilisateur désactivé avec un cookie existant est re-déconnecté à la prochaine re-vérification DB (fréquence bornée ~60 s, cache mémoire mono-instance) ; au pire ~1 minute de grâce, jamais « plusieurs jours ».
21.8 « Mon compte » (/Account)
- Tout utilisateur authentifié peut changer son propre mot de passe :
mot de passe actuel(vérifié réellement) +nouveau+confirmation. En cas de mot de passe actuel faux → refus sans modifier le hash. - Les opérateurs bootstrap (configuration) ne peuvent pas changer leur mot de passe ici.
22. Bootstrap du premier Admin Production (T23)
Production démarre sans utilisateur DB. Conserver la possibilité de configurer
temporairement un opérateur bootstrap (DiagnosticsAuth:Operators) pour créer le premier Admin DB.
22.1 Générer le hash bootstrap (hors ligne, pas d'endpoint Web)
Outil console dédié (jamais un endpoint Web anonyme) :
dotnet run --project tools/Omika.DiagnosticHashTool -- "<mot-de-passe-bootstrap>"
# ou, pour éviter de laisser le mot de passe dans l'historique du shell :
dotnet run --project tools/Omika.DiagnosticHashTool -- --stdin
⚠️ Le mot de passe bootstrap ne doit jamais être dans Git, dans le rapport, ni dans un
appsettingsversionné. Seul le hash est placé dans la configuration / le secret store Production.
22.2 Procédure premier déploiement (12 étapes)
- Déployer
Omika.Diagnostics.Web(services + reverse proxy HTTPS, cf. §3-§5). - Configurer temporairement l'opérateur bootstrap Admin (hash seulement) :
DiagnosticsAuth__Operators__0__Username/...__PasswordHash/...__Roles__0=Admin. - Démarrer le service
OmikaDiagnosticsWeb. - Se connecter avec l'opérateur bootstrap.
- Aller sur
/Users. - Créer l'Admin DB permanent (username + mot de passe + rôle
Admin). - Se déconnecter.
- Tester le login avec l'Admin DB (plus le bootstrap).
- Retirer l'opérateur bootstrap de la configuration (
DiagnosticsAuth:Operators = []). - Redémarrer le service
OmikaDiagnosticsWeb. - Confirmer que le bootstrap est refusé (login → « Identifiants invalides. »).
- Confirmer que l'Admin DB fonctionne (Dashboard / Diagnostics / Clients / Users).
22.3 Installation Production neuve
Si PostgreSQL Diagnostics Production est créé de zéro : appliquer 001 → 010 dans l'ordre
(jamais uniquement les dernières). Si une installation existe déjà : appliquer uniquement les
migrations manquantes, dans l'ordre.