SPB Git forge

spb/uqo-imm1033

Public
5commits 1branches 0releases
30.2 MBsize
maindefault branch
38 min agolast push
JavaScript 68% CSS 32%
28.1 KB · 440 lines markdown
Rendered Raw Blame History
1# uqo-imm1033 — Méthodes du coût en évaluation immobilière23> **Notes de cours interactives du cours IMM1033 (IMM1033-20, Hiver 2026) de l'Université du Québec en Outaouais (UQO).**4> Site statique généré à partir des sources LaTeX du manuel, servi par le cluster MacLustr.56| | |7|---|---|8| **Site public** | https://www.uqo-imm1033.app |9| **Cours** | IMM1033 — Méthodes du coût en évaluation immobilière · 3 crédits · premier cycle · 14 séances |10| **Trimestre** | Hiver 2026 |11| **Cours jumeau** | IMM1003 — Éléments d’évaluation immobilière · https://www.uqo-imm1003.app |12| **App `mld`** | `uqo-imm1033` · port `8161` · nœud actuel : voir `mld status` (au 2026-09-06 : **M3U96a**) |13| **Processus PM2** | `uqo-imm1033` (Node, `server.mjs`) · `uqo-imm1033-ngrok` (tunnel `www.uqo-imm1033.app`) |14| **Santé** | `GET /api/health` → `{"ok":true,"started":…,"root":…,"uptime":…}` |15| **Dépôt** | `gitsrv:~/srv/git/uqo-imm1033.git` (spbgit, git.spboucher.ai) |16| **Auteur / contact** | **Simon-Pierre Boucher** — contact@spboucher.ai |17| **Version publiée** | v2 « refonte majeure » — build du 2026-09-24 14:23:05, déployée le 2026-09-05 23:37 |1819---2021## Sommaire22231. [Présentation](#1-présentation)242. [Ce que contient le site](#2-ce-que-contient-le-site)253. [Fonctionnalités interactives](#3-fonctionnalités-interactives)264. [Structure du cours publiée](#4-structure-du-cours-publiée)275. [Contenu du dépôt](#5-contenu-du-dépôt)286. [Arborescence du site généré (`dist/`)](#6-arborescence-du-site-généré-dist)297. [Le serveur `server.mjs`](#7-le-serveur-servermjs)308. [Chaîne de génération LaTeX → HTML](#8-chaîne-de-génération-latex--html)319. [Déploiement sur le cluster MacLustr (`mld`)](#9-déploiement-sur-le-cluster-maclustr-mld)3210. [Exploitation au quotidien](#10-exploitation-au-quotidien)3311. [Mettre à jour le contenu](#11-mettre-à-jour-le-contenu)3412. [Données personnelles, sécurité, performance](#12-données-personnelles-sécurité-performance)3513. [Identité visuelle](#13-identité-visuelle)3614. [Historique](#14-historique)3715. [Droits et licence](#15-droits-et-licence)3816. [Contact](#16-contact)3940---4142## 1. Présentation4344`uqo-imm1033` est la version web, interactive et « mobile-first » des notes de cours de **IMM1033 — Méthodes du coût en évaluation immobilière**45(IMM1033-20, Hiver 2026, 3 crédits · premier cycle · 14 séances), enseigné à l'UQO par Simon-Pierre Boucher.4647La méthode du coût en évaluation immobilière : évaluation du terrain, coût de reproduction et de remplacement, estimation des coûts de construction et ventilation complète de la dépréciation.4849Le site n'est **pas** une application avec base de données : c'est un **site statique** (HTML, CSS, JavaScript,50JSON, SVG, PDF) produit par un générateur maison à partir des **sources LaTeX** du manuel (`uqo-notes.sty`) et du51rapport *Le marché de l'habitation au Québec*. Toute l'interactivité (quiz, entraînement, jeux, progression, notes,52recherche, synthèse vocale, explorateurs) s'exécute **dans le navigateur** ; la progression est conservée53localement (`localStorage`) et exportable en JSON. Aucun compte, aucune collecte côté serveur.5455Le rendu est optimisé pour le téléphone (375 px) autant que pour l'ordinateur, installable comme PWA56(`manifest.webmanifest`, icônes 192/512), et indexable (`sitemap.xml`, `robots.txt`, balises Open Graph).5758**Source de vérité du contenu = les fichiers `.tex`** du dépôt de cours `UQO_COURS`. On ne modifie jamais le HTML59généré à la main : on modifie le LaTeX, on reconstruit, on redéploie (voir §11).6061## 2. Ce que contient le site6263Statistiques du build publié (`dist/data/meta.json`, build `2026-09-24 14:23:05`) :6465| Indicateur | Valeur |66|---|---|67| Séances (chapitres) | 14 |68| Mots de notes | 113 574 |69| Définitions | 64 |70| Formules encadrées | 43 |71| Exemples résolus | 96 |72| Exercices | 89 |73| Figures (TikZ → SVG, PDF → SVG) | 64 |74| Questions de quiz (14 chapitres) | 103 |75| Entrées de glossaire | 67 |76| Fiches recto-verso | 174 |77| Explorateurs interactifs insérés dans les séances | 9 |78| Générateurs de problèmes d'entraînement | 13 |79| Séquences (jeu de remise en ordre) | 6 |80| Entrées de l'index de recherche plein texte | 2 587 |81| Diapositives (PDF, une par séance) | 14 |82| Travaux pratiques publiés (énoncé PDF + gabarit Excel) | 3 |83| Rapport marché de l'habitation | 21 sections · 67 figures SVG · 28 tableaux |84| Fichiers dans `dist/` | 481 (≈ 454 Mo) |8586**Publié** : notes intégrales des 14 séances, annexes, bibliographie, plan de cours (PDF), notes complètes (PDF),87diapositives (PDF), énoncés des TP et gabarits Excel, rapport marché (HTML + PDF + données HPI ACI xlsx + script88Python d'analyse).8990**Jamais publié** (règle absolue du projet) : solutionnaires des TP, questionnaires d'examen, grilles de correction.91Le générateur ne les copie pas ; ne pas les ajouter à la main dans `dist/`.9293## 3. Fonctionnalités interactives9495### 3.1 Séances (`/seance/01` … `/seance/14`)96- Notes intégrales converties depuis LaTeX : boîtes pédagogiques (définition, formule, exemple, exercice, attention,97  à retenir), **notes marginales** façon Tufte, mathématiques **KaTeX** pré-rendues au build, tableaux, figures98  **TikZ** rendues en SVG, références auteur-année (`references.bib`).99- **Stepper de sections** (précédent / suivant), sommaire latéral avec sections déjà lues, **objectifs cochables**,100  **mode révision** (masque les exemples, met en avant définitions et formules).101- **Explorateurs SVG** insérés à la fin de la première sous-section ciblée (9 par cours, voir §4) : curseurs et102  graphiques recalculés en direct.103- **Surlignage + notes personnelles** (sélection de texte → surligner / annoter ; export Markdown), **lecture audio**104  (synthèse vocale du navigateur, section par section), **quiz de fin de séance** intégré.105- Infobulles de glossaire sur les termes définis.106107### 3.2 Réviser108- `/aide-memoire` : toutes les formules et règles clés par séance.109- `/glossaire` et `/definitions` : glossaire alphabétique, définitions intégrales avec lien vers la séance.110- `/fiches` : fiches recto-verso (question / réponse) mélangeables, filtrables par séance.111- `/carte` : **carte du cours** (SVG radial : parties → séances → objectifs).112- `/exercices` : banque de tous les exercices avec lien vers le contexte.113114### 3.3 S'exercer115- `/quiz` : quiz par séance ou **examen blanc** (tirage aléatoire multi-séances, correction commentée, score).116- `/entrainement` : **problèmes à données aléatoires** (13 générateurs, `data/entrainement.js`) avec solution117  détaillée recalculée à chaque tirage.118- `/jeux` : association (terme ↔ définition), vrai / faux, **remise en ordre** (6 séquences du cours).119- `/outils` : calculateurs spécialisés (`data/outils.js`).120- `/progression` : tableau de bord (séances lues, objectifs cochés, quiz réussis, fiches maîtrisées) ;121  **export / import JSON** pour changer d'appareil.122123### 3.4 Ressources124- `/diapositives` : 14 PDF (`files/slides/`), `/ressources` : téléchargements (plan, notes PDF, TP, gabarits).125- `/rapport` : rapport *Le marché de l'habitation au Québec* en 21 sections HTML (`rapport/0` … `rapport/15`,126  annexes `A` … `F`), 67 figures SVG, 28 tableaux, valeurs clés, **explorateurs HPI ACI** (`data/hpi.json`) et127  **FRED** (`data/fred.json`), PDF complet et données sources dans `files/rapport/`.128- `/bibliographie` : bibliographie fusionnée du manuel et du rapport.129- `/recherche` : recherche plein texte côté client (`data/search.json`, 2 587 entrées).130131### 3.5 Transversal132- Thème clair UQO par défaut, thème sombre, taille de texte réglable, navigation clavier.133- PWA installable, `404.html` personnalisée, redirections propres (`/glossaire` → `/glossaire/`).134135## 4. Structure du cours publiée136137**Parties et séances**138139| Partie | Titre | Séances |140|---|---|---|141| I | Fondements de la méthode du coût | 1 — Introduction à la méthode du coût · 2 — Cadre conceptuel et terminologie |142| II | Évaluation du terrain | 3 — Méthodes d'évaluation du terrain · 4 — Analyse du terrain et ajustements |143| III | Coût de construction | 5 — Coût de reproduction et coût de remplacement · 6 — Méthodes d'estimation des coûts · 7 — Coûts directs de construction · 8 — Coûts indirects et profit entrepreneurial |144| IV | La dépréciation | 9 — Concepts de dépréciation · 10 — Dépréciation physique · 11 — Dépréciation fonctionnelle · 12 — Dépréciation économique (externe) |145| V | Applications et intégration | 13 — Applications spécialisées · 14 — Synthèse et révision |146147**Évaluations affichées sur le site** (la pondération et le calendrier viennent de `courses.py`) :148149| Évaluation | Portée / format | Pondération | Échéance |150|---|---|---|---|151| TP1 — Évaluation d’un terrain vacant avec UQO Éval (46, rue Michaud, Saint-Rosaire) | Données réelles d’UQO Éval · grille $/m² + note à l’acheteur | 10 % | Séance 5 |152| TP2 — Bordereau de coût de remplacement neuf (quadruplex locatif) | Bordereau chaîné (Excel) | 15 % | Séance 9 |153| Examen intra | Séances 1 à 8 · maison, fenêtre de 72 h | 25 % | Séance 9 |154| TP3 — Ventilation complète de la dépréciation (atelier-entrepôt, Hull) | Ventilation anti-double-comptage (Excel) | 20 % | Séance 13 |155| Examen final | Accent dépréciation et intégration · maison, 72 h | 30 % | Période d’examens |156157**Travaux pratiques publiés** (`files/tp/`) :158159| TP | Pondération | Remise | Fichiers publiés | Description |160|---|---|---|---|---|161| TP1 — Évaluation d’un terrain avec UQO Éval | 10 % | Séance 5 | `files/tp/IMM1033-20_TP1_enonce.pdf`, `files/tp/IMM1033-20_TP1_gabarit.xlsx` | Terrain réel à vendre au 46, rue Michaud (Saint-Rosaire) : neuf ventes réelles de terrains vacants, tendance du marché foncier par le ratio prix/rôle, grille $/m² (temps, superficie, Harper, équité du rôle), contrôle par affectation et rôle indexé, zones inondables 2026 ; gabarit Excel avec suivi de progression. |162| TP2 — Bordereau de coût neuf | 15 % | Séance 9 | `files/tp/IMM1033-20_TP2_enonce.pdf`, `files/tp/IMM1033-20_TP2_gabarit.xlsx` | Quadruplex locatif de Gatineau : coûts directs, indirects, profit ; validation avec les guides de coûts. |163| TP3 — Ventilation de la dépréciation | 20 % | Séance 13 | `files/tp/IMM1033-20_TP3_enonce.pdf`, `files/tp/IMM1033-20_TP3_gabarit.xlsx` | Atelier-entrepôt de Hull : physique (curable, CT, LT), fonctionnelle, externe ; garde-fous anti-double-comptage. |164165**Explorateurs interactifs** (widget → emplacement dans la séance) :166167| Widget | Inséré dans | Séance |168|---|---|---|169| `cascade-cout` | `#s-2-3` | 2 — Cadre conceptuel et terminologie |170| `hbu` | `#s-3-1` | 3 — Méthodes d'évaluation du terrain |171| `harper` | `#s-4-2` | 4 — Analyse du terrain et ajustements |172| `indexation` | `#s-5-5` | 5 — Coût de reproduction et coût de remplacement |173| `cascade-cout` | `#s-8-7` | 8 — Coûts indirects et profit entrepreneurial |174| `age-vie` | `#s-9-4` | 9 — Concepts de dépréciation |175| `ventilation` | `#s-10-3` | 10 — Dépréciation physique |176| `allocation` | `#s-12-6` | 12 — Dépréciation économique (externe) |177| `bail-vie` | `#s-13-8` | 13 — Applications spécialisées |178179**Séquences du jeu de remise en ordre** :180181- **L’ordre de ventilation de la dépréciation** (5 étapes) → `/seance/13/#s-13-10`182- **Les quatre critères du PHMU** (4 étapes) → `/seance/03/#s-3-1`183- **Le processus de la méthode du coût en cinq étapes** (5 étapes) → `/seance/14/#s-14-1`184- **L’assemblage du coût neuf** (5 étapes) → `/seance/08/#s-8-7`185- **La hiérarchie normative de l’aménagement** (4 étapes) → `/seance/04/#s-4-3`186- **Les huit étapes de l’estimation du coût neuf** (8 étapes) → `/seance/05/#s-5-8`187188## 5. Contenu du dépôt189190```191uqo-imm1033/192├── README.md                 ← ce document193├── server.mjs                ← serveur statique Node ≥ 20, zéro dépendance (déployé tel quel)194├── package.json              ← {"start": "node server.mjs"} (aucune dépendance npm)195├── dist/                     ← LE SITE GÉNÉRÉ, identique octet pour octet à ce qui tourne sur le nœud196├── deploy/197│   └── uqo-imm1033.manifest.json   ← copie du manifeste mld (M1M32:~/dispatch/apps/uqo-imm1033.json) — sans secret198└── generator/                ← instantané du générateur au moment du build (lecture seule, voir ci-dessous)199    ├── README.md             ← README du générateur (_Site_web)200    ├── package.json          ← dépendance KaTeX pour le rendu des maths au build201    ├── build/                ← build.py, latex2html.py, rapport.py, tikz.py, render_math.mjs, bib.py,202    │                            brand.py, templates.py, courses.py, test_convert.py203    ├── data/                 ← quiz-*.json, outils-*.js, entrainement-*.js (les deux cours)204    └── assets/               ← css/site.css, js/app.js, brand/ (logos UQO sources)205```206207⚠️ **`generator/` est un instantané.** Le générateur canonique vit dans le dépôt de cours208`UQO_COURS/_Site_web/` (GitHub `spboucher-ai/UQO_COURS`, dossier partagé par les deux cours). Il est copié ici pour209que le dépôt de l'app soit auto-suffisant et lisible, mais **toute modification doit se faire dans `UQO_COURS`**, puis210être reconstruite et resynchronisée (§11). Les sources LaTeX (`.tex`) ne sont **pas** dans ce dépôt : elles211contiennent aussi les solutionnaires et examens, qui ne doivent jamais sortir de `UQO_COURS`.212213Ce qui est volontairement exclu : `cache/` du générateur (SVG TikZ et figures rendues, régénérables),214`node_modules/`, `.DS_Store`.215216## 6. Arborescence du site généré (`dist/`)217218| Chemin | Fichiers | Taille | Rôle |219|---|---|---|---|220| `aide-memoire/` | 1 | 278 Ko | Aide-mémoire (formules et règles par séance) |221| `assets/` | 172 | 20 Mo | CSS, JS, polices, SVG des figures (TikZ + rapport), logos, icônes PWA, image OG |222| `bibliographie/` | 1 | 55 Ko | Bibliographie fusionnée manuel + rapport |223| `carte/` | 1 | 44 Ko | Carte du cours (SVG radial) |224| `data/` | 9 | 2 Mo | JSON/JS consommés par le client (quiz, fiches, glossaire, recherche, outils, entraînement, HPI, FRED, meta) |225| `definitions/` | 1 | 119 Ko | Toutes les définitions |226| `diapositives/` | 1 | 31 Ko | Liste des 14 PDF de diapositives |227| `entrainement/` | 1 | 25 Ko | Problèmes à données aléatoires |228| `exercices/` | 1 | 711 Ko | Banque d'exercices |229| `fiches/` | 1 | 26 Ko | Fiches recto-verso |230| `files/` | 27 | 21 Mo | PDF (notes, plan, diapositives, TP, rapport), gabarits xlsx, données HPI, script Python |231| `glossaire/` | 1 | 55 Ko | Glossaire alphabétique |232| `jeux/` | 1 | 27 Ko | Association, vrai/faux, remise en ordre |233| `outils/` | 1 | 25 Ko | Calculateurs |234| `progression/` | 1 | 26 Ko | Tableau de bord + export/import JSON |235| `quiz/` | 1 | 25 Ko | Quiz par séance + examen blanc |236| `rapport/` | 22 | 878 Ko | Rapport marché de l'habitation : 21 sections + annexes A–F |237| `recherche/` | 1 | 25 Ko | Recherche plein texte |238| `ressources/` | 1 | 39 Ko | Téléchargements |239| `seance/` | 14 | 4 Mo | Les 14 séances (`seance/01` … `seance/14`) |240| `videos/` | 215 | 404 Mo | Séances vidéo : enregistrements Zoom (mp4/m4a hors git), sous-titres VTT, transcription synchronisée, chapitres, storyboard |241| `index.html` | 1 | — | Accueil : héros, parties, calendrier, évaluations, accès rapides |242| `404.html` | 1 | — | Page introuvable (servie avec le statut 404) |243| `manifest.webmanifest` | 1 | — | PWA (`name`, `short_name`, icônes, `theme_color #0f6180`) |244| `sitemap.xml`, `robots.txt` | 2 | — | Indexation (`Allow: /`) |245| `favicon.ico`, `favicon.svg` | 2 | — | Icônes (générées par `brand.py`) |246247`dist/data/` en détail : `meta.json` (statistiques + chapitres), `quiz.json` (103 questions en 14 chapitres),248`cards.json` (174 fiches), `glossaire.json`, `search.json` (index plein texte), `outils.js`,249`entrainement.js`, `hpi.json` (indice HPI ACI mensuel, désaisonnalisé et brut), `fred.json` (séries FRED).250251`dist/files/` en détail : `IMM1033_notes_de_cours.pdf`, `IMM1033_plan_de_cours.pdf`, `slides/` (14 PDF),252`tp/` (3 énoncés PDF + 3 gabarits `.xlsx`), `rapport/` (`rapport_immobilier_quebec.pdf`,253`HPI_ACI_mensuel_desaisonnalise.xlsx`, `HPI_ACI_mensuel_non_desaisonnalise.xlsx`, `analyse_hpi_quebec.py`).254255## 7. Le serveur `server.mjs`256257Serveur HTTP statique en **Node.js pur** (`node:http`, `node:fs`, `node:zlib`), aucune dépendance npm, ≈ 170 lignes.258259```260node server.mjs <port> <dossier-dist>261# en production : node server.mjs 8161 /Users/simon-pierreboucher/apps/uqo-imm1033/dist262```263264Comportement :265266| Aspect | Détail |267|---|---|268| Méthodes | `GET` et `HEAD` seulement ; autres → `405` + `Allow: GET, HEAD` |269| Santé | `GET /api/health` → JSON `{ok, started, root, uptime}` avec `Cache-Control: no-store` (utilisé par `mld` et par le monitoring) |270| Résolution | `/x/` → `x/index.html` ; `/x` sans extension → redirection `301` vers `/x/` si `x/index.html` existe, sinon `x.html` |271| Sécurité chemin | `safeJoin` : normalisation, refus de sortie de la racine (`400`) |272| Types MIME | html, css, js/mjs, json, svg, png, jpg, webp, ico, pdf, xlsx, woff/woff2/ttf, txt, xml, webmanifest |273| Compression | **Brotli** (qualité 5) ou **gzip** (niveau 6) à la volée pour html/css/js/json/svg/txt/xml/webmanifest > 1 Ko, selon `Accept-Encoding` ; `Vary: Accept-Encoding` |274| Cache | `ETag` faible (taille + mtime) + `304` ; `Cache-Control: no-cache` pour HTML et JSON ; `public, max-age=86400, stale-while-revalidate=604800` sous `/assets/` et `/files/` ; `public, max-age=3600` ailleurs |275| Plages | `Range: bytes=…` → `206` / `416` (lecture partielle des PDF dans le navigateur) |276| En-têtes | `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`, `Accept-Ranges: bytes`, `Content-Security-Policy: frame-ancestors 'self'` sur le HTML |277| 404 | Sert `404.html` avec le statut 404 |278| Écoute | `0.0.0.0:<port>` (ngrok se connecte en local) ; journal de démarrage `[uqo-cours] port … · racine …` |279280Les SVG des figures matplotlib du rapport font ≈ 300 Ko chacun ; la compression Brotli/gzip les ramène à quelques281dizaines de Ko sur le fil.282283## 8. Chaîne de génération LaTeX → HTML284285Le pipeline (`generator/build/build.py`, ≈ 1 s par cours grâce aux caches) :2862871. **Lecture des métadonnées** (`courses.py`) : identité, parties et couleurs, calendrier, évaluations, TP à publier,288   widgets et séquences.2892. **Conversion LaTeX → HTML** (`latex2html.py`, ≈ 1 500 lignes) : dialecte `uqo-notes.sty` (boîtes, notes290   marginales, `\oe` avec avalement d'espace TeX, tableaux, listes, références croisées) et article du rapport.291   0 avertissement sur les 32 fichiers de séances + le rapport.2923. **TikZ → SVG** (`tikz.py`) : chaque `tikzpicture` est compilé en `standalone` avec `pdflatex`, converti par293   `pdftocairo`, mis en cache dans `cache/tikz/` (clé = hachage du source).2944. **Mathématiques** (`render_math.mjs`) : KaTeX exécuté en lot par Node au build → HTML statique, aucun JS295   mathématique côté client.2965. **Bibliographie** (`bib.py`) : `references.bib` → citations auteur-année + page `/bibliographie`.2976. **Rapport** (`rapport.py`) : découpage en 21 sections, tableaux `\input`, valeurs clés, figures PDF → SVG298   (`cache/rapport-fig/`), extraction HPI (xlsx → `hpi.json`) et FRED (json).2997. **Identité** (`brand.py`, Pillow + Fira Sans OTF de TeX Live) : logo UQO recoloré, favicons, `apple-touch-icon`,300   image Open Graph 1200 × 630 par cours.3018. **Gabarits** (`templates.py`) : accueil, séance, carte, rapport, jeux, entraînement, progression, recherche…3029. **Données** : `quiz-<code>.json`, `outils-<code>.js`, `entrainement-<code>.js` copiés dans `dist/data/`,303   index de recherche et fiches générés.30410. **Client** : `assets/css/site.css` (Fraunces / Source Serif 4 / Fira Sans, couleur par partie, mobile) et305    `assets/js/app.js` (recherche, quiz, fiches, widgets SVG, entraînement, jeux, progression, notes, TTS,306    explorateurs HPI/FRED).307308**Prérequis** : Python ≥ 3.12 (Pillow, openpyxl), Node ≥ 20 (`npm install` pour KaTeX), TeX Live (`pdflatex`,309FiraSans, fontawesome5, pgfplots), poppler (`pdftocairo`, `pdfinfo`).310311```bash312cd ~/Desktop/Academique/UQO/UQO_COURS/_Site_web313npm install                              # KaTeX, une fois314python3 build/build.py imm1033            # → dist/imm1033315node server/server.mjs 8161 dist/imm1033 # test local : http://localhost:8161316python3 build/test_convert.py            # test de conversion complet317```318319Pièges connus : Python 3.14 refuse `\"` dans les expressions de f-strings imbriquées (utiliser des variables320intermédiaires) ; un widget doit être inséré en fin de première sous-section, jamais dans une boîte ; `\oe` suivi321d'un espace doit avaler l'espace (sémantique TeX).322323## 9. Déploiement sur le cluster MacLustr (`mld`)324325L'app est orchestrée par **maclustr-dispatch (`mld`)** depuis la passerelle **M1M32** : elle choisit le nœud le plus326efficient, synchronise par rsync, démarre les processus PM2, ouvre le tunnel ngrok, vérifie la santé et met à jour327le registre (`M1M32:~/dispatch/registry.json`, copie laptop `~/Desktop/cluster-skill/cluster-registry.json`).328329Manifeste (`deploy/uqo-imm1033.manifest.json`, copie de `M1M32:~/dispatch/apps/uqo-imm1033.json`) :330331| Clé | Valeur |332|---|---|333| `domain` / `port` | `www.uqo-imm1033.app` / `8161` |334| `health_path` | `/api/health` |335| `requires.runtimes` | `ngrok`, `node`, `pm2` · `ram_gb: 1` · port `8161` libre |336| `processes[0]` | PM2 `uqo-imm1033` : `/opt/homebrew/bin/node server.mjs 8161 ~/apps/uqo-imm1033/dist`, `autorestart`, `max_memory_restart: 300M` (≈ 80 Mo observés) |337| `ngrok` | PM2 `uqo-imm1033-ngrok` → `https://www.uqo-imm1033.app` (CNAME chez le registraire → ngrok) |338| `placement` | libre (pas de `pin`), `source_node: laptop` |339| `sync_excludes` | `.DS_Store` |340341Procédure complète depuis le laptop :342343```bash344# 1. (re)construire le site345cd ~/Desktop/Academique/UQO/UQO_COURS/_Site_web && python3 build/build.py imm1033346347# 2. rafraîchir le dossier d'app (= ce dépôt) et versionner348rm -rf stage/uqo-imm1033/dist && cp -R dist/imm1033 stage/uqo-imm1033/dist349cd stage/uqo-imm1033 && git add -A && git commit -m "build $(date +%F)" && git push origin main350351# 3. laptop → passerelle M1M32 (staging), puis déploiement sur le nœud choisi par score352~/Desktop/cluster-skill/mld stage ~/Desktop/Academique/UQO/UQO_COURS/_Site_web/stage/uqo-imm1033 uqo-imm1033353~/Desktop/cluster-skill/mld deploy uqo-imm1033            # --node X pour imposer un nœud354355# 4. vérifier356~/Desktop/cluster-skill/mld status --live | grep uqo-imm1033357curl -s https://www.uqo-imm1033.app/api/health358```359360Autres commandes utiles : `mld move uqo-imm1033 --to <nœud>` (migration à chaud avec rollback), `mld plan uqo-imm1033`361(placement simulé), `mld apps` (manifestes). Le nœud n'a **pas** de dépôt git : c'est `mld` qui synchronise depuis le362staging de M1M32 ; ce dépôt spbgit est la référence versionnée de ce qui est déployé.363364## 10. Exploitation au quotidien365366```bash367NODE=$(~/Desktop/cluster-skill/mld status | awk '/uqo-imm1033 /{print $2}')   # ou lire mld status368ssh $NODE 'pm2 ls | grep uqo-imm1033; pm2 logs uqo-imm1033 --lines 50 --nostream'369ssh $NODE 'pm2 restart uqo-imm1033'                 # redémarrage du serveur Node370ssh $NODE 'pm2 restart uqo-imm1033-ngrok'           # tunnel371curl -sI https://www.uqo-imm1033.app/ | head -5           # 200 + en-têtes372curl -s  https://www.uqo-imm1033.app/api/health           # uptime373```374375- PM2 est configuré au démarrage (`pm2 startup`) sur tous les nœuds d'apps : l'app revient après un redémarrage.376- Le site est aussi surveillé par l'app MacLustr (macOS / iOS) via le registre `mld` (santé loopback + PM2).377- Emplacement disque sur le nœud : `~/apps/uqo-imm1033/` (`server.mjs`, `package.json`, `README.md`, `dist/`, ≈ 454 Mo).378- Si `mld status` montre `stale`/`offline` : `ssh <nœud> pm2 ls`, puis `mld deploy uqo-imm1033` (idempotent).379380## 11. Mettre à jour le contenu381382| Changement | Où | Puis |383|---|---|---|384| Texte, exemple, exercice, figure d'une séance | `.tex` dans `UQO_COURS/IMM1033-20_Methodes_du_cout/IMM1033_Notes_de_cours/sources/` | build → §9 |385| Question de quiz | `_Site_web/data/quiz-imm1033.json` (`q`, `c` choix, `a` index, `e` explication, `url`) | build → §9 |386| Problème d'entraînement | `_Site_web/data/entrainement-imm1033.js` : objet `{id, title, ch, url, gen(R)}` | build → §9 |387| Calculateur | `_Site_web/data/outils-imm1033.js` | build → §9 |388| Widget dans une séance | `courses.py → widgets` : `("s-<ch>-<sec>", "<nom>")` + `Widgets.register("<nom>", …)` dans `assets/js/app.js` | build → §9 |389| Séquence (remise en ordre) | `courses.py → sequences` : `(titre, [étapes…], "/seance/NN/#ancre")` | build → §9 |390| Calendrier, évaluations, TP publiés | `courses.py → events / evaluation / tps` | build → §9 |391| Diapositives | PDF dans `02_Slides/pdf/seance*.pdf` du cours | build → §9 |392| Rapport marché | `Rapport_Immobilier_Quebec/` (LaTeX, figures PDF, xlsx HPI, json FRED) | build → §9 |393| Style / comportement client | `assets/css/site.css`, `assets/js/app.js` | build → §9 |394395Après un rebuild des notes, penser à **ré-ingérer** le site dans **UQO-Chat** (tuteur IA, dépôt `uqo-chat`) : il396indexe le HTML de `dist/<cours>/seance/NN` pour son RAG.397398## 12. Données personnelles, sécurité, performance399400- **Aucune donnée côté serveur** : pas de compte, pas de base, pas de formulaire, pas de cookie de suivi. La401  progression, les notes, les surlignages et les préférences sont dans le `localStorage` du navigateur de402  l'étudiant·e (export/import JSON depuis `/progression`).403- Polices servies localement ou via le CSS du site ; KaTeX pré-rendu (pas de CDN mathématique au chargement).404- En-têtes de sécurité posés par `server.mjs` (§7) ; ngrok termine le TLS (`https://www.uqo-imm1033.app`).405- Performance : HTML < 300 Ko par séance avant compression, SVG compressés à la volée, cache long sur `/assets/` et406  `/files/`, `ETag`/`304`. Un site complet pèse ≈ 454 Mo dont ≈ 18 Mo de PDF.407- Accessibilité : contrastes du thème UQO vérifiés, navigation clavier, `lang="fr-CA"`, lecture audio.408409## 13. Identité visuelle410411- Couleur principale UQO **teal `#0F6180`**, or `#cca424`, couleur par partie (`part_colors`), accent du cours412  `#cca424`.413- Typographies : **Fraunces** (titres), **Source Serif 4** (texte), **Fira Sans** (interface).414- Logo : mot-symbole UQO (source Wikimedia + sources LaTeX, `generator/assets/brand/`) recoloré par `brand.py` ;415  favicons, `apple-touch-icon`, icônes PWA 192/512 et image OG 1200 × 630 générés au build.416- Le logo et le nom UQO appartiennent à l'Université du Québec en Outaouais ; usage dans le cadre du cours.417418## 14. Historique419420| Date | Étape |421|---|---|422| 2026-08-28 | Manuels LaTeX IMM1003 / IMM1033 (`uqo-notes.sty`, `latexmk`) — base du contenu |423| 2026-09-04 → 05 (nuit) | v1 : générateur `_Site_web` (latex2html, TikZ→SVG, KaTeX, quiz, outils), `server.mjs`, premier déploiement `mld` |424| 2026-09-05 (soir) | **v2 « refonte majeure »** : thème UQO, brand.py, 9 explorateurs par cours, entraînement, jeux, carte, progression, notes/audio, rapport marché intégré (HPI + FRED) ; build `2026-09-24 14:23:05`, déployé à 23:37 sur M3U96a |425| 2026-09-06 | UQO-Chat (tuteur IA) indexe ce site pour son RAG (714 passages pour les deux cours) |426| 2026-09-06 | Dépôt spbgit `uqo-imm1033.git` créé : artefact déployé + instantané du générateur + ce README |427428## 15. Droits et licence429430Contenu pédagogique © Simon-Pierre Boucher, UQO — usage réservé aux étudiant·es du cours ; toute reproduction431hors de ce cadre requiert une autorisation écrite. Code du générateur et du serveur : © Simon-Pierre Boucher, tous432droits réservés (dépôt privé). Données externes : ACI (HPI), FRED, sources citées dans la bibliographie du rapport.433434## 16. Contact435436**Simon-Pierre Boucher**437Courriel : **contact@spboucher.ai**438Git personnel : https://git.spboucher.ai (spbgit, dépôt `uqo-imm1033`)439Cours : https://www.uqo-imm1033.app · cours jumeau : https://www.uqo-imm1003.app · tuteur IA : https://www.uqo-chat.app440