RADAR & ELECTRONIC WARFARE — DOCUMENTATION TECHNIQUE

Déploiement, maintenance et extension

Ce document décrit l'architecture de la plateforme, son déploiement sur Apache, sa maintenance et les procédures d'extension : contenu, langue, module, formation et passage à un backend.

1. Architecture générale

La plateforme est une application web entièrement statique. Aucun processus serveur ne lui est nécessaire : Apache sert des fichiers, le navigateur fait le reste.

2. Arborescence des fichiers

index.html                  point d'entrée unique, à la racine du site
.htaccess                   compression, cache, en-têtes de sécurité, MIME
robots.txt / sitemap.xml    référencement
assets/
  css/     tokens.css base.css layout.css components.css pages.css viz.css
  js/
    app.js                  amorçage et déclaration des routes
    core/                   router, i18n, theme, store, dataService, utils
    components/             header, blocks, search, quiz
    pages/                  une page par route
    viz/                    plot.js + registre + implémentations
  i18n/    fr.json en.json  dictionnaires d'interface
  icons/   favicon.svg og-image.svg
  fonts/                    polices auto-hébergées (facultatif)
  images/
data/                       contenu : modules, parcours, glossaire, quiz, fiches
downloads/                  guides HTML imprimables et PDF
docs/                       ce document
config/  manifest.webmanifest
components/ modules/ pages/ points d'extension réservés (voir README)

3. Installation

Copier le contenu du dossier dans la racine web d'Apache. Sur Debian ou Ubuntu :

sudo apt install apache2
sudo rsync -a --delete ./site/ /var/www/html/
sudo chown -R www-data:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
sudo service apache2 start        # ou : sudo systemctl enable --now apache2

Vérification immédiate : curl -I http://localhost/ doit répondre 200 et curl -s http://localhost/data/radar.json | head doit renvoyer du JSON. Si le JSON est servi en text/plain, le module mod_mime ou le .htaccess n'est pas pris en compte.

4. Configuration d'Apache

Le fichier .htaccess fourni suffit, à condition qu'Apache l'autorise. Activer les modules utiles puis permettre les surcharges :

sudo a2enmod deflate expires headers rewrite mime
sudo nano /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
    ServerName radar-ew.exemple.fr
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All          # indispensable pour .htaccess
        Require all granted
    </Directory>

    ErrorLog  ${APACHE_LOG_DIR}/radar-ew-error.log
    CustomLog ${APACHE_LOG_DIR}/radar-ew-access.log combined
</VirtualHost>
sudo apache2ctl configtest
sudo service apache2 reload

En production, recopier le contenu du .htaccess directement dans le bloc <Directory> et passer AllowOverride None : Apache évite ainsi de relire le fichier à chaque requête.

5. Accès par adresse IP ou nom de domaine

Aucune adaptation n'est nécessaire. Tous les chemins du projet sont relatifs et le routage passe par le fragment d'URL :

ContexteURLAction
Adresse IPhttp://192.0.2.10/aucune
Sous-dossierhttp://192.0.2.10/radar/aucune : les chemins sont résolus sur document.baseURI
Nom de domainehttps://radar-ew.exemple.fr/enregistrement DNS de type A vers l'IP, puis ServerName dans le VirtualHost

6. Mise en place de HTTPS

sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d radar-ew.exemple.fr
sudo systemctl status certbot.timer      # renouvellement automatique

Une fois le certificat validé et le site accessible en HTTPS, décommenter la ligne Strict-Transport-Security du .htaccess. La politique de sécurité du contenu fournie n'autorise que les ressources du site lui-même ; si vous ajoutez une ressource externe, elle devra être déclarée explicitement.

7. Maintenance courante

8. Ajouter du contenu

Un module de connaissance est un objet du tableau modules dans data/radar.json, data/electronic_warfare.json ou data/modeling.json :

{
  "id": "mon-module",
  "cat": "radar",                       radar | ew | modeling
  "levels": ["manager", "expert"],
  "duration": 25,
  "tags": ["antenne", "gain"],
  "title":   { "fr": "...", "en": "..." },
  "summary": { "fr": "...", "en": "..." },
  "source":  { "ref": "eGuide p. 12", "doc": "eguide" },
  "blocks": [
    { "type": "p",    "fr": "...", "en": "..." },
    { "type": "list", "label": {...}, "fr": ["..."], "en": ["..."] },
    { "type": "eq",   "label": {...}, "html": "...", "vars": [{ "s": "G", "fr": "...", "en": "..." }] },
    { "type": "table","head": { "fr": [...], "en": [...] }, "rows": [[...]] },
    { "type": "note" | "example" | "complement", "fr": "...", "en": "..." },
    { "type": "viz",  "viz": "antenna-pattern" }
  ]
}

Types de blocs disponibles : p, list, steps, eq, table, note, example, complement, viz. Le bloc complement est réservé aux apports qui ne proviennent pas des documents sources ; il est affiché comme tel. Le module devient immédiatement visible dans la recherche et le glossaire des tags ; pour l'inscrire dans un parcours, ajouter son identifiant aux units du chapitre voulu.

9. Ajouter une langue

  1. Copier assets/i18n/fr.json en assets/i18n/es.json et traduire les valeurs, sans toucher aux clés.
  2. Déclarer la langue dans assets/js/core/i18n.js : AVAILABLE = [{ code: 'fr', ... }, { code: 'en', ... }, { code: 'es', label: 'Español' }].
  3. Ajouter la clé correspondante dans les objets de contenu des fichiers /data ({ "fr": ..., "en": ..., "es": ... }). En son absence, la fonction pick() retombe automatiquement sur le français : le site reste fonctionnel pendant la traduction.

Le bouton de langue de l'en-tête parcourt la liste AVAILABLE ; aucune autre modification n'est nécessaire.

10. Ajouter un module de visualisation

  1. Écrire une fabrique dans un fichier de assets/js/viz/ en utilisant le cadre commun :
    import { vizFrame } from './plot.js';
    
    export function monOutil() {
      return vizFrame({
        id: 'mon-outil',
        title:   { fr: '...', en: '...' },
        caption: { fr: '...', en: '...' },
        controls: [
          { key: 'gain', label: { fr: 'Gain', en: 'Gain' }, min: 0, max: 40, step: 1, value: 20, unit: 'dB' }
        ],
        draw(p, plot) {
          const points = [];                       // calcul réel
          plot.setRange({ xMin: 0, xMax: 10, yMin: -40, yMax: 10 })
              .clear().axes({ xLabel: 'x', yLabel: 'dB' }).line(points);
          return [{ label: { fr: 'Résultat', en: 'Result' }, value: '…' }];
        }
      });
    }
    
  2. L'inscrire dans assets/js/viz/index.js (titre, description, catégorie, module lié, import dynamique).
  3. La référencer depuis un module de contenu avec un bloc { "type": "viz", "viz": "mon-outil" }. Elle apparaît alors dans la galerie et dans le module, sans autre intervention.

11. Ajouter un parcours de formation

  1. Créer data/analyste.json sur le modèle de data/operator.json : id, code, title, tagline, description, prerequisites, objectives, chapters[{ title, units[] }], quizzes[].
  2. Déclarer le fichier dans ENDPOINTS puis dans getPaths() (assets/js/core/dataService.js).
  3. Ajouter les quiz correspondants dans data/quiz.json avec le champ level égal à l'identifiant du parcours.
  4. Compléter les libellés common.<id> et docs.guide<Id> dans les dictionnaires i18n, ainsi que la couleur de niveau dans components.css (.path-card[data-level="analyste"]).
  5. Régénérer les guides : ajouter l'entrée dans TITLES de generate_guides.py.

12. Passer à un backend

Deux modules concentrent tous les accès externes ; aucune page ne connaît le format de transport.

BesoinFichier à modifierNature du changement
Contenu servi par une API REST core/dataService.js Remplacer les chemins de ENDPOINTS par des URL d'API et, si besoin, ajouter l'authentification dans request(). Les fonctions exposées (getModules, getPaths…) conservent leur signature.
Progression synchronisée entre appareils core/store.js Remplacer read() et write() par des appels réseau et rendre asynchrones les fonctions exportées ; les appelants utilisent déjà des accesseurs, pas localStorage directement.
Recherche côté serveur components/search.js Remplacer search() par un appel à l'index distant en respectant la forme de retour { modules, glossary, sheets, total }.

Si un backend est introduit, ajuster la directive Content-Security-Policy du .htaccess : la valeur actuelle connect-src 'self' interdit tout appel vers un autre domaine.

Radar & Electronic Warfare — documentation de déploiement. Contenu technique de la plateforme issu des deux documents sources cités dans les guides.