📘 Architecture & Documentation
MES-FGAM — Système de suivi de production peinture aéronautique
1. Vue d'ensemble
🎯 Objectif
MES-FGAM est un Manufacturing Execution System (MES) dédié à l'atelier peinture de Figeac Aéro. Il assure le suivi en temps réel de la production, la traçabilité complète des opérations de peinture, et la gestion des fiches techniques de préparation peinture.
📋 Fonctions principales
- Lancement de lots (GROF) — Création de groupements d'OFs avec sélection de cabine et type de peinture
- Suivi poste par poste — Progression step-by-step à travers 16 étapes (Prépa → Peinture → Désolvatation → Étuve × 4 passes)
- Préparation labo peinture — Consultation des fiches techniques avec checkpoints par OF
- Supervision en temps réel — Vue globale de tous les GROFs actifs avec état courant
- Traçabilité & export PDF — Archives des lots terminés avec formulaire FORM-589
- Gestion des accès — Matrice de permissions configurable par rôle
2. Architecture technique
🏗️ Stack technologique
| Couche | Technologie | Détail |
| Frontend | HTML5 / CSS3 / JavaScript vanilla | Pages statiques servies par Express. Aucun framework (React, Vue, etc.) |
| Backend | Node.js 20 + Express 4 | API REST JSON, middleware JWT |
| Base de données | PostgreSQL 16 | Schéma relationnel, 6 tables, volume Docker persistant |
| Auth | JWT (jsonwebtoken) + bcrypt | Tokens 12h, mots de passe hashés |
| Déploiement | Docker Compose | 2 containers : mes-fgam-app + mes-fgam-db |
| Reverse Proxy | Nginx + Certbot SSL | HTTPS sur le VPS OVH |
📁 Structure des fichiers
MES-FGAM/
├── server.js # Serveur Express (API + fichiers statiques)
├── package.json # Dépendances Node.js
├── paint_data.js # Catalogue peintures source (152 fiches)
├── Dockerfile # Image Node.js 20 Alpine
├── docker-compose.yml # Orchestration PostgreSQL + App
├── .env # Variables d'env (DB, JWT — non versionné)
│
├── db/
│ ├── schema.sql # Schéma des 6 tables
│ ├── pool.js # Pool de connexion PostgreSQL
│ ├── init.js # Initialisation du schéma au démarrage
│ └── seed.js # Import peintures + users + permissions
│
├── middleware/
│ └── auth.js # Vérification JWT + contrôle de rôle
│
├── routes/
│ ├── auth.js # Authentification + permissions
│ ├── grofs.js # CRUD lots de production
│ └── paints.js # Catalogue peintures
│
└── public/ # Fichiers servis en statique
├── index.html # Portail principal + login
├── lancement.html # Création de GROFs
├── poste_prepa.html # Préparation (masquage, ponçage)
├── labo_peinture.html # Fiches techniques labo
├── poste_cabine.html # Application peinture + désolvatation
├── poste_etuve.html # Étuvage + suivi T°C
├── supervision_live.html # Vue temps réel
├── tracabilite.html # Archives + FORM-589
├── admin_access.html # Gestion permissions
├── architecture.html # Cette page
└── js/api.js # Module API partagé (fetch + JWT)
3. Workflow de production
🔄 Flux principal
Chaque pièce aéronautique suit un cycle de peinture en 4 passes, chacune composée de 4 sous-étapes :
① Lancement
→
② Prépa Labo
→
③ Préparation
→
④ Peinture
→
⑤ Désolvatation
→
⑥ Étuve
→
✅ Terminé
Ce cycle est répété 4 fois pour couvrir les 2 couches (Primaire + Finition) × 2 faces (F1 + F2), soit 16 étapes au total.
📦 Qu'est-ce qu'un GROF ?
Un GROF (GROupement de Fabrication) est un lot de production regroupant plusieurs OFs (Ordres de Fabrication) assignés à une même cabine de peinture. Chaque GROF :
- Est identifié par un code unique (ex:
G847291)
- Est assigné à une cabine (
SAIMA 1, SAIMA 2 ou SAIMA 3)
- Contient 1 à N ordres de fabrication (OFs)
- Progresse à travers 16 étapes séquentielles
- Passe par 3 statuts : EN COURS → TERMINÉ ou ANNULÉ
4. Les 16 étapes du GROF
| Step | Nom | Passe | Poste | Type |
| 0 | F1 — Alignement | Primaire Face 1 | Poste Prépa | PREP |
| 1 | Peinture Primaire F1 | Primaire Face 1 | Poste Cabine | PAINT |
| 2 | Désolvatation Prim F1 | Primaire Face 1 | Poste Cabine | DESOL |
| 3 | Étuve Prim F1 | Primaire Face 1 | Poste Étuve | ÉTUVE |
| 4 | F2 — Retournement | Primaire Face 2 | Poste Prépa | PREP |
| 5 | Peinture Primaire F2 | Primaire Face 2 | Poste Cabine | PAINT |
| 6 | Désolvatation Prim F2 | Primaire Face 2 | Poste Cabine | DESOL |
| 7 | Étuve Prim F2 | Primaire Face 2 | Poste Étuve | ÉTUVE |
| 8 | F1 — Prépa Finition | Finition Face 1 | Poste Prépa | PREP |
| 9 | Finition F1 | Finition Face 1 | Poste Cabine | PAINT |
| 10 | Désolvatation Fin F1 | Finition Face 1 | Poste Cabine | DESOL |
| 11 | Étuve Fin F1 | Finition Face 1 | Poste Étuve | ÉTUVE |
| 12 | F2 — Prépa Finition | Finition Face 2 | Poste Prépa | PREP |
| 13 | Finition F2 | Finition Face 2 | Poste Cabine | PAINT |
| 14 | Désolvatation Fin F2 | Finition Face 2 | Poste Cabine | DESOL |
| 15 | Étuve Fin F2 | Finition Face 2 | Poste Étuve | ÉTUVE |
Désolvatation (Flash-Off) — Temps de repos entre l'application de peinture et l'étuvage. Un timer démarre automatiquement. L'opérateur doit attendre la fin du temps réglementaire avant de valider l'étape.
5. Écrans & Fonctions
🏠 Portail (index.html)
- Login — Code opérateur + mot de passe. Token JWT stocké en
sessionStorage
- Menu — Cartes de navigation filtrées par les permissions du rôle
- Liens admin — Visibles uniquement pour le rôle
admin
➕ Lancement de Lots (lancement.html)
- Sélection de cabine — SAIMA 1, SAIMA 2 ou SAIMA 3
- Ajout d'OFs — Numéro d'OF, recherche dans le catalogue peintures (auto-complete)
- Champs par OF — Numéro OF, fournisseur, type/couleur peinture, type (P/F/V), quantité (g), n° fiche
- Création GROF — Génère un ID unique
G + 6 chiffres, statut initial EN COURS, step 0
🔧 Poste Préparation (poste_prepa.html)
- Steps affichés — 0 (Alignement F1), 4 (Retournement F2), 8 (Prépa Fin F1), 12 (Prépa Fin F2)
- Action — Bouton « Valider » pour avancer au step suivant
- Log — Enregistre l'opérateur, l'horodatage et les éventuelles notes
🧪 Prépa Labo Peinture (labo_peinture.html)
- Vue par cabine — Onglets SAIMA 1/2/3 avec compteurs de GROFs en attente
- Fiches techniques — Clic sur un OF pour afficher la fiche de préparation peinture complète (proportions, durcisseur, diluant, durée de vie, conditions d'application)
- Checkpoint — Cocher chaque OF pour confirmer la préparation
- Envoi en peinture — Bouton actif uniquement quand tous les OFs sont cochés. Passe le GROF en
paintReady = true
🎨 Poste Peinture (poste_cabine.html)
- Steps peinture — 1 (Prim F1), 5 (Prim F2), 9 (Fin F1), 13 (Fin F2)
- Steps désolvatation — 2 (Desol Prim F1), 6 (Desol Prim F2), 10 (Desol Fin F1), 14 (Desol Fin F2)
- Timer Flash-Off — Démarre automatiquement après validation de la peinture
- Saisie — Température (°C), Hygrométrie (%), Notes libres
🔥 Poste Étuve (poste_etuve.html)
- Steps — 3 (Étuve Prim F1), 7 (Étuve Prim F2), 11 (Étuve Fin F1), 15 (Étuve Fin F2)
- Saisie — Température, durée de cuisson, humidité
- Fin de gamme — Le step 15 termine le GROF → statut
TERMINÉ
📊 Supervision Live (supervision_live.html)
- Vue synthétique — Tous les GROFs
EN COURS avec step courant et cabine
- Couleurs — Indicateurs visuels par type d'étape
- Reset — Bouton admin uniquement pour réinitialiser toute la production
📄 Traçabilité & Archives (tracabilite.html)
- Historique — Liste des GROFs terminés avec détails complets
- Logs — Timeline de chaque étape (opérateur, heure, durée, T°C, humidité)
- Export FORM-589 — Impression PDF de la fiche de traçabilité conforme au formulaire qualité
⚙️ Gestion des Accès (admin_access.html)
- Matrice checkbox — Rôles (colonnes) × Écrans (lignes)
- Admin only — Seul le rôle
admin peut modifier les permissions
- Effet immédiat — Les changements s'appliquent au prochain chargement de page
6. Utilisateurs & Rôles
👥 Les 5 rôles
| Rôle | Description | Écrans par défaut |
| admin |
Administrateur système — accès total |
Tous les écrans + Gestion des accès |
| responsable |
Responsable peinture — supervision complète |
Lancement, Prépa, Labo, Peinture, Étuve, Supervision, Traçabilité |
| peintre |
Opérateur cabine de peinture |
Prépa, Peinture, Étuve |
| labo |
Opérateur laboratoire peinture |
Lancement, Labo Peinture |
| qualite |
Contrôleur qualité |
Supervision, Traçabilité |
🔐 Utilisateurs par défaut
| Code | Nom | Rôle | Mot de passe |
ADMIN | Administrateur | admin | admin2026 |
RESP01 | Responsable Peinture | responsable | resp2026 |
PEINT1 | Peintre 1 | peintre | 1234 |
PEINT2 | Peintre 2 | peintre | 1234 |
LABO01 | Opérateur Labo | labo | 1234 |
QUAL01 | Contrôleur Qualité | qualite | qual2026 |
7. Base de données
📐 Schéma relationnel — 6 tables
Table users
| Colonne | Type | Contrainte | Description |
id | SERIAL | PRIMARY KEY | Identifiant auto-incrémenté |
code | VARCHAR(20) | UNIQUE NOT NULL | Code badge / matricule (ex: PEINT1) |
name | VARCHAR(100) | NOT NULL | Nom complet de l'utilisateur |
role | VARCHAR(20) | CHECK (peintre, labo, responsable, qualite, admin) | Rôle fonctionnel |
password_hash | VARCHAR(255) | NOT NULL | Hash bcrypt du mot de passe |
active | BOOLEAN | DEFAULT TRUE | Compte actif/désactivé |
created_at | TIMESTAMPTZ | DEFAULT NOW() | Date de création du compte |
Table screen_permissions
| Colonne | Type | Contrainte | Description |
role | VARCHAR(20) | PK (composite) | Rôle utilisateur |
screen | VARCHAR(50) | PK (composite) | Identifiant de l'écran (ex: poste_cabine) |
allowed | BOOLEAN | DEFAULT TRUE | Accès autorisé ou non |
Table paints — Catalogue peintures (152 fiches)
| Colonne | Type | Contrainte | Description |
id | SERIAL | PRIMARY KEY | Identifiant interne |
fournisseur | VARCHAR(100) | NOT NULL | Fournisseur (AKZO, PPG, MAPAERO, etc.) |
type_et_couleur | VARCHAR(255) | NOT NULL | Désignation complète (ex: "Finition Polyuréthane gris bac 707") |
type_peinture | VARCHAR(5) | DEFAULT '' | P = Primaire, F = Finition, V = Vernis, A = Apprêt |
fiche_num | INTEGER | UNIQUE NOT NULL | Numéro de fiche technique (1-152) |
indice | VARCHAR(10) | DEFAULT '/' | Indice de révision de la fiche |
Table grofs — Lots de production
| Colonne | Type | Contrainte | Description |
id | VARCHAR(20) | PRIMARY KEY | Identifiant GROF (ex: G847291) |
cabine | VARCHAR(20) | NOT NULL | Cabine assignée : SAIMA 1, SAIMA 2 ou SAIMA 3 |
current_step | INTEGER | DEFAULT 0 | Étape courante (0 à 15, >15 = terminé) |
status | VARCHAR(20) | CHECK (EN COURS, TERMINÉ, ANNULÉ) | Statut global du lot |
paint_ready | BOOLEAN | DEFAULT FALSE | Préparation labo validée (tous OFs cochés) |
flash_off_start | TIMESTAMPTZ | NULLABLE | Heure de début du timer de désolvatation |
created_by | INTEGER | FK → users(id) | Utilisateur ayant créé le GROF |
created_at | TIMESTAMPTZ | DEFAULT NOW() | Date de création |
updated_at | TIMESTAMPTZ | DEFAULT NOW() | Dernière modification |
Table grof_ofs — OFs rattachés à un GROF
| Colonne | Type | Contrainte | Description |
id | SERIAL | PRIMARY KEY | ID interne |
grof_id | VARCHAR(20) | FK → grofs(id) CASCADE | GROF parent |
of_number | VARCHAR(50) | UNIQUE(grof_id, of_number) | Numéro d'ordre de fabrication |
paint_id | INTEGER | FK → paints(id) | Référence peinture du catalogue |
quantity | VARCHAR(20) | NULLABLE | Quantité de peinture en grammes |
fournisseur | VARCHAR(100) | NULLABLE | Fournisseur peinture (copie dénormalisée) |
type_peinture | VARCHAR(5) | NULLABLE | Type de peinture (P/F/V/A) |
paint_label | VARCHAR(255) | NULLABLE | Désignation peinture (copie dénormalisée) |
Table grof_logs — Journal de traçabilité
| Colonne | Type | Contrainte | Description |
id | SERIAL | PRIMARY KEY | ID interne |
grof_id | VARCHAR(20) | FK → grofs(id) CASCADE | GROF concerné |
step | INTEGER | NOT NULL | Numéro d'étape (0-15) |
step_name | VARCHAR(100) | NULLABLE | Nom de l'étape (ex: "Peinture Primaire F1") |
type | VARCHAR(20) | DEFAULT 'PAINT' | Type : PAINT, DESOL, PREPA, ETUVE |
operator_id | INTEGER | FK → users(id) | Opérateur ayant validé l'étape |
started_at | TIMESTAMPTZ | NULLABLE | Début de l'opération |
ended_at | TIMESTAMPTZ | NULLABLE | Fin de l'opération |
duration | VARCHAR(20) | NULLABLE | Durée de l'opération (format libre) |
temp | VARCHAR(10) | NULLABLE | Température relevée (°C) |
humidity | VARCHAR(10) | NULLABLE | Hygrométrie relevée (%) |
notes | TEXT | NULLABLE | Observations libres de l'opérateur |
created_at | TIMESTAMPTZ | DEFAULT NOW() | Horodatage de l'enregistrement |
8. API REST
🔑 Authentification (/api/auth)
| Méthode | Route | Auth | Description |
| POST | /api/auth/login | ❌ | Connexion — retourne JWT + user |
| GET | /api/auth/me | ✅ | Info utilisateur courant |
| GET | /api/auth/users | 🔒 admin | Liste tous les utilisateurs |
| POST | /api/auth/users | 🔒 admin | Créer un utilisateur |
| GET | /api/auth/permissions | ✅ | Écrans autorisés pour le rôle courant |
| GET | /api/auth/permissions/all | 🔒 admin | Matrice complète (tous rôles × écrans) |
| PUT | /api/auth/permissions | 🔒 admin | Modifier les permissions d'un rôle |
📦 GROFs (/api/grofs)
| Méthode | Route | Description | Query Params |
| GET | /api/grofs | Liste des GROFs | status, step, steps, cabine |
| GET | /api/grofs/:id | Détail d'un GROF | — |
| POST | /api/grofs | Créer un GROF | Body: cabine, ofsDetails[] |
| PATCH | /api/grofs/:id/step | Avancer/modifier le step | Body: action (next, set, flash_off_start, flash_off_end) |
| PATCH | /api/grofs/:id/paint-ready | Valider prépa labo | Body: paintReady (boolean) |
| GET | /api/grofs/:id/logs | Logs de traçabilité | — |
| DELETE | /api/grofs/:id | Supprimer un GROF | admin/responsable |
| DELETE | /api/grofs | Reset total | admin only |
🎨 Peintures (/api/paints)
| Méthode | Route | Description |
| GET | /api/paints?q=&limit= | Recherche peintures (autocomplete) |
| GET | /api/paints/all | Catalogue complet |
❤️ Santé
| Méthode | Route | Description |
| GET | /api/health | Statut serveur — {"status":"ok"} |
9. Sécurité & Authentification
🔒 Mécanisme JWT
- Login —
POST /api/auth/login → retourne un token JWT signé
- Durée — Token valide 12 heures, stocké en
sessionStorage
- Transfert — Header
Authorization: Bearer <token> sur chaque requête API
- Expiration — L'API retourne
401, le frontend redirige vers le login
🔑 Mot de passe
- Hashés avec
bcrypt (10 rounds de salage)
- Jamais stockés en clair dans la base
- Comparaison sécurisée via
bcrypt.compare()
🛡️ RBAC (contrôle d'accès par rôle)
- Côté API — Middleware
requireRole('admin') pour les routes sensibles
- Côté Frontend —
MES_API.checkAccess('screenName') à l'ouverture de chaque page
- Portail — Cartes masquées pour les écrans non autorisés via
getPermissions()
10. Déploiement
🐳 Docker Compose
# Démarrer l'application
docker compose up -d --build
# Seed la base de données
docker compose exec app node db/seed.js
# Voir les logs
docker compose logs -f app
# Redémarrer
docker compose restart app
📍 Infrastructure VPS
| Paramètre | Valeur |
| Serveur | VPS OVH — 151.80.61.38 |
| OS | Ubuntu 25.04 |
| SSH | Port 49222 (clé SSH) |
| Container App | mes-fgam-app → port 3002 |
| Container DB | mes-fgam-db → port 5432 (interne) |
| Volume | mes-fgam_pgdata (données PostgreSQL persistées) |
| Nginx | mes-fgam.aerolean-supply.com → localhost:3002 |
Mise à jour : Depuis votre Mac, exécutez :
rsync -avz --exclude='node_modules' --exclude='.git' --exclude='.env' -e 'ssh -p 49222' ./ ubuntu@151.80.61.38:~/MES-FGAM/
puis ssh -p 49222 ubuntu@151.80.61.38 'cd ~/MES-FGAM && docker compose up -d --build app'
11. Glossaire
| Terme | Définition |
| GROF | GROupement de Fabrication — lot regroupant plusieurs OFs pour traitement en cabine |
| OF | Ordre de Fabrication — commande de peinture pour une pièce spécifique |
| SAIMA | Nom des cabines de peinture (marque d'équipement). 3 cabines : SAIMA 1, 2, 3 |
| Flash-Off / Désolvatation | Temps de repos obligatoire entre l'application de peinture et le passage en étuve |
| Primaire | Première couche de peinture (accroche, protection anti-corrosion) |
| Finition | Couche finale de peinture (couleur, aspect, protection UV) |
| F1 / F2 | Face 1 et Face 2 de la pièce — chaque face reçoit le cycle complet |
| FORM-589 | Formulaire qualité de traçabilité peinture (document de référence) |
| LIS-098 | Liste des fiches techniques de préparation peinture (152 fiches) |
| JWT | JSON Web Token — jeton d'authentification signé |
| RBAC | Role-Based Access Control — contrôle d'accès par rôle |
| MES | Manufacturing Execution System — système de pilotage de production |